Fix an issue that prevented tjEncodeYUV3() and TJCompressor.encodeYUV() from working properly if the source image was very tiny. Basically, jpeg_start_compress() was attempting to write the JPEG headers, which was overrunning the YUV buffer. This patch removes the call to jpeg_start_compress() in tjEncodeYUV3() and replaces it with calls to the individual routines that are necessary to initialize the color converter and downsampler. TJUnitTest has also been modified to test for this condition (the buffer size regression test now works in YUV mode.)

This commit is contained in:
DRC
2014-02-11 09:45:18 +00:00
parent d3d06f42c1
commit 040c688263
4 changed files with 76 additions and 28 deletions

View File

@@ -56,6 +56,10 @@ omitted at compile time".
[4] Fixed a couple of issues whereby malformed JPEG images would cause
libjpeg-turbo to use uninitialized memory during decompression.
[5] Fixed an error ("Buffer passed to JPEG library is too small") that occurred
when calling the TurboJPEG YUV encoding function with a very small (< 5x5)
source image, and added a unit test to check for this error.
1.3.0
=====

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C)2011-2013 D. R. Commander. All Rights Reserved.
* Copyright (C)2011-2014 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -945,7 +945,7 @@ public class TJUnitTest {
private static void bufSizeTest() throws Exception {
int w, h, i, subsamp;
byte[] srcBuf, jpegBuf;
byte[] srcBuf, dstBuf;
TJCompressor tjc = null;
Random r = new Random();
@@ -959,22 +959,35 @@ public class TJUnitTest {
if (h % 100 == 0)
System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
srcBuf = new byte[w * h * 4];
jpegBuf = new byte[TJ.bufSize(w, h, subsamp)];
if (yuv == YUVENCODE)
dstBuf = new byte[TJ.bufSizeYUV(w, pad, h, subsamp)];
else
dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
for (i = 0; i < w * h * 4; i++) {
srcBuf[i] = (byte)(r.nextInt(2) * 255);
}
tjc.setSourceImage(srcBuf, w, 0, h, TJ.PF_BGRX);
tjc.setSubsamp(subsamp);
tjc.setJPEGQuality(100);
tjc.compress(jpegBuf, 0);
tjc.setYUVPad(pad);
if (yuv == YUVENCODE)
tjc.encodeYUV(dstBuf, 0);
else
tjc.compress(dstBuf, 0);
srcBuf = new byte[h * w * 4];
jpegBuf = new byte[TJ.bufSize(h, w, subsamp)];
if (yuv == YUVENCODE)
dstBuf = new byte[TJ.bufSizeYUV(h, pad, w, subsamp)];
else
dstBuf = new byte[TJ.bufSize(h, w, subsamp)];
for (i = 0; i < h * w * 4; i++) {
srcBuf[i] = (byte)(r.nextInt(2) * 255);
}
tjc.setSourceImage(srcBuf, h, 0, w, TJ.PF_BGRX);
tjc.compress(jpegBuf, 0);
if (yuv == YUVENCODE)
tjc.encodeYUV(dstBuf, 0);
else
tjc.compress(dstBuf, 0);
}
}
}
@@ -1033,9 +1046,10 @@ public class TJUnitTest {
_4byteFormats[4] = -1;
doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY,
testName);
if (!doyuv && !bi)
if (!bi)
bufSizeTest();
if (doyuv && !bi) {
System.out.print("\n--------------------\n\n");
yuv = YUVDECODE;
doTest(48, 48, onlyRGB, TJ.SAMP_444, "javatest_yuv0");
doTest(35, 39, onlyRGB, TJ.SAMP_444, "javatest_yuv1");

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C)2009-2013 D. R. Commander. All Rights Reserved.
* Copyright (C)2009-2014 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -667,9 +667,9 @@ void doTest(int w, int h, const int *formats, int nformats, int subsamp,
void bufSizeTest(void)
{
int w, h, i, subsamp;
unsigned char *srcBuf=NULL, *jpegBuf=NULL;
unsigned char *srcBuf=NULL, *dstBuf=NULL;
tjhandle handle=NULL;
unsigned long jpegSize=0;
unsigned long dstSize=0;
if((handle=tjInitCompress())==NULL) _throwtj();
@@ -684,12 +684,12 @@ void bufSizeTest(void)
if(h%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
if((srcBuf=(unsigned char *)malloc(w*h*4))==NULL)
_throw("Memory allocation failure");
if(!alloc)
if(!alloc || yuv==YUVENCODE)
{
if((jpegBuf=(unsigned char *)tjAlloc(tjBufSize(w, h, subsamp)))
==NULL)
if(yuv==YUVENCODE) dstSize=tjBufSizeYUV2(w, pad, h, subsamp);
else dstSize=tjBufSize(w, h, subsamp);
if((dstBuf=(unsigned char *)tjAlloc(dstSize))==NULL)
_throw("Memory allocation failure");
jpegSize=tjBufSize(w, h, subsamp);
}
for(i=0; i<w*h*4; i++)
@@ -698,19 +698,27 @@ void bufSizeTest(void)
else srcBuf[i]=255;
}
_tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &jpegBuf,
&jpegSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
if(yuv==YUVENCODE)
{
_tj(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
subsamp, 0));
}
else
{
_tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
&dstSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
}
free(srcBuf); srcBuf=NULL;
tjFree(jpegBuf); jpegBuf=NULL;
tjFree(dstBuf); dstBuf=NULL;
if((srcBuf=(unsigned char *)malloc(h*w*4))==NULL)
_throw("Memory allocation failure");
if(!alloc)
if(!alloc || yuv==YUVENCODE)
{
if((jpegBuf=(unsigned char *)tjAlloc(tjBufSize(h, w, subsamp)))
==NULL)
if(yuv==YUVENCODE) dstSize=tjBufSizeYUV2(h, pad, w, subsamp);
else dstSize=tjBufSize(h, w, subsamp);
if((dstBuf=(unsigned char *)tjAlloc(dstSize))==NULL)
_throw("Memory allocation failure");
jpegSize=tjBufSize(h, w, subsamp);
}
for(i=0; i<h*w*4; i++)
@@ -719,10 +727,18 @@ void bufSizeTest(void)
else srcBuf[i]=255;
}
_tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &jpegBuf,
&jpegSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
if(yuv==YUVENCODE)
{
_tj(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
subsamp, 0));
}
else
{
_tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
&dstSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
}
free(srcBuf); srcBuf=NULL;
tjFree(jpegBuf); jpegBuf=NULL;
tjFree(dstBuf); dstBuf=NULL;
}
}
}
@@ -730,7 +746,7 @@ void bufSizeTest(void)
bailout:
if(srcBuf) free(srcBuf);
if(jpegBuf) free(jpegBuf);
if(dstBuf) free(dstBuf);
if(handle) tjDestroy(handle);
}
@@ -767,9 +783,10 @@ int main(int argc, char *argv[])
doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
if(!doyuv) bufSizeTest();
bufSizeTest();
if(doyuv)
{
printf("\n--------------------\n\n");
yuv=YUVDECODE;
doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
doTest(35, 39, _onlyRGB, 1, TJSAMP_444, "test_yuv1");

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C)2009-2013 D. R. Commander. All Rights Reserved.
* Copyright (C)2009-2014 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -759,7 +759,20 @@ DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
jpeg_start_compress(cinfo, TRUE);
/* Execute only the parts of jpeg_start_compress() that we need. If we
were to call the whole jpeg_start_compress() function, then it would try
to write the file headers, which could overflow the output buffer if the
YUV image were very small. */
if(cinfo->global_state!=CSTATE_START)
_throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
(*cinfo->dest->init_destination)(cinfo);
jinit_c_master_control(cinfo, FALSE);
jinit_color_converter(cinfo);
jinit_downsampler(cinfo);
jinit_c_prep_controller(cinfo, FALSE);
(*cinfo->mem->realize_virt_arrays)((j_common_ptr)cinfo);
pw=PAD(width, cinfo->max_h_samp_factor);
ph=PAD(height, cinfo->max_v_samp_factor);