TJBench.java 35 KB

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