/* Copyright (C)2004 Landmark Graphics Corporation * Copyright (C)2005, 2006 Sun Microsystems, Inc. * Copyright (C)2009-2011 D. R. Commander * * This library is free software and may be redistributed and/or modified under * the terms of the wxWindows Library License, Version 3.1 or (at your option) * any later version. The full license is in the LICENSE.txt file included * with this distribution. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * wxWindows Library License for more details. */ #include #include #include #include #include #include "./bmp.h" #include "./rrutil.h" #include "./rrtimer.h" #include "./turbojpeg.h" #define _throw(op, err) { \ printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \ retval=-1; goto bailout;} #define _throwunix(m) _throw(m, strerror(errno)) #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, quiet=0, dotile=0, pf=BMP_BGR, bu=0, useppm=0, scale_num=1, scale_denom=1; const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4}; const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR, TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST}; const int _rindex[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1}; const int _gindex[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2}; const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3}; const char *_pfname[]={"RGB", "RGBX", "BGR", "BGRX", "XBGR", "XRGB"}; const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"}; const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"}; tjscalingfactor *sf=NULL; int nsf=0; void printsigfig(double val, int figs) { char format[80]; double _l=log10(val); int l; if(_l<0.) { l=(int)fabs(_l); sprintf(format, "%%%d.%df", figs+l+2, figs+l); } else { l=(int)_l+1; if(figs<=l) sprintf(format, "%%.0f"); else sprintf(format, "%%%d.%df", figs+1, figs-l); } printf(format, val); } // Decompression test int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf, unsigned long *comptilesize, unsigned char *rgbbuf, int w, int h, int jpegsub, int qual, char *filename, int tilesizex, int tilesizey) { char tempstr[1024], qualstr[5]="\0"; FILE *outfile=NULL; tjhandle hnd=NULL; int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0) |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0) |(fastupsample?TJ_FASTUPSAMPLE:0); int i, j, ITER, rgbbufalloc=0, retval=0; double start, elapsed; int ps=_ps[pf]; int yuvsize=TJBUFSIZEYUV(w, h, jpegsub), bufsize; int scaledw=(yuv==YUVDECODE)? w : (w*scale_num+scale_denom-1)/scale_denom; int scaledh=(yuv==YUVDECODE)? h : (h*scale_num+scale_denom-1)/scale_denom; int pitch=scaledw*ps; if(qual>0) { snprintf(qualstr, 5, "Q%d", qual); qualstr[4]=0; } flags |= _flags[pf]; if(bu) flags |= TJ_BOTTOMUP; if((hnd=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()"); bufsize=(yuv==YUVDECODE? yuvsize:pitch*h); if(rgbbuf==NULL) { if((rgbbuf=(unsigned char *)malloc(bufsize)) == NULL) _throwunix("allocating image buffer"); rgbbufalloc=1; } // Grey image means decompressor did nothing memset(rgbbuf, 127, bufsize); if(yuv==YUVDECODE) { if(tjDecompressToYUV(hnd, jpegbuf[0], comptilesize[0], rgbbuf, flags)==-1) _throwtj("executing tjDecompressToYUV()"); } else if(tjDecompress(hnd, jpegbuf[0], comptilesize[0], rgbbuf, scaledw, pitch, scaledh, ps, flags)==-1) _throwtj("executing tjDecompress()"); ITER=0; start=rrtime(); do { int tilen=0; for(i=0; i Frame rate: %f fps\n", (double)ITER/elapsed); printf(" Dest. throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)ITER/elapsed); } if(yuv==YUVDECODE) { sprintf(tempstr, "%s_%s%s.yuv", filename, _subnames[jpegsub], qualstr); 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 { if(tilesizex==w && tilesizey==h) { if(decomponly) sprintf(tempstr, "%s_full.%s", filename, useppm?"ppm":"bmp"); else sprintf(tempstr, "%s_%s%s_full.%s", filename, _subnames[jpegsub], qualstr, useppm?"ppm":"bmp"); } else sprintf(tempstr, "%s_%s%s_%dx%d.%s", filename, _subnames[jpegsub], qualstr, tilesizex, tilesizey, useppm?"ppm":"bmp"); if(savebmp(tempstr, rgbbuf, scaledw, scaledh, pf, pitch, bu)==-1) _throwbmp("saving bitmap"); sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp"); if(srcbuf && scale_num==1 && scale_denom==1) { if(!quiet) printf("Computing compression error and saving to %s.\n", tempstr); if(jpegsub==TJ_GRAYSCALE) { 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); } } } else { for(j=0; j>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf], bu?"Bottom-up":"Top-down", _subnamel[jpegsub]); else printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf], bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual); } if(yuv) dotile=0; if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;} do { tilesizex*=2; if(tilesizex>w) tilesizex=w; tilesizey*=2; if(tilesizey>h) tilesizey=h; numtilesx=(w+tilesizex-1)/tilesizex; numtilesy=(h+tilesizey-1)/tilesizey; if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)*numtilesx*numtilesy)) == NULL || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)*numtilesx*numtilesy)) == NULL) _throwunix("allocating image buffers"); memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy); for(i=0; i Frame rate: %f fps\n", (double)ITER/elapsed); printf(" Output image size: %d bytes\n", jpgbufsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)jpgbufsize); printf(" Source throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)ITER/elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)jpgbufsize*8./1000000.*(double)ITER/elapsed); } if(tilesizex==w && tilesizey==h) { if(yuv==YUVENCODE) sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]); else sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual); if((outfile=fopen(tempstr, "wb"))==NULL) _throwunix("opening reference image"); if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1) _throwunix("writing reference image"); fclose(outfile); outfile=NULL; if(!quiet) printf("Reference image written to %s\n", tempstr); } if(yuv==YUVENCODE) { if(quiet==1) printf("\n"); goto bailout; } // Decompression test if(decomptest(srcbuf, jpegbuf, comptilesize, rgbbuf, w, h, jpegsub, qual, filename, tilesizex, tilesizey)==-1) goto bailout; // Cleanup for(i=0; i>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf], bu?"Bottom-up":"Top-down"); } do { tilesizex*=2; if(tilesizex>w) tilesizex=w; tilesizey*=2; if(tilesizey>h) tilesizey=h; numtilesx=(w+tilesizex-1)/tilesizex; numtilesy=(h+tilesizey-1)/tilesizey; if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long) *numtilesx*numtilesy))==NULL || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) *numtilesx*numtilesy))==NULL) _throwunix("allocating image buffers"); memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy); for(i=0; i Frame rate: %f fps\n", 1.0/elapsed); printf(" Output image size: %lu bytes\n", jpgbufsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)jpgbufsize); printf(" Source throughput: %f Megapixels/sec\n", (double)(w*h)/1000000./elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)jpgbufsize*8./1000000./elapsed); } if(decomptest(NULL, jpegbuf, comptilesize, NULL, w, h, jpegsub, 0, filename, tilesizex, tilesizey)==-1) goto bailout; // Cleanup for(i=0; i>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]); else printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf], bu?"Bottom-up":"Top-down"); printf("\nImage size: %d x %d", w, h); if(scale_num!=1 || scale_denom!=1) printf(" --> %d x %d", (w*scale_num+scale_denom-1)/scale_denom, (h*scale_num+scale_denom-1)/scale_denom); printf("\n"); } decomptest(NULL, &srcbuf, &srcbufsize, NULL, w, h, jpegsub, 0, filename, w, h); } bailout: if(file) {fclose(file); file=NULL;} if(jpegbuf) { for(i=0; i <%% Quality> [options]\n\n"); printf(" %s\n", progname); printf(" [options]\n\n"); printf("Options:\n\n"); printf("-tile = Test performance of the codec when the image is encoded as separate\n"); printf(" tiles of varying sizes.\n"); printf("-forcemmx, -forcesse, -forcesse2, -forcesse3 =\n"); printf(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n"); printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n"); printf(" Test the specified color conversion path in the codec (default: BGR)\n"); printf("-fastupsample = Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n"); printf(" YUV decoding in libjpeg decompressor\n"); printf("-quiet = Output results in tabular rather than verbose format\n"); printf("-yuvencode = Encode RGB input as planar YUV rather than compressing as JPEG\n"); printf("-yuvdecode = Decode JPEG image to planar YUV rather than RGB\n"); printf("-scale M/N = scale down the width/height of the decompressed JPEG image by a\n"); printf(" factor of M/N (M/N = "); for(i=0; i2) { if(i!=nsf-1) printf(", "); if(i==nsf-2) printf("or "); } } printf(")\n\n"); printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n"); printf("test will be performed for all quality values in the range.\n\n"); exit(1); } int main(int argc, char *argv[]) { unsigned char *bmpbuf=NULL; int w, h, i, j; int qual=-1, hiqual=-1; char *temp; int minarg=2; int retval=0; if((sf=tjGetScalingFactors(&nsf))==NULL || nsf==0) _throwtj("executing tjGetScalingFactors()"); if(argcminarg) { for(i=minarg; i100) { puts("ERROR: Quality must be between 1 and 100."); exit(1); } if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1 && sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1 && hiqual<=100) {} else hiqual=qual; } if(argc>minarg) { for(i=minarg; i=qual; i--) dotest(bmpbuf, w, h, TJ_GRAYSCALE, i, argv[1]); printf("\n"); for(i=hiqual; i>=qual; i--) dotest(bmpbuf, w, h, TJ_420, i, argv[1]); printf("\n"); for(i=hiqual; i>=qual; i--) dotest(bmpbuf, w, h, TJ_422, i, argv[1]); printf("\n"); for(i=hiqual; i>=qual; i--) dotest(bmpbuf, w, h, TJ_444, i, argv[1]); printf("\n"); bailout: if(bmpbuf) free(bmpbuf); return retval; }