Provide TJ_YUV option for tjDecompress() as well

git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@307 632fc199-4ca6-4c93-a231-07263d6284db
This commit is contained in:
DRC 2010-12-10 04:59:13 +00:00
Родитель ac08ef624c
Коммит 9e17f7d9bc
5 изменённых файлов: 214 добавлений и 98 удалений

Просмотреть файл

@ -21,8 +21,8 @@ when the library is built with libjpeg v6b emulation.
[7] Added arithmetic encoding and decoding support (can be disabled via
configure or CMake options)
[8] TurboJPEG/OSS can now leverage the SIMD-accelerated color conversion
routines in libjpeg-turbo to generate planar YUV images from RGB input.
[8] Added a TJ_YUV flag to TurboJPEG/OSS which causes both the compressor and
decompressor to output planar YUV images.
Significant changes since 1.0.0

103
jpegut.c
Просмотреть файл

@ -29,6 +29,7 @@ const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
const int _hsf[NUMSUBOPT]={1, 2, 2, 1};
const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
enum {YUVENCODE=1, YUVDECODE};
int yuv=0;
int exitstatus=0;
@ -225,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 subsamp, int decode)
{
int i, j;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
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);
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 retval=1;
unsigned long correctsize=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
@ -348,7 +349,7 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
char tempstr[1024]; unsigned char *bmpbuf=NULL;
const char *pixformat; double t;
if(yuv) flags|=TJ_YUV;
if(yuv==YUVENCODE) flags|=TJ_YUV;
if(flags&TJ_BGR)
{
@ -361,7 +362,7 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB"; else pixformat="RGBA";}
}
if(ps==1) pixformat="Grayscale";
if(yuv)
if(yuv==YUVENCODE)
printf("%s %s -> %s YUV ... ", pixformat,
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp]);
else
@ -379,16 +380,16 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
t=rrtime()-t;
if(yuv)
if(yuv==YUVENCODE)
sprintf(tempstr, "%s_enc_%s_%s_%s.yuv", basefilename, pixformat,
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp]);
else
sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
writejpeg(jpegbuf, *size, tempstr);
if(yuv)
if(yuv==YUVENCODE)
{
if(checkbufyuv(jpegbuf, *size, w, h, subsamp)) printf("Passed.");
if(checkbufyuv(jpegbuf, *size, w, h, subsamp, 0)) printf("Passed.");
else printf("FAILED!");
}
else printf("Done.");
@ -399,12 +400,16 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
}
void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
int w, int h, int ps, char *basefilename, int subsamp, int qual, int flags)
int w, int h, int ps, char *basefilename, int subsamp, int flags)
{
unsigned char *bmpbuf=NULL;
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);
if(yuv) return;
if(yuv==YUVDECODE) flags|=TJ_YUV;
else if(yuv==YUVENCODE) return;
if(flags&TJ_BGR)
{
@ -417,7 +422,11 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB"; else pixformat="RGBA";}
}
if(ps==1) pixformat="Grayscale";
printf("JPEG -> %s %s ... ", pixformat, (flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
if(yuv==YUVDECODE)
printf("JPEG -> YUV %s ... ", _subnames[subsamp]);
else
printf("JPEG -> %s %s ... ", pixformat,
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
_catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
if(_w!=w || _h!=h)
@ -425,19 +434,31 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
printf("Incorrect JPEG header\n"); bailout();
}
if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
if(yuv==YUVDECODE)
size=pw*ph + (subsamp==TJ_GRAYSCALE? 0:cw*ch*(ps-1));
else
size=w*h*ps;
if((bmpbuf=(unsigned char *)malloc(size+1))==NULL)
{
printf("ERROR: Could not allocate buffer\n"); bailout();
}
memset(bmpbuf, 0, w*ps*h);
memset(bmpbuf, 0, size+1);
t=rrtime();
_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
t=rrtime()-t;
if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
else {printf("FAILED!"); dumpbuf(bmpbuf, w, h, ps, flags);}
if(yuv==YUVDECODE)
{
if(checkbufyuv(bmpbuf, size, pw, ph, subsamp, 1))
printf("Passed.");
else printf("FAILED!");
}
else
{
if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
else {printf("FAILED!"); dumpbuf(bmpbuf, w, h, ps, flags);}
}
printf(" %f ms\n\n", t*1000.);
finally:
@ -460,32 +481,32 @@ void dotest(int w, int h, int ps, int subsamp, char *basefilename)
{printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr()); bailout();}
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, 0);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, 0);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 0);
if(ps==1) goto finally;
if(ps==1 || yuv==YUVDECODE) goto finally;
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BGR);
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BOTTOMUP);
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BGR|TJ_BOTTOMUP);
if(ps==4)
{
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST);
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BGR);
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BOTTOMUP);
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
}
finally:
@ -549,20 +570,28 @@ void dotest1(void)
int main(int argc, char *argv[])
{
if(argc>1 && !stricmp(argv[1], "-yuv")) yuv=1;
dotest(35, 41, 3, TJ_444, "test");
dotest(35, 41, 4, TJ_444, "test");
if(yuv)
int doyuv=0;
if(argc>1 && !stricmp(argv[1], "-yuv")) doyuv=1;
if(doyuv) yuv=YUVENCODE;
dotest(35, 39, 3, TJ_444, "test");
dotest(39, 41, 4, TJ_444, "test");
if(doyuv)
{
dotest(35, 41, 3, TJ_422, "test");
dotest(35, 41, 4, TJ_422, "test");
dotest(35, 41, 3, TJ_420, "test");
dotest(35, 41, 4, TJ_420, "test");
dotest(41, 35, 3, TJ_422, "test");
dotest(35, 39, 4, TJ_422, "test");
dotest(39, 41, 3, TJ_420, "test");
dotest(41, 35, 4, TJ_420, "test");
}
dotest(35, 39, 1, TJ_GRAYSCALE, "test");
dotest(39, 41, 3, TJ_GRAYSCALE, "test");
dotest(41, 35, 4, TJ_GRAYSCALE, "test");
if(!doyuv) dotest1();
if(doyuv)
{
yuv=YUVDECODE;
dotest(35, 39, 3, TJ_444, "test");
dotest(39, 41, 1, TJ_GRAYSCALE, "test");
}
dotest(35, 41, 1, TJ_GRAYSCALE, "test");
dotest(35, 41, 3, TJ_GRAYSCALE, "test");
dotest(35, 41, 4, TJ_GRAYSCALE, "test");
dotest1();
return exitstatus;
}

Просмотреть файл

@ -29,6 +29,9 @@
#define _throwtj(m) _throw(m, tjGetErrorStr())
#define _throwbmp(m) _throw(m, bmpgeterr())
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
enum {YUVENCODE=1, YUVDECODE};
int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
decomponly=0, yuv=0;
const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
@ -40,6 +43,8 @@ const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
const char *_pfname[]={"RGB", "RGBA", "BGR", "BGRA", "ABGR", "ARGB"};
const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
const int _hsf[NUMSUBOPT]={1, 2, 2, 1};
const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
void printsigfig(double val, int figs)
{
@ -63,7 +68,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
{
char tempstr[1024];
FILE *outfile; tjhandle hnd;
FILE *outfile=NULL; tjhandle hnd;
unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
rrtimer timer; double elapsed;
int jpgbufsize=0, i, j, tilesizex, tilesizey, numtilesx, numtilesy, ITER;
@ -72,24 +77,28 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
|(fastupsample?TJ_FASTUPSAMPLE:0);
int ps=_ps[pf];
int pitch=w*ps;
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);
flags |= _flags[pf];
if(bu) flags |= TJ_BOTTOMUP;
if(yuv) flags |= TJ_YUV;
if(yuv==YUVENCODE) flags |= TJ_YUV;
if((rgbbuf=(unsigned char *)malloc(pitch*h)) == NULL)
yuvsize=pw*ph + (jpegsub==TJ_GRAYSCALE? 0:cw*ch*2);
if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h))) == NULL)
_throwunix("allocating image buffer");
if(!quiet)
{
if(yuv)
if(yuv==YUVENCODE)
printf("\n>>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf],
bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
else
printf("\n>>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf],
bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
}
if(yuv==YUVDECODE) dotile=0;
if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;}
do
@ -163,7 +172,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
}
if(tilesizex==w && tilesizey==h)
{
if(yuv)
if(yuv==YUVENCODE)
sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
else
sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
@ -171,13 +180,14 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
_throwunix("opening reference image");
if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
_throwunix("writing reference image");
fclose(outfile);
fclose(outfile); outfile=NULL;
if(!quiet) printf("Reference image written to %s\n", tempstr);
}
if(yuv) goto bailout;
if(yuv==YUVENCODE) goto bailout;
// Decompression test
memset(rgbbuf, 127, pitch*h); // Grey image means decompressor did nothing
if(yuv==YUVDECODE) flags |= TJ_YUV;
memset(rgbbuf, 127, max(yuvsize, pitch*h)); // Grey image means decompressor did nothing
if((hnd=tjInitDecompress())==NULL)
_throwtj("executing tjInitDecompress()");
if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
@ -214,41 +224,54 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
printf(" Dest. throughput: %f Megapixels/sec\n",
(double)(w*h)/1000000.*(double)ITER/elapsed);
}
if(tilesizex==w && tilesizey==h)
sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
useppm?"ppm":"bmp");
else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
_throwbmp("saving bitmap");
sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
if(!quiet)
printf("Computing compression error and saving to %s.\n", tempstr);
if(jpegsub==TJ_GRAYSCALE)
if(yuv==YUVDECODE)
{
for(j=0; j<h; j++)
{
for(i=0; i<w*ps; i+=ps)
{
int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
+ (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
if(y>255) y=255; if(y<0) y=0;
rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
}
}
}
sprintf(tempstr, "%s_%sQ%d.yuv", filename, _subnames[jpegsub], qual);
if((outfile=fopen(tempstr, "wb"))==NULL)
_throwunix("opening YUV image for output");
if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
_throwunix("writing YUV image");
fclose(outfile); outfile=NULL;
}
else
{
for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
if(tilesizex==w && tilesizey==h)
sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
useppm?"ppm":"bmp");
else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
_throwbmp("saving bitmap");
sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
if(!quiet)
printf("Computing compression error and saving to %s.\n", tempstr);
if(jpegsub==TJ_GRAYSCALE)
{
for(j=0; j<h; j++)
{
for(i=0; i<w*ps; i+=ps)
{
int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
+ (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
if(y>255) y=255; if(y<0) y=0;
rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
}
}
}
else
{
for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
}
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
_throwbmp("saving bitmap");
}
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
_throwbmp("saving bitmap");
// Cleanup
if(outfile) {fclose(outfile); outfile=NULL;}
if(jpegbuf)
{
for(i=0; i<numtilesx*numtilesy; i++)
@ -262,6 +285,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
return;
bailout:
if(outfile) {fclose(outfile); outfile=NULL;}
if(jpegbuf)
{
for(i=0; i<numtilesx*numtilesy; i++)
@ -384,8 +408,10 @@ void usage(char *progname)
printf(" YUV decoding in libjpeg decompressor\n\n");
printf(" [-quiet]\n");
printf(" Output in tabular rather than verbose format\n\n");
printf(" [-yuv]\n");
printf(" [-yuvencode]\n");
printf(" Encode RGB input as planar YUV rather than compressing as JPEG\n\n");
printf(" [-yuvdecode]\n");
printf(" Decode JPEG image to planar YUV rather than RGB\n\n");
printf(" NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
printf(" test will be performed for all quality values in the range.\n");
exit(1);
@ -414,15 +440,20 @@ int main(int argc, char *argv[])
{
for(i=minarg; i<argc; i++)
{
if(!stricmp(argv[i], "-yuv"))
if(!stricmp(argv[i], "-yuvencode"))
{
printf("Testing YUV planar encoding\n");
yuv=1; hiqual=qual=100;
yuv=YUVENCODE; hiqual=qual=100;
}
if(!stricmp(argv[i], "-yuvdecode"))
{
printf("Testing YUV planar decoding\n");
yuv=YUVDECODE;
}
}
}
if(!decomponly && !yuv)
if(!decomponly && yuv!=YUVENCODE)
{
minarg=3;
if(argc<minarg) usage(argv[0]);

Просмотреть файл

@ -54,13 +54,22 @@ enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE};
/* Use fast, inaccurate 4:2:2 and 4:2:0 YUV upsampling routines
(libjpeg version only) */
#define TJ_YUV 512
/* Use the TurboJPEG YUV encoder to produce a planar YUV image that is
suitable for X Video. Specifically, if either the width or the height is
subsampled, then that dimension is padded to 2 in the output image. Also,
each line of each plane in the output image is padded to 4 bytes.
/* 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 format. */
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.
*/
typedef void* tjhandle;

Просмотреть файл

@ -356,7 +356,7 @@ DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
if(setjmp(j->jerr.jb))
{ // this will execute if LIBJPEG has an error
free(j); return NULL;
}
}
jpeg_create_decompress(&j->dinfo);
j->dinfo.src=&j->jsms;
@ -405,10 +405,13 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
unsigned char *dstbuf, int width, int pitch, int height, int ps,
int flags)
{
int i; JSAMPROW *row_pointer=NULL;
int i, row; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
checkhandle(h);
for(i=0; i<MAX_COMPONENTS; i++) outbuf[i]=NULL;
if(srcbuf==NULL || size<=0
|| dstbuf==NULL || width<=0 || pitch<0 || height<=0)
_throw("Invalid argument in tjDecompress()");
@ -424,21 +427,45 @@ 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(outbuf[i]!=NULL) free(outbuf[i]);
if(row_pointer) free(row_pointer);
return -1;
}
}
j->jsms.bytes_in_buffer = size;
j->jsms.next_input_byte = srcbuf;
jpeg_read_header(&j->dinfo, TRUE);
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
_throw("Memory allocation failed in tjInitDecompress()");
for(i=0; i<height; i++)
if(flags&TJ_YUV)
{
if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
else row_pointer[i]= &dstbuf[i*pitch];
j_decompress_ptr dinfo=&j->dinfo;
JSAMPLE *ptr=dstbuf;
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;
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];
}
}
}
else
{
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
_throw("Memory allocation failed in tjInitDecompress()");
for(i=0; i<height; i++)
{
if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
else row_pointer[i]= &dstbuf[i*pitch];
}
}
if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
@ -459,15 +486,35 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
#endif
if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
jpeg_start_decompress(&j->dinfo);
while(j->dinfo.output_scanline<j->dinfo.output_height)
if(flags&TJ_YUV)
{
jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
j->dinfo.output_height-j->dinfo.output_scanline);
for(row=0; row<j->dinfo.output_height;
row+=j->dinfo.max_v_samp_factor*DCTSIZE)
{
JSAMPARRAY yuvptr[MAX_COMPONENTS];
for(i=0; i<j->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_read_raw_data(&j->dinfo, yuvptr, j->dinfo.max_v_samp_factor*DCTSIZE);
}
}
else
{
while(j->dinfo.output_scanline<j->dinfo.output_height)
{
jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
j->dinfo.output_height-j->dinfo.output_scanline);
}
}
jpeg_finish_decompress(&j->dinfo);
for(i=0; i<MAX_COMPONENTS; i++)
if(outbuf[i]) free(outbuf[i]);
if(row_pointer) free(row_pointer);
return 0;
}