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:
18
jpegut.c
18
jpegut.c
@@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
24
turbojpeg.h
24
turbojpeg.h
@@ -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;
|
||||||
|
|||||||
79
turbojpegl.c
79
turbojpegl.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user