TJBench.java revision a5830628b9cc92f9305ecb7d127ebc7207b12582
1/* 2 * Copyright (C)2009-2013 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 29import java.io.*; 30import java.awt.image.*; 31import javax.imageio.*; 32import java.util.*; 33import org.libjpegturbo.turbojpeg.*; 34 35class TJBench { 36 37 static final int YUVENCODE = 1; 38 static final int YUVDECODE = 2; 39 40 static int flags = 0, yuv = 0, quiet = 0, pf = TJ.PF_BGR; 41 static boolean decompOnly, doTile; 42 43 static final String[] pixFormatStr = { 44 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY" 45 }; 46 47 static final String[] subNameLong = { 48 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1" 49 }; 50 51 static final String[] subName = { 52 "444", "422", "420", "GRAY", "440", "411" 53 }; 54 55 static TJScalingFactor sf; 56 static int xformOp = TJTransform.OP_NONE, xformOpt = 0; 57 static double benchTime = 5.0; 58 59 60 static final double getTime() { 61 return (double)System.nanoTime() / 1.0e9; 62 } 63 64 65 static String sigFig(double val, int figs) { 66 String format; 67 int digitsAfterDecimal = figs - (int)Math.ceil(Math.log10(Math.abs(val))); 68 if (digitsAfterDecimal < 1) 69 format = new String("%.0f"); 70 else 71 format = new String("%." + digitsAfterDecimal + "f"); 72 return String.format(format, val); 73 } 74 75 76 static byte[] loadImage(String fileName, int[] w, int[] h, int pixelFormat) 77 throws Exception { 78 BufferedImage img = ImageIO.read(new File(fileName)); 79 if (img == null) 80 throw new Exception("Could not read " + fileName); 81 w[0] = img.getWidth(); 82 h[0] = img.getHeight(); 83 int[] rgb = img.getRGB(0, 0, w[0], h[0], null, 0, w[0]); 84 int ps = TJ.getPixelSize(pixelFormat); 85 int rindex = TJ.getRedOffset(pixelFormat); 86 int gindex = TJ.getGreenOffset(pixelFormat); 87 int bindex = TJ.getBlueOffset(pixelFormat); 88 byte[] dstBuf = new byte[w[0] * h[0] * ps]; 89 int pixels = w[0] * h[0], dstPtr = 0, rgbPtr = 0; 90 while (pixels-- > 0) { 91 dstBuf[dstPtr + rindex] = (byte)((rgb[rgbPtr] >> 16) & 0xff); 92 dstBuf[dstPtr + gindex] = (byte)((rgb[rgbPtr] >> 8) & 0xff); 93 dstBuf[dstPtr + bindex] = (byte)(rgb[rgbPtr] & 0xff); 94 dstPtr += ps; 95 rgbPtr++; 96 } 97 return dstBuf; 98 } 99 100 101 static void saveImage(String fileName, byte[] srcBuf, int w, int h, 102 int pixelFormat) throws Exception { 103 BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 104 int pixels = w * h, srcPtr = 0; 105 int ps = TJ.getPixelSize(pixelFormat); 106 int rindex = TJ.getRedOffset(pixelFormat); 107 int gindex = TJ.getGreenOffset(pixelFormat); 108 int bindex = TJ.getBlueOffset(pixelFormat); 109 for (int y = 0; y < h; y++) { 110 for (int x = 0; x < w; x++, srcPtr += ps) { 111 int pixel = (srcBuf[srcPtr + rindex] & 0xff) << 16 | 112 (srcBuf[srcPtr + gindex] & 0xff) << 8 | 113 (srcBuf[srcPtr + bindex] & 0xff); 114 img.setRGB(x, y, pixel); 115 } 116 } 117 ImageIO.write(img, "bmp", new File(fileName)); 118 } 119 120 121 /* Decompression test */ 122 static void decompTest(byte[] srcBuf, byte[][] jpegBuf, int[] jpegSize, 123 byte[] dstBuf, int w, int h, int subsamp, 124 int jpegQual, String fileName, int tilew, int tileh) 125 throws Exception { 126 String qualStr = new String(""), sizeStr, tempStr; 127 TJDecompressor tjd; 128 double start, elapsed; 129 int ps = TJ.getPixelSize(pf), i; 130 int yuvSize = TJ.bufSizeYUV(w, h, subsamp), bufsize; 131 int scaledw = (yuv == YUVDECODE) ? w : sf.getScaled(w); 132 int scaledh = (yuv == YUVDECODE) ? h : sf.getScaled(h); 133 int pitch = scaledw * ps; 134 135 if (jpegQual > 0) 136 qualStr = new String("_Q" + jpegQual); 137 138 tjd = new TJDecompressor(); 139 140 int bufSize = (yuv == YUVDECODE ? yuvSize : pitch * scaledh); 141 if (dstBuf == null) 142 dstBuf = new byte[bufSize]; 143 144 /* Set the destination buffer to gray so we know whether the decompressor 145 attempted to write to it */ 146 Arrays.fill(dstBuf, (byte)127); 147 148 /* Execute once to preload cache */ 149 tjd.setJPEGImage(jpegBuf[0], jpegSize[0]); 150 if (yuv == YUVDECODE) 151 tjd.decompressToYUV(dstBuf, flags); 152 else 153 tjd.decompress(dstBuf, scaledw, pitch, scaledh, pf, flags); 154 155 /* Benchmark */ 156 for (i = 0, start = getTime(); (elapsed = getTime() - start) < benchTime; 157 i++) { 158 int tile = 0; 159 if (yuv == YUVDECODE) 160 tjd.decompressToYUV(dstBuf, flags); 161 else { 162 for (int y = 0; y < h; y += tileh) { 163 for (int x = 0; x < w; x += tilew, tile++) { 164 int width = doTile ? Math.min(tilew, w - x) : scaledw; 165 int height = doTile ? Math.min(tileh, h - y) : scaledh; 166 tjd.setJPEGImage(jpegBuf[tile], jpegSize[tile]); 167 tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags); 168 } 169 } 170 } 171 } 172 173 tjd = null; 174 System.gc(); 175 176 if (quiet != 0) 177 System.out.println( 178 sigFig((double)(w * h) / 1000000. * (double)i / elapsed, 4)); 179 else { 180 System.out.format("D--> Frame rate: %f fps\n", 181 (double)i / elapsed); 182 System.out.format(" Dest. throughput: %f Megapixels/sec\n", 183 (double)(w * h) / 1000000. * (double)i / elapsed); 184 } 185 186 if (yuv == YUVDECODE) { 187 tempStr = fileName + "_" + subName[subsamp] + qualStr + ".yuv"; 188 FileOutputStream fos = new FileOutputStream(tempStr); 189 fos.write(dstBuf, 0, yuvSize); 190 fos.close(); 191 } else { 192 if (sf.getNum() != 1 || sf.getDenom() != 1) 193 sizeStr = new String(sf.getNum() + "_" + sf.getDenom()); 194 else if (tilew != w || tileh != h) 195 sizeStr = new String(tilew + "x" + tileh); 196 else 197 sizeStr = new String("full"); 198 if (decompOnly) 199 tempStr = new String(fileName + "_" + sizeStr + ".bmp"); 200 else 201 tempStr = new String(fileName + "_" + subName[subsamp] + qualStr + 202 "_" + sizeStr + ".bmp"); 203 saveImage(tempStr, dstBuf, scaledw, scaledh, pf); 204 int ndx = tempStr.indexOf('.'); 205 tempStr = new String(tempStr.substring(0, ndx) + "-err.bmp"); 206 if (srcBuf != null && sf.getNum() == 1 && sf.getDenom() == 1) { 207 if (quiet == 0) 208 System.out.println("Compression error written to " + tempStr + "."); 209 if (subsamp == TJ.SAMP_GRAY) { 210 for (int y = 0, index = 0; y < h; y++, index += pitch) { 211 for (int x = 0, index2 = index; x < w; x++, index2 += ps) { 212 int rindex = index2 + TJ.getRedOffset(pf); 213 int gindex = index2 + TJ.getGreenOffset(pf); 214 int bindex = index2 + TJ.getBlueOffset(pf); 215 int lum = (int)((double)(srcBuf[rindex] & 0xff) * 0.299 + 216 (double)(srcBuf[gindex] & 0xff) * 0.587 + 217 (double)(srcBuf[bindex] & 0xff) * 0.114 + 0.5); 218 if (lum > 255) lum = 255; 219 if (lum < 0) lum = 0; 220 dstBuf[rindex] = (byte)Math.abs((dstBuf[rindex] & 0xff) - lum); 221 dstBuf[gindex] = (byte)Math.abs((dstBuf[gindex] & 0xff) - lum); 222 dstBuf[bindex] = (byte)Math.abs((dstBuf[bindex] & 0xff) - lum); 223 } 224 } 225 } else { 226 for (int y = 0; y < h; y++) 227 for (int x = 0; x < w * ps; x++) 228 dstBuf[pitch * y + x] = 229 (byte)Math.abs((dstBuf[pitch * y + x] & 0xff) - 230 (srcBuf[pitch * y + x] & 0xff)); 231 } 232 saveImage(tempStr, dstBuf, w, h, pf); 233 } 234 } 235 } 236 237 238 static void doTestYUV(byte[] srcBuf, int w, int h, int subsamp, 239 String fileName) throws Exception { 240 TJCompressor tjc; 241 byte[] dstBuf; 242 double start, elapsed; 243 int ps = TJ.getPixelSize(pf), i; 244 int yuvSize = 0; 245 246 yuvSize = TJ.bufSizeYUV(w, h, subsamp); 247 dstBuf = new byte[yuvSize]; 248 249 if (quiet == 0) 250 System.out.format(">>>>> %s (%s) <--> YUV %s <<<<<\n", 251 pixFormatStr[pf], 252 (flags & TJ.FLAG_BOTTOMUP) != 0 ? "Bottom-up" : "Top-down", 253 subNameLong[subsamp]); 254 255 if (quiet == 1) 256 System.out.format("%s\t%s\t%s\tN/A\t", pixFormatStr[pf], 257 (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD", 258 subNameLong[subsamp]); 259 260 tjc = new TJCompressor(srcBuf, w, 0, h, pf); 261 tjc.setSubsamp(subsamp); 262 263 /* Execute once to preload cache */ 264 tjc.encodeYUV(dstBuf, flags); 265 266 /* Benchmark */ 267 for (i = 0, start = getTime(); 268 (elapsed = getTime() - start) < benchTime; i++) 269 tjc.encodeYUV(dstBuf, flags); 270 271 if (quiet == 1) 272 System.out.format("%-4d %-4d\t", w, h); 273 if (quiet != 0) { 274 System.out.format("%s%c%s%c", 275 sigFig((double)(w * h) / 1000000. * (double) i / elapsed, 4), 276 quiet == 2 ? '\n' : '\t', 277 sigFig((double)(w * h * ps) / (double)yuvSize, 4), 278 quiet == 2 ? '\n' : '\t'); 279 } else { 280 System.out.format("\n%s size: %d x %d\n", "Image", w, h); 281 System.out.format("C--> Frame rate: %f fps\n", 282 (double)i / elapsed); 283 System.out.format(" Output image size: %d bytes\n", yuvSize); 284 System.out.format(" Compression ratio: %f:1\n", 285 (double)(w * h * ps) / (double)yuvSize); 286 System.out.format(" Source throughput: %f Megapixels/sec\n", 287 (double)(w * h) / 1000000. * (double)i / elapsed); 288 System.out.format(" Output bit stream: %f Megabits/sec\n", 289 (double)yuvSize * 8. / 1000000. * (double)i / elapsed); 290 } 291 String tempStr = fileName + "_" + subName[subsamp] + ".yuv"; 292 FileOutputStream fos = new FileOutputStream(tempStr); 293 fos.write(dstBuf, 0, yuvSize); 294 fos.close(); 295 if (quiet == 0) 296 System.out.println("Reference image written to " + tempStr); 297 } 298 299 300 static void doTest(byte[] srcBuf, int w, int h, int subsamp, int jpegQual, 301 String fileName) throws Exception { 302 TJCompressor tjc; 303 byte[] tmpBuf; 304 byte[][] jpegBuf; 305 int[] jpegSize; 306 double start, elapsed; 307 int totalJpegSize = 0, tilew, tileh, i; 308 int ps = TJ.getPixelSize(pf), ntilesw = 1, ntilesh = 1, pitch = w * ps; 309 310 if (yuv == YUVENCODE) { 311 doTestYUV(srcBuf, w, h, subsamp, fileName); 312 return; 313 } 314 315 tmpBuf = new byte[pitch * h]; 316 317 if (quiet == 0) 318 System.out.format(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", 319 pixFormatStr[pf], 320 (flags & TJ.FLAG_BOTTOMUP) != 0 ? "Bottom-up" : "Top-down", 321 subNameLong[subsamp], jpegQual); 322 323 tjc = new TJCompressor(); 324 325 for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ; 326 tilew *= 2, tileh *= 2) { 327 if (tilew > w) 328 tilew = w; 329 if (tileh > h) 330 tileh = h; 331 ntilesw = (w + tilew - 1) / tilew; 332 ntilesh = (h + tileh - 1) / tileh; 333 334 jpegBuf = new byte[ntilesw * ntilesh][TJ.bufSize(tilew, tileh, subsamp)]; 335 jpegSize = new int[ntilesw * ntilesh]; 336 337 /* Compression test */ 338 if (quiet == 1) 339 System.out.format("%s\t%s\t%s\t%d\t", pixFormatStr[pf], 340 (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD", 341 subNameLong[subsamp], jpegQual); 342 for (i = 0; i < h; i++) 343 System.arraycopy(srcBuf, w * ps * i, tmpBuf, pitch * i, w * ps); 344 tjc.setSourceImage(srcBuf, tilew, pitch, tileh, pf); 345 tjc.setJPEGQuality(jpegQual); 346 tjc.setSubsamp(subsamp); 347 348 /* Execute once to preload cache */ 349 tjc.compress(jpegBuf[0], flags); 350 351 /* Benchmark */ 352 for (i = 0, start = getTime(); 353 (elapsed = getTime() - start) < benchTime; i++) { 354 int tile = 0; 355 totalJpegSize = 0; 356 for (int y = 0; y < h; y += tileh) { 357 for (int x = 0; x < w; x += tilew, tile++) { 358 int width = Math.min(tilew, w - x); 359 int height = Math.min(tileh, h - y); 360 tjc.setSourceImage(srcBuf, x, y, width, pitch, height, pf); 361 tjc.compress(jpegBuf[tile], flags); 362 jpegSize[tile] = tjc.getCompressedSize(); 363 totalJpegSize += jpegSize[tile]; 364 } 365 } 366 } 367 368 if (quiet == 1) 369 System.out.format("%-4d %-4d\t", tilew, tileh); 370 if (quiet != 0) { 371 System.out.format("%s%c%s%c", 372 sigFig((double)(w * h) / 1000000. * (double) i / elapsed, 4), 373 quiet == 2 ? '\n' : '\t', 374 sigFig((double)(w * h * ps) / (double)totalJpegSize, 4), 375 quiet == 2 ? '\n' : '\t'); 376 } else { 377 System.out.format("\n%s size: %d x %d\n", doTile ? "Tile" : "Image", 378 tilew, tileh); 379 System.out.format("C--> Frame rate: %f fps\n", 380 (double)i / elapsed); 381 System.out.format(" Output image size: %d bytes\n", 382 totalJpegSize); 383 System.out.format(" Compression ratio: %f:1\n", 384 (double)(w * h * ps) / (double)totalJpegSize); 385 System.out.format(" Source throughput: %f Megapixels/sec\n", 386 (double)(w * h) / 1000000. * (double)i / elapsed); 387 System.out.format(" Output bit stream: %f Megabits/sec\n", 388 (double)totalJpegSize * 8. / 1000000. * (double)i / elapsed); 389 } 390 if (tilew == w && tileh == h) { 391 String tempStr = fileName + "_" + subName[subsamp] + "_" + "Q" + 392 jpegQual + ".jpg"; 393 FileOutputStream fos = new FileOutputStream(tempStr); 394 fos.write(jpegBuf[0], 0, jpegSize[0]); 395 fos.close(); 396 if (quiet == 0) 397 System.out.println("Reference image written to " + tempStr); 398 } 399 400 /* Decompression test */ 401 decompTest(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual, 402 fileName, tilew, tileh); 403 404 for (i = 0; i < ntilesw * ntilesh; i++) 405 jpegBuf[i] = null; 406 jpegBuf = null; jpegSize = null; 407 System.gc(); 408 409 if (tilew == w && tileh == h) break; 410 } 411 } 412 413 414 static void doDecompTest(String fileName) throws Exception { 415 TJTransformer tjt; 416 byte[][] jpegBuf; 417 byte[] srcBuf; 418 int[] jpegSize; 419 int totalJpegSize; 420 int w = 0, h = 0, subsamp = -1, _w, _h, _tilew, _tileh, 421 _ntilesw, _ntilesh, _subsamp, x, y; 422 int ntilesw = 1, ntilesh = 1; 423 double start, elapsed; 424 int ps = TJ.getPixelSize(pf), tile; 425 426 FileInputStream fis = new FileInputStream(fileName); 427 int srcSize = (int)fis.getChannel().size(); 428 srcBuf = new byte[srcSize]; 429 fis.read(srcBuf, 0, srcSize); 430 fis.close(); 431 432 int index = fileName.indexOf('.'); 433 if (index >= 0) 434 fileName = new String(fileName.substring(0, index)); 435 436 tjt = new TJTransformer(); 437 438 tjt.setJPEGImage(srcBuf, srcSize); 439 w = tjt.getWidth(); 440 h = tjt.getHeight(); 441 subsamp = tjt.getSubsamp(); 442 443 if (quiet == 1) { 444 System.out.println("All performance values in Mpixels/sec\n"); 445 System.out.format("Bitmap\tBitmap\tJPEG\t%s %s \tXform\tComp\tDecomp\n", 446 (doTile ? "Tile " : "Image"), 447 (doTile ? "Tile " : "Image")); 448 System.out.println("Format\tOrder\tSubsamp\tWidth Height\tPerf \tRatio\tPerf\n"); 449 } else if (quiet == 0) { 450 System.out.format(">>>>> JPEG %s --> %s (%s) <<<<<", 451 subNameLong[subsamp], pixFormatStr[pf], 452 (flags & TJ.FLAG_BOTTOMUP) != 0 ? "Bottom-up" : "Top-down"); 453 } 454 455 for (int tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ; 456 tilew *= 2, tileh *= 2) { 457 if (tilew > w) 458 tilew = w; 459 if (tileh > h) 460 tileh = h; 461 ntilesw = (w + tilew - 1) / tilew; 462 ntilesh = (h + tileh - 1) / tileh; 463 464 _w = w; _h = h; _tilew = tilew; _tileh = tileh; 465 if (quiet == 0) { 466 System.out.format("\n%s size: %d x %d", (doTile ? "Tile" : "Image"), 467 _tilew, _tileh); 468 if (sf.getNum() != 1 || sf.getDenom() != 1) 469 System.out.format(" --> %d x %d", sf.getScaled(_w), 470 sf.getScaled(_h)); 471 System.out.println(""); 472 } else if (quiet == 1) { 473 System.out.format("%s\t%s\t%s\t", pixFormatStr[pf], 474 (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD", 475 subNameLong[subsamp]); 476 System.out.format("%-4d %-4d\t", tilew, tileh); 477 } 478 479 _subsamp = subsamp; 480 if (doTile || xformOp != TJTransform.OP_NONE || xformOpt != 0) { 481 if (xformOp == TJTransform.OP_TRANSPOSE || 482 xformOp == TJTransform.OP_TRANSVERSE || 483 xformOp == TJTransform.OP_ROT90 || 484 xformOp == TJTransform.OP_ROT270) { 485 _w = h; _h = w; _tilew = tileh; _tileh = tilew; 486 } 487 488 if ((xformOpt & TJTransform.OPT_GRAY) != 0) 489 _subsamp = TJ.SAMP_GRAY; 490 if (xformOp == TJTransform.OP_HFLIP || 491 xformOp == TJTransform.OP_ROT180) 492 _w = _w - (_w % TJ.getMCUWidth(_subsamp)); 493 if (xformOp == TJTransform.OP_VFLIP || 494 xformOp == TJTransform.OP_ROT180) 495 _h = _h - (_h % TJ.getMCUHeight(_subsamp)); 496 if (xformOp == TJTransform.OP_TRANSVERSE || 497 xformOp == TJTransform.OP_ROT90) 498 _w = _w - (_w % TJ.getMCUHeight(_subsamp)); 499 if (xformOp == TJTransform.OP_TRANSVERSE || 500 xformOp == TJTransform.OP_ROT270) 501 _h = _h - (_h % TJ.getMCUWidth(_subsamp)); 502 _ntilesw = (_w + _tilew - 1) / _tilew; 503 _ntilesh = (_h + _tileh - 1) / _tileh; 504 505 TJTransform[] t = new TJTransform[_ntilesw * _ntilesh]; 506 jpegBuf = new byte[_ntilesw * _ntilesh][TJ.bufSize(_tilew, _tileh, subsamp)]; 507 508 for (y = 0, tile = 0; y < _h; y += _tileh) { 509 for (x = 0; x < _w; x += _tilew, tile++) { 510 t[tile] = new TJTransform(); 511 t[tile].width = Math.min(_tilew, _w - x); 512 t[tile].height = Math.min(_tileh, _h - y); 513 t[tile].x = x; 514 t[tile].y = y; 515 t[tile].op = xformOp; 516 t[tile].options = xformOpt | TJTransform.OPT_TRIM; 517 if ((t[tile].options & TJTransform.OPT_NOOUTPUT) != 0 && 518 jpegBuf[tile] != null) 519 jpegBuf[tile] = null; 520 } 521 } 522 523 start = getTime(); 524 tjt.transform(jpegBuf, t, flags); 525 jpegSize = tjt.getTransformedSizes(); 526 elapsed = getTime() - start; 527 528 t = null; 529 530 for (tile = 0, totalJpegSize = 0; tile < _ntilesw * _ntilesh; tile++) 531 totalJpegSize += jpegSize[tile]; 532 533 if (quiet != 0) { 534 System.out.format("%s%c%s%c", 535 sigFig((double)(w * h) / 1000000. / elapsed, 4), 536 quiet == 2 ? '\n' : '\t', 537 sigFig((double)(w * h * ps) / (double)totalJpegSize, 4), 538 quiet == 2 ? '\n' : '\t'); 539 } else if (quiet == 0) { 540 System.out.format("X--> Frame rate: %f fps\n", 541 1.0 / elapsed); 542 System.out.format(" Output image size: %lu bytes\n", 543 totalJpegSize); 544 System.out.format(" Compression ratio: %f:1\n", 545 (double)(w * h * ps) / (double)totalJpegSize); 546 System.out.format(" Source throughput: %f Megapixels/sec\n", 547 (double)(w * h) / 1000000. / elapsed); 548 System.out.format(" Output bit stream: %f Megabits/sec\n", 549 (double)totalJpegSize * 8. / 1000000. / elapsed); 550 } 551 } else { 552 if (quiet == 1) 553 System.out.print("N/A\tN/A\t"); 554 jpegBuf = new byte[1][TJ.bufSize(_tilew, _tileh, subsamp)]; 555 jpegSize = new int[1]; 556 jpegSize[0] = srcSize; 557 System.arraycopy(srcBuf, 0, jpegBuf[0], 0, srcSize); 558 } 559 560 if (w == tilew) 561 _tilew = _w; 562 if (h == tileh) 563 _tileh = _h; 564 if ((xformOpt & TJTransform.OPT_NOOUTPUT) == 0) 565 decompTest(null, jpegBuf, jpegSize, null, _w, _h, _subsamp, 0, 566 fileName, _tilew, _tileh); 567 else if (quiet == 1) 568 System.out.println("N/A"); 569 570 jpegBuf = null; 571 jpegSize = null; 572 573 if (tilew == w && tileh == h) break; 574 } 575 } 576 577 578 static void usage() throws Exception { 579 int i; 580 TJScalingFactor[] scalingFactors = TJ.getScalingFactors(); 581 int nsf = scalingFactors.length; 582 String className = new TJBench().getClass().getName(); 583 584 System.out.println("\nUSAGE: java " + className); 585 System.out.println(" <Inputfile (BMP)> <Quality> [options]\n"); 586 System.out.println(" java " + className); 587 System.out.println(" <Inputfile (JPG)> [options]\n"); 588 System.out.println("Options:\n"); 589 System.out.println("-alloc = Dynamically allocate JPEG image buffers"); 590 System.out.println("-bottomup = Test bottom-up compression/decompression"); 591 System.out.println("-tile = Test performance of the codec when the image is encoded as separate"); 592 System.out.println(" tiles of varying sizes."); 593 System.out.println("-forcemmx, -forcesse, -forcesse2, -forcesse3 ="); 594 System.out.println(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec"); 595 System.out.println("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb ="); 596 System.out.println(" Test the specified color conversion path in the codec (default: BGR)"); 597 System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available in"); 598 System.out.println(" the underlying codec"); 599 System.out.println("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying"); 600 System.out.println(" codec"); 601 System.out.println("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the"); 602 System.out.println(" underlying codec"); 603 System.out.println("-440 = Test 4:4:0 chrominance subsampling instead of 4:2:2"); 604 System.out.println("-411 = Test 4:1:1 chrominance subsampling instead of 4:2:0"); 605 System.out.println("-quiet = Output results in tabular rather than verbose format"); 606 System.out.println("-yuvencode = Encode RGB input as planar YUV rather than compressing as JPEG"); 607 System.out.println("-yuvdecode = Decode JPEG image to planar YUV rather than RGB"); 608 System.out.println("-scale M/N = scale down the width/height of the decompressed JPEG image by a"); 609 System.out.print (" factor of M/N (M/N = "); 610 for (i = 0; i < nsf; i++) { 611 System.out.format("%d/%d", scalingFactors[i].getNum(), 612 scalingFactors[i].getDenom()); 613 if (nsf == 2 && i != nsf - 1) 614 System.out.print(" or "); 615 else if (nsf > 2) { 616 if (i != nsf - 1) 617 System.out.print(", "); 618 if (i == nsf - 2) 619 System.out.print("or "); 620 } 621 if (i % 8 == 0 && i != 0) 622 System.out.print("\n "); 623 } 624 System.out.println(")"); 625 System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 ="); 626 System.out.println(" Perform the corresponding lossless transform prior to"); 627 System.out.println(" decompression (these options are mutually exclusive)"); 628 System.out.println("-grayscale = Perform lossless grayscale conversion prior to decompression"); 629 System.out.println(" test (can be combined with the other transforms above)"); 630 System.out.println("-benchTime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n"); 631 System.out.println("NOTE: If the quality is specified as a range (e.g. 90-100), a separate"); 632 System.out.println("test will be performed for all quality values in the range.\n"); 633 System.exit(1); 634 } 635 636 637 public static void main(String[] argv) { 638 byte[] srcBuf = null; int w = 0, h = 0; 639 int minQual = -1, maxQual = -1; 640 int minArg = 1; int retval = 0; 641 boolean do440 = false, do411 = false; 642 643 try { 644 645 if (argv.length < minArg) 646 usage(); 647 648 String tempStr = argv[0].toLowerCase(); 649 if (tempStr.endsWith(".jpg") || tempStr.endsWith(".jpeg")) 650 decompOnly = true; 651 652 System.out.println(""); 653 654 if (argv.length > minArg) { 655 for (int i = minArg; i < argv.length; i++) { 656 if (argv[i].equalsIgnoreCase("-yuvencode")) { 657 System.out.println("Testing YUV planar encoding\n"); 658 yuv = YUVENCODE; maxQual = minQual = 100; 659 } 660 if (argv[i].equalsIgnoreCase("-yuvdecode")) { 661 System.out.println("Testing YUV planar decoding\n"); 662 yuv = YUVDECODE; 663 } 664 } 665 } 666 667 if (!decompOnly && yuv != YUVENCODE) { 668 minArg = 2; 669 if (argv.length < minArg) 670 usage(); 671 try { 672 minQual = Integer.parseInt(argv[1]); 673 } catch (NumberFormatException e) {} 674 if (minQual < 1 || minQual > 100) 675 throw new Exception("Quality must be between 1 and 100."); 676 int dashIndex = argv[1].indexOf('-'); 677 if (dashIndex > 0 && argv[1].length() > dashIndex + 1) { 678 try { 679 maxQual = Integer.parseInt(argv[1].substring(dashIndex + 1)); 680 } catch (NumberFormatException e) {} 681 } 682 if (maxQual < 1 || maxQual > 100) 683 maxQual = minQual; 684 } 685 686 if (argv.length > minArg) { 687 for (int i = minArg; i < argv.length; i++) { 688 if (argv[i].equalsIgnoreCase("-tile")) { 689 doTile = true; xformOpt |= TJTransform.OPT_CROP; 690 } 691 if (argv[i].equalsIgnoreCase("-forcesse3")) { 692 System.out.println("Forcing SSE3 code\n"); 693 flags |= TJ.FLAG_FORCESSE3; 694 } 695 if (argv[i].equalsIgnoreCase("-forcesse2")) { 696 System.out.println("Forcing SSE2 code\n"); 697 flags |= TJ.FLAG_FORCESSE2; 698 } 699 if (argv[i].equalsIgnoreCase("-forcesse")) { 700 System.out.println("Forcing SSE code\n"); 701 flags |= TJ.FLAG_FORCESSE; 702 } 703 if (argv[i].equalsIgnoreCase("-forcemmx")) { 704 System.out.println("Forcing MMX code\n"); 705 flags |= TJ.FLAG_FORCEMMX; 706 } 707 if (argv[i].equalsIgnoreCase("-fastupsample")) { 708 System.out.println("Using fast upsampling code\n"); 709 flags |= TJ.FLAG_FASTUPSAMPLE; 710 } 711 if (argv[i].equalsIgnoreCase("-fastdct")) { 712 System.out.println("Using fastest DCT/IDCT algorithm\n"); 713 flags |= TJ.FLAG_FASTDCT; 714 } 715 if (argv[i].equalsIgnoreCase("-accuratedct")) { 716 System.out.println("Using most accurate DCT/IDCT algorithm\n"); 717 flags |= TJ.FLAG_ACCURATEDCT; 718 } 719 if (argv[i].equals("-440")) 720 do440 = true; 721 if (argv[i].equals("-411")) 722 do411 = true; 723 if (argv[i].equalsIgnoreCase("-rgb")) 724 pf = TJ.PF_RGB; 725 if (argv[i].equalsIgnoreCase("-rgbx")) 726 pf = TJ.PF_RGBX; 727 if (argv[i].equalsIgnoreCase("-bgr")) 728 pf = TJ.PF_BGR; 729 if (argv[i].equalsIgnoreCase("-bgrx")) 730 pf = TJ.PF_BGRX; 731 if (argv[i].equalsIgnoreCase("-xbgr")) 732 pf = TJ.PF_XBGR; 733 if (argv[i].equalsIgnoreCase("-xrgb")) 734 pf = TJ.PF_XRGB; 735 if (argv[i].equalsIgnoreCase("-bottomup")) 736 flags |= TJ.FLAG_BOTTOMUP; 737 if (argv[i].equalsIgnoreCase("-quiet")) 738 quiet = 1; 739 if (argv[i].equalsIgnoreCase("-qq")) 740 quiet = 2; 741 if (argv[i].equalsIgnoreCase("-scale") && i < argv.length - 1) { 742 int temp1 = 0, temp2 = 0; 743 boolean match = false, scanned = true; 744 Scanner scanner = new Scanner(argv[++i]).useDelimiter("/"); 745 try { 746 temp1 = scanner.nextInt(); 747 temp2 = scanner.nextInt(); 748 } catch(Exception e) {} 749 if (temp2 <= 0) temp2 = 1; 750 if (temp1 > 0) { 751 TJScalingFactor[] scalingFactors = TJ.getScalingFactors(); 752 for (int j = 0; j < scalingFactors.length; j++) { 753 if ((double)temp1 / (double)temp2 == 754 (double)scalingFactors[j].getNum() / 755 (double)scalingFactors[j].getDenom()) { 756 sf = scalingFactors[j]; 757 match = true; break; 758 } 759 } 760 if (!match) usage(); 761 } else 762 usage(); 763 } 764 if (argv[i].equalsIgnoreCase("-hflip")) 765 xformOp = TJTransform.OP_HFLIP; 766 if (argv[i].equalsIgnoreCase("-vflip")) 767 xformOp = TJTransform.OP_VFLIP; 768 if (argv[i].equalsIgnoreCase("-transpose")) 769 xformOp = TJTransform.OP_TRANSPOSE; 770 if (argv[i].equalsIgnoreCase("-transverse")) 771 xformOp = TJTransform.OP_TRANSVERSE; 772 if (argv[i].equalsIgnoreCase("-rot90")) 773 xformOp = TJTransform.OP_ROT90; 774 if (argv[i].equalsIgnoreCase("-rot180")) 775 xformOp = TJTransform.OP_ROT180; 776 if (argv[i].equalsIgnoreCase("-rot270")) 777 xformOp = TJTransform.OP_ROT270; 778 if (argv[i].equalsIgnoreCase("-grayscale")) 779 xformOpt |= TJTransform.OPT_GRAY; 780 if (argv[i].equalsIgnoreCase("-nooutput")) 781 xformOpt |= TJTransform.OPT_NOOUTPUT; 782 if (argv[i].equalsIgnoreCase("-benchtime") && i < argv.length - 1) { 783 double temp = -1; 784 try { 785 temp = Double.parseDouble(argv[++i]); 786 } catch (NumberFormatException e) {} 787 if (temp > 0.0) 788 benchTime = temp; 789 else 790 usage(); 791 } 792 if (argv[i].equalsIgnoreCase("-?")) 793 usage(); 794 } 795 } 796 797 if (sf == null) 798 sf = new TJScalingFactor(1, 1); 799 800 if ((sf.getNum() != 1 || sf.getDenom() != 1) && doTile) { 801 System.out.println("Disabling tiled compression/decompression tests, because those tests do not"); 802 System.out.println("work when scaled decompression is enabled."); 803 doTile = false; 804 } 805 806 if (yuv != 0 && doTile) { 807 System.out.println("Disabling tiled compression/decompression tests, because those tests do not"); 808 System.out.println("work when YUV encoding or decoding is enabled.\n"); 809 doTile = false; 810 } 811 812 if (!decompOnly) { 813 int[] width = new int[1], height = new int[1]; 814 srcBuf = loadImage(argv[0], width, height, pf); 815 w = width[0]; h = height[0]; 816 int index = -1; 817 if ((index = argv[0].indexOf('.')) >= 0) 818 argv[0] = argv[0].substring(0, index); 819 } 820 821 if (quiet == 1 && !decompOnly) { 822 System.out.println("All performance values in Mpixels/sec\n"); 823 System.out.format("Bitmap\tBitmap\tJPEG\tJPEG\t%s %s \tComp\tComp\tDecomp\n", 824 (doTile ? "Tile " : "Image"), (doTile ? "Tile " : "Image")); 825 System.out.println("Format\tOrder\tSubsamp\tQual\tWidth Height\tPerf \tRatio\tPerf\n"); 826 } 827 828 if (decompOnly) { 829 doDecompTest(argv[0]); 830 System.out.println(""); 831 System.exit(retval); 832 } 833 834 System.gc(); 835 for (int i = maxQual; i >= minQual; i--) 836 doTest(srcBuf, w, h, TJ.SAMP_GRAY, i, argv[0]); 837 System.out.println(""); 838 System.gc(); 839 for (int i = maxQual; i >= minQual; i--) 840 doTest(srcBuf, w, h, do411 ? TJ.SAMP_411 : TJ.SAMP_420, i, argv[0]); 841 System.out.println(""); 842 System.gc(); 843 for (int i = maxQual; i >= minQual; i--) 844 doTest(srcBuf, w, h, do440 ? TJ.SAMP_440 : TJ.SAMP_422, i, argv[0]); 845 System.out.println(""); 846 System.gc(); 847 for (int i = maxQual; i >= minQual; i--) 848 doTest(srcBuf, w, h, TJ.SAMP_444, i, argv[0]); 849 System.out.println(""); 850 851 } catch (Exception e) { 852 System.out.println("ERROR: " + e.getMessage()); 853 e.printStackTrace(); 854 retval = -1; 855 } 856 857 System.exit(retval); 858 } 859 860} 861