tjbench.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. /*
  2. * Copyright (C)2009-2019 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. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <ctype.h>
  32. #include <math.h>
  33. #include <errno.h>
  34. #include <limits.h>
  35. #include <cdjpeg.h>
  36. #include "./tjutil.h"
  37. #include "./turbojpeg.h"
  38. #define THROW(op, err) { \
  39. printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \
  40. retval = -1; goto bailout; \
  41. }
  42. #define THROW_UNIX(m) THROW(m, strerror(errno))
  43. char tjErrorStr[JMSG_LENGTH_MAX] = "\0", tjErrorMsg[JMSG_LENGTH_MAX] = "\0";
  44. int tjErrorLine = -1, tjErrorCode = -1;
  45. #define THROW_TJG(m) { \
  46. printf("ERROR in line %d while %s:\n%s\n", __LINE__, m, \
  47. tjGetErrorStr2(NULL)); \
  48. retval = -1; goto bailout; \
  49. }
  50. #define THROW_TJ(m) { \
  51. int _tjErrorCode = tjGetErrorCode(handle); \
  52. char *_tjErrorStr = tjGetErrorStr2(handle); \
  53. \
  54. if (!(flags & TJFLAG_STOPONWARNING) && _tjErrorCode == TJERR_WARNING) { \
  55. if (strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \
  56. strncmp(tjErrorMsg, m, JMSG_LENGTH_MAX) || \
  57. tjErrorCode != _tjErrorCode || tjErrorLine != __LINE__) { \
  58. strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX - 1); \
  59. strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX - 1); \
  60. tjErrorCode = _tjErrorCode; \
  61. tjErrorLine = __LINE__; \
  62. printf("WARNING in line %d while %s:\n%s\n", __LINE__, m, _tjErrorStr); \
  63. } \
  64. } else { \
  65. printf("%s in line %d while %s:\n%s\n", \
  66. _tjErrorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, m, \
  67. _tjErrorStr); \
  68. retval = -1; goto bailout; \
  69. } \
  70. }
  71. int flags = TJFLAG_NOREALLOC, compOnly = 0, decompOnly = 0, doYUV = 0,
  72. quiet = 0, doTile = 0, pf = TJPF_BGR, yuvPad = 1, doWrite = 1;
  73. char *ext = "ppm";
  74. const char *pixFormatStr[TJ_NUMPF] = {
  75. "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", "CMYK"
  76. };
  77. const char *subNameLong[TJ_NUMSAMP] = {
  78. "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
  79. };
  80. const char *csName[TJ_NUMCS] = {
  81. "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
  82. };
  83. const char *subName[TJ_NUMSAMP] = {
  84. "444", "422", "420", "GRAY", "440", "411"
  85. };
  86. tjscalingfactor *scalingFactors = NULL, sf = { 1, 1 };
  87. int nsf = 0, xformOp = TJXOP_NONE, xformOpt = 0;
  88. int (*customFilter) (short *, tjregion, tjregion, int, int, tjtransform *);
  89. double benchTime = 5.0, warmup = 1.0;
  90. static char *formatName(int subsamp, int cs, char *buf)
  91. {
  92. if (cs == TJCS_YCbCr)
  93. return (char *)subNameLong[subsamp];
  94. else if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
  95. snprintf(buf, 80, "%s %s", csName[cs], subNameLong[subsamp]);
  96. return buf;
  97. } else
  98. return (char *)csName[cs];
  99. }
  100. static char *sigfig(double val, int figs, char *buf, int len)
  101. {
  102. char format[80];
  103. int digitsAfterDecimal = figs - (int)ceil(log10(fabs(val)));
  104. if (digitsAfterDecimal < 1)
  105. snprintf(format, 80, "%%.0f");
  106. else
  107. snprintf(format, 80, "%%.%df", digitsAfterDecimal);
  108. snprintf(buf, len, format, val);
  109. return buf;
  110. }
  111. /* Custom DCT filter which produces a negative of the image */
  112. static int dummyDCTFilter(short *coeffs, tjregion arrayRegion,
  113. tjregion planeRegion, int componentIndex,
  114. int transformIndex, tjtransform *transform)
  115. {
  116. int i;
  117. for (i = 0; i < arrayRegion.w * arrayRegion.h; i++)
  118. coeffs[i] = -coeffs[i];
  119. return 0;
  120. }
  121. /* Decompression test */
  122. static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
  123. unsigned long *jpegSize, unsigned char *dstBuf, int w, int h,
  124. int subsamp, int jpegQual, char *fileName, int tilew,
  125. int tileh)
  126. {
  127. char tempStr[1024], sizeStr[24] = "\0", qualStr[13] = "\0", *ptr;
  128. FILE *file = NULL;
  129. tjhandle handle = NULL;
  130. int row, col, iter = 0, dstBufAlloc = 0, retval = 0;
  131. double elapsed, elapsedDecode;
  132. int ps = tjPixelSize[pf];
  133. int scaledw = TJSCALED(w, sf);
  134. int scaledh = TJSCALED(h, sf);
  135. int pitch = scaledw * ps;
  136. int ntilesw = (w + tilew - 1) / tilew, ntilesh = (h + tileh - 1) / tileh;
  137. unsigned char *dstPtr, *dstPtr2, *yuvBuf = NULL;
  138. if (jpegQual > 0) {
  139. snprintf(qualStr, 13, "_Q%d", jpegQual);
  140. qualStr[12] = 0;
  141. }
  142. if ((handle = tjInitDecompress()) == NULL)
  143. THROW_TJ("executing tjInitDecompress()");
  144. if (dstBuf == NULL) {
  145. if ((unsigned long long)pitch * (unsigned long long)scaledh >
  146. (unsigned long long)((size_t)-1))
  147. THROW("allocating destination buffer", "Image is too large");
  148. if ((dstBuf = (unsigned char *)malloc((size_t)pitch * scaledh)) == NULL)
  149. THROW_UNIX("allocating destination buffer");
  150. dstBufAlloc = 1;
  151. }
  152. /* Set the destination buffer to gray so we know whether the decompressor
  153. attempted to write to it */
  154. memset(dstBuf, 127, (size_t)pitch * scaledh);
  155. if (doYUV) {
  156. int width = doTile ? tilew : scaledw;
  157. int height = doTile ? tileh : scaledh;
  158. unsigned long yuvSize = tjBufSizeYUV2(width, yuvPad, height, subsamp);
  159. if (yuvSize == (unsigned long)-1)
  160. THROW_TJ("allocating YUV buffer");
  161. if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
  162. THROW_UNIX("allocating YUV buffer");
  163. memset(yuvBuf, 127, yuvSize);
  164. }
  165. /* Benchmark */
  166. iter = -1;
  167. elapsed = elapsedDecode = 0.;
  168. while (1) {
  169. int tile = 0;
  170. double start = getTime();
  171. for (row = 0, dstPtr = dstBuf; row < ntilesh;
  172. row++, dstPtr += (size_t)pitch * tileh) {
  173. for (col = 0, dstPtr2 = dstPtr; col < ntilesw;
  174. col++, tile++, dstPtr2 += ps * tilew) {
  175. int width = doTile ? min(tilew, w - col * tilew) : scaledw;
  176. int height = doTile ? min(tileh, h - row * tileh) : scaledh;
  177. if (doYUV) {
  178. double startDecode;
  179. if (tjDecompressToYUV2(handle, jpegBuf[tile], jpegSize[tile], yuvBuf,
  180. width, yuvPad, height, flags) == -1)
  181. THROW_TJ("executing tjDecompressToYUV2()");
  182. startDecode = getTime();
  183. if (tjDecodeYUV(handle, yuvBuf, yuvPad, subsamp, dstPtr2, width,
  184. pitch, height, pf, flags) == -1)
  185. THROW_TJ("executing tjDecodeYUV()");
  186. if (iter >= 0) elapsedDecode += getTime() - startDecode;
  187. } else if (tjDecompress2(handle, jpegBuf[tile], jpegSize[tile],
  188. dstPtr2, width, pitch, height, pf,
  189. flags) == -1)
  190. THROW_TJ("executing tjDecompress2()");
  191. }
  192. }
  193. elapsed += getTime() - start;
  194. if (iter >= 0) {
  195. iter++;
  196. if (elapsed >= benchTime) break;
  197. } else if (elapsed >= warmup) {
  198. iter = 0;
  199. elapsed = elapsedDecode = 0.;
  200. }
  201. }
  202. if (doYUV) elapsed -= elapsedDecode;
  203. if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
  204. handle = NULL;
  205. if (quiet) {
  206. printf("%-6s%s",
  207. sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
  208. tempStr, 1024),
  209. quiet == 2 ? "\n" : " ");
  210. if (doYUV)
  211. printf("%s\n",
  212. sigfig((double)(w * h) / 1000000. * (double)iter / elapsedDecode,
  213. 4, tempStr, 1024));
  214. else if (quiet != 2) printf("\n");
  215. } else {
  216. printf("%s --> Frame rate: %f fps\n",
  217. doYUV ? "Decomp to YUV" : "Decompress ", (double)iter / elapsed);
  218. printf(" Throughput: %f Megapixels/sec\n",
  219. (double)(w * h) / 1000000. * (double)iter / elapsed);
  220. if (doYUV) {
  221. printf("YUV Decode --> Frame rate: %f fps\n",
  222. (double)iter / elapsedDecode);
  223. printf(" Throughput: %f Megapixels/sec\n",
  224. (double)(w * h) / 1000000. * (double)iter / elapsedDecode);
  225. }
  226. }
  227. if (!doWrite) goto bailout;
  228. if (sf.num != 1 || sf.denom != 1)
  229. snprintf(sizeStr, 24, "%d_%d", sf.num, sf.denom);
  230. else if (tilew != w || tileh != h)
  231. snprintf(sizeStr, 24, "%dx%d", tilew, tileh);
  232. else snprintf(sizeStr, 24, "full");
  233. if (decompOnly)
  234. snprintf(tempStr, 1024, "%s_%s.%s", fileName, sizeStr, ext);
  235. else
  236. snprintf(tempStr, 1024, "%s_%s%s_%s.%s", fileName, subName[subsamp],
  237. qualStr, sizeStr, ext);
  238. if (tjSaveImage(tempStr, dstBuf, scaledw, 0, scaledh, pf, flags) == -1)
  239. THROW_TJG("saving bitmap");
  240. ptr = strrchr(tempStr, '.');
  241. snprintf(ptr, 1024 - (ptr - tempStr), "-err.%s", ext);
  242. if (srcBuf && sf.num == 1 && sf.denom == 1) {
  243. if (!quiet) printf("Compression error written to %s.\n", tempStr);
  244. if (subsamp == TJ_GRAYSCALE) {
  245. unsigned long index, index2;
  246. for (row = 0, index = 0; row < h; row++, index += pitch) {
  247. for (col = 0, index2 = index; col < w; col++, index2 += ps) {
  248. unsigned long rindex = index2 + tjRedOffset[pf];
  249. unsigned long gindex = index2 + tjGreenOffset[pf];
  250. unsigned long bindex = index2 + tjBlueOffset[pf];
  251. int y = (int)((double)srcBuf[rindex] * 0.299 +
  252. (double)srcBuf[gindex] * 0.587 +
  253. (double)srcBuf[bindex] * 0.114 + 0.5);
  254. if (y > 255) y = 255;
  255. if (y < 0) y = 0;
  256. dstBuf[rindex] = abs(dstBuf[rindex] - y);
  257. dstBuf[gindex] = abs(dstBuf[gindex] - y);
  258. dstBuf[bindex] = abs(dstBuf[bindex] - y);
  259. }
  260. }
  261. } else {
  262. for (row = 0; row < h; row++)
  263. for (col = 0; col < w * ps; col++)
  264. dstBuf[pitch * row + col] =
  265. abs(dstBuf[pitch * row + col] - srcBuf[pitch * row + col]);
  266. }
  267. if (tjSaveImage(tempStr, dstBuf, w, 0, h, pf, flags) == -1)
  268. THROW_TJG("saving bitmap");
  269. }
  270. bailout:
  271. if (file) fclose(file);
  272. if (handle) tjDestroy(handle);
  273. if (dstBufAlloc) free(dstBuf);
  274. free(yuvBuf);
  275. return retval;
  276. }
  277. static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
  278. int jpegQual, char *fileName)
  279. {
  280. char tempStr[1024], tempStr2[80];
  281. FILE *file = NULL;
  282. tjhandle handle = NULL;
  283. unsigned char **jpegBuf = NULL, *yuvBuf = NULL, *tmpBuf = NULL, *srcPtr,
  284. *srcPtr2;
  285. double start, elapsed, elapsedEncode;
  286. int totalJpegSize = 0, row, col, i, tilew = w, tileh = h, retval = 0;
  287. int iter;
  288. unsigned long *jpegSize = NULL, yuvSize = 0;
  289. int ps = tjPixelSize[pf];
  290. int ntilesw = 1, ntilesh = 1, pitch = w * ps;
  291. const char *pfStr = pixFormatStr[pf];
  292. if ((unsigned long long)pitch * (unsigned long long)h >
  293. (unsigned long long)((size_t)-1))
  294. THROW("allocating temporary image buffer", "Image is too large");
  295. if ((tmpBuf = (unsigned char *)malloc((size_t)pitch * h)) == NULL)
  296. THROW_UNIX("allocating temporary image buffer");
  297. if (!quiet)
  298. printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pfStr,
  299. (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down",
  300. subNameLong[subsamp], jpegQual);
  301. for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
  302. tilew *= 2, tileh *= 2) {
  303. if (tilew > w) tilew = w;
  304. if (tileh > h) tileh = h;
  305. ntilesw = (w + tilew - 1) / tilew;
  306. ntilesh = (h + tileh - 1) / tileh;
  307. if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
  308. ntilesw * ntilesh)) == NULL)
  309. THROW_UNIX("allocating JPEG tile array");
  310. memset(jpegBuf, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
  311. if ((jpegSize = (unsigned long *)malloc(sizeof(unsigned long) *
  312. ntilesw * ntilesh)) == NULL)
  313. THROW_UNIX("allocating JPEG size array");
  314. memset(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
  315. if ((flags & TJFLAG_NOREALLOC) != 0)
  316. for (i = 0; i < ntilesw * ntilesh; i++) {
  317. if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
  318. THROW("getting buffer size", "Image is too large");
  319. if ((jpegBuf[i] = (unsigned char *)
  320. tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
  321. THROW_UNIX("allocating JPEG tiles");
  322. }
  323. /* Compression test */
  324. if (quiet == 1)
  325. printf("%-4s (%s) %-5s %-3d ", pfStr,
  326. (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", subNameLong[subsamp],
  327. jpegQual);
  328. for (i = 0; i < h; i++)
  329. memcpy(&tmpBuf[pitch * i], &srcBuf[w * ps * i], w * ps);
  330. if ((handle = tjInitCompress()) == NULL)
  331. THROW_TJ("executing tjInitCompress()");
  332. if (doYUV) {
  333. yuvSize = tjBufSizeYUV2(tilew, yuvPad, tileh, subsamp);
  334. if (yuvSize == (unsigned long)-1)
  335. THROW_TJ("allocating YUV buffer");
  336. if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
  337. THROW_UNIX("allocating YUV buffer");
  338. memset(yuvBuf, 127, yuvSize);
  339. }
  340. /* Benchmark */
  341. iter = -1;
  342. elapsed = elapsedEncode = 0.;
  343. while (1) {
  344. int tile = 0;
  345. totalJpegSize = 0;
  346. start = getTime();
  347. for (row = 0, srcPtr = srcBuf; row < ntilesh;
  348. row++, srcPtr += pitch * tileh) {
  349. for (col = 0, srcPtr2 = srcPtr; col < ntilesw;
  350. col++, tile++, srcPtr2 += ps * tilew) {
  351. int width = min(tilew, w - col * tilew);
  352. int height = min(tileh, h - row * tileh);
  353. if (doYUV) {
  354. double startEncode = getTime();
  355. if (tjEncodeYUV3(handle, srcPtr2, width, pitch, height, pf, yuvBuf,
  356. yuvPad, subsamp, flags) == -1)
  357. THROW_TJ("executing tjEncodeYUV3()");
  358. if (iter >= 0) elapsedEncode += getTime() - startEncode;
  359. if (tjCompressFromYUV(handle, yuvBuf, width, yuvPad, height,
  360. subsamp, &jpegBuf[tile], &jpegSize[tile],
  361. jpegQual, flags) == -1)
  362. THROW_TJ("executing tjCompressFromYUV()");
  363. } else {
  364. if (tjCompress2(handle, srcPtr2, width, pitch, height, pf,
  365. &jpegBuf[tile], &jpegSize[tile], subsamp, jpegQual,
  366. flags) == -1)
  367. THROW_TJ("executing tjCompress2()");
  368. }
  369. totalJpegSize += jpegSize[tile];
  370. }
  371. }
  372. elapsed += getTime() - start;
  373. if (iter >= 0) {
  374. iter++;
  375. if (elapsed >= benchTime) break;
  376. } else if (elapsed >= warmup) {
  377. iter = 0;
  378. elapsed = elapsedEncode = 0.;
  379. }
  380. }
  381. if (doYUV) elapsed -= elapsedEncode;
  382. if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
  383. handle = NULL;
  384. if (quiet == 1) printf("%-5d %-5d ", tilew, tileh);
  385. if (quiet) {
  386. if (doYUV)
  387. printf("%-6s%s",
  388. sigfig((double)(w * h) / 1000000. *
  389. (double)iter / elapsedEncode, 4, tempStr, 1024),
  390. quiet == 2 ? "\n" : " ");
  391. printf("%-6s%s",
  392. sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
  393. tempStr, 1024),
  394. quiet == 2 ? "\n" : " ");
  395. printf("%-6s%s",
  396. sigfig((double)(w * h * ps) / (double)totalJpegSize, 4, tempStr2,
  397. 80),
  398. quiet == 2 ? "\n" : " ");
  399. } else {
  400. printf("\n%s size: %d x %d\n", doTile ? "Tile" : "Image", tilew, tileh);
  401. if (doYUV) {
  402. printf("Encode YUV --> Frame rate: %f fps\n",
  403. (double)iter / elapsedEncode);
  404. printf(" Output image size: %lu bytes\n", yuvSize);
  405. printf(" Compression ratio: %f:1\n",
  406. (double)(w * h * ps) / (double)yuvSize);
  407. printf(" Throughput: %f Megapixels/sec\n",
  408. (double)(w * h) / 1000000. * (double)iter / elapsedEncode);
  409. printf(" Output bit stream: %f Megabits/sec\n",
  410. (double)yuvSize * 8. / 1000000. * (double)iter / elapsedEncode);
  411. }
  412. printf("%s --> Frame rate: %f fps\n",
  413. doYUV ? "Comp from YUV" : "Compress ",
  414. (double)iter / elapsed);
  415. printf(" Output image size: %d bytes\n",
  416. totalJpegSize);
  417. printf(" Compression ratio: %f:1\n",
  418. (double)(w * h * ps) / (double)totalJpegSize);
  419. printf(" Throughput: %f Megapixels/sec\n",
  420. (double)(w * h) / 1000000. * (double)iter / elapsed);
  421. printf(" Output bit stream: %f Megabits/sec\n",
  422. (double)totalJpegSize * 8. / 1000000. * (double)iter / elapsed);
  423. }
  424. if (tilew == w && tileh == h && doWrite) {
  425. snprintf(tempStr, 1024, "%s_%s_Q%d.jpg", fileName, subName[subsamp],
  426. jpegQual);
  427. if ((file = fopen(tempStr, "wb")) == NULL)
  428. THROW_UNIX("opening reference image");
  429. if (fwrite(jpegBuf[0], jpegSize[0], 1, file) != 1)
  430. THROW_UNIX("writing reference image");
  431. fclose(file); file = NULL;
  432. if (!quiet) printf("Reference image written to %s\n", tempStr);
  433. }
  434. /* Decompression test */
  435. if (!compOnly) {
  436. if (decomp(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual,
  437. fileName, tilew, tileh) == -1)
  438. goto bailout;
  439. } else if (quiet == 1) printf("N/A\n");
  440. for (i = 0; i < ntilesw * ntilesh; i++) {
  441. tjFree(jpegBuf[i]);
  442. jpegBuf[i] = NULL;
  443. }
  444. free(jpegBuf); jpegBuf = NULL;
  445. free(jpegSize); jpegSize = NULL;
  446. if (doYUV) {
  447. free(yuvBuf); yuvBuf = NULL;
  448. }
  449. if (tilew == w && tileh == h) break;
  450. }
  451. bailout:
  452. if (file) fclose(file);
  453. if (jpegBuf) {
  454. for (i = 0; i < ntilesw * ntilesh; i++)
  455. tjFree(jpegBuf[i]);
  456. }
  457. free(jpegBuf);
  458. free(yuvBuf);
  459. free(jpegSize);
  460. free(tmpBuf);
  461. if (handle) tjDestroy(handle);
  462. return retval;
  463. }
  464. static int decompTest(char *fileName)
  465. {
  466. FILE *file = NULL;
  467. tjhandle handle = NULL;
  468. unsigned char **jpegBuf = NULL, *srcBuf = NULL;
  469. unsigned long *jpegSize = NULL, srcSize, totalJpegSize;
  470. tjtransform *t = NULL;
  471. double start, elapsed;
  472. int ps = tjPixelSize[pf], tile, row, col, i, iter, retval = 0, decompsrc = 0;
  473. char *temp = NULL, tempStr[80], tempStr2[80];
  474. /* Original image */
  475. int w = 0, h = 0, tilew, tileh, ntilesw = 1, ntilesh = 1, subsamp = -1,
  476. cs = -1;
  477. /* Transformed image */
  478. int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
  479. if ((file = fopen(fileName, "rb")) == NULL)
  480. THROW_UNIX("opening file");
  481. if (fseek(file, 0, SEEK_END) < 0 ||
  482. (srcSize = ftell(file)) == (unsigned long)-1)
  483. THROW_UNIX("determining file size");
  484. if ((srcBuf = (unsigned char *)malloc(srcSize)) == NULL)
  485. THROW_UNIX("allocating memory");
  486. if (fseek(file, 0, SEEK_SET) < 0)
  487. THROW_UNIX("setting file position");
  488. if (fread(srcBuf, srcSize, 1, file) < 1)
  489. THROW_UNIX("reading JPEG data");
  490. fclose(file); file = NULL;
  491. temp = strrchr(fileName, '.');
  492. if (temp != NULL) *temp = '\0';
  493. if ((handle = tjInitTransform()) == NULL)
  494. THROW_TJ("executing tjInitTransform()");
  495. if (tjDecompressHeader3(handle, srcBuf, srcSize, &w, &h, &subsamp,
  496. &cs) == -1)
  497. THROW_TJ("executing tjDecompressHeader3()");
  498. if (w < 1 || h < 1)
  499. THROW("reading JPEG header", "Invalid image dimensions");
  500. if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
  501. pf = TJPF_CMYK; ps = tjPixelSize[pf];
  502. }
  503. if (quiet == 1) {
  504. printf("All performance values in Mpixels/sec\n\n");
  505. printf("Bitmap JPEG JPEG %s %s Xform Comp Decomp ",
  506. doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
  507. if (doYUV) printf("Decode");
  508. printf("\n");
  509. printf("Format CS Subsamp Width Height Perf Ratio Perf ");
  510. if (doYUV) printf("Perf");
  511. printf("\n\n");
  512. } else if (!quiet)
  513. printf(">>>>> JPEG %s --> %s (%s) <<<<<\n",
  514. formatName(subsamp, cs, tempStr), pixFormatStr[pf],
  515. (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down");
  516. for (tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ;
  517. tilew *= 2, tileh *= 2) {
  518. if (tilew > w) tilew = w;
  519. if (tileh > h) tileh = h;
  520. ntilesw = (w + tilew - 1) / tilew;
  521. ntilesh = (h + tileh - 1) / tileh;
  522. if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
  523. ntilesw * ntilesh)) == NULL)
  524. THROW_UNIX("allocating JPEG tile array");
  525. memset(jpegBuf, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
  526. if ((jpegSize = (unsigned long *)malloc(sizeof(unsigned long) *
  527. ntilesw * ntilesh)) == NULL)
  528. THROW_UNIX("allocating JPEG size array");
  529. memset(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
  530. if ((flags & TJFLAG_NOREALLOC) != 0 &&
  531. (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter))
  532. for (i = 0; i < ntilesw * ntilesh; i++) {
  533. if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
  534. THROW("getting buffer size", "Image is too large");
  535. if ((jpegBuf[i] = (unsigned char *)
  536. tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
  537. THROW_UNIX("allocating JPEG tiles");
  538. }
  539. tw = w; th = h; ttilew = tilew; ttileh = tileh;
  540. if (!quiet) {
  541. printf("\n%s size: %d x %d", doTile ? "Tile" : "Image", ttilew, ttileh);
  542. if (sf.num != 1 || sf.denom != 1)
  543. printf(" --> %d x %d", TJSCALED(tw, sf), TJSCALED(th, sf));
  544. printf("\n");
  545. } else if (quiet == 1) {
  546. printf("%-4s (%s) %-5s %-5s ", pixFormatStr[pf],
  547. (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", csName[cs],
  548. subNameLong[subsamp]);
  549. printf("%-5d %-5d ", tilew, tileh);
  550. }
  551. tsubsamp = subsamp;
  552. if (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter) {
  553. if ((t = (tjtransform *)malloc(sizeof(tjtransform) * ntilesw *
  554. ntilesh)) == NULL)
  555. THROW_UNIX("allocating image transform array");
  556. if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
  557. xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
  558. tw = h; th = w; ttilew = tileh; ttileh = tilew;
  559. }
  560. if (xformOpt & TJXOPT_GRAY) tsubsamp = TJ_GRAYSCALE;
  561. if (xformOp == TJXOP_HFLIP || xformOp == TJXOP_ROT180)
  562. tw = tw - (tw % tjMCUWidth[tsubsamp]);
  563. if (xformOp == TJXOP_VFLIP || xformOp == TJXOP_ROT180)
  564. th = th - (th % tjMCUHeight[tsubsamp]);
  565. if (xformOp == TJXOP_TRANSVERSE || xformOp == TJXOP_ROT90)
  566. tw = tw - (tw % tjMCUHeight[tsubsamp]);
  567. if (xformOp == TJXOP_TRANSVERSE || xformOp == TJXOP_ROT270)
  568. th = th - (th % tjMCUWidth[tsubsamp]);
  569. tntilesw = (tw + ttilew - 1) / ttilew;
  570. tntilesh = (th + ttileh - 1) / ttileh;
  571. if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
  572. xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
  573. if (tsubsamp == TJSAMP_422) tsubsamp = TJSAMP_440;
  574. else if (tsubsamp == TJSAMP_440) tsubsamp = TJSAMP_422;
  575. }
  576. for (row = 0, tile = 0; row < tntilesh; row++) {
  577. for (col = 0; col < tntilesw; col++, tile++) {
  578. t[tile].r.w = min(ttilew, tw - col * ttilew);
  579. t[tile].r.h = min(ttileh, th - row * ttileh);
  580. t[tile].r.x = col * ttilew;
  581. t[tile].r.y = row * ttileh;
  582. t[tile].op = xformOp;
  583. t[tile].options = xformOpt | TJXOPT_TRIM;
  584. t[tile].customFilter = customFilter;
  585. if (t[tile].options & TJXOPT_NOOUTPUT && jpegBuf[tile]) {
  586. tjFree(jpegBuf[tile]); jpegBuf[tile] = NULL;
  587. }
  588. }
  589. }
  590. iter = -1;
  591. elapsed = 0.;
  592. while (1) {
  593. start = getTime();
  594. if (tjTransform(handle, srcBuf, srcSize, tntilesw * tntilesh, jpegBuf,
  595. jpegSize, t, flags) == -1)
  596. THROW_TJ("executing tjTransform()");
  597. elapsed += getTime() - start;
  598. if (iter >= 0) {
  599. iter++;
  600. if (elapsed >= benchTime) break;
  601. } else if (elapsed >= warmup) {
  602. iter = 0;
  603. elapsed = 0.;
  604. }
  605. }
  606. free(t); t = NULL;
  607. for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
  608. totalJpegSize += jpegSize[tile];
  609. if (quiet) {
  610. printf("%-6s%s%-6s%s",
  611. sigfig((double)(w * h) / 1000000. / elapsed, 4, tempStr, 80),
  612. quiet == 2 ? "\n" : " ",
  613. sigfig((double)(w * h * ps) / (double)totalJpegSize, 4,
  614. tempStr2, 80),
  615. quiet == 2 ? "\n" : " ");
  616. } else if (!quiet) {
  617. printf("Transform --> Frame rate: %f fps\n",
  618. 1.0 / elapsed);
  619. printf(" Output image size: %lu bytes\n",
  620. totalJpegSize);
  621. printf(" Compression ratio: %f:1\n",
  622. (double)(w * h * ps) / (double)totalJpegSize);
  623. printf(" Throughput: %f Megapixels/sec\n",
  624. (double)(w * h) / 1000000. / elapsed);
  625. printf(" Output bit stream: %f Megabits/sec\n",
  626. (double)totalJpegSize * 8. / 1000000. / elapsed);
  627. }
  628. } else {
  629. if (quiet == 1) printf("N/A N/A ");
  630. tjFree(jpegBuf[0]);
  631. jpegBuf[0] = NULL;
  632. decompsrc = 1;
  633. }
  634. if (w == tilew) ttilew = tw;
  635. if (h == tileh) ttileh = th;
  636. if (!(xformOpt & TJXOPT_NOOUTPUT)) {
  637. if (decomp(NULL, decompsrc ? &srcBuf : jpegBuf,
  638. decompsrc ? &srcSize : jpegSize, NULL, tw, th, tsubsamp, 0,
  639. fileName, ttilew, ttileh) == -1)
  640. goto bailout;
  641. } else if (quiet == 1) printf("N/A\n");
  642. for (i = 0; i < ntilesw * ntilesh; i++) {
  643. tjFree(jpegBuf[i]);
  644. jpegBuf[i] = NULL;
  645. }
  646. free(jpegBuf); jpegBuf = NULL;
  647. free(jpegSize); jpegSize = NULL;
  648. if (tilew == w && tileh == h) break;
  649. }
  650. bailout:
  651. if (file) fclose(file);
  652. if (jpegBuf) {
  653. for (i = 0; i < ntilesw * ntilesh; i++)
  654. tjFree(jpegBuf[i]);
  655. }
  656. free(jpegBuf);
  657. free(jpegSize);
  658. free(srcBuf);
  659. free(t);
  660. if (handle) { tjDestroy(handle); handle = NULL; }
  661. return retval;
  662. }
  663. static void usage(char *progName)
  664. {
  665. int i;
  666. printf("USAGE: %s\n", progName);
  667. printf(" <Inputfile (BMP|PPM)> <Quality> [options]\n\n");
  668. printf(" %s\n", progName);
  669. printf(" <Inputfile (JPG)> [options]\n\n");
  670. printf("Options:\n\n");
  671. printf("-alloc = Dynamically allocate JPEG image buffers\n");
  672. printf("-bmp = Generate output images in Windows Bitmap format (default = PPM)\n");
  673. printf("-bottomup = Test bottom-up compression/decompression\n");
  674. printf("-tile = Test performance of the codec when the image is encoded as separate\n");
  675. printf(" tiles of varying sizes.\n");
  676. printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
  677. printf(" Test the specified color conversion path in the codec (default = BGR)\n");
  678. printf("-cmyk = Indirectly test YCCK JPEG compression/decompression (the source\n");
  679. printf(" and destination bitmaps are still RGB. The conversion is done\n");
  680. printf(" internally prior to compression or after decompression.)\n");
  681. printf("-fastupsample = Use the fastest chrominance upsampling algorithm available in\n");
  682. printf(" the underlying codec\n");
  683. printf("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying\n");
  684. printf(" codec\n");
  685. printf("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the\n");
  686. printf(" underlying codec\n");
  687. printf("-progressive = Use progressive entropy coding in JPEG images generated by\n");
  688. printf(" compression and transform operations.\n");
  689. printf("-subsamp <s> = When testing JPEG compression, this option specifies the level\n");
  690. printf(" of chrominance subsampling to use (<s> = 444, 422, 440, 420, 411, or\n");
  691. printf(" GRAY). The default is to test Grayscale, 4:2:0, 4:2:2, and 4:4:4 in\n");
  692. printf(" sequence.\n");
  693. printf("-quiet = Output results in tabular rather than verbose format\n");
  694. printf("-yuv = Test YUV encoding/decoding functions\n");
  695. printf("-yuvpad <p> = If testing YUV encoding/decoding, this specifies the number of\n");
  696. printf(" bytes to which each row of each plane in the intermediate YUV image is\n");
  697. printf(" padded (default = 1)\n");
  698. printf("-scale M/N = Scale down the width/height of the decompressed JPEG image by a\n");
  699. printf(" factor of M/N (M/N = ");
  700. for (i = 0; i < nsf; i++) {
  701. printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
  702. if (nsf == 2 && i != nsf - 1) printf(" or ");
  703. else if (nsf > 2) {
  704. if (i != nsf - 1) printf(", ");
  705. if (i == nsf - 2) printf("or ");
  706. }
  707. if (i % 8 == 0 && i != 0) printf("\n ");
  708. }
  709. printf(")\n");
  710. printf("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =\n");
  711. printf(" Perform the corresponding lossless transform prior to\n");
  712. printf(" decompression (these options are mutually exclusive)\n");
  713. printf("-grayscale = Perform lossless grayscale conversion prior to decompression\n");
  714. printf(" test (can be combined with the other transforms above)\n");
  715. printf("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)\n");
  716. printf(" when transforming the image.\n");
  717. printf("-benchtime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n");
  718. printf("-warmup <t> = Run each benchmark for <t> seconds (default = 1.0) prior to\n");
  719. printf(" starting the timer, in order to prime the caches and thus improve the\n");
  720. printf(" consistency of the results.\n");
  721. printf("-componly = Stop after running compression tests. Do not test decompression.\n");
  722. printf("-nowrite = Do not write reference or output images (improves consistency of\n");
  723. printf(" performance measurements.)\n");
  724. printf("-stoponwarning = Immediately discontinue the current\n");
  725. printf(" compression/decompression/transform operation if the underlying codec\n");
  726. printf(" throws a warning (non-fatal error)\n\n");
  727. printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
  728. printf("test will be performed for all quality values in the range.\n\n");
  729. exit(1);
  730. }
  731. int main(int argc, char *argv[])
  732. {
  733. unsigned char *srcBuf = NULL;
  734. int w = 0, h = 0, i, j, minQual = -1, maxQual = -1;
  735. char *temp;
  736. int minArg = 2, retval = 0, subsamp = -1;
  737. if ((scalingFactors = tjGetScalingFactors(&nsf)) == NULL || nsf == 0)
  738. THROW("executing tjGetScalingFactors()", tjGetErrorStr());
  739. if (argc < minArg) usage(argv[0]);
  740. temp = strrchr(argv[1], '.');
  741. if (temp != NULL) {
  742. if (!strcasecmp(temp, ".bmp")) ext = "bmp";
  743. if (!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg"))
  744. decompOnly = 1;
  745. }
  746. printf("\n");
  747. if (!decompOnly) {
  748. minArg = 3;
  749. if (argc < minArg) usage(argv[0]);
  750. if ((minQual = atoi(argv[2])) < 1 || minQual > 100) {
  751. puts("ERROR: Quality must be between 1 and 100.");
  752. exit(1);
  753. }
  754. if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 &&
  755. sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual &&
  756. maxQual >= 1 && maxQual <= 100) {}
  757. else maxQual = minQual;
  758. }
  759. if (argc > minArg) {
  760. for (i = minArg; i < argc; i++) {
  761. if (!strcasecmp(argv[i], "-tile")) {
  762. doTile = 1; xformOpt |= TJXOPT_CROP;
  763. } else if (!strcasecmp(argv[i], "-fastupsample")) {
  764. printf("Using fast upsampling code\n\n");
  765. flags |= TJFLAG_FASTUPSAMPLE;
  766. } else if (!strcasecmp(argv[i], "-fastdct")) {
  767. printf("Using fastest DCT/IDCT algorithm\n\n");
  768. flags |= TJFLAG_FASTDCT;
  769. } else if (!strcasecmp(argv[i], "-accuratedct")) {
  770. printf("Using most accurate DCT/IDCT algorithm\n\n");
  771. flags |= TJFLAG_ACCURATEDCT;
  772. } else if (!strcasecmp(argv[i], "-progressive")) {
  773. printf("Using progressive entropy coding\n\n");
  774. flags |= TJFLAG_PROGRESSIVE;
  775. } else if (!strcasecmp(argv[i], "-rgb"))
  776. pf = TJPF_RGB;
  777. else if (!strcasecmp(argv[i], "-rgbx"))
  778. pf = TJPF_RGBX;
  779. else if (!strcasecmp(argv[i], "-bgr"))
  780. pf = TJPF_BGR;
  781. else if (!strcasecmp(argv[i], "-bgrx"))
  782. pf = TJPF_BGRX;
  783. else if (!strcasecmp(argv[i], "-xbgr"))
  784. pf = TJPF_XBGR;
  785. else if (!strcasecmp(argv[i], "-xrgb"))
  786. pf = TJPF_XRGB;
  787. else if (!strcasecmp(argv[i], "-cmyk"))
  788. pf = TJPF_CMYK;
  789. else if (!strcasecmp(argv[i], "-bottomup"))
  790. flags |= TJFLAG_BOTTOMUP;
  791. else if (!strcasecmp(argv[i], "-quiet"))
  792. quiet = 1;
  793. else if (!strcasecmp(argv[i], "-qq"))
  794. quiet = 2;
  795. else if (!strcasecmp(argv[i], "-scale") && i < argc - 1) {
  796. int temp1 = 0, temp2 = 0, match = 0;
  797. if (sscanf(argv[++i], "%d/%d", &temp1, &temp2) == 2) {
  798. for (j = 0; j < nsf; j++) {
  799. if ((double)temp1 / (double)temp2 ==
  800. (double)scalingFactors[j].num /
  801. (double)scalingFactors[j].denom) {
  802. sf = scalingFactors[j];
  803. match = 1; break;
  804. }
  805. }
  806. if (!match) usage(argv[0]);
  807. } else usage(argv[0]);
  808. } else if (!strcasecmp(argv[i], "-hflip"))
  809. xformOp = TJXOP_HFLIP;
  810. else if (!strcasecmp(argv[i], "-vflip"))
  811. xformOp = TJXOP_VFLIP;
  812. else if (!strcasecmp(argv[i], "-transpose"))
  813. xformOp = TJXOP_TRANSPOSE;
  814. else if (!strcasecmp(argv[i], "-transverse"))
  815. xformOp = TJXOP_TRANSVERSE;
  816. else if (!strcasecmp(argv[i], "-rot90"))
  817. xformOp = TJXOP_ROT90;
  818. else if (!strcasecmp(argv[i], "-rot180"))
  819. xformOp = TJXOP_ROT180;
  820. else if (!strcasecmp(argv[i], "-rot270"))
  821. xformOp = TJXOP_ROT270;
  822. else if (!strcasecmp(argv[i], "-grayscale"))
  823. xformOpt |= TJXOPT_GRAY;
  824. else if (!strcasecmp(argv[i], "-custom"))
  825. customFilter = dummyDCTFilter;
  826. else if (!strcasecmp(argv[i], "-nooutput"))
  827. xformOpt |= TJXOPT_NOOUTPUT;
  828. else if (!strcasecmp(argv[i], "-copynone"))
  829. xformOpt |= TJXOPT_COPYNONE;
  830. else if (!strcasecmp(argv[i], "-benchtime") && i < argc - 1) {
  831. double tempd = atof(argv[++i]);
  832. if (tempd > 0.0) benchTime = tempd;
  833. else usage(argv[0]);
  834. } else if (!strcasecmp(argv[i], "-warmup") && i < argc - 1) {
  835. double tempd = atof(argv[++i]);
  836. if (tempd >= 0.0) warmup = tempd;
  837. else usage(argv[0]);
  838. printf("Warmup time = %.1f seconds\n\n", warmup);
  839. } else if (!strcasecmp(argv[i], "-alloc"))
  840. flags &= (~TJFLAG_NOREALLOC);
  841. else if (!strcasecmp(argv[i], "-bmp"))
  842. ext = "bmp";
  843. else if (!strcasecmp(argv[i], "-yuv")) {
  844. printf("Testing YUV planar encoding/decoding\n\n");
  845. doYUV = 1;
  846. } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) {
  847. int tempi = atoi(argv[++i]);
  848. if (tempi >= 1) yuvPad = tempi;
  849. } else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) {
  850. i++;
  851. if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY;
  852. else {
  853. int tempi = atoi(argv[i]);
  854. switch (tempi) {
  855. case 444: subsamp = TJSAMP_444; break;
  856. case 422: subsamp = TJSAMP_422; break;
  857. case 440: subsamp = TJSAMP_440; break;
  858. case 420: subsamp = TJSAMP_420; break;
  859. case 411: subsamp = TJSAMP_411; break;
  860. }
  861. }
  862. } else if (!strcasecmp(argv[i], "-componly"))
  863. compOnly = 1;
  864. else if (!strcasecmp(argv[i], "-nowrite"))
  865. doWrite = 0;
  866. else if (!strcasecmp(argv[i], "-stoponwarning"))
  867. flags |= TJFLAG_STOPONWARNING;
  868. else usage(argv[0]);
  869. }
  870. }
  871. if ((sf.num != 1 || sf.denom != 1) && doTile) {
  872. printf("Disabling tiled compression/decompression tests, because those tests do not\n");
  873. printf("work when scaled decompression is enabled.\n");
  874. doTile = 0;
  875. }
  876. if ((flags & TJFLAG_NOREALLOC) == 0 && doTile) {
  877. printf("Disabling tiled compression/decompression tests, because those tests do not\n");
  878. printf("work when dynamic JPEG buffer allocation is enabled.\n\n");
  879. doTile = 0;
  880. }
  881. if (!decompOnly) {
  882. if ((srcBuf = tjLoadImage(argv[1], &w, 1, &h, &pf, flags)) == NULL)
  883. THROW_TJG("loading bitmap");
  884. temp = strrchr(argv[1], '.');
  885. if (temp != NULL) *temp = '\0';
  886. }
  887. if (quiet == 1 && !decompOnly) {
  888. printf("All performance values in Mpixels/sec\n\n");
  889. printf("Bitmap JPEG JPEG %s %s ",
  890. doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
  891. if (doYUV) printf("Encode ");
  892. printf("Comp Comp Decomp ");
  893. if (doYUV) printf("Decode");
  894. printf("\n");
  895. printf("Format Subsamp Qual Width Height ");
  896. if (doYUV) printf("Perf ");
  897. printf("Perf Ratio Perf ");
  898. if (doYUV) printf("Perf");
  899. printf("\n\n");
  900. }
  901. if (decompOnly) {
  902. decompTest(argv[1]);
  903. printf("\n");
  904. goto bailout;
  905. }
  906. if (subsamp >= 0 && subsamp < TJ_NUMSAMP) {
  907. for (i = maxQual; i >= minQual; i--)
  908. fullTest(srcBuf, w, h, subsamp, i, argv[1]);
  909. printf("\n");
  910. } else {
  911. if (pf != TJPF_CMYK) {
  912. for (i = maxQual; i >= minQual; i--)
  913. fullTest(srcBuf, w, h, TJSAMP_GRAY, i, argv[1]);
  914. printf("\n");
  915. }
  916. for (i = maxQual; i >= minQual; i--)
  917. fullTest(srcBuf, w, h, TJSAMP_420, i, argv[1]);
  918. printf("\n");
  919. for (i = maxQual; i >= minQual; i--)
  920. fullTest(srcBuf, w, h, TJSAMP_422, i, argv[1]);
  921. printf("\n");
  922. for (i = maxQual; i >= minQual; i--)
  923. fullTest(srcBuf, w, h, TJSAMP_444, i, argv[1]);
  924. printf("\n");
  925. }
  926. bailout:
  927. tjFree(srcBuf);
  928. return retval;
  929. }