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))) #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
int checkbufyuv(unsigned char *buf, unsigned long size, int w, int h, int checkbufyuv(unsigned char *buf, unsigned long size, int w, int h,
int subsamp, int decode) int subsamp)
{ {
int i, j; int i, j;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp]; int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
int pw=PAD(w, hsf), ph=PAD(h, vsf); 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 cw=pw/hsf, ch=ph/vsf;
int ypitch=PAD(pw, decode? 8:4), uvpitch=PAD(cw, decode? 8:4); int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
int retval=1; int retval=1;
unsigned long correctsize=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2); 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); writejpeg(jpegbuf, *size, tempstr);
if(yuv==YUVENCODE) 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("FAILED!");
} }
else printf("Done."); 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; const char *pixformat; int _w=0, _h=0; double t;
unsigned long size=0; unsigned long size=0;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp]; 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; if(yuv==YUVDECODE) flags|=TJ_YUV;
else if(yuv==YUVENCODE) return; else if(yuv==YUVENCODE) return;
@@ -435,7 +437,7 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
} }
if(yuv==YUVDECODE) 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 else
size=w*h*ps; size=w*h*ps;
if((bmpbuf=(unsigned char *)malloc(size+1))==NULL) 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(yuv==YUVDECODE)
{ {
if(checkbufyuv(bmpbuf, size, pw, ph, subsamp, 1)) if(checkbufyuv(bmpbuf, size, pw, ph, subsamp))
printf("Passed."); printf("Passed.");
else printf("FAILED!"); else printf("FAILED!");
} }
@@ -589,7 +591,9 @@ int main(int argc, char *argv[])
if(doyuv) if(doyuv)
{ {
yuv=YUVDECODE; yuv=YUVDECODE;
dotest(48, 48, 3, TJ_444, "test");
dotest(35, 39, 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"); 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 ps=_ps[pf];
int pitch=w*ps, yuvsize; int pitch=w*ps, yuvsize;
int hsf=_hsf[jpegsub], vsf=_vsf[jpegsub]; 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]; flags |= _flags[pf];
if(bu) flags |= TJ_BOTTOMUP; if(bu) flags |= TJ_BOTTOMUP;
if(yuv==YUVENCODE) flags |= TJ_YUV; 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) if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h))) == NULL)
_throwunix("allocating image buffer"); _throwunix("allocating image buffer");

View File

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

View File

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