blob: 11d679cf3c761cfbd3b49ba51988f0a05820f3ae [file] [log] [blame]
DRC2e7b76b2009-04-03 12:04:24 +00001/* Copyright (C)2004 Landmark Graphics Corporation
2 * Copyright (C)2005, 2006 Sun Microsystems, Inc.
DRC2e4d0442011-02-08 01:18:37 +00003 * Copyright (C)2009-2011 D. R. Commander
DRC2e7b76b2009-04-03 12:04:24 +00004 *
5 * This library is free software and may be redistributed and/or modified under
6 * the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 * any later version. The full license is in the LICENSE.txt file included
8 * with this distribution.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * wxWindows Library License for more details.
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <math.h>
DRCe8ce2e02010-11-12 10:14:11 +000020#include <errno.h>
DRC2e7b76b2009-04-03 12:04:24 +000021#include "./bmp.h"
22#include "./rrutil.h"
23#include "./rrtimer.h"
24#include "./turbojpeg.h"
25
DRCe8ce2e02010-11-12 10:14:11 +000026#define _throw(op, err) { \
27 printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); goto bailout;}
28#define _throwunix(m) _throw(m, strerror(errno))
29#define _throwtj(m) _throw(m, tjGetErrorStr())
30#define _throwbmp(m) _throw(m, bmpgeterr())
DRC2e7b76b2009-04-03 12:04:24 +000031
DRC9e17f7d2010-12-10 04:59:13 +000032#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
33
34enum {YUVENCODE=1, YUVDECODE};
DRCe8ce2e02010-11-12 10:14:11 +000035int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
DRCfbb67472010-11-24 04:02:37 +000036 decomponly=0, yuv=0;
DRC2e7b76b2009-04-03 12:04:24 +000037const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
38const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR,
39 TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST};
40const int _rindex[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
41const int _gindex[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
42const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
DRCb4b31402011-02-19 17:31:24 +000043const char *_pfname[]={"RGB", "RGBX", "BGR", "BGRX", "XBGR", "XRGB"};
DRC61e51f92009-04-05 21:53:20 +000044const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
45const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
DRC2e7b76b2009-04-03 12:04:24 +000046
47void printsigfig(double val, int figs)
48{
49 char format[80];
50 double _l=log10(val); int l;
51 if(_l<0.)
52 {
53 l=(int)fabs(_l);
54 sprintf(format, "%%%d.%df", figs+l+2, figs+l);
55 }
56 else
57 {
58 l=(int)_l+1;
59 if(figs<=l) sprintf(format, "%%.0f");
60 else sprintf(format, "%%%d.%df", figs+1, figs-l);
61 }
62 printf(format, val);
63}
64
DRC2e4d0442011-02-08 01:18:37 +000065void dotest(unsigned char *srcbuf, int w, int h, int pf, int bu,
DRC2e7b76b2009-04-03 12:04:24 +000066 int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
67{
68 char tempstr[1024];
DRC9e17f7d2010-12-10 04:59:13 +000069 FILE *outfile=NULL; tjhandle hnd;
DRC2e7b76b2009-04-03 12:04:24 +000070 unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
DRC2e4d0442011-02-08 01:18:37 +000071 double start, elapsed;
DRC2e7b76b2009-04-03 12:04:24 +000072 int jpgbufsize=0, i, j, tilesizex, tilesizey, numtilesx, numtilesy, ITER;
73 unsigned long *comptilesize=NULL;
74 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
DRC61e51f92009-04-05 21:53:20 +000075 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
76 |(fastupsample?TJ_FASTUPSAMPLE:0);
DRC2e4d0442011-02-08 01:18:37 +000077 int ps=_ps[pf], tilen;
DRC9e17f7d2010-12-10 04:59:13 +000078 int pitch=w*ps, yuvsize;
DRC2e7b76b2009-04-03 12:04:24 +000079
80 flags |= _flags[pf];
81 if(bu) flags |= TJ_BOTTOMUP;
DRC9e17f7d2010-12-10 04:59:13 +000082 if(yuv==YUVENCODE) flags |= TJ_YUV;
DRC2e7b76b2009-04-03 12:04:24 +000083
DRCeeab6952011-02-25 00:02:04 +000084 yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
DRC9e17f7d2010-12-10 04:59:13 +000085 if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h))) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +000086 _throwunix("allocating image buffer");
DRC2e7b76b2009-04-03 12:04:24 +000087
DRCfbb67472010-11-24 04:02:37 +000088 if(!quiet)
89 {
DRC9e17f7d2010-12-10 04:59:13 +000090 if(yuv==YUVENCODE)
DRC0b11d1c2011-02-24 21:43:35 +000091 printf(">>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf],
DRCfbb67472010-11-24 04:02:37 +000092 bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
93 else
DRC0b11d1c2011-02-24 21:43:35 +000094 printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf],
DRCfbb67472010-11-24 04:02:37 +000095 bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
96 }
DRC5cb1b682011-02-24 22:13:20 +000097 if(yuv) dotile=0;
DRC2e7b76b2009-04-03 12:04:24 +000098 if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;}
99
100 do
101 {
102 tilesizex*=2; if(tilesizex>w) tilesizex=w;
103 tilesizey*=2; if(tilesizey>h) tilesizey=h;
104 numtilesx=(w+tilesizex-1)/tilesizex;
105 numtilesy=(h+tilesizey-1)/tilesizey;
106 if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)*numtilesx*numtilesy)) == NULL
107 || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)*numtilesx*numtilesy)) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000108 _throwunix("allocating image buffers");
DRC2e7b76b2009-04-03 12:04:24 +0000109 memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
110 for(i=0; i<numtilesx*numtilesy; i++)
111 {
112 if((jpegbuf[i]=(unsigned char *)malloc(TJBUFSIZE(tilesizex, tilesizey))) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000113 _throwunix("allocating image buffers");
DRC2e7b76b2009-04-03 12:04:24 +0000114 }
115
116 // Compression test
DRC2a285992011-02-19 17:20:11 +0000117 if(quiet==1) printf("%s\t%s\t%s\t%d\t", _pfname[pf], bu?"BU":"TD",
DRC2e7b76b2009-04-03 12:04:24 +0000118 _subnamel[jpegsub], qual);
119 for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
120 if((hnd=tjInitCompress())==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000121 _throwtj("executing tjInitCompress()");
DRCeeab6952011-02-25 00:02:04 +0000122 if(yuv==YUVENCODE)
123 {
124 if(tjEncodeYUV(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
125 jpegbuf[0], jpegsub, flags)==-1)
126 _throwtj("executing tjEncodeYUV()");
127 comptilesize[0]=TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub);
128 }
129 else if(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
DRCe8ce2e02010-11-12 10:14:11 +0000130 jpegbuf[0], &comptilesize[0], jpegsub, qual, flags)==-1)
131 _throwtj("executing tjCompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000132 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000133 start=rrtime();
DRC2e7b76b2009-04-03 12:04:24 +0000134 do
135 {
DRC2e4d0442011-02-08 01:18:37 +0000136 jpgbufsize=0; tilen=0;
DRC2e7b76b2009-04-03 12:04:24 +0000137 for(i=0; i<h; i+=tilesizey)
138 {
139 for(j=0; j<w; j+=tilesizex)
140 {
141 int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
DRCeeab6952011-02-25 00:02:04 +0000142 if(yuv==YUVENCODE)
143 {
144 if(tjEncodeYUV(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
145 temph, ps, jpegbuf[tilen], jpegsub, flags)==-1)
146 _throwtj("executing tjEncodeYUV()");
147 comptilesize[tilen]=TJBUFSIZEYUV(tempw, temph, jpegsub);
148 }
149 else if(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
DRC2e7b76b2009-04-03 12:04:24 +0000150 temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
DRCe8ce2e02010-11-12 10:14:11 +0000151 flags)==-1)
152 _throwtj("executing tjCompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000153 jpgbufsize+=comptilesize[tilen];
154 tilen++;
155 }
156 }
157 ITER++;
DRC2e4d0442011-02-08 01:18:37 +0000158 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000159 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
160 hnd=NULL;
DRC2a285992011-02-19 17:20:11 +0000161 if(quiet==1)
DRC2e7b76b2009-04-03 12:04:24 +0000162 {
163 if(tilesizex==w && tilesizey==h) printf("Full \t");
164 else printf("%-4d %-4d\t", tilesizex, tilesizey);
DRC2a285992011-02-19 17:20:11 +0000165 }
166 if(quiet)
167 {
DRC2e7b76b2009-04-03 12:04:24 +0000168 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
DRC2a285992011-02-19 17:20:11 +0000169 printf("%c", quiet==2? '\n':'\t');
DRC2e7b76b2009-04-03 12:04:24 +0000170 printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
DRC2a285992011-02-19 17:20:11 +0000171 printf("%c", quiet==2? '\n':'\t');
DRC2e7b76b2009-04-03 12:04:24 +0000172 }
173 else
174 {
175 if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
176 else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
177 printf("C--> Frame rate: %f fps\n", (double)ITER/elapsed);
178 printf(" Output image size: %d bytes\n", jpgbufsize);
179 printf(" Compression ratio: %f:1\n",
180 (double)(w*h*ps)/(double)jpgbufsize);
181 printf(" Source throughput: %f Megapixels/sec\n",
182 (double)(w*h)/1000000.*(double)ITER/elapsed);
183 printf(" Output bit stream: %f Megabits/sec\n",
184 (double)jpgbufsize*8./1000000.*(double)ITER/elapsed);
185 }
186 if(tilesizex==w && tilesizey==h)
187 {
DRC9e17f7d2010-12-10 04:59:13 +0000188 if(yuv==YUVENCODE)
DRCfbb67472010-11-24 04:02:37 +0000189 sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
190 else
191 sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
DRC2e7b76b2009-04-03 12:04:24 +0000192 if((outfile=fopen(tempstr, "wb"))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000193 _throwunix("opening reference image");
DRC2e7b76b2009-04-03 12:04:24 +0000194 if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
DRCe8ce2e02010-11-12 10:14:11 +0000195 _throwunix("writing reference image");
DRC9e17f7d2010-12-10 04:59:13 +0000196 fclose(outfile); outfile=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000197 if(!quiet) printf("Reference image written to %s\n", tempstr);
198 }
DRC0b11d1c2011-02-24 21:43:35 +0000199 if(yuv==YUVENCODE)
200 {
201 if(quiet==1) printf("\n"); goto bailout;
202 }
DRC2e7b76b2009-04-03 12:04:24 +0000203
204 // Decompression test
DRC9e17f7d2010-12-10 04:59:13 +0000205 memset(rgbbuf, 127, max(yuvsize, pitch*h)); // Grey image means decompressor did nothing
DRC2e7b76b2009-04-03 12:04:24 +0000206 if((hnd=tjInitDecompress())==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000207 _throwtj("executing tjInitDecompress()");
DRCeeab6952011-02-25 00:02:04 +0000208 if(yuv==YUVDECODE)
209 {
210 if(tjDecompressToYUV(hnd, jpegbuf[0], jpgbufsize, rgbbuf, flags)==-1)
211 _throwtj("executing tjDecompressToYUV()");
212 }
213 else if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
DRCe8ce2e02010-11-12 10:14:11 +0000214 tilesizey, ps, flags)==-1)
215 _throwtj("executing tjDecompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000216 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000217 start=rrtime();
DRC2e7b76b2009-04-03 12:04:24 +0000218 do
219 {
220 int tilen=0;
221 for(i=0; i<h; i+=tilesizey)
222 {
223 for(j=0; j<w; j+=tilesizex)
224 {
225 int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
DRCeeab6952011-02-25 00:02:04 +0000226 if(yuv==YUVDECODE)
227 {
228 if(tjDecompressToYUV(hnd, jpegbuf[tilen], comptilesize[tilen],
229 &rgbbuf[pitch*i+ps*j], flags)==-1)
230 _throwtj("executing tjDecompressToYUV()");
231 }
232 else if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
DRCe8ce2e02010-11-12 10:14:11 +0000233 &rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags)==-1)
234 _throwtj("executing tjDecompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000235 tilen++;
236 }
237 }
238 ITER++;
DRC2e4d0442011-02-08 01:18:37 +0000239 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000240 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
241 hnd=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000242 if(quiet)
243 {
244 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
245 printf("\n");
246 }
247 else
248 {
249 printf("D--> Frame rate: %f fps\n", (double)ITER/elapsed);
250 printf(" Dest. throughput: %f Megapixels/sec\n",
251 (double)(w*h)/1000000.*(double)ITER/elapsed);
252 }
DRC9e17f7d2010-12-10 04:59:13 +0000253 if(yuv==YUVDECODE)
DRC2e7b76b2009-04-03 12:04:24 +0000254 {
DRC9e17f7d2010-12-10 04:59:13 +0000255 sprintf(tempstr, "%s_%sQ%d.yuv", filename, _subnames[jpegsub], qual);
256 if((outfile=fopen(tempstr, "wb"))==NULL)
257 _throwunix("opening YUV image for output");
258 if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
259 _throwunix("writing YUV image");
260 fclose(outfile); outfile=NULL;
261 }
DRC2e7b76b2009-04-03 12:04:24 +0000262 else
263 {
DRC9e17f7d2010-12-10 04:59:13 +0000264 if(tilesizex==w && tilesizey==h)
265 sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
266 useppm?"ppm":"bmp");
267 else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
268 qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
269 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
270 _throwbmp("saving bitmap");
271 sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
272 if(!quiet)
273 printf("Computing compression error and saving to %s.\n", tempstr);
274 if(jpegsub==TJ_GRAYSCALE)
275 {
276 for(j=0; j<h; j++)
277 {
278 for(i=0; i<w*ps; i+=ps)
279 {
280 int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
281 + (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
282 + (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
283 if(y>255) y=255; if(y<0) y=0;
284 rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
285 rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
286 rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
287 }
288 }
289 }
290 else
291 {
292 for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
293 rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
294 }
295 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
296 _throwbmp("saving bitmap");
DRC2e7b76b2009-04-03 12:04:24 +0000297 }
DRC2e7b76b2009-04-03 12:04:24 +0000298
299 // Cleanup
DRC9e17f7d2010-12-10 04:59:13 +0000300 if(outfile) {fclose(outfile); outfile=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000301 if(jpegbuf)
302 {
303 for(i=0; i<numtilesx*numtilesy; i++)
304 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
305 free(jpegbuf); jpegbuf=NULL;
306 }
307 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
308 } while(tilesizex<w || tilesizey<h);
309
310 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
311 return;
312
313 bailout:
DRC9e17f7d2010-12-10 04:59:13 +0000314 if(outfile) {fclose(outfile); outfile=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000315 if(jpegbuf)
316 {
317 for(i=0; i<numtilesx*numtilesy; i++)
318 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
319 free(jpegbuf); jpegbuf=NULL;
320 }
321 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
322 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
DRCe8ce2e02010-11-12 10:14:11 +0000323 if(hnd) {tjDestroy(hnd); hnd=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000324 return;
325}
326
327
DRC2e4d0442011-02-08 01:18:37 +0000328void dodecomptest(char *filename, int pf, int bu, int useppm,
DRCe8ce2e02010-11-12 10:14:11 +0000329 int quiet)
330{
331 char tempstr[1024];
332 FILE *file=NULL; tjhandle hnd;
333 unsigned char *jpegbuf=NULL, *rgbbuf=NULL;
DRC2e4d0442011-02-08 01:18:37 +0000334 double start, elapsed;
DRCe8ce2e02010-11-12 10:14:11 +0000335 int w, h, ITER;
336 unsigned long jpgbufsize=0;
337 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
338 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
339 |(fastupsample?TJ_FASTUPSAMPLE:0);
DRCcad1cfe2010-12-14 01:22:00 +0000340 int ps=_ps[pf], pitch, jpegsub=-1;
DRC61c15bd2010-11-13 05:31:25 +0000341 char *temp=NULL;
DRCeeab6952011-02-25 00:02:04 +0000342 int yuvsize, bufsize;
DRCe8ce2e02010-11-12 10:14:11 +0000343
344 flags |= _flags[pf];
345 if(bu) flags |= TJ_BOTTOMUP;
346
347 if((file=fopen(filename, "rb"))==NULL)
348 _throwunix("opening file");
DRC61c15bd2010-11-13 05:31:25 +0000349 if(fseek(file, 0, SEEK_END)<0 || (jpgbufsize=ftell(file))<0)
DRCe8ce2e02010-11-12 10:14:11 +0000350 _throwunix("determining file size");
DRC61c15bd2010-11-13 05:31:25 +0000351 if((jpegbuf=(unsigned char *)malloc(jpgbufsize))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000352 _throwunix("allocating memory");
353 if(fseek(file, 0, SEEK_SET)<0)
354 _throwunix("setting file position");
DRC61c15bd2010-11-13 05:31:25 +0000355 if(fread(jpegbuf, jpgbufsize, 1, file)<1)
DRCe8ce2e02010-11-12 10:14:11 +0000356 _throwunix("reading JPEG data");
DRCcad1cfe2010-12-14 01:22:00 +0000357 fclose(file); file=NULL;
DRCe8ce2e02010-11-12 10:14:11 +0000358
359 temp=strrchr(filename, '.');
360 if(temp!=NULL) *temp='\0';
361
362 if((hnd=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()");
DRCcad1cfe2010-12-14 01:22:00 +0000363 if(tjDecompressHeader2(hnd, jpegbuf, jpgbufsize, &w, &h, &jpegsub)==-1)
364 _throwtj("executing tjDecompressHeader2()");
365
DRCeeab6952011-02-25 00:02:04 +0000366 yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
DRCe8ce2e02010-11-12 10:14:11 +0000367
368 pitch=w*ps;
369
DRC2a285992011-02-19 17:20:11 +0000370 if(quiet==1)
DRCe8ce2e02010-11-12 10:14:11 +0000371 {
DRC0b11d1c2011-02-24 21:43:35 +0000372 printf("All performance values in Mpixels/sec\n\n");
DRCe8ce2e02010-11-12 10:14:11 +0000373 printf("Bitmap\tBitmap\tImage Size\tDecomp\n"),
374 printf("Format\tOrder\t X Y \tPerf\n\n");
375 printf("%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD", w, h);
376 }
377
DRCeeab6952011-02-25 00:02:04 +0000378 bufsize=(yuv==YUVDECODE? yuvsize:pitch*h);
379 if((rgbbuf=(unsigned char *)malloc(bufsize))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000380 _throwunix("allocating image buffer");
381
382 if(!quiet)
383 {
DRCcad1cfe2010-12-14 01:22:00 +0000384 if(yuv==YUVDECODE)
DRC0b11d1c2011-02-24 21:43:35 +0000385 printf(">>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]);
DRCcad1cfe2010-12-14 01:22:00 +0000386 else
DRC0b11d1c2011-02-24 21:43:35 +0000387 printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
DRCcad1cfe2010-12-14 01:22:00 +0000388 bu?"Bottom-up":"Top-down");
DRCe8ce2e02010-11-12 10:14:11 +0000389 printf("\nImage size: %d x %d\n", w, h);
390 }
391
DRCeeab6952011-02-25 00:02:04 +0000392 memset(rgbbuf, 127, bufsize); // Grey image means decompressor did nothing
393 if(yuv==YUVDECODE)
394 {
395 if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
396 _throwtj("executing tjDecompressToYUV()");
397 }
398 else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
399 flags)==-1)
DRCe8ce2e02010-11-12 10:14:11 +0000400 _throwtj("executing tjDecompress()");
401 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000402 start=rrtime();
DRCe8ce2e02010-11-12 10:14:11 +0000403 do
404 {
DRCeeab6952011-02-25 00:02:04 +0000405 if(yuv==YUVDECODE)
406 {
407 if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
408 _throwtj("executing tjDecompressToYUV()");
409 }
410 else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
411 flags)==-1)
DRCe8ce2e02010-11-12 10:14:11 +0000412 _throwtj("executing tjDecompress()");
413 ITER++;
DRC2e4d0442011-02-08 01:18:37 +0000414 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000415 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
416 hnd=NULL;
417 if(quiet)
418 {
419 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
420 printf("\n");
421 }
422 else
423 {
424 printf("D--> Frame rate: %f fps\n", (double)ITER/elapsed);
425 printf(" Dest. throughput: %f Megapixels/sec\n",
426 (double)(w*h)/1000000.*(double)ITER/elapsed);
427 }
428 sprintf(tempstr, "%s_full.%s", filename, useppm?"ppm":"bmp");
DRCcad1cfe2010-12-14 01:22:00 +0000429 if(yuv==YUVDECODE)
430 {
431 sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
432 if((file=fopen(tempstr, "wb"))==NULL)
433 _throwunix("opening YUV image for output");
434 if(fwrite(rgbbuf, yuvsize, 1, file)!=1)
435 _throwunix("writing YUV image");
436 fclose(file); file=NULL;
437 }
438 else
439 {
440 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
441 _throwbmp("saving bitmap");
442 }
DRCe8ce2e02010-11-12 10:14:11 +0000443
444 bailout:
DRCcad1cfe2010-12-14 01:22:00 +0000445 if(file) {fclose(file); file=NULL;}
DRCe8ce2e02010-11-12 10:14:11 +0000446 if(jpegbuf) {free(jpegbuf); jpegbuf=NULL;}
447 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
448 if(hnd) {tjDestroy(hnd); hnd=NULL;}
449 return;
450}
451
452
453void usage(char *progname)
454{
DRCe89bbae2010-11-12 10:18:08 +0000455 printf("USAGE: %s <Inputfile (BMP|PPM))> <%% Quality>\n", progname);
456 printf(" %s <Inputfile (JPG))>\n\n", progname);
DRCe8ce2e02010-11-12 10:14:11 +0000457 printf(" [-tile]\n");
458 printf(" Test performance of the codec when the image is encoded\n");
459 printf(" as separate tiles of varying sizes.\n\n");
460 printf(" [-forcemmx] [-forcesse] [-forcesse2] [-forcesse3]\n");
DRCb4b31402011-02-19 17:31:24 +0000461 printf(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n\n");
462 printf(" [-rgb | -bgr | -rgbx | -bgrx | -xbgr | -xrgb]\n");
DRCe8ce2e02010-11-12 10:14:11 +0000463 printf(" Test the specified color conversion path in the codec (default: BGR)\n\n");
464 printf(" [-fastupsample]\n");
465 printf(" Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n");
466 printf(" YUV decoding in libjpeg decompressor\n\n");
467 printf(" [-quiet]\n");
DRCac08ef62010-12-09 10:01:57 +0000468 printf(" Output in tabular rather than verbose format\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000469 printf(" [-yuvencode]\n");
DRCfbb67472010-11-24 04:02:37 +0000470 printf(" Encode RGB input as planar YUV rather than compressing as JPEG\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000471 printf(" [-yuvdecode]\n");
472 printf(" Decode JPEG image to planar YUV rather than RGB\n\n");
DRCe8ce2e02010-11-12 10:14:11 +0000473 printf(" NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
474 printf(" test will be performed for all quality values in the range.\n");
475 exit(1);
476}
477
478
DRC2e7b76b2009-04-03 12:04:24 +0000479int main(int argc, char *argv[])
480{
481 unsigned char *bmpbuf=NULL; int w, h, i, useppm=0;
482 int qual, dotile=0, quiet=0, hiqual=-1; char *temp;
DRC2e4d0442011-02-08 01:18:37 +0000483 int pf=BMP_BGR;
DRCe8ce2e02010-11-12 10:14:11 +0000484 int bu=0, minarg=2;
DRC2e7b76b2009-04-03 12:04:24 +0000485
DRCe8ce2e02010-11-12 10:14:11 +0000486 if(argc<minarg) usage(argv[0]);
DRC2e7b76b2009-04-03 12:04:24 +0000487
DRCe8ce2e02010-11-12 10:14:11 +0000488 temp=strrchr(argv[1], '.');
489 if(temp!=NULL)
DRC2e7b76b2009-04-03 12:04:24 +0000490 {
DRCe8ce2e02010-11-12 10:14:11 +0000491 if(!stricmp(temp, ".ppm")) useppm=1;
492 if(!stricmp(temp, ".jpg") || !stricmp(temp, ".jpeg")) decomponly=1;
493 }
494
DRC0b11d1c2011-02-24 21:43:35 +0000495 printf("\n");
496
DRCac08ef62010-12-09 10:01:57 +0000497 if(argc>minarg)
498 {
499 for(i=minarg; i<argc; i++)
500 {
DRC9e17f7d2010-12-10 04:59:13 +0000501 if(!stricmp(argv[i], "-yuvencode"))
DRCac08ef62010-12-09 10:01:57 +0000502 {
DRC0b11d1c2011-02-24 21:43:35 +0000503 printf("Testing YUV planar encoding\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000504 yuv=YUVENCODE; hiqual=qual=100;
505 }
506 if(!stricmp(argv[i], "-yuvdecode"))
507 {
DRC0b11d1c2011-02-24 21:43:35 +0000508 printf("Testing YUV planar decoding\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000509 yuv=YUVDECODE;
DRCac08ef62010-12-09 10:01:57 +0000510 }
511 }
512 }
513
DRC9e17f7d2010-12-10 04:59:13 +0000514 if(!decomponly && yuv!=YUVENCODE)
DRCe8ce2e02010-11-12 10:14:11 +0000515 {
516 minarg=3;
517 if(argc<minarg) usage(argv[0]);
518 if((qual=atoi(argv[2]))<1 || qual>100)
519 {
520 puts("ERROR: Quality must be between 1 and 100.");
521 exit(1);
522 }
523 if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
524 && sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1
525 && hiqual<=100) {}
526 else hiqual=qual;
527 }
528
529 if(argc>minarg)
530 {
531 for(i=minarg; i<argc; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000532 {
533 if(!stricmp(argv[i], "-tile")) dotile=1;
534 if(!stricmp(argv[i], "-forcesse3"))
535 {
DRC0b11d1c2011-02-24 21:43:35 +0000536 printf("Using SSE3 code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000537 forcesse3=1;
538 }
539 if(!stricmp(argv[i], "-forcesse2"))
540 {
DRC0b11d1c2011-02-24 21:43:35 +0000541 printf("Using SSE2 code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000542 forcesse2=1;
543 }
544 if(!stricmp(argv[i], "-forcesse"))
545 {
DRC0b11d1c2011-02-24 21:43:35 +0000546 printf("Using SSE code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000547 forcesse=1;
548 }
549 if(!stricmp(argv[i], "-forcemmx"))
550 {
DRC0b11d1c2011-02-24 21:43:35 +0000551 printf("Using MMX code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000552 forcemmx=1;
553 }
DRC61e51f92009-04-05 21:53:20 +0000554 if(!stricmp(argv[i], "-fastupsample"))
555 {
DRC0b11d1c2011-02-24 21:43:35 +0000556 printf("Using fast upsampling code\n\n");
DRC61e51f92009-04-05 21:53:20 +0000557 fastupsample=1;
558 }
DRC2e7b76b2009-04-03 12:04:24 +0000559 if(!stricmp(argv[i], "-rgb")) pf=BMP_RGB;
DRCb4b31402011-02-19 17:31:24 +0000560 if(!stricmp(argv[i], "-rgbx")) pf=BMP_RGBX;
DRC2e7b76b2009-04-03 12:04:24 +0000561 if(!stricmp(argv[i], "-bgr")) pf=BMP_BGR;
DRCb4b31402011-02-19 17:31:24 +0000562 if(!stricmp(argv[i], "-bgrx")) pf=BMP_BGRX;
563 if(!stricmp(argv[i], "-xbgr")) pf=BMP_XBGR;
564 if(!stricmp(argv[i], "-xrgb")) pf=BMP_XRGB;
DRC2e7b76b2009-04-03 12:04:24 +0000565 if(!stricmp(argv[i], "-bottomup")) bu=1;
566 if(!stricmp(argv[i], "-quiet")) quiet=1;
DRC2a285992011-02-19 17:20:11 +0000567 if(!stricmp(argv[i], "-qq")) quiet=2;
DRC2e7b76b2009-04-03 12:04:24 +0000568 }
569 }
570
DRCe8ce2e02010-11-12 10:14:11 +0000571 if(!decomponly)
DRC2e7b76b2009-04-03 12:04:24 +0000572 {
DRCe8ce2e02010-11-12 10:14:11 +0000573 if(loadbmp(argv[1], &bmpbuf, &w, &h, pf, 1, bu)==-1)
574 _throwbmp("loading bitmap");
575 temp=strrchr(argv[1], '.');
576 if(temp!=NULL) *temp='\0';
DRC2e7b76b2009-04-03 12:04:24 +0000577 }
578
DRC2a285992011-02-19 17:20:11 +0000579 if(quiet==1 && !decomponly)
DRC2e7b76b2009-04-03 12:04:24 +0000580 {
DRC0b11d1c2011-02-24 21:43:35 +0000581 printf("All performance values in Mpixels/sec\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000582 printf("Bitmap\tBitmap\tJPEG\tJPEG\tTile Size\tCompr\tCompr\tDecomp\n");
583 printf("Format\tOrder\tFormat\tQual\t X Y \tPerf \tRatio\tPerf\n\n");
584 }
585
DRCe8ce2e02010-11-12 10:14:11 +0000586 if(decomponly)
587 {
588 dodecomptest(argv[1], pf, bu, 1, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000589 printf("\n");
DRCe8ce2e02010-11-12 10:14:11 +0000590 goto bailout;
591 }
DRC2e7b76b2009-04-03 12:04:24 +0000592 for(i=hiqual; i>=qual; i--)
593 dotest(bmpbuf, w, h, pf, bu, TJ_GRAYSCALE, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000594 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000595 for(i=hiqual; i>=qual; i--)
DRC61e51f92009-04-05 21:53:20 +0000596 dotest(bmpbuf, w, h, pf, bu, TJ_420, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000597 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000598 for(i=hiqual; i>=qual; i--)
599 dotest(bmpbuf, w, h, pf, bu, TJ_422, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000600 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000601 for(i=hiqual; i>=qual; i--)
602 dotest(bmpbuf, w, h, pf, bu, TJ_444, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000603 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000604
DRCe8ce2e02010-11-12 10:14:11 +0000605 bailout:
DRC2e7b76b2009-04-03 12:04:24 +0000606 if(bmpbuf) free(bmpbuf);
607 return 0;
608}