1/* 2 * Copyright (C)2009-2014 D. R. Commander. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of the libjpeg-turbo Project nor the names of its 13 * contributors may be used to endorse or promote products derived from this 14 * software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <ctype.h> 33#include <math.h> 34#include <errno.h> 35#include <cdjpeg.h> 36#include "./bmp.h" 37#include "./tjutil.h" 38#include "./turbojpeg.h" 39 40 41#define _throw(op, err) { \ 42 printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \ 43 retval=-1; goto bailout;} 44#define _throwunix(m) _throw(m, strerror(errno)) 45#define _throwtj(m) _throw(m, tjGetErrorStr()) 46#define _throwbmp(m) _throw(m, bmpgeterr()) 47 48enum {YUVENCODE=1, YUVDECODE}; 49int flags=TJFLAG_NOREALLOC, decomponly=0, yuv=0, quiet=0, dotile=0, 50 pf=TJPF_BGR; 51char *ext="ppm"; 52const char *pixFormatStr[TJ_NUMPF]= 53{ 54 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY" 55}; 56const char *subNameLong[TJ_NUMSAMP]= 57{ 58 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0" 59}; 60const char *subName[NUMSUBOPT]={"444", "422", "420", "GRAY", "440"}; 61tjscalingfactor *scalingfactors=NULL, sf={1, 1}; int nsf=0; 62int xformop=TJXOP_NONE, xformopt=0; 63int (*customFilter)(short *, tjregion, tjregion, int, int, tjtransform *); 64double benchtime=5.0; 65 66 67char *sigfig(double val, int figs, char *buf, int len) 68{ 69 char format[80]; 70 int digitsafterdecimal=figs-(int)ceil(log10(fabs(val))); 71 if(digitsafterdecimal<1) snprintf(format, 80, "%%.0f"); 72 else snprintf(format, 80, "%%.%df", digitsafterdecimal); 73 snprintf(buf, len, format, val); 74 return buf; 75} 76 77 78/* Custom DCT filter which produces a negative of the image */ 79int dummyDCTFilter(short *coeffs, tjregion arrayRegion, tjregion planeRegion, 80 int componentIndex, int transformIndex, tjtransform *transform) 81{ 82 int i; 83 for(i=0; i<arrayRegion.w*arrayRegion.h; i++) coeffs[i]=-coeffs[i]; 84 return 0; 85} 86 87 88/* Decompression test */ 89int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf, 90 unsigned long *jpegsize, unsigned char *dstbuf, int w, int h, 91 int subsamp, int jpegqual, char *filename, int tilew, int tileh) 92{ 93 char tempstr[1024], sizestr[20]="\0", qualstr[6]="\0", *ptr; 94 FILE *file=NULL; tjhandle handle=NULL; 95 int row, col, i, dstbufalloc=0, retval=0; 96 double start, elapsed; 97 int ps=tjPixelSize[pf]; 98 int yuvsize=tjBufSizeYUV(w, h, subsamp), bufsize; 99 int scaledw=(yuv==YUVDECODE)? w : TJSCALED(w, sf); 100 int scaledh=(yuv==YUVDECODE)? h : TJSCALED(h, sf); 101 int pitch=scaledw*ps; 102 int ntilesw=(w+tilew-1)/tilew, ntilesh=(h+tileh-1)/tileh; 103 unsigned char *dstptr, *dstptr2; 104 105 if(jpegqual>0) 106 { 107 snprintf(qualstr, 6, "_Q%d", jpegqual); 108 qualstr[5]=0; 109 } 110 111 if((handle=tjInitDecompress())==NULL) 112 _throwtj("executing tjInitDecompress()"); 113 114 bufsize=(yuv==YUVDECODE? yuvsize:pitch*scaledh); 115 if(dstbuf==NULL) 116 { 117 if((dstbuf=(unsigned char *)malloc(bufsize)) == NULL) 118 _throwunix("allocating image buffer"); 119 dstbufalloc=1; 120 } 121 /* Set the destination buffer to gray so we know whether the decompressor 122 attempted to write to it */ 123 memset(dstbuf, 127, bufsize); 124 125 /* Execute once to preload cache */ 126 if(yuv==YUVDECODE) 127 { 128 if(tjDecompressToYUV(handle, jpegbuf[0], jpegsize[0], dstbuf, flags)==-1) 129 _throwtj("executing tjDecompressToYUV()"); 130 } 131 else if(tjDecompress2(handle, jpegbuf[0], jpegsize[0], dstbuf, scaledw, 132 pitch, scaledh, pf, flags)==-1) 133 _throwtj("executing tjDecompress2()"); 134 135 /* Benchmark */ 136 for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++) 137 { 138 int tile=0; 139 if(yuv==YUVDECODE) 140 { 141 if(tjDecompressToYUV(handle, jpegbuf[0], jpegsize[0], dstbuf, flags)==-1) 142 _throwtj("executing tjDecompressToYUV()"); 143 } 144 else for(row=0, dstptr=dstbuf; row<ntilesh; row++, dstptr+=pitch*tileh) 145 { 146 for(col=0, dstptr2=dstptr; col<ntilesw; col++, tile++, dstptr2+=ps*tilew) 147 { 148 int width=dotile? min(tilew, w-col*tilew):scaledw; 149 int height=dotile? min(tileh, h-row*tileh):scaledh; 150 if(tjDecompress2(handle, jpegbuf[tile], jpegsize[tile], dstptr2, width, 151 pitch, height, pf, flags)==-1) 152 _throwtj("executing tjDecompress2()"); 153 } 154 } 155 } 156 157 if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); 158 handle=NULL; 159 160 if(quiet) 161 { 162 printf("%s\n", 163 sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024)); 164 } 165 else 166 { 167 printf("D--> Frame rate: %f fps\n", (double)i/elapsed); 168 printf(" Dest. throughput: %f Megapixels/sec\n", 169 (double)(w*h)/1000000.*(double)i/elapsed); 170 } 171 if(yuv==YUVDECODE) 172 { 173 snprintf(tempstr, 1024, "%s_%s%s.yuv", filename, subName[subsamp], 174 qualstr); 175 if((file=fopen(tempstr, "wb"))==NULL) 176 _throwunix("opening YUV image for output"); 177 if(fwrite(dstbuf, yuvsize, 1, file)!=1) 178 _throwunix("writing YUV image"); 179 fclose(file); file=NULL; 180 } 181 else 182 { 183 if(sf.num!=1 || sf.denom!=1) 184 snprintf(sizestr, 20, "%d_%d", sf.num, sf.denom); 185 else if(tilew!=w || tileh!=h) 186 snprintf(sizestr, 20, "%dx%d", tilew, tileh); 187 else snprintf(sizestr, 20, "full"); 188 if(decomponly) 189 snprintf(tempstr, 1024, "%s_%s.%s", filename, sizestr, ext); 190 else 191 snprintf(tempstr, 1024, "%s_%s%s_%s.%s", filename, subName[subsamp], 192 qualstr, sizestr, ext); 193 if(savebmp(tempstr, dstbuf, scaledw, scaledh, pf, 194 (flags&TJFLAG_BOTTOMUP)!=0)==-1) 195 _throwbmp("saving bitmap"); 196 ptr=strrchr(tempstr, '.'); 197 snprintf(ptr, 1024-(ptr-tempstr), "-err.%s", ext); 198 if(srcbuf && sf.num==1 && sf.denom==1) 199 { 200 if(!quiet) printf("Compression error written to %s.\n", tempstr); 201 if(subsamp==TJ_GRAYSCALE) 202 { 203 int index, index2; 204 for(row=0, index=0; row<h; row++, index+=pitch) 205 { 206 for(col=0, index2=index; col<w; col++, index2+=ps) 207 { 208 int rindex=index2+tjRedOffset[pf]; 209 int gindex=index2+tjGreenOffset[pf]; 210 int bindex=index2+tjBlueOffset[pf]; 211 int y=(int)((double)srcbuf[rindex]*0.299 212 + (double)srcbuf[gindex]*0.587 213 + (double)srcbuf[bindex]*0.114 + 0.5); 214 if(y>255) y=255; if(y<0) y=0; 215 dstbuf[rindex]=abs(dstbuf[rindex]-y); 216 dstbuf[gindex]=abs(dstbuf[gindex]-y); 217 dstbuf[bindex]=abs(dstbuf[bindex]-y); 218 } 219 } 220 } 221 else 222 { 223 for(row=0; row<h; row++) 224 for(col=0; col<w*ps; col++) 225 dstbuf[pitch*row+col] 226 =abs(dstbuf[pitch*row+col]-srcbuf[pitch*row+col]); 227 } 228 if(savebmp(tempstr, dstbuf, w, h, pf, 229 (flags&TJFLAG_BOTTOMUP)!=0)==-1) 230 _throwbmp("saving bitmap"); 231 } 232 } 233 234 bailout: 235 if(file) {fclose(file); file=NULL;} 236 if(handle) {tjDestroy(handle); handle=NULL;} 237 if(dstbuf && dstbufalloc) {free(dstbuf); dstbuf=NULL;} 238 return retval; 239} 240 241 242void dotestyuv(unsigned char *srcbuf, int w, int h, int subsamp, 243 char *filename) 244{ 245 char tempstr[1024], tempstr2[80]; 246 FILE *file=NULL; tjhandle handle=NULL; 247 unsigned char *dstbuf=NULL; 248 double start, elapsed; 249 int i, retval=0, ps=tjPixelSize[pf]; 250 int yuvsize=0; 251 252 yuvsize=tjBufSizeYUV(w, h, subsamp); 253 if((dstbuf=(unsigned char *)malloc(yuvsize)) == NULL) 254 _throwunix("allocating image buffer"); 255 256 if(!quiet) 257 printf(">>>>> %s (%s) <--> YUV %s <<<<<\n", pixFormatStr[pf], 258 (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down", subNameLong[subsamp]); 259 260 if(quiet==1) 261 printf("%s\t%s\t%s\tN/A\t", pixFormatStr[pf], 262 (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp]); 263 264 if((handle=tjInitCompress())==NULL) 265 _throwtj("executing tjInitCompress()"); 266 267 /* Execute once to preload cache */ 268 if(tjEncodeYUV2(handle, srcbuf, w, 0, h, pf, dstbuf, subsamp, flags)==-1) 269 _throwtj("executing tjEncodeYUV2()"); 270 271 /* Benchmark */ 272 for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++) 273 { 274 if(tjEncodeYUV2(handle, srcbuf, w, 0, h, pf, dstbuf, subsamp, flags)==-1) 275 _throwtj("executing tjEncodeYUV2()"); 276 } 277 278 if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); 279 handle=NULL; 280 281 if(quiet==1) printf("%-4d %-4d\t", w, h); 282 if(quiet) 283 { 284 printf("%s%c%s%c", 285 sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024), 286 quiet==2? '\n':'\t', 287 sigfig((double)(w*h*ps)/(double)yuvsize, 4, tempstr2, 80), 288 quiet==2? '\n':'\t'); 289 } 290 else 291 { 292 printf("\n%s size: %d x %d\n", "Image", w, h); 293 printf("C--> Frame rate: %f fps\n", (double)i/elapsed); 294 printf(" Output image size: %d bytes\n", yuvsize); 295 printf(" Compression ratio: %f:1\n", 296 (double)(w*h*ps)/(double)yuvsize); 297 printf(" Source throughput: %f Megapixels/sec\n", 298 (double)(w*h)/1000000.*(double)i/elapsed); 299 printf(" Output bit stream: %f Megabits/sec\n", 300 (double)yuvsize*8./1000000.*(double)i/elapsed); 301 } 302 snprintf(tempstr, 1024, "%s_%s.yuv", filename, subName[subsamp]); 303 if((file=fopen(tempstr, "wb"))==NULL) 304 _throwunix("opening reference image"); 305 if(fwrite(dstbuf, yuvsize, 1, file)!=1) 306 _throwunix("writing reference image"); 307 fclose(file); file=NULL; 308 if(!quiet) printf("Reference image written to %s\n", tempstr); 309 310 bailout: 311 if(file) {fclose(file); file=NULL;} 312 if(dstbuf) {free(dstbuf); dstbuf=NULL;} 313 if(handle) {tjDestroy(handle); handle=NULL;} 314 return; 315} 316 317 318void dotest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual, 319 char *filename) 320{ 321 char tempstr[1024], tempstr2[80]; 322 FILE *file=NULL; tjhandle handle=NULL; 323 unsigned char **jpegbuf=NULL, *tmpbuf=NULL, *srcptr, *srcptr2; 324 double start, elapsed; 325 int totaljpegsize=0, row, col, i, tilew=w, tileh=h, retval=0; 326 unsigned long *jpegsize=NULL; 327 int ps=tjPixelSize[pf], ntilesw=1, ntilesh=1, pitch=w*ps; 328 329 if(yuv==YUVENCODE) {dotestyuv(srcbuf, w, h, subsamp, filename); return;} 330 331 if((tmpbuf=(unsigned char *)malloc(pitch*h)) == NULL) 332 _throwunix("allocating temporary image buffer"); 333 334 if(!quiet) 335 printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pixFormatStr[pf], 336 (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down", subNameLong[subsamp], 337 jpegqual); 338 339 for(tilew=dotile? 8:w, tileh=dotile? 8:h; ; tilew*=2, tileh*=2) 340 { 341 if(tilew>w) tilew=w; if(tileh>h) tileh=h; 342 ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; 343 344 if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) 345 *ntilesw*ntilesh))==NULL) 346 _throwunix("allocating JPEG tile array"); 347 memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh); 348 if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long) 349 *ntilesw*ntilesh))==NULL) 350 _throwunix("allocating JPEG size array"); 351 memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh); 352 353 if((flags&TJFLAG_NOREALLOC)!=0) 354 for(i=0; i<ntilesw*ntilesh; i++) 355 { 356 if((jpegbuf[i]=(unsigned char *)malloc(tjBufSize(tilew, tileh, 357 subsamp)))==NULL) 358 _throwunix("allocating JPEG tiles"); 359 } 360 361 /* Compression test */ 362 if(quiet==1) 363 printf("%s\t%s\t%s\t%d\t", pixFormatStr[pf], 364 (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp], jpegqual); 365 for(i=0; i<h; i++) 366 memcpy(&tmpbuf[pitch*i], &srcbuf[w*ps*i], w*ps); 367 if((handle=tjInitCompress())==NULL) 368 _throwtj("executing tjInitCompress()"); 369 370 /* Execute once to preload cache */ 371 if(tjCompress2(handle, srcbuf, tilew, pitch, tileh, pf, &jpegbuf[0], 372 &jpegsize[0], subsamp, jpegqual, flags)==-1) 373 _throwtj("executing tjCompress2()"); 374 375 /* Benchmark */ 376 for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++) 377 { 378 int tile=0; 379 totaljpegsize=0; 380 for(row=0, srcptr=srcbuf; row<ntilesh; row++, srcptr+=pitch*tileh) 381 { 382 for(col=0, srcptr2=srcptr; col<ntilesw; col++, tile++, 383 srcptr2+=ps*tilew) 384 { 385 int width=min(tilew, w-col*tilew); 386 int height=min(tileh, h-row*tileh); 387 if(tjCompress2(handle, srcptr2, width, pitch, height, pf, 388 &jpegbuf[tile], &jpegsize[tile], subsamp, jpegqual, flags)==-1) 389 _throwtj("executing tjCompress()2"); 390 totaljpegsize+=jpegsize[tile]; 391 } 392 } 393 } 394 395 if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); 396 handle=NULL; 397 398 if(quiet==1) printf("%-4d %-4d\t", tilew, tileh); 399 if(quiet) 400 { 401 printf("%s%c%s%c", 402 sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024), 403 quiet==2? '\n':'\t', 404 sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80), 405 quiet==2? '\n':'\t'); 406 } 407 else 408 { 409 printf("\n%s size: %d x %d\n", dotile? "Tile":"Image", tilew, 410 tileh); 411 printf("C--> Frame rate: %f fps\n", (double)i/elapsed); 412 printf(" Output image size: %d bytes\n", totaljpegsize); 413 printf(" Compression ratio: %f:1\n", 414 (double)(w*h*ps)/(double)totaljpegsize); 415 printf(" Source throughput: %f Megapixels/sec\n", 416 (double)(w*h)/1000000.*(double)i/elapsed); 417 printf(" Output bit stream: %f Megabits/sec\n", 418 (double)totaljpegsize*8./1000000.*(double)i/elapsed); 419 } 420 if(tilew==w && tileh==h) 421 { 422 snprintf(tempstr, 1024, "%s_%s_Q%d.jpg", filename, subName[subsamp], 423 jpegqual); 424 if((file=fopen(tempstr, "wb"))==NULL) 425 _throwunix("opening reference image"); 426 if(fwrite(jpegbuf[0], jpegsize[0], 1, file)!=1) 427 _throwunix("writing reference image"); 428 fclose(file); file=NULL; 429 if(!quiet) printf("Reference image written to %s\n", tempstr); 430 } 431 432 /* Decompression test */ 433 if(decomptest(srcbuf, jpegbuf, jpegsize, tmpbuf, w, h, subsamp, jpegqual, 434 filename, tilew, tileh)==-1) 435 goto bailout; 436 437 for(i=0; i<ntilesw*ntilesh; i++) 438 { 439 if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL; 440 } 441 free(jpegbuf); jpegbuf=NULL; 442 free(jpegsize); jpegsize=NULL; 443 444 if(tilew==w && tileh==h) break; 445 } 446 447 bailout: 448 if(file) {fclose(file); file=NULL;} 449 if(jpegbuf) 450 { 451 for(i=0; i<ntilesw*ntilesh; i++) 452 { 453 if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL; 454 } 455 free(jpegbuf); jpegbuf=NULL; 456 } 457 if(jpegsize) {free(jpegsize); jpegsize=NULL;} 458 if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;} 459 if(handle) {tjDestroy(handle); handle=NULL;} 460 return; 461} 462 463 464void dodecomptest(char *filename) 465{ 466 FILE *file=NULL; tjhandle handle=NULL; 467 unsigned char **jpegbuf=NULL, *srcbuf=NULL; 468 unsigned long *jpegsize=NULL, srcsize, totaljpegsize; 469 tjtransform *t=NULL; 470 int w=0, h=0, subsamp=-1, _w, _h, _tilew, _tileh, 471 _ntilesw, _ntilesh, _subsamp; 472 char *temp=NULL, tempstr[80], tempstr2[80]; 473 int row, col, i, tilew, tileh, ntilesw=1, ntilesh=1, retval=0; 474 double start, elapsed; 475 int ps=tjPixelSize[pf], tile; 476 477 if((file=fopen(filename, "rb"))==NULL) 478 _throwunix("opening file"); 479 if(fseek(file, 0, SEEK_END)<0 || (srcsize=ftell(file))==(unsigned long)-1) 480 _throwunix("determining file size"); 481 if((srcbuf=(unsigned char *)malloc(srcsize))==NULL) 482 _throwunix("allocating memory"); 483 if(fseek(file, 0, SEEK_SET)<0) 484 _throwunix("setting file position"); 485 if(fread(srcbuf, srcsize, 1, file)<1) 486 _throwunix("reading JPEG data"); 487 fclose(file); file=NULL; 488 489 temp=strrchr(filename, '.'); 490 if(temp!=NULL) *temp='\0'; 491 492 if((handle=tjInitTransform())==NULL) 493 _throwtj("executing tjInitTransform()"); 494 if(tjDecompressHeader2(handle, srcbuf, srcsize, &w, &h, &subsamp)==-1) 495 _throwtj("executing tjDecompressHeader2()"); 496 497 if(quiet==1) 498 { 499 printf("All performance values in Mpixels/sec\n\n"); 500 printf("Bitmap\tBitmap\tJPEG\t%s %s \tXform\tComp\tDecomp\n", 501 dotile? "Tile ":"Image", dotile? "Tile ":"Image"); 502 printf("Format\tOrder\tSubsamp\tWidth Height\tPerf \tRatio\tPerf\n\n"); 503 } 504 else if(!quiet) 505 { 506 printf(">>>>> JPEG %s --> %s (%s) <<<<<\n", subNameLong[subsamp], 507 pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down"); 508 } 509 510 for(tilew=dotile? 16:w, tileh=dotile? 16:h; ; tilew*=2, tileh*=2) 511 { 512 if(tilew>w) tilew=w; if(tileh>h) tileh=h; 513 ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; 514 515 if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) 516 *ntilesw*ntilesh))==NULL) 517 _throwunix("allocating JPEG tile array"); 518 memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh); 519 if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long) 520 *ntilesw*ntilesh))==NULL) 521 _throwunix("allocating JPEG size array"); 522 memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh); 523 524 if((flags&TJFLAG_NOREALLOC)!=0 || !dotile) 525 for(i=0; i<ntilesw*ntilesh; i++) 526 { 527 if((jpegbuf[i]=(unsigned char *)malloc(tjBufSize(tilew, tileh, 528 subsamp)))==NULL) 529 _throwunix("allocating JPEG tiles"); 530 } 531 532 _w=w; _h=h; _tilew=tilew; _tileh=tileh; 533 if(!quiet) 534 { 535 printf("\n%s size: %d x %d", dotile? "Tile":"Image", _tilew, 536 _tileh); 537 if(sf.num!=1 || sf.denom!=1) 538 printf(" --> %d x %d", TJSCALED(_w, sf), TJSCALED(_h, sf)); 539 printf("\n"); 540 } 541 else if(quiet==1) 542 { 543 printf("%s\t%s\t%s\t", pixFormatStr[pf], 544 (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp]); 545 printf("%-4d %-4d\t", tilew, tileh); 546 } 547 548 _subsamp=subsamp; 549 if(dotile || xformop!=TJXOP_NONE || xformopt!=0 || customFilter) 550 { 551 if((t=(tjtransform *)malloc(sizeof(tjtransform)*ntilesw*ntilesh)) 552 ==NULL) 553 _throwunix("allocating image transform array"); 554 555 if(xformop==TJXOP_TRANSPOSE || xformop==TJXOP_TRANSVERSE 556 || xformop==TJXOP_ROT90 || xformop==TJXOP_ROT270) 557 { 558 _w=h; _h=w; _tilew=tileh; _tileh=tilew; 559 } 560 561 if(xformopt&TJXOPT_GRAY) _subsamp=TJ_GRAYSCALE; 562 if(xformop==TJXOP_HFLIP || xformop==TJXOP_ROT180) 563 _w=_w-(_w%tjMCUWidth[_subsamp]); 564 if(xformop==TJXOP_VFLIP || xformop==TJXOP_ROT180) 565 _h=_h-(_h%tjMCUHeight[_subsamp]); 566 if(xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT90) 567 _w=_w-(_w%tjMCUHeight[_subsamp]); 568 if(xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT270) 569 _h=_h-(_h%tjMCUWidth[_subsamp]); 570 _ntilesw=(_w+_tilew-1)/_tilew; 571 _ntilesh=(_h+_tileh-1)/_tileh; 572 573 for(row=0, tile=0; row<_ntilesh; row++) 574 { 575 for(col=0; col<_ntilesw; col++, tile++) 576 { 577 t[tile].r.w=min(_tilew, _w-col*_tilew); 578 t[tile].r.h=min(_tileh, _h-row*_tileh); 579 t[tile].r.x=col*_tilew; 580 t[tile].r.y=row*_tileh; 581 t[tile].op=xformop; 582 t[tile].options=xformopt|TJXOPT_TRIM; 583 t[tile].customFilter=customFilter; 584 if(t[tile].options&TJXOPT_NOOUTPUT && jpegbuf[tile]) 585 { 586 free(jpegbuf[tile]); jpegbuf[tile]=NULL; 587 } 588 } 589 } 590 591 start=gettime(); 592 if(tjTransform(handle, srcbuf, srcsize, _ntilesw*_ntilesh, jpegbuf, 593 jpegsize, t, flags)==-1) 594 _throwtj("executing tjTransform()"); 595 elapsed=gettime()-start; 596 597 free(t); t=NULL; 598 599 for(tile=0, totaljpegsize=0; tile<_ntilesw*_ntilesh; tile++) 600 totaljpegsize+=jpegsize[tile]; 601 602 if(quiet) 603 { 604 printf("%s%c%s%c", 605 sigfig((double)(w*h)/1000000./elapsed, 4, tempstr, 80), 606 quiet==2? '\n':'\t', 607 sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80), 608 quiet==2? '\n':'\t'); 609 } 610 else if(!quiet) 611 { 612 printf("X--> Frame rate: %f fps\n", 1.0/elapsed); 613 printf(" Output image size: %lu bytes\n", totaljpegsize); 614 printf(" Compression ratio: %f:1\n", 615 (double)(w*h*ps)/(double)totaljpegsize); 616 printf(" Source throughput: %f Megapixels/sec\n", 617 (double)(w*h)/1000000./elapsed); 618 printf(" Output bit stream: %f Megabits/sec\n", 619 (double)totaljpegsize*8./1000000./elapsed); 620 } 621 } 622 else 623 { 624 if(quiet==1) printf("N/A\tN/A\t"); 625 jpegsize[0]=srcsize; 626 memcpy(jpegbuf[0], srcbuf, srcsize); 627 } 628 629 if(w==tilew) _tilew=_w; 630 if(h==tileh) _tileh=_h; 631 if(!(xformopt&TJXOPT_NOOUTPUT)) 632 { 633 if(decomptest(NULL, jpegbuf, jpegsize, NULL, _w, _h, _subsamp, 0, 634 filename, _tilew, _tileh)==-1) 635 goto bailout; 636 } 637 else if(quiet==1) printf("N/A\n"); 638 639 for(i=0; i<ntilesw*ntilesh; i++) 640 { 641 free(jpegbuf[i]); jpegbuf[i]=NULL; 642 } 643 free(jpegbuf); jpegbuf=NULL; 644 if(jpegsize) {free(jpegsize); jpegsize=NULL;} 645 646 if(tilew==w && tileh==h) break; 647 } 648 649 bailout: 650 if(file) {fclose(file); file=NULL;} 651 if(jpegbuf) 652 { 653 for(i=0; i<ntilesw*ntilesh; i++) 654 { 655 if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL; 656 } 657 free(jpegbuf); jpegbuf=NULL; 658 } 659 if(jpegsize) {free(jpegsize); jpegsize=NULL;} 660 if(srcbuf) {free(srcbuf); srcbuf=NULL;} 661 if(t) {free(t); t=NULL;} 662 if(handle) {tjDestroy(handle); handle=NULL;} 663 return; 664} 665 666 667void usage(char *progname) 668{ 669 int i; 670 printf("USAGE: %s\n", progname); 671 printf(" <Inputfile (BMP|PPM)> <Quality> [options]\n\n"); 672 printf(" %s\n", progname); 673 printf(" <Inputfile (JPG)> [options]\n\n"); 674 printf("Options:\n\n"); 675 printf("-alloc = Dynamically allocate JPEG image buffers\n"); 676 printf("-bmp = Generate output images in Windows Bitmap format (default=PPM)\n"); 677 printf("-bottomup = Test bottom-up compression/decompression\n"); 678 printf("-tile = Test performance of the codec when the image is encoded as separate\n"); 679 printf(" tiles of varying sizes.\n"); 680 printf("-forcemmx, -forcesse, -forcesse2, -forcesse3 =\n"); 681 printf(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n"); 682 printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n"); 683 printf(" Test the specified color conversion path in the codec (default: BGR)\n"); 684 printf("-fastupsample = Use the fastest chrominance upsampling algorithm available in\n"); 685 printf(" the underlying codec\n"); 686 printf("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying\n"); 687 printf(" codec\n"); 688 printf("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the\n"); 689 printf(" underlying codec\n"); 690 printf("-subsamp <s> = When testing JPEG compression, this option specifies the level\n"); 691 printf(" of chrominance subsampling to use (<s> = 444, 422, 440, 420, or GRAY).\n"); 692 printf(" The default is to test Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence.\n"); 693 printf("-quiet = Output results in tabular rather than verbose format\n"); 694 printf("-yuvencode = Encode RGB input as planar YUV rather than compressing as JPEG\n"); 695 printf("-yuvdecode = Decode JPEG image to planar YUV rather than RGB\n"); 696 printf("-scale M/N = scale down the width/height of the decompressed JPEG image by a\n"); 697 printf(" factor of M/N (M/N = "); 698 for(i=0; i<nsf; i++) 699 { 700 printf("%d/%d", scalingfactors[i].num, scalingfactors[i].denom); 701 if(nsf==2 && i!=nsf-1) printf(" or "); 702 else if(nsf>2) 703 { 704 if(i!=nsf-1) printf(", "); 705 if(i==nsf-2) printf("or "); 706 } 707 if(i%8==0 && i!=0) printf("\n "); 708 } 709 printf(")\n"); 710 printf("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =\n"); 711 printf(" Perform the corresponding lossless transform prior to\n"); 712 printf(" decompression (these options are mutually exclusive)\n"); 713 printf("-grayscale = Perform lossless grayscale conversion prior to decompression\n"); 714 printf(" test (can be combined with the other transforms above)\n"); 715 printf("-benchtime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n\n"); 716 printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n"); 717 printf("test will be performed for all quality values in the range.\n\n"); 718 exit(1); 719} 720 721 722int main(int argc, char *argv[]) 723{ 724 unsigned char *srcbuf=NULL; int w, h, i, j; 725 int minqual=-1, maxqual=-1; char *temp; 726 int minarg=2, retval=0, subsamp=-1; 727 728 if((scalingfactors=tjGetScalingFactors(&nsf))==NULL || nsf==0) 729 _throwtj("executing tjGetScalingFactors()"); 730 731 if(argc<minarg) usage(argv[0]); 732 733 temp=strrchr(argv[1], '.'); 734 if(temp!=NULL) 735 { 736 if(!strcasecmp(temp, ".bmp")) ext="bmp"; 737 if(!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg")) decomponly=1; 738 } 739 740 printf("\n"); 741 742 if(argc>minarg) 743 { 744 for(i=minarg; i<argc; i++) 745 { 746 if(!strcasecmp(argv[i], "-yuvencode")) 747 { 748 printf("Testing YUV planar encoding\n\n"); 749 yuv=YUVENCODE; maxqual=minqual=100; 750 } 751 if(!strcasecmp(argv[i], "-yuvdecode")) 752 { 753 printf("Testing YUV planar decoding\n\n"); 754 yuv=YUVDECODE; 755 } 756 } 757 } 758 759 if(!decomponly && yuv!=YUVENCODE) 760 { 761 minarg=3; 762 if(argc<minarg) usage(argv[0]); 763 if((minqual=atoi(argv[2]))<1 || minqual>100) 764 { 765 puts("ERROR: Quality must be between 1 and 100."); 766 exit(1); 767 } 768 if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1 769 && sscanf(&temp[1], "%d", &maxqual)==1 && maxqual>minqual && maxqual>=1 770 && maxqual<=100) {} 771 else maxqual=minqual; 772 } 773 774 if(argc>minarg) 775 { 776 for(i=minarg; i<argc; i++) 777 { 778 if(!strcasecmp(argv[i], "-tile")) 779 { 780 dotile=1; xformopt|=TJXOPT_CROP; 781 } 782 if(!strcasecmp(argv[i], "-forcesse3")) 783 { 784 printf("Forcing SSE3 code\n\n"); 785 flags|=TJFLAG_FORCESSE3; 786 } 787 if(!strcasecmp(argv[i], "-forcesse2")) 788 { 789 printf("Forcing SSE2 code\n\n"); 790 flags|=TJFLAG_FORCESSE2; 791 } 792 if(!strcasecmp(argv[i], "-forcesse")) 793 { 794 printf("Forcing SSE code\n\n"); 795 flags|=TJFLAG_FORCESSE; 796 } 797 if(!strcasecmp(argv[i], "-forcemmx")) 798 { 799 printf("Forcing MMX code\n\n"); 800 flags|=TJFLAG_FORCEMMX; 801 } 802 if(!strcasecmp(argv[i], "-fastupsample")) 803 { 804 printf("Using fast upsampling code\n\n"); 805 flags|=TJFLAG_FASTUPSAMPLE; 806 } 807 if(!strcasecmp(argv[i], "-fastdct")) 808 { 809 printf("Using fastest DCT/IDCT algorithm\n\n"); 810 flags|=TJFLAG_FASTDCT; 811 } 812 if(!strcasecmp(argv[i], "-accuratedct")) 813 { 814 printf("Using most accurate DCT/IDCT algorithm\n\n"); 815 flags|=TJFLAG_ACCURATEDCT; 816 } 817 if(!strcasecmp(argv[i], "-rgb")) pf=TJPF_RGB; 818 if(!strcasecmp(argv[i], "-rgbx")) pf=TJPF_RGBX; 819 if(!strcasecmp(argv[i], "-bgr")) pf=TJPF_BGR; 820 if(!strcasecmp(argv[i], "-bgrx")) pf=TJPF_BGRX; 821 if(!strcasecmp(argv[i], "-xbgr")) pf=TJPF_XBGR; 822 if(!strcasecmp(argv[i], "-xrgb")) pf=TJPF_XRGB; 823 if(!strcasecmp(argv[i], "-bottomup")) flags|=TJFLAG_BOTTOMUP; 824 if(!strcasecmp(argv[i], "-quiet")) quiet=1; 825 if(!strcasecmp(argv[i], "-qq")) quiet=2; 826 if(!strcasecmp(argv[i], "-scale") && i<argc-1) 827 { 828 int temp1=0, temp2=0, match=0; 829 if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)==2) 830 { 831 for(j=0; j<nsf; j++) 832 { 833 if((double)temp1/(double)temp2 834 == (double)scalingfactors[j].num/(double)scalingfactors[j].denom) 835 { 836 sf=scalingfactors[j]; 837 match=1; break; 838 } 839 } 840 if(!match) usage(argv[0]); 841 } 842 else usage(argv[0]); 843 } 844 if(!strcasecmp(argv[i], "-hflip")) xformop=TJXOP_HFLIP; 845 if(!strcasecmp(argv[i], "-vflip")) xformop=TJXOP_VFLIP; 846 if(!strcasecmp(argv[i], "-transpose")) xformop=TJXOP_TRANSPOSE; 847 if(!strcasecmp(argv[i], "-transverse")) xformop=TJXOP_TRANSVERSE; 848 if(!strcasecmp(argv[i], "-rot90")) xformop=TJXOP_ROT90; 849 if(!strcasecmp(argv[i], "-rot180")) xformop=TJXOP_ROT180; 850 if(!strcasecmp(argv[i], "-rot270")) xformop=TJXOP_ROT270; 851 if(!strcasecmp(argv[i], "-grayscale")) xformopt|=TJXOPT_GRAY; 852 if(!strcasecmp(argv[i], "-custom")) customFilter=dummyDCTFilter; 853 if(!strcasecmp(argv[i], "-nooutput")) xformopt|=TJXOPT_NOOUTPUT; 854 if(!strcasecmp(argv[i], "-benchtime") && i<argc-1) 855 { 856 double temp=atof(argv[++i]); 857 if(temp>0.0) benchtime=temp; 858 else usage(argv[0]); 859 } 860 if(!strcmp(argv[i], "-?")) usage(argv[0]); 861 if(!strcasecmp(argv[i], "-alloc")) flags&=(~TJFLAG_NOREALLOC); 862 if(!strcasecmp(argv[i], "-bmp")) ext="bmp"; 863 if(!strcasecmp(argv[i], "-subsamp") && i<argc-1) 864 { 865 i++; 866 if(toupper(argv[i][0])=='G') subsamp=TJSAMP_GRAY; 867 else 868 { 869 int temp=atoi(argv[i]); 870 switch(temp) 871 { 872 case 444: subsamp=TJSAMP_444; break; 873 case 422: subsamp=TJSAMP_422; break; 874 case 440: subsamp=TJSAMP_440; break; 875 case 420: subsamp=TJSAMP_420; break; 876 } 877 } 878 } 879 } 880 } 881 882 if((sf.num!=1 || sf.denom!=1) && dotile) 883 { 884 printf("Disabling tiled compression/decompression tests, because those tests do not\n"); 885 printf("work when scaled decompression is enabled.\n"); 886 dotile=0; 887 } 888 889 if(yuv && dotile) 890 { 891 printf("Disabling tiled compression/decompression tests, because those tests do not\n"); 892 printf("work when YUV encoding or decoding is enabled.\n\n"); 893 dotile=0; 894 } 895 896 if(!decomponly) 897 { 898 if(loadbmp(argv[1], &srcbuf, &w, &h, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) 899 _throwbmp("loading bitmap"); 900 temp=strrchr(argv[1], '.'); 901 if(temp!=NULL) *temp='\0'; 902 } 903 904 if(quiet==1 && !decomponly) 905 { 906 printf("All performance values in Mpixels/sec\n\n"); 907 printf("Bitmap\tBitmap\tJPEG\tJPEG\t%s %s \tComp\tComp\tDecomp\n", 908 dotile? "Tile ":"Image", dotile? "Tile ":"Image"); 909 printf("Format\tOrder\tSubsamp\tQual\tWidth Height\tPerf \tRatio\tPerf\n\n"); 910 } 911 912 if(decomponly) 913 { 914 dodecomptest(argv[1]); 915 printf("\n"); 916 goto bailout; 917 } 918 if(subsamp>=0 && subsamp<TJ_NUMSAMP) 919 { 920 for(i=maxqual; i>=minqual; i--) 921 dotest(srcbuf, w, h, subsamp, i, argv[1]); 922 printf("\n"); 923 } 924 else 925 { 926 for(i=maxqual; i>=minqual; i--) 927 dotest(srcbuf, w, h, TJSAMP_GRAY, i, argv[1]); 928 printf("\n"); 929 for(i=maxqual; i>=minqual; i--) 930 dotest(srcbuf, w, h, TJSAMP_420, i, argv[1]); 931 printf("\n"); 932 for(i=maxqual; i>=minqual; i--) 933 dotest(srcbuf, w, h, TJSAMP_422, i, argv[1]); 934 printf("\n"); 935 for(i=maxqual; i>=minqual; i--) 936 dotest(srcbuf, w, h, TJSAMP_444, i, argv[1]); 937 printf("\n"); 938 } 939 940 bailout: 941 if(srcbuf) free(srcbuf); 942 return retval; 943} 944