From: DRC Date: Fri, 10 Dec 2010 04:59:13 +0000 (+0000) Subject: Provide TJ_YUV option for tjDecompress() as well X-Git-Tag: 1.0.90~10 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9e17f7d9bcfe77c82550d90ea674b795baef5a5a;p=libjpeg-turbo 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 --- diff --git a/ChangeLog.txt b/ChangeLog.txt index 7a7a671..cd93045 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -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 diff --git a/jpegut.c b/jpegut.c index 3344ca8..be2f126 100644 --- a/jpegut.c +++ b/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(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) { - 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"); + 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; } diff --git a/jpgtest.cxx b/jpgtest.cxx index 9fe0b2c..d0e34b4 100644 --- a/jpgtest.cxx +++ b/jpgtest.cxx @@ -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) + { + 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; j255) 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); + for(i=0; i255) 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; jjerr.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; ijerr.jb)) { // this will execute if LIBJPEG has an error + for(i=0; ijsms.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; idinfo; + JSAMPLE *ptr=dstbuf; + + for(i=0; inum_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; rowdinfo.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_scanlinedinfo.output_height) + if(flags&TJ_YUV) + { + for(row=0; rowdinfo.output_height; + row+=j->dinfo.max_v_samp_factor*DCTSIZE) + { + JSAMPARRAY yuvptr[MAX_COMPONENTS]; + for(i=0; idinfo.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 { - jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline], - j->dinfo.output_height-j->dinfo.output_scanline); + while(j->dinfo.output_scanlinedinfo.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