]> granicus.if.org Git - libjpeg-turbo/commitdiff
Provide TJ_YUV option for tjDecompress() as well
authorDRC <dcommander@users.sourceforge.net>
Fri, 10 Dec 2010 04:59:13 +0000 (04:59 +0000)
committerDRC <dcommander@users.sourceforge.net>
Fri, 10 Dec 2010 04:59:13 +0000 (04:59 +0000)
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@307 632fc199-4ca6-4c93-a231-07263d6284db

ChangeLog.txt
jpegut.c
jpgtest.cxx
turbojpeg.h
turbojpegl.c

index 7a7a6713ba36e01a15535ff2a38300517bc2ca99..cd93045b3918de29470d04d5bb3a7bd444cb3ae6 100644 (file)
@@ -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
index 3344ca82df16f4a793ee0442fa0f8ced1817b78e..be2f126b1eeae9ae4b89f878a849c1c7d1769074 100644 (file)
--- 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;
 }
index 9fe0b2c49cce89fbff8f5f85c745ce52395ceacb..d0e34b414cdef4e929ea5a6874ce372dbcc717de 100644 (file)
@@ -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; j<h; j++)
+                       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(i=0; i<w*ps; i+=ps)
+                               for(j=0; j<h; j++)
                                {
-                                       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);
+                                       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]);
                        }
-               }               
-               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]);
index b4bbd2d6666fcfa7b579b8c141c9ec6020fb84bb..d2fd6d063228faa1fd327daf76580e39aee56c96 100644 (file)
@@ -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;
 
index 1d719cb59ac41189f90e65a29f45709496297dff..5ca4b4a38a89d1140b069dfeb07956eecbd0152b 100644 (file)
@@ -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)
+       {
+               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(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
-               else row_pointer[i]= &dstbuf[i*pitch];
+               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)
+       {
+               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
        {
-               jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
-                       j->dinfo.output_height-j->dinfo.output_scanline);
+               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;
 }