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