Provide TJ_YUV option for tjDecompress() as well
This commit is contained in:
@@ -21,8 +21,8 @@ when the library is built with libjpeg v6b emulation.
|
|||||||
[7] Added arithmetic encoding and decoding support (can be disabled via
|
[7] Added arithmetic encoding and decoding support (can be disabled via
|
||||||
configure or CMake options)
|
configure or CMake options)
|
||||||
|
|
||||||
[8] TurboJPEG/OSS can now leverage the SIMD-accelerated color conversion
|
[8] Added a TJ_YUV flag to TurboJPEG/OSS which causes both the compressor and
|
||||||
routines in libjpeg-turbo to generate planar YUV images from RGB input.
|
decompressor to output planar YUV images.
|
||||||
|
|
||||||
|
|
||||||
Significant changes since 1.0.0
|
Significant changes since 1.0.0
|
||||||
|
|||||||
103
jpegut.c
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 _hsf[NUMSUBOPT]={1, 2, 2, 1};
|
||||||
const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
|
const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
|
||||||
|
|
||||||
|
enum {YUVENCODE=1, YUVDECODE};
|
||||||
int yuv=0;
|
int yuv=0;
|
||||||
|
|
||||||
int exitstatus=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)))
|
#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 subsamp, int decode)
|
||||||
{
|
{
|
||||||
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=pw/hsf, ch=ph/vsf;
|
int cw=PAD(pw/hsf, decode? 8:1), ch=PAD(ph/vsf, decode? 8:1);
|
||||||
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
|
int ypitch=PAD(pw, decode? 8:4), uvpitch=PAD(cw, decode? 8: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);
|
||||||
|
|
||||||
@@ -348,7 +349,7 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
|
|||||||
char tempstr[1024]; unsigned char *bmpbuf=NULL;
|
char tempstr[1024]; unsigned char *bmpbuf=NULL;
|
||||||
const char *pixformat; double t;
|
const char *pixformat; double t;
|
||||||
|
|
||||||
if(yuv) flags|=TJ_YUV;
|
if(yuv==YUVENCODE) flags|=TJ_YUV;
|
||||||
|
|
||||||
if(flags&TJ_BGR)
|
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";}
|
else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB"; else pixformat="RGBA";}
|
||||||
}
|
}
|
||||||
if(ps==1) pixformat="Grayscale";
|
if(ps==1) pixformat="Grayscale";
|
||||||
if(yuv)
|
if(yuv==YUVENCODE)
|
||||||
printf("%s %s -> %s YUV ... ", pixformat,
|
printf("%s %s -> %s YUV ... ", pixformat,
|
||||||
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp]);
|
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp]);
|
||||||
else
|
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));
|
_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
|
||||||
t=rrtime()-t;
|
t=rrtime()-t;
|
||||||
|
|
||||||
if(yuv)
|
if(yuv==YUVENCODE)
|
||||||
sprintf(tempstr, "%s_enc_%s_%s_%s.yuv", basefilename, pixformat,
|
sprintf(tempstr, "%s_enc_%s_%s_%s.yuv", basefilename, pixformat,
|
||||||
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp]);
|
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp]);
|
||||||
else
|
else
|
||||||
sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
|
sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
|
||||||
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
|
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
|
||||||
writejpeg(jpegbuf, *size, tempstr);
|
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("FAILED!");
|
||||||
}
|
}
|
||||||
else printf("Done.");
|
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,
|
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;
|
unsigned char *bmpbuf=NULL;
|
||||||
const char *pixformat; int _w=0, _h=0; double t;
|
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)
|
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";}
|
else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB"; else pixformat="RGBA";}
|
||||||
}
|
}
|
||||||
if(ps==1) pixformat="Grayscale";
|
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));
|
_catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
|
||||||
if(_w!=w || _h!=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();
|
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();
|
printf("ERROR: Could not allocate buffer\n"); bailout();
|
||||||
}
|
}
|
||||||
memset(bmpbuf, 0, w*ps*h);
|
memset(bmpbuf, 0, size+1);
|
||||||
|
|
||||||
t=rrtime();
|
t=rrtime();
|
||||||
_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
|
_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
|
||||||
t=rrtime()-t;
|
t=rrtime()-t;
|
||||||
|
|
||||||
if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
|
if(yuv==YUVDECODE)
|
||||||
else {printf("FAILED!"); dumpbuf(bmpbuf, w, h, ps, flags);}
|
{
|
||||||
|
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.);
|
printf(" %f ms\n\n", t*1000.);
|
||||||
|
|
||||||
finally:
|
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();}
|
{printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr()); bailout();}
|
||||||
|
|
||||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, 0);
|
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);
|
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);
|
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);
|
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)
|
if(ps==4)
|
||||||
{
|
{
|
||||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
|
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);
|
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);
|
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);
|
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:
|
finally:
|
||||||
@@ -549,20 +570,28 @@ void dotest1(void)
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(argc>1 && !stricmp(argv[1], "-yuv")) yuv=1;
|
int doyuv=0;
|
||||||
dotest(35, 41, 3, TJ_444, "test");
|
if(argc>1 && !stricmp(argv[1], "-yuv")) doyuv=1;
|
||||||
dotest(35, 41, 4, TJ_444, "test");
|
if(doyuv) yuv=YUVENCODE;
|
||||||
if(yuv)
|
dotest(35, 39, 3, TJ_444, "test");
|
||||||
|
dotest(39, 41, 4, TJ_444, "test");
|
||||||
|
if(doyuv)
|
||||||
{
|
{
|
||||||
dotest(35, 41, 3, TJ_422, "test");
|
dotest(41, 35, 3, TJ_422, "test");
|
||||||
dotest(35, 41, 4, TJ_422, "test");
|
dotest(35, 39, 4, TJ_422, "test");
|
||||||
dotest(35, 41, 3, TJ_420, "test");
|
dotest(39, 41, 3, TJ_420, "test");
|
||||||
dotest(35, 41, 4, 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;
|
return exitstatus;
|
||||||
}
|
}
|
||||||
|
|||||||
115
jpgtest.cxx
115
jpgtest.cxx
@@ -29,6 +29,9 @@
|
|||||||
#define _throwtj(m) _throw(m, tjGetErrorStr())
|
#define _throwtj(m) _throw(m, tjGetErrorStr())
|
||||||
#define _throwbmp(m) _throw(m, bmpgeterr())
|
#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,
|
int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
|
||||||
decomponly=0, yuv=0;
|
decomponly=0, yuv=0;
|
||||||
const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
|
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 *_pfname[]={"RGB", "RGBA", "BGR", "BGRA", "ABGR", "ARGB"};
|
||||||
const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
|
const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
|
||||||
const char *_subnames[NUMSUBOPT]={"444", "422", "420", "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)
|
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)
|
int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
|
||||||
{
|
{
|
||||||
char tempstr[1024];
|
char tempstr[1024];
|
||||||
FILE *outfile; tjhandle hnd;
|
FILE *outfile=NULL; tjhandle hnd;
|
||||||
unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
|
unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
|
||||||
rrtimer timer; double elapsed;
|
rrtimer timer; double elapsed;
|
||||||
int jpgbufsize=0, i, j, tilesizex, tilesizey, numtilesx, numtilesy, ITER;
|
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)
|
|(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
|
||||||
|(fastupsample?TJ_FASTUPSAMPLE:0);
|
|(fastupsample?TJ_FASTUPSAMPLE:0);
|
||||||
int ps=_ps[pf];
|
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];
|
flags |= _flags[pf];
|
||||||
if(bu) flags |= TJ_BOTTOMUP;
|
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");
|
_throwunix("allocating image buffer");
|
||||||
|
|
||||||
if(!quiet)
|
if(!quiet)
|
||||||
{
|
{
|
||||||
if(yuv)
|
if(yuv==YUVENCODE)
|
||||||
printf("\n>>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf],
|
printf("\n>>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf],
|
||||||
bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
|
bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
|
||||||
else
|
else
|
||||||
printf("\n>>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf],
|
printf("\n>>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf],
|
||||||
bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
|
bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
|
||||||
}
|
}
|
||||||
|
if(yuv==YUVDECODE) dotile=0;
|
||||||
if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;}
|
if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;}
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -163,7 +172,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||||||
}
|
}
|
||||||
if(tilesizex==w && tilesizey==h)
|
if(tilesizex==w && tilesizey==h)
|
||||||
{
|
{
|
||||||
if(yuv)
|
if(yuv==YUVENCODE)
|
||||||
sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
|
sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
|
||||||
else
|
else
|
||||||
sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
|
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");
|
_throwunix("opening reference image");
|
||||||
if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
|
if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
|
||||||
_throwunix("writing reference image");
|
_throwunix("writing reference image");
|
||||||
fclose(outfile);
|
fclose(outfile); outfile=NULL;
|
||||||
if(!quiet) printf("Reference image written to %s\n", tempstr);
|
if(!quiet) printf("Reference image written to %s\n", tempstr);
|
||||||
}
|
}
|
||||||
if(yuv) goto bailout;
|
if(yuv==YUVENCODE) goto bailout;
|
||||||
|
|
||||||
// Decompression test
|
// 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)
|
if((hnd=tjInitDecompress())==NULL)
|
||||||
_throwtj("executing tjInitDecompress()");
|
_throwtj("executing tjInitDecompress()");
|
||||||
if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
|
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",
|
printf(" Dest. throughput: %f Megapixels/sec\n",
|
||||||
(double)(w*h)/1000000.*(double)ITER/elapsed);
|
(double)(w*h)/1000000.*(double)ITER/elapsed);
|
||||||
}
|
}
|
||||||
if(tilesizex==w && tilesizey==h)
|
if(yuv==YUVDECODE)
|
||||||
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++)
|
sprintf(tempstr, "%s_%sQ%d.yuv", filename, _subnames[jpegsub], qual);
|
||||||
{
|
if((outfile=fopen(tempstr, "wb"))==NULL)
|
||||||
for(i=0; i<w*ps; i+=ps)
|
_throwunix("opening YUV image for output");
|
||||||
{
|
if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
|
||||||
int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
|
_throwunix("writing YUV image");
|
||||||
+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
|
fclose(outfile); outfile=NULL;
|
||||||
+ (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
|
else
|
||||||
{
|
{
|
||||||
for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
|
if(tilesizex==w && tilesizey==h)
|
||||||
rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
|
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
|
// Cleanup
|
||||||
|
if(outfile) {fclose(outfile); outfile=NULL;}
|
||||||
if(jpegbuf)
|
if(jpegbuf)
|
||||||
{
|
{
|
||||||
for(i=0; i<numtilesx*numtilesy; i++)
|
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;
|
return;
|
||||||
|
|
||||||
bailout:
|
bailout:
|
||||||
|
if(outfile) {fclose(outfile); outfile=NULL;}
|
||||||
if(jpegbuf)
|
if(jpegbuf)
|
||||||
{
|
{
|
||||||
for(i=0; i<numtilesx*numtilesy; i++)
|
for(i=0; i<numtilesx*numtilesy; i++)
|
||||||
@@ -384,8 +408,10 @@ void usage(char *progname)
|
|||||||
printf(" YUV decoding in libjpeg decompressor\n\n");
|
printf(" YUV decoding in libjpeg decompressor\n\n");
|
||||||
printf(" [-quiet]\n");
|
printf(" [-quiet]\n");
|
||||||
printf(" Output in tabular rather than verbose format\n\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(" 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(" 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");
|
printf(" test will be performed for all quality values in the range.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -414,15 +440,20 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
for(i=minarg; i<argc; i++)
|
for(i=minarg; i<argc; i++)
|
||||||
{
|
{
|
||||||
if(!stricmp(argv[i], "-yuv"))
|
if(!stricmp(argv[i], "-yuvencode"))
|
||||||
{
|
{
|
||||||
printf("Testing YUV planar encoding\n");
|
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;
|
minarg=3;
|
||||||
if(argc<minarg) usage(argv[0]);
|
if(argc<minarg) usage(argv[0]);
|
||||||
|
|||||||
21
turbojpeg.h
21
turbojpeg.h
@@ -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
|
/* Use fast, inaccurate 4:2:2 and 4:2:0 YUV upsampling routines
|
||||||
(libjpeg version only) */
|
(libjpeg version only) */
|
||||||
#define TJ_YUV 512
|
#define TJ_YUV 512
|
||||||
/* Use the TurboJPEG YUV encoder to produce a planar YUV image that is
|
/* If passed to tjCompress(), this causes TurboJPEG/OSS to use the
|
||||||
suitable for X Video. Specifically, if either the width or the height is
|
accelerated color conversion routines in libjpeg-turbo to produce a planar
|
||||||
subsampled, then that dimension is padded to 2 in the output image. Also,
|
YUV image that is suitable for X Video. Specifically, if a component is
|
||||||
each line of each plane in the output image is padded to 4 bytes.
|
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
|
Although this will work with any subsampling option, it is really only
|
||||||
useful in combination with TJ_420, which produces an image compatible
|
useful in combination with TJ_420, which produces an image compatible with
|
||||||
with the I420 format. */
|
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;
|
typedef void* tjhandle;
|
||||||
|
|
||||||
|
|||||||
69
turbojpegl.c
69
turbojpegl.c
@@ -356,7 +356,7 @@ DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
|
|||||||
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
|
||||||
free(j); return NULL;
|
free(j); return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_create_decompress(&j->dinfo);
|
jpeg_create_decompress(&j->dinfo);
|
||||||
j->dinfo.src=&j->jsms;
|
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,
|
unsigned char *dstbuf, int width, int pitch, int height, int ps,
|
||||||
int flags)
|
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);
|
checkhandle(h);
|
||||||
|
|
||||||
|
for(i=0; i<MAX_COMPONENTS; i++) 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)
|
||||||
_throw("Invalid argument in tjDecompress()");
|
_throw("Invalid argument in tjDecompress()");
|
||||||
@@ -424,21 +427,45 @@ 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++)
|
||||||
|
if(outbuf[i]!=NULL) free(outbuf[i]);
|
||||||
if(row_pointer) free(row_pointer);
|
if(row_pointer) free(row_pointer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
j->jsms.bytes_in_buffer = size;
|
j->jsms.bytes_in_buffer = size;
|
||||||
j->jsms.next_input_byte = srcbuf;
|
j->jsms.next_input_byte = srcbuf;
|
||||||
|
|
||||||
jpeg_read_header(&j->dinfo, TRUE);
|
jpeg_read_header(&j->dinfo, TRUE);
|
||||||
|
|
||||||
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
|
if(flags&TJ_YUV)
|
||||||
_throw("Memory allocation failed in tjInitDecompress()");
|
|
||||||
for(i=0; i<height; i++)
|
|
||||||
{
|
{
|
||||||
if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
|
j_decompress_ptr dinfo=&j->dinfo;
|
||||||
else row_pointer[i]= &dstbuf[i*pitch];
|
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;
|
if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
|
||||||
@@ -459,15 +486,35 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
|
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);
|
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],
|
for(row=0; row<j->dinfo.output_height;
|
||||||
j->dinfo.output_height-j->dinfo.output_scanline);
|
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);
|
jpeg_finish_decompress(&j->dinfo);
|
||||||
|
|
||||||
|
for(i=0; i<MAX_COMPONENTS; i++)
|
||||||
|
if(outbuf[i]) free(outbuf[i]);
|
||||||
if(row_pointer) free(row_pointer);
|
if(row_pointer) free(row_pointer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user