If the output width/height are not an even number of MCU's, then use an intermediate buffer to ensure that the output format is XVideo-compatible

git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@308 632fc199-4ca6-4c93-a231-07263d6284db
This commit is contained in:
DRC
2010-12-10 10:58:49 +00:00
parent 9e17f7d9bc
commit f9cf5c799d
4 changed files with 97 additions and 30 deletions

View File

@@ -226,13 +226,13 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
int checkbufyuv(unsigned char *buf, unsigned long size, int w, int h,
int subsamp, int decode)
int subsamp)
{
int i, j;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
int pw=PAD(w, hsf), ph=PAD(h, vsf);
int cw=PAD(pw/hsf, decode? 8:1), ch=PAD(ph/vsf, decode? 8:1);
int ypitch=PAD(pw, decode? 8:4), uvpitch=PAD(cw, decode? 8:4);
int cw=pw/hsf, ch=ph/vsf;
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
int retval=1;
unsigned long correctsize=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
@@ -389,7 +389,7 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
writejpeg(jpegbuf, *size, tempstr);
if(yuv==YUVENCODE)
{
if(checkbufyuv(jpegbuf, *size, w, h, subsamp, 0)) printf("Passed.");
if(checkbufyuv(jpegbuf, *size, w, h, subsamp)) printf("Passed.");
else printf("FAILED!");
}
else printf("Done.");
@@ -406,7 +406,9 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
const char *pixformat; int _w=0, _h=0; double t;
unsigned long size=0;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
int pw=PAD(w, 8), ph=PAD(h, 8), cw=PAD(pw/hsf, 8), ch=PAD(ph/vsf, 8);
int pw=PAD(w, hsf), ph=PAD(h, vsf);
int cw=pw/hsf, ch=ph/vsf;
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
if(yuv==YUVDECODE) flags|=TJ_YUV;
else if(yuv==YUVENCODE) return;
@@ -435,7 +437,7 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
}
if(yuv==YUVDECODE)
size=pw*ph + (subsamp==TJ_GRAYSCALE? 0:cw*ch*(ps-1));
size=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
else
size=w*h*ps;
if((bmpbuf=(unsigned char *)malloc(size+1))==NULL)
@@ -450,7 +452,7 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
if(yuv==YUVDECODE)
{
if(checkbufyuv(bmpbuf, size, pw, ph, subsamp, 1))
if(checkbufyuv(bmpbuf, size, pw, ph, subsamp))
printf("Passed.");
else printf("FAILED!");
}
@@ -589,7 +591,9 @@ int main(int argc, char *argv[])
if(doyuv)
{
yuv=YUVDECODE;
dotest(48, 48, 3, TJ_444, "test");
dotest(35, 39, 3, TJ_444, "test");
dotest(48, 48, 1, TJ_GRAYSCALE, "test");
dotest(39, 41, 1, TJ_GRAYSCALE, "test");
}

View File

@@ -79,13 +79,15 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
int ps=_ps[pf];
int pitch=w*ps, yuvsize;
int hsf=_hsf[jpegsub], vsf=_vsf[jpegsub];
int pw=PAD(w, 8), ph=PAD(h, 8), cw=PAD(pw/hsf, 8), ch=PAD(ph/vsf, 8);
int pw=PAD(w, hsf), ph=PAD(h, vsf);
int cw=pw/hsf, ch=ph/vsf;
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
flags |= _flags[pf];
if(bu) flags |= TJ_BOTTOMUP;
if(yuv==YUVENCODE) flags |= TJ_YUV;
yuvsize=pw*ph + (jpegsub==TJ_GRAYSCALE? 0:cw*ch*2);
yuvsize=ypitch*ph + (jpegsub==TJ_GRAYSCALE? 0:uvpitch*ch*2);
if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h))) == NULL)
_throwunix("allocating image buffer");

View File

@@ -56,19 +56,23 @@ enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE};
#define TJ_YUV 512
/* If passed to tjCompress(), this causes TurboJPEG/OSS to use the
accelerated color conversion routines in libjpeg-turbo to produce a planar
YUV image that is suitable for X Video. Specifically, if a component is
subsampled along the horizontal dimension, then the width of the plane for
that component is padded to 2 in the output image (same goes for the
height, if the component is subsampled along the vertical dimension.)
Also, each line of each plane in the output image is padded to 4 bytes.
Although this will work with any subsampling option, it is really only
useful in combination with TJ_420, which produces an image compatible with
the I420 (AKA "YUV420P") format.
YUV image that is suitable for X Video. Specifically, if the chrominance
components are subsampled along the horizontal dimension, then the width
of the luminance plane is padded to 2 in the output image (same goes for
the height of the luminance plane, if the chrominance components are
subsampled along the vertical dimension.) Also, each line of each plane
in the output image is padded to 4 bytes. Although this will work with
any subsampling option, it is really only useful in combination with
TJ_420, which produces an image compatible with the I420 (AKA "YUV420P")
format.
If passed to tjDecompress(), this tells TurboJPEG/OSS to perform JPEG
decompression but to leave out the color conversion step, so a planar YUV
image is generated instead of an RGB image. In this case, the width and
height of all planes are padded to 8 in the output image.
image is generated instead of an RGB image. The padding of the planes in
this image is the same as in the above case. Note that, if the width or
height of the output image is not a multiple of 8 (or a multiple of 16
along any dimension in which chrominance subsampling is used), then an
intermediate buffer copy will be performed within TurboJPEG/OSS.
*/
typedef void* tjhandle;

View File

@@ -406,11 +406,16 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
int flags)
{
int i, row; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
checkhandle(h);
for(i=0; i<MAX_COMPONENTS; i++) outbuf[i]=NULL;
for(i=0; i<MAX_COMPONENTS; i++)
{
tmpbuf[i]=NULL; outbuf[i]=NULL;
}
if(srcbuf==NULL || size<=0
|| dstbuf==NULL || width<=0 || pitch<0 || height<=0)
@@ -428,7 +433,11 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
if(setjmp(j->jerr.jb))
{ // this will execute if LIBJPEG has an error
for(i=0; i<MAX_COMPONENTS; i++)
{
if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
if(outbuf[i]!=NULL) free(outbuf[i]);
}
if(_tmpbuf) free(_tmpbuf);
if(row_pointer) free(row_pointer);
return -1;
}
@@ -446,14 +455,42 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
for(i=0; i<dinfo->num_components; i++)
{
jpeg_component_info *compptr=&dinfo->comp_info[i];
cw[i]=compptr->width_in_blocks*DCTSIZE;
ch[i]=compptr->height_in_blocks*DCTSIZE;
int ih;
iw[i]=compptr->width_in_blocks*DCTSIZE;
ih=compptr->height_in_blocks*DCTSIZE;
cw[i]=PAD(width, dinfo->max_h_samp_factor)*compptr->h_samp_factor
/dinfo->max_h_samp_factor;
ch[i]=PAD(height, dinfo->max_v_samp_factor)*compptr->v_samp_factor
/dinfo->max_v_samp_factor;
if(iw[i]!=cw[i] || ih!=ch[i])
{
usetmpbuf=1;
th[i]=compptr->v_samp_factor*DCTSIZE/dinfo->max_v_samp_factor;
tmpbufsize+=iw[i]*th[i];
}
if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
_throw("Memory allocation failed in tjInitDecompress()");
for(row=0; row<ch[i]; row++)
{
outbuf[i][row]=ptr;
ptr+=cw[i];
ptr+=PAD(cw[i], 4);
}
}
if(usetmpbuf)
{
if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
_throw("Memory allocation failed in tjInitDecompress()");
ptr=_tmpbuf;
for(i=0; i<dinfo->num_components; i++)
{
jpeg_component_info *compptr=&dinfo->comp_info[i];
if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
_throw("Memory allocation failed in tjInitDecompress()");
for(row=0; row<th[i]; row++)
{
tmpbuf[i][row]=ptr;
ptr+=iw[i];
}
}
}
}
@@ -491,16 +528,32 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
jpeg_start_decompress(&j->dinfo);
if(flags&TJ_YUV)
{
for(row=0; row<j->dinfo.output_height;
row+=j->dinfo.max_v_samp_factor*DCTSIZE)
j_decompress_ptr dinfo=&j->dinfo;
for(row=0; row<dinfo->output_height;
row+=dinfo->max_v_samp_factor*DCTSIZE)
{
JSAMPARRAY yuvptr[MAX_COMPONENTS];
for(i=0; i<j->dinfo.num_components; i++)
for(i=0; i<dinfo->num_components; i++)
{
jpeg_component_info *compptr=&j->dinfo.comp_info[i];
yuvptr[i]=&outbuf[i][row*compptr->v_samp_factor/j->dinfo.max_v_samp_factor];
jpeg_component_info *compptr=&dinfo->comp_info[i];
if(usetmpbuf) yuvptr[i]=tmpbuf[i];
else yuvptr[i]=&outbuf[i][row*compptr->v_samp_factor
/dinfo->max_v_samp_factor];
}
jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
if(usetmpbuf)
{
int j;
for(i=0; i<dinfo->num_components; i++)
{
jpeg_component_info *compptr=&dinfo->comp_info[i];
for(j=0; j<min(th[i], dinfo->output_height-row); j++)
{
memcpy(outbuf[i][row*compptr->v_samp_factor
/dinfo->max_v_samp_factor+j], tmpbuf[i][j], cw[i]);
}
}
}
jpeg_read_raw_data(&j->dinfo, yuvptr, j->dinfo.max_v_samp_factor*DCTSIZE);
}
}
else
@@ -514,7 +567,11 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
jpeg_finish_decompress(&j->dinfo);
for(i=0; i<MAX_COMPONENTS; i++)
{
if(tmpbuf[i]) free(tmpbuf[i]);
if(outbuf[i]) free(outbuf[i]);
}
if(_tmpbuf) free(_tmpbuf);
if(row_pointer) free(row_pointer);
return 0;
}