blob: cac5ce3f2bfe8804197aa96ecdf381c7eff364fd [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];
DRC361a6372011-02-26 19:46:27 +000069 FILE *outfile=NULL; tjhandle hnd=NULL;
DRC2e7b76b2009-04-03 12:04:24 +000070 unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
DRC2e4d0442011-02-08 01:18:37 +000071 double start, elapsed;
DRC0769f502011-02-26 21:08:39 +000072 int jpgbufsize=0, i, j, tilesizex=w, tilesizey=h, numtilesx=1, numtilesy=1,
73 ITER;
DRC2e7b76b2009-04-03 12:04:24 +000074 unsigned long *comptilesize=NULL;
75 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
DRC61e51f92009-04-05 21:53:20 +000076 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
77 |(fastupsample?TJ_FASTUPSAMPLE:0);
DRC2e4d0442011-02-08 01:18:37 +000078 int ps=_ps[pf], tilen;
DRC361a6372011-02-26 19:46:27 +000079 int pitch=w*ps, yuvsize=0;
DRC2e7b76b2009-04-03 12:04:24 +000080
81 flags |= _flags[pf];
82 if(bu) flags |= TJ_BOTTOMUP;
83
DRC94476c62011-02-25 01:14:46 +000084 if(yuv==YUVENCODE) yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
85 if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h+1))) == 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 {
DRC0cc12792011-02-25 00:54:29 +0000112 if((jpegbuf[i]=(unsigned char *)malloc(
113 yuv==YUVENCODE? TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub)
114 : TJBUFSIZE(tilesizex, tilesizey))) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000115 _throwunix("allocating image buffers");
DRC2e7b76b2009-04-03 12:04:24 +0000116 }
117
118 // Compression test
DRC2a285992011-02-19 17:20:11 +0000119 if(quiet==1) printf("%s\t%s\t%s\t%d\t", _pfname[pf], bu?"BU":"TD",
DRC2e7b76b2009-04-03 12:04:24 +0000120 _subnamel[jpegsub], qual);
121 for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
122 if((hnd=tjInitCompress())==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000123 _throwtj("executing tjInitCompress()");
DRCeeab6952011-02-25 00:02:04 +0000124 if(yuv==YUVENCODE)
125 {
126 if(tjEncodeYUV(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
127 jpegbuf[0], jpegsub, flags)==-1)
128 _throwtj("executing tjEncodeYUV()");
129 comptilesize[0]=TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub);
130 }
131 else if(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
DRCe8ce2e02010-11-12 10:14:11 +0000132 jpegbuf[0], &comptilesize[0], jpegsub, qual, flags)==-1)
133 _throwtj("executing tjCompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000134 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000135 start=rrtime();
DRC2e7b76b2009-04-03 12:04:24 +0000136 do
137 {
DRC2e4d0442011-02-08 01:18:37 +0000138 jpgbufsize=0; tilen=0;
DRC2e7b76b2009-04-03 12:04:24 +0000139 for(i=0; i<h; i+=tilesizey)
140 {
141 for(j=0; j<w; j+=tilesizex)
142 {
143 int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
DRCeeab6952011-02-25 00:02:04 +0000144 if(yuv==YUVENCODE)
145 {
146 if(tjEncodeYUV(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
147 temph, ps, jpegbuf[tilen], jpegsub, flags)==-1)
148 _throwtj("executing tjEncodeYUV()");
149 comptilesize[tilen]=TJBUFSIZEYUV(tempw, temph, jpegsub);
150 }
151 else if(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
DRC2e7b76b2009-04-03 12:04:24 +0000152 temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
DRCe8ce2e02010-11-12 10:14:11 +0000153 flags)==-1)
154 _throwtj("executing tjCompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000155 jpgbufsize+=comptilesize[tilen];
156 tilen++;
157 }
158 }
159 ITER++;
DRC2e4d0442011-02-08 01:18:37 +0000160 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000161 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
162 hnd=NULL;
DRC2a285992011-02-19 17:20:11 +0000163 if(quiet==1)
DRC2e7b76b2009-04-03 12:04:24 +0000164 {
165 if(tilesizex==w && tilesizey==h) printf("Full \t");
166 else printf("%-4d %-4d\t", tilesizex, tilesizey);
DRC2a285992011-02-19 17:20:11 +0000167 }
168 if(quiet)
169 {
DRC2e7b76b2009-04-03 12:04:24 +0000170 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
DRC2a285992011-02-19 17:20:11 +0000171 printf("%c", quiet==2? '\n':'\t');
DRC2e7b76b2009-04-03 12:04:24 +0000172 printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
DRC2a285992011-02-19 17:20:11 +0000173 printf("%c", quiet==2? '\n':'\t');
DRC2e7b76b2009-04-03 12:04:24 +0000174 }
175 else
176 {
177 if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
178 else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
179 printf("C--> Frame rate: %f fps\n", (double)ITER/elapsed);
180 printf(" Output image size: %d bytes\n", jpgbufsize);
181 printf(" Compression ratio: %f:1\n",
182 (double)(w*h*ps)/(double)jpgbufsize);
183 printf(" Source throughput: %f Megapixels/sec\n",
184 (double)(w*h)/1000000.*(double)ITER/elapsed);
185 printf(" Output bit stream: %f Megabits/sec\n",
186 (double)jpgbufsize*8./1000000.*(double)ITER/elapsed);
187 }
188 if(tilesizex==w && tilesizey==h)
189 {
DRC9e17f7d2010-12-10 04:59:13 +0000190 if(yuv==YUVENCODE)
DRCfbb67472010-11-24 04:02:37 +0000191 sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
192 else
193 sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
DRC2e7b76b2009-04-03 12:04:24 +0000194 if((outfile=fopen(tempstr, "wb"))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000195 _throwunix("opening reference image");
DRC2e7b76b2009-04-03 12:04:24 +0000196 if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
DRCe8ce2e02010-11-12 10:14:11 +0000197 _throwunix("writing reference image");
DRC9e17f7d2010-12-10 04:59:13 +0000198 fclose(outfile); outfile=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000199 if(!quiet) printf("Reference image written to %s\n", tempstr);
200 }
DRC0b11d1c2011-02-24 21:43:35 +0000201 if(yuv==YUVENCODE)
202 {
203 if(quiet==1) printf("\n"); goto bailout;
204 }
DRC2e7b76b2009-04-03 12:04:24 +0000205
206 // Decompression test
DRC9e17f7d2010-12-10 04:59:13 +0000207 memset(rgbbuf, 127, max(yuvsize, pitch*h)); // Grey image means decompressor did nothing
DRC2e7b76b2009-04-03 12:04:24 +0000208 if((hnd=tjInitDecompress())==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000209 _throwtj("executing tjInitDecompress()");
DRCeeab6952011-02-25 00:02:04 +0000210 if(yuv==YUVDECODE)
211 {
212 if(tjDecompressToYUV(hnd, jpegbuf[0], jpgbufsize, rgbbuf, flags)==-1)
213 _throwtj("executing tjDecompressToYUV()");
214 }
215 else if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
DRCe8ce2e02010-11-12 10:14:11 +0000216 tilesizey, ps, flags)==-1)
217 _throwtj("executing tjDecompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000218 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000219 start=rrtime();
DRC2e7b76b2009-04-03 12:04:24 +0000220 do
221 {
222 int tilen=0;
223 for(i=0; i<h; i+=tilesizey)
224 {
225 for(j=0; j<w; j+=tilesizex)
226 {
227 int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
DRCeeab6952011-02-25 00:02:04 +0000228 if(yuv==YUVDECODE)
229 {
230 if(tjDecompressToYUV(hnd, jpegbuf[tilen], comptilesize[tilen],
231 &rgbbuf[pitch*i+ps*j], flags)==-1)
232 _throwtj("executing tjDecompressToYUV()");
233 }
234 else if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
DRCe8ce2e02010-11-12 10:14:11 +0000235 &rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags)==-1)
236 _throwtj("executing tjDecompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000237 tilen++;
238 }
239 }
240 ITER++;
DRC2e4d0442011-02-08 01:18:37 +0000241 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000242 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
243 hnd=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000244 if(quiet)
245 {
246 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
247 printf("\n");
248 }
249 else
250 {
251 printf("D--> Frame rate: %f fps\n", (double)ITER/elapsed);
252 printf(" Dest. throughput: %f Megapixels/sec\n",
253 (double)(w*h)/1000000.*(double)ITER/elapsed);
254 }
DRC9e17f7d2010-12-10 04:59:13 +0000255 if(yuv==YUVDECODE)
DRC2e7b76b2009-04-03 12:04:24 +0000256 {
DRC9e17f7d2010-12-10 04:59:13 +0000257 sprintf(tempstr, "%s_%sQ%d.yuv", filename, _subnames[jpegsub], qual);
258 if((outfile=fopen(tempstr, "wb"))==NULL)
259 _throwunix("opening YUV image for output");
260 if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
261 _throwunix("writing YUV image");
262 fclose(outfile); outfile=NULL;
263 }
DRC2e7b76b2009-04-03 12:04:24 +0000264 else
265 {
DRC9e17f7d2010-12-10 04:59:13 +0000266 if(tilesizex==w && tilesizey==h)
267 sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
268 useppm?"ppm":"bmp");
269 else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
270 qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
271 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
272 _throwbmp("saving bitmap");
273 sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
274 if(!quiet)
275 printf("Computing compression error and saving to %s.\n", tempstr);
276 if(jpegsub==TJ_GRAYSCALE)
277 {
278 for(j=0; j<h; j++)
279 {
280 for(i=0; i<w*ps; i+=ps)
281 {
282 int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
283 + (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
284 + (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
285 if(y>255) y=255; if(y<0) y=0;
286 rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
287 rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
288 rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
289 }
290 }
291 }
292 else
293 {
294 for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
295 rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
296 }
297 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
298 _throwbmp("saving bitmap");
DRC2e7b76b2009-04-03 12:04:24 +0000299 }
DRC2e7b76b2009-04-03 12:04:24 +0000300
301 // Cleanup
DRC9e17f7d2010-12-10 04:59:13 +0000302 if(outfile) {fclose(outfile); outfile=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000303 if(jpegbuf)
304 {
305 for(i=0; i<numtilesx*numtilesy; i++)
306 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
307 free(jpegbuf); jpegbuf=NULL;
308 }
309 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
310 } while(tilesizex<w || tilesizey<h);
311
312 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
313 return;
314
315 bailout:
DRC9e17f7d2010-12-10 04:59:13 +0000316 if(outfile) {fclose(outfile); outfile=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000317 if(jpegbuf)
318 {
319 for(i=0; i<numtilesx*numtilesy; i++)
320 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
321 free(jpegbuf); jpegbuf=NULL;
322 }
323 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
324 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
DRCe8ce2e02010-11-12 10:14:11 +0000325 if(hnd) {tjDestroy(hnd); hnd=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000326 return;
327}
328
329
DRC2e4d0442011-02-08 01:18:37 +0000330void dodecomptest(char *filename, int pf, int bu, int useppm,
DRCe8ce2e02010-11-12 10:14:11 +0000331 int quiet)
332{
333 char tempstr[1024];
DRC361a6372011-02-26 19:46:27 +0000334 FILE *file=NULL; tjhandle hnd=NULL;
DRCe8ce2e02010-11-12 10:14:11 +0000335 unsigned char *jpegbuf=NULL, *rgbbuf=NULL;
DRC2e4d0442011-02-08 01:18:37 +0000336 double start, elapsed;
DRCe8ce2e02010-11-12 10:14:11 +0000337 int w, h, ITER;
338 unsigned long jpgbufsize=0;
339 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
340 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
341 |(fastupsample?TJ_FASTUPSAMPLE:0);
DRCcad1cfe2010-12-14 01:22:00 +0000342 int ps=_ps[pf], pitch, jpegsub=-1;
DRC61c15bd2010-11-13 05:31:25 +0000343 char *temp=NULL;
DRCeeab6952011-02-25 00:02:04 +0000344 int yuvsize, bufsize;
DRCe8ce2e02010-11-12 10:14:11 +0000345
346 flags |= _flags[pf];
347 if(bu) flags |= TJ_BOTTOMUP;
348
349 if((file=fopen(filename, "rb"))==NULL)
350 _throwunix("opening file");
DRC61c15bd2010-11-13 05:31:25 +0000351 if(fseek(file, 0, SEEK_END)<0 || (jpgbufsize=ftell(file))<0)
DRCe8ce2e02010-11-12 10:14:11 +0000352 _throwunix("determining file size");
DRC61c15bd2010-11-13 05:31:25 +0000353 if((jpegbuf=(unsigned char *)malloc(jpgbufsize))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000354 _throwunix("allocating memory");
355 if(fseek(file, 0, SEEK_SET)<0)
356 _throwunix("setting file position");
DRC61c15bd2010-11-13 05:31:25 +0000357 if(fread(jpegbuf, jpgbufsize, 1, file)<1)
DRCe8ce2e02010-11-12 10:14:11 +0000358 _throwunix("reading JPEG data");
DRCcad1cfe2010-12-14 01:22:00 +0000359 fclose(file); file=NULL;
DRCe8ce2e02010-11-12 10:14:11 +0000360
361 temp=strrchr(filename, '.');
362 if(temp!=NULL) *temp='\0';
363
364 if((hnd=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()");
DRCcad1cfe2010-12-14 01:22:00 +0000365 if(tjDecompressHeader2(hnd, jpegbuf, jpgbufsize, &w, &h, &jpegsub)==-1)
366 _throwtj("executing tjDecompressHeader2()");
367
DRCeeab6952011-02-25 00:02:04 +0000368 yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
DRCe8ce2e02010-11-12 10:14:11 +0000369
370 pitch=w*ps;
371
DRC2a285992011-02-19 17:20:11 +0000372 if(quiet==1)
DRCe8ce2e02010-11-12 10:14:11 +0000373 {
DRC0b11d1c2011-02-24 21:43:35 +0000374 printf("All performance values in Mpixels/sec\n\n");
DRCe8ce2e02010-11-12 10:14:11 +0000375 printf("Bitmap\tBitmap\tImage Size\tDecomp\n"),
376 printf("Format\tOrder\t X Y \tPerf\n\n");
377 printf("%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD", w, h);
378 }
379
DRCeeab6952011-02-25 00:02:04 +0000380 bufsize=(yuv==YUVDECODE? yuvsize:pitch*h);
381 if((rgbbuf=(unsigned char *)malloc(bufsize))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000382 _throwunix("allocating image buffer");
383
384 if(!quiet)
385 {
DRCcad1cfe2010-12-14 01:22:00 +0000386 if(yuv==YUVDECODE)
DRC0b11d1c2011-02-24 21:43:35 +0000387 printf(">>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]);
DRCcad1cfe2010-12-14 01:22:00 +0000388 else
DRC0b11d1c2011-02-24 21:43:35 +0000389 printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
DRCcad1cfe2010-12-14 01:22:00 +0000390 bu?"Bottom-up":"Top-down");
DRCe8ce2e02010-11-12 10:14:11 +0000391 printf("\nImage size: %d x %d\n", w, h);
392 }
393
DRCeeab6952011-02-25 00:02:04 +0000394 memset(rgbbuf, 127, bufsize); // Grey image means decompressor did nothing
395 if(yuv==YUVDECODE)
396 {
397 if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
398 _throwtj("executing tjDecompressToYUV()");
399 }
400 else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
401 flags)==-1)
DRCe8ce2e02010-11-12 10:14:11 +0000402 _throwtj("executing tjDecompress()");
403 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000404 start=rrtime();
DRCe8ce2e02010-11-12 10:14:11 +0000405 do
406 {
DRCeeab6952011-02-25 00:02:04 +0000407 if(yuv==YUVDECODE)
408 {
409 if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
410 _throwtj("executing tjDecompressToYUV()");
411 }
412 else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
413 flags)==-1)
DRCe8ce2e02010-11-12 10:14:11 +0000414 _throwtj("executing tjDecompress()");
415 ITER++;
DRC2e4d0442011-02-08 01:18:37 +0000416 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000417 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
418 hnd=NULL;
419 if(quiet)
420 {
421 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
422 printf("\n");
423 }
424 else
425 {
426 printf("D--> Frame rate: %f fps\n", (double)ITER/elapsed);
427 printf(" Dest. throughput: %f Megapixels/sec\n",
428 (double)(w*h)/1000000.*(double)ITER/elapsed);
429 }
430 sprintf(tempstr, "%s_full.%s", filename, useppm?"ppm":"bmp");
DRCcad1cfe2010-12-14 01:22:00 +0000431 if(yuv==YUVDECODE)
432 {
433 sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
434 if((file=fopen(tempstr, "wb"))==NULL)
435 _throwunix("opening YUV image for output");
436 if(fwrite(rgbbuf, yuvsize, 1, file)!=1)
437 _throwunix("writing YUV image");
438 fclose(file); file=NULL;
439 }
440 else
441 {
442 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
443 _throwbmp("saving bitmap");
444 }
DRCe8ce2e02010-11-12 10:14:11 +0000445
446 bailout:
DRCcad1cfe2010-12-14 01:22:00 +0000447 if(file) {fclose(file); file=NULL;}
DRCe8ce2e02010-11-12 10:14:11 +0000448 if(jpegbuf) {free(jpegbuf); jpegbuf=NULL;}
449 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
450 if(hnd) {tjDestroy(hnd); hnd=NULL;}
451 return;
452}
453
454
455void usage(char *progname)
456{
DRCe89bbae2010-11-12 10:18:08 +0000457 printf("USAGE: %s <Inputfile (BMP|PPM))> <%% Quality>\n", progname);
458 printf(" %s <Inputfile (JPG))>\n\n", progname);
DRCe8ce2e02010-11-12 10:14:11 +0000459 printf(" [-tile]\n");
460 printf(" Test performance of the codec when the image is encoded\n");
461 printf(" as separate tiles of varying sizes.\n\n");
462 printf(" [-forcemmx] [-forcesse] [-forcesse2] [-forcesse3]\n");
DRCb4b31402011-02-19 17:31:24 +0000463 printf(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n\n");
464 printf(" [-rgb | -bgr | -rgbx | -bgrx | -xbgr | -xrgb]\n");
DRCe8ce2e02010-11-12 10:14:11 +0000465 printf(" Test the specified color conversion path in the codec (default: BGR)\n\n");
466 printf(" [-fastupsample]\n");
467 printf(" Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n");
468 printf(" YUV decoding in libjpeg decompressor\n\n");
469 printf(" [-quiet]\n");
DRCac08ef62010-12-09 10:01:57 +0000470 printf(" Output in tabular rather than verbose format\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000471 printf(" [-yuvencode]\n");
DRCfbb67472010-11-24 04:02:37 +0000472 printf(" Encode RGB input as planar YUV rather than compressing as JPEG\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000473 printf(" [-yuvdecode]\n");
474 printf(" Decode JPEG image to planar YUV rather than RGB\n\n");
DRCe8ce2e02010-11-12 10:14:11 +0000475 printf(" NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
476 printf(" test will be performed for all quality values in the range.\n");
477 exit(1);
478}
479
480
DRC2e7b76b2009-04-03 12:04:24 +0000481int main(int argc, char *argv[])
482{
483 unsigned char *bmpbuf=NULL; int w, h, i, useppm=0;
DRC361a6372011-02-26 19:46:27 +0000484 int qual=-1, dotile=0, quiet=0, hiqual=-1; char *temp;
DRC2e4d0442011-02-08 01:18:37 +0000485 int pf=BMP_BGR;
DRCe8ce2e02010-11-12 10:14:11 +0000486 int bu=0, minarg=2;
DRC2e7b76b2009-04-03 12:04:24 +0000487
DRCe8ce2e02010-11-12 10:14:11 +0000488 if(argc<minarg) usage(argv[0]);
DRC2e7b76b2009-04-03 12:04:24 +0000489
DRCe8ce2e02010-11-12 10:14:11 +0000490 temp=strrchr(argv[1], '.');
491 if(temp!=NULL)
DRC2e7b76b2009-04-03 12:04:24 +0000492 {
DRCe8ce2e02010-11-12 10:14:11 +0000493 if(!stricmp(temp, ".ppm")) useppm=1;
494 if(!stricmp(temp, ".jpg") || !stricmp(temp, ".jpeg")) decomponly=1;
495 }
496
DRC0b11d1c2011-02-24 21:43:35 +0000497 printf("\n");
498
DRCac08ef62010-12-09 10:01:57 +0000499 if(argc>minarg)
500 {
501 for(i=minarg; i<argc; i++)
502 {
DRC9e17f7d2010-12-10 04:59:13 +0000503 if(!stricmp(argv[i], "-yuvencode"))
DRCac08ef62010-12-09 10:01:57 +0000504 {
DRC0b11d1c2011-02-24 21:43:35 +0000505 printf("Testing YUV planar encoding\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000506 yuv=YUVENCODE; hiqual=qual=100;
507 }
508 if(!stricmp(argv[i], "-yuvdecode"))
509 {
DRC0b11d1c2011-02-24 21:43:35 +0000510 printf("Testing YUV planar decoding\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000511 yuv=YUVDECODE;
DRCac08ef62010-12-09 10:01:57 +0000512 }
513 }
514 }
515
DRC9e17f7d2010-12-10 04:59:13 +0000516 if(!decomponly && yuv!=YUVENCODE)
DRCe8ce2e02010-11-12 10:14:11 +0000517 {
518 minarg=3;
519 if(argc<minarg) usage(argv[0]);
520 if((qual=atoi(argv[2]))<1 || qual>100)
521 {
522 puts("ERROR: Quality must be between 1 and 100.");
523 exit(1);
524 }
525 if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
526 && sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1
527 && hiqual<=100) {}
528 else hiqual=qual;
529 }
530
531 if(argc>minarg)
532 {
533 for(i=minarg; i<argc; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000534 {
535 if(!stricmp(argv[i], "-tile")) dotile=1;
536 if(!stricmp(argv[i], "-forcesse3"))
537 {
DRC0b11d1c2011-02-24 21:43:35 +0000538 printf("Using SSE3 code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000539 forcesse3=1;
540 }
541 if(!stricmp(argv[i], "-forcesse2"))
542 {
DRC0b11d1c2011-02-24 21:43:35 +0000543 printf("Using SSE2 code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000544 forcesse2=1;
545 }
546 if(!stricmp(argv[i], "-forcesse"))
547 {
DRC0b11d1c2011-02-24 21:43:35 +0000548 printf("Using SSE code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000549 forcesse=1;
550 }
551 if(!stricmp(argv[i], "-forcemmx"))
552 {
DRC0b11d1c2011-02-24 21:43:35 +0000553 printf("Using MMX code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000554 forcemmx=1;
555 }
DRC61e51f92009-04-05 21:53:20 +0000556 if(!stricmp(argv[i], "-fastupsample"))
557 {
DRC0b11d1c2011-02-24 21:43:35 +0000558 printf("Using fast upsampling code\n\n");
DRC61e51f92009-04-05 21:53:20 +0000559 fastupsample=1;
560 }
DRC2e7b76b2009-04-03 12:04:24 +0000561 if(!stricmp(argv[i], "-rgb")) pf=BMP_RGB;
DRCb4b31402011-02-19 17:31:24 +0000562 if(!stricmp(argv[i], "-rgbx")) pf=BMP_RGBX;
DRC2e7b76b2009-04-03 12:04:24 +0000563 if(!stricmp(argv[i], "-bgr")) pf=BMP_BGR;
DRCb4b31402011-02-19 17:31:24 +0000564 if(!stricmp(argv[i], "-bgrx")) pf=BMP_BGRX;
565 if(!stricmp(argv[i], "-xbgr")) pf=BMP_XBGR;
566 if(!stricmp(argv[i], "-xrgb")) pf=BMP_XRGB;
DRC2e7b76b2009-04-03 12:04:24 +0000567 if(!stricmp(argv[i], "-bottomup")) bu=1;
568 if(!stricmp(argv[i], "-quiet")) quiet=1;
DRC2a285992011-02-19 17:20:11 +0000569 if(!stricmp(argv[i], "-qq")) quiet=2;
DRC2e7b76b2009-04-03 12:04:24 +0000570 }
571 }
572
DRCe8ce2e02010-11-12 10:14:11 +0000573 if(!decomponly)
DRC2e7b76b2009-04-03 12:04:24 +0000574 {
DRCe8ce2e02010-11-12 10:14:11 +0000575 if(loadbmp(argv[1], &bmpbuf, &w, &h, pf, 1, bu)==-1)
576 _throwbmp("loading bitmap");
577 temp=strrchr(argv[1], '.');
578 if(temp!=NULL) *temp='\0';
DRC2e7b76b2009-04-03 12:04:24 +0000579 }
580
DRC2a285992011-02-19 17:20:11 +0000581 if(quiet==1 && !decomponly)
DRC2e7b76b2009-04-03 12:04:24 +0000582 {
DRC0b11d1c2011-02-24 21:43:35 +0000583 printf("All performance values in Mpixels/sec\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000584 printf("Bitmap\tBitmap\tJPEG\tJPEG\tTile Size\tCompr\tCompr\tDecomp\n");
585 printf("Format\tOrder\tFormat\tQual\t X Y \tPerf \tRatio\tPerf\n\n");
586 }
587
DRCe8ce2e02010-11-12 10:14:11 +0000588 if(decomponly)
589 {
590 dodecomptest(argv[1], pf, bu, 1, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000591 printf("\n");
DRCe8ce2e02010-11-12 10:14:11 +0000592 goto bailout;
593 }
DRC2e7b76b2009-04-03 12:04:24 +0000594 for(i=hiqual; i>=qual; i--)
595 dotest(bmpbuf, w, h, pf, bu, TJ_GRAYSCALE, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000596 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000597 for(i=hiqual; i>=qual; i--)
DRC61e51f92009-04-05 21:53:20 +0000598 dotest(bmpbuf, w, h, pf, bu, TJ_420, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000599 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000600 for(i=hiqual; i>=qual; i--)
601 dotest(bmpbuf, w, h, pf, bu, TJ_422, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000602 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000603 for(i=hiqual; i>=qual; i--)
604 dotest(bmpbuf, w, h, pf, bu, TJ_444, i, argv[1], dotile, useppm, quiet);
DRC0b11d1c2011-02-24 21:43:35 +0000605 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000606
DRCe8ce2e02010-11-12 10:14:11 +0000607 bailout:
DRC2e7b76b2009-04-03 12:04:24 +0000608 if(bmpbuf) free(bmpbuf);
609 return 0;
610}