blob: 06efa49ea7b4c42929366561058c6ad09bed75a1 [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) { \
DRC0f1f60d2011-03-01 20:23:12 +000027 printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \
28 retval=-1; goto bailout;}
DRCe8ce2e02010-11-12 10:14:11 +000029#define _throwunix(m) _throw(m, strerror(errno))
30#define _throwtj(m) _throw(m, tjGetErrorStr())
31#define _throwbmp(m) _throw(m, bmpgeterr())
DRC2e7b76b2009-04-03 12:04:24 +000032
DRC9e17f7d2010-12-10 04:59:13 +000033#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
34
35enum {YUVENCODE=1, YUVDECODE};
DRCe8ce2e02010-11-12 10:14:11 +000036int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
DRCdae3ee92011-02-16 02:08:17 +000037 decomponly=0, yuv=0, quiet=0, dotile=0, pf=BMP_BGR, bu=0, useppm=0,
DRC109a5782011-03-01 09:53:07 +000038 scale_num=1, scale_denom=1;
DRC2e7b76b2009-04-03 12:04:24 +000039const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
40const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR,
41 TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST};
42const int _rindex[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
43const int _gindex[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
44const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
DRC035aac42011-02-19 18:10:05 +000045const char *_pfname[]={"RGB", "RGBX", "BGR", "BGRX", "XBGR", "XRGB"};
DRC61e51f92009-04-05 21:53:20 +000046const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
47const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
DRC109a5782011-03-01 09:53:07 +000048tjscalingfactor *sf=NULL; int nsf=0;
DRC2e7b76b2009-04-03 12:04:24 +000049
50void printsigfig(double val, int figs)
51{
52 char format[80];
53 double _l=log10(val); int l;
54 if(_l<0.)
55 {
56 l=(int)fabs(_l);
57 sprintf(format, "%%%d.%df", figs+l+2, figs+l);
58 }
59 else
60 {
61 l=(int)_l+1;
62 if(figs<=l) sprintf(format, "%%.0f");
63 else sprintf(format, "%%%d.%df", figs+1, figs-l);
64 }
65 printf(format, val);
66}
67
DRC993bf0e2011-02-15 21:57:26 +000068// Decompression test
69int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
70 unsigned long *comptilesize, unsigned char *rgbbuf, int w, int h,
71 int jpegsub, int qual, char *filename, int tilesizex, int tilesizey)
72{
73 char tempstr[1024], qualstr[5]="\0";
74 FILE *outfile=NULL; tjhandle hnd=NULL;
75 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
76 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
77 |(fastupsample?TJ_FASTUPSAMPLE:0);
DRC0f1f60d2011-03-01 20:23:12 +000078 int i, j, ITER, rgbbufalloc=0, retval=0;
DRC993bf0e2011-02-15 21:57:26 +000079 double start, elapsed;
80 int ps=_ps[pf];
DRC84241602011-02-25 02:08:23 +000081 int yuvsize=TJBUFSIZEYUV(w, h, jpegsub), bufsize;
DRC109a5782011-03-01 09:53:07 +000082 int scaledw=(yuv==YUVDECODE)? w : (w*scale_num+scale_denom-1)/scale_denom;
83 int scaledh=(yuv==YUVDECODE)? h : (h*scale_num+scale_denom-1)/scale_denom;
DRCb28fc572011-02-22 06:41:29 +000084 int pitch=scaledw*ps;
DRC993bf0e2011-02-15 21:57:26 +000085
86 if(qual>0)
87 {
88 snprintf(qualstr, 5, "Q%d", qual);
89 qualstr[4]=0;
90 }
91
92 flags |= _flags[pf];
93 if(bu) flags |= TJ_BOTTOMUP;
DRC993bf0e2011-02-15 21:57:26 +000094 if((hnd=tjInitDecompress())==NULL)
95 _throwtj("executing tjInitDecompress()");
96
DRC17ac3722011-02-26 21:20:46 +000097 bufsize=(yuv==YUVDECODE? yuvsize:pitch*h);
DRC993bf0e2011-02-15 21:57:26 +000098 if(rgbbuf==NULL)
99 {
DRC84241602011-02-25 02:08:23 +0000100 if((rgbbuf=(unsigned char *)malloc(bufsize)) == NULL)
DRC993bf0e2011-02-15 21:57:26 +0000101 _throwunix("allocating image buffer");
102 rgbbufalloc=1;
103 }
DRCb28fc572011-02-22 06:41:29 +0000104 // Grey image means decompressor did nothing
DRC84241602011-02-25 02:08:23 +0000105 memset(rgbbuf, 127, bufsize);
DRC993bf0e2011-02-15 21:57:26 +0000106
DRC84241602011-02-25 02:08:23 +0000107 if(yuv==YUVDECODE)
108 {
109 if(tjDecompressToYUV(hnd, jpegbuf[0], comptilesize[0], rgbbuf, flags)==-1)
110 _throwtj("executing tjDecompressToYUV()");
111 }
112 else if(tjDecompress(hnd, jpegbuf[0], comptilesize[0], rgbbuf, scaledw,
113 pitch, scaledh, ps, flags)==-1)
DRC993bf0e2011-02-15 21:57:26 +0000114 _throwtj("executing tjDecompress()");
115 ITER=0;
116 start=rrtime();
117 do
118 {
119 int tilen=0;
120 for(i=0; i<h; i+=tilesizey)
121 {
122 for(j=0; j<w; j+=tilesizex)
123 {
DRC890f1e02011-02-26 22:02:37 +0000124 int tempw=dotile? min(tilesizex, w-j):scaledw;
125 int temph=dotile? min(tilesizey, h-i):scaledh;
DRC84241602011-02-25 02:08:23 +0000126 if(yuv==YUVDECODE)
127 {
128 if(tjDecompressToYUV(hnd, jpegbuf[tilen], comptilesize[tilen],
129 &rgbbuf[pitch*i+ps*j], flags)==-1)
130 _throwtj("executing tjDecompressToYUV()");
131 }
132 else if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
DRC890f1e02011-02-26 22:02:37 +0000133 &rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags)==-1)
DRCb28fc572011-02-22 06:41:29 +0000134 _throwtj("executing tjDecompress()");
DRC993bf0e2011-02-15 21:57:26 +0000135 tilen++;
136 }
137 }
138 ITER++;
DRC0a192ac2011-02-25 02:12:11 +0000139 } while((elapsed=rrtime()-start)<5.);
DRC993bf0e2011-02-15 21:57:26 +0000140 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
141 hnd=NULL;
142 if(quiet)
143 {
144 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
145 printf("\n");
146 }
147 else
148 {
149 printf("D--> Frame rate: %f fps\n", (double)ITER/elapsed);
150 printf(" Dest. throughput: %f Megapixels/sec\n",
151 (double)(w*h)/1000000.*(double)ITER/elapsed);
152 }
153 if(yuv==YUVDECODE)
154 {
155 sprintf(tempstr, "%s_%s%s.yuv", filename, _subnames[jpegsub], qualstr);
156 if((outfile=fopen(tempstr, "wb"))==NULL)
157 _throwunix("opening YUV image for output");
158 if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
159 _throwunix("writing YUV image");
160 fclose(outfile); outfile=NULL;
161 }
162 else
163 {
164 if(tilesizex==w && tilesizey==h)
DRCbc507f62011-02-16 01:23:48 +0000165 {
166 if(decomponly)
167 sprintf(tempstr, "%s_full.%s", filename, useppm?"ppm":"bmp");
168 else
169 sprintf(tempstr, "%s_%s%s_full.%s", filename, _subnames[jpegsub],
170 qualstr, useppm?"ppm":"bmp");
171 }
DRC993bf0e2011-02-15 21:57:26 +0000172 else sprintf(tempstr, "%s_%s%s_%dx%d.%s", filename, _subnames[jpegsub],
173 qualstr, tilesizex, tilesizey, useppm?"ppm":"bmp");
DRCb28fc572011-02-22 06:41:29 +0000174 if(savebmp(tempstr, rgbbuf, scaledw, scaledh, pf, pitch, bu)==-1)
DRC993bf0e2011-02-15 21:57:26 +0000175 _throwbmp("saving bitmap");
176 sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
DRC109a5782011-03-01 09:53:07 +0000177 if(srcbuf && scale_num==1 && scale_denom==1)
DRC993bf0e2011-02-15 21:57:26 +0000178 {
179 if(!quiet)
180 printf("Computing compression error and saving to %s.\n", tempstr);
181 if(jpegsub==TJ_GRAYSCALE)
182 {
183 for(j=0; j<h; j++)
184 {
185 for(i=0; i<w*ps; i+=ps)
186 {
187 int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
188 + (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
189 + (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
190 if(y>255) y=255; if(y<0) y=0;
191 rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
192 rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
193 rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
194 }
195 }
196 }
197 else
198 {
199 for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
200 rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
201 }
202 if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
203 _throwbmp("saving bitmap");
204 }
205 }
206
DRC993bf0e2011-02-15 21:57:26 +0000207 bailout:
208 if(outfile) {fclose(outfile); outfile=NULL;}
209 if(hnd) {tjDestroy(hnd); hnd=NULL;}
210 if(rgbbuf && rgbbufalloc) {free(rgbbuf); rgbbuf=NULL;}
DRC0f1f60d2011-03-01 20:23:12 +0000211 return retval;
DRC993bf0e2011-02-15 21:57:26 +0000212}
213
214void dotest(unsigned char *srcbuf, int w, int h, int jpegsub, int qual,
215 char *filename)
DRC2e7b76b2009-04-03 12:04:24 +0000216{
217 char tempstr[1024];
DRC17ac3722011-02-26 21:20:46 +0000218 FILE *outfile=NULL; tjhandle hnd=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000219 unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
DRC2e4d0442011-02-08 01:18:37 +0000220 double start, elapsed;
DRC17ac3722011-02-26 21:20:46 +0000221 int jpgbufsize=0, i, j, tilesizex=w, tilesizey=h, numtilesx=1, numtilesy=1,
DRC0f1f60d2011-03-01 20:23:12 +0000222 ITER, retval=0;
DRC2e7b76b2009-04-03 12:04:24 +0000223 unsigned long *comptilesize=NULL;
224 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
DRC61e51f92009-04-05 21:53:20 +0000225 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
226 |(fastupsample?TJ_FASTUPSAMPLE:0);
DRC2e4d0442011-02-08 01:18:37 +0000227 int ps=_ps[pf], tilen;
DRC17ac3722011-02-26 21:20:46 +0000228 int pitch=w*ps, yuvsize=0;
DRC2e7b76b2009-04-03 12:04:24 +0000229
230 flags |= _flags[pf];
231 if(bu) flags |= TJ_BOTTOMUP;
232
DRC84241602011-02-25 02:08:23 +0000233 if(yuv==YUVENCODE) yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
234 if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h+1))) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000235 _throwunix("allocating image buffer");
DRC2e7b76b2009-04-03 12:04:24 +0000236
DRCfbb67472010-11-24 04:02:37 +0000237 if(!quiet)
238 {
DRC9e17f7d2010-12-10 04:59:13 +0000239 if(yuv==YUVENCODE)
DRC0b11d1c2011-02-24 21:43:35 +0000240 printf(">>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf],
DRCfbb67472010-11-24 04:02:37 +0000241 bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
242 else
DRC0b11d1c2011-02-24 21:43:35 +0000243 printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf],
DRCfbb67472010-11-24 04:02:37 +0000244 bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
245 }
DRC5cb1b682011-02-24 22:13:20 +0000246 if(yuv) dotile=0;
DRC2e7b76b2009-04-03 12:04:24 +0000247 if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;}
248
249 do
250 {
251 tilesizex*=2; if(tilesizex>w) tilesizex=w;
252 tilesizey*=2; if(tilesizey>h) tilesizey=h;
253 numtilesx=(w+tilesizex-1)/tilesizex;
254 numtilesy=(h+tilesizey-1)/tilesizey;
255 if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)*numtilesx*numtilesy)) == NULL
256 || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)*numtilesx*numtilesy)) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000257 _throwunix("allocating image buffers");
DRC2e7b76b2009-04-03 12:04:24 +0000258 memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
259 for(i=0; i<numtilesx*numtilesy; i++)
260 {
DRC84241602011-02-25 02:08:23 +0000261 if((jpegbuf[i]=(unsigned char *)malloc(
262 yuv==YUVENCODE? TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub)
263 : TJBUFSIZE(tilesizex, tilesizey))) == NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000264 _throwunix("allocating image buffers");
DRC2e7b76b2009-04-03 12:04:24 +0000265 }
266
267 // Compression test
DRC2a285992011-02-19 17:20:11 +0000268 if(quiet==1) printf("%s\t%s\t%s\t%d\t", _pfname[pf], bu?"BU":"TD",
DRC2e7b76b2009-04-03 12:04:24 +0000269 _subnamel[jpegsub], qual);
270 for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
271 if((hnd=tjInitCompress())==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000272 _throwtj("executing tjInitCompress()");
DRC84241602011-02-25 02:08:23 +0000273 if(yuv==YUVENCODE)
274 {
275 if(tjEncodeYUV(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
276 jpegbuf[0], jpegsub, flags)==-1)
277 _throwtj("executing tjEncodeYUV()");
278 comptilesize[0]=TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub);
279 }
280 else if(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
DRCe8ce2e02010-11-12 10:14:11 +0000281 jpegbuf[0], &comptilesize[0], jpegsub, qual, flags)==-1)
282 _throwtj("executing tjCompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000283 ITER=0;
DRC2e4d0442011-02-08 01:18:37 +0000284 start=rrtime();
DRC2e7b76b2009-04-03 12:04:24 +0000285 do
286 {
DRC2e4d0442011-02-08 01:18:37 +0000287 jpgbufsize=0; tilen=0;
DRC2e7b76b2009-04-03 12:04:24 +0000288 for(i=0; i<h; i+=tilesizey)
289 {
290 for(j=0; j<w; j+=tilesizex)
291 {
292 int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
DRC84241602011-02-25 02:08:23 +0000293 if(yuv==YUVENCODE)
294 {
295 if(tjEncodeYUV(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
296 temph, ps, jpegbuf[tilen], jpegsub, flags)==-1)
297 _throwtj("executing tjEncodeYUV()");
298 comptilesize[tilen]=TJBUFSIZEYUV(tempw, temph, jpegsub);
299 }
300 else if(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
DRC2e7b76b2009-04-03 12:04:24 +0000301 temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
DRCe8ce2e02010-11-12 10:14:11 +0000302 flags)==-1)
303 _throwtj("executing tjCompress()");
DRC2e7b76b2009-04-03 12:04:24 +0000304 jpgbufsize+=comptilesize[tilen];
305 tilen++;
306 }
307 }
308 ITER++;
DRC0a192ac2011-02-25 02:12:11 +0000309 } while((elapsed=rrtime()-start)<5.);
DRCe8ce2e02010-11-12 10:14:11 +0000310 if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
311 hnd=NULL;
DRC2a285992011-02-19 17:20:11 +0000312 if(quiet==1)
DRC2e7b76b2009-04-03 12:04:24 +0000313 {
314 if(tilesizex==w && tilesizey==h) printf("Full \t");
315 else printf("%-4d %-4d\t", tilesizex, tilesizey);
DRC2a285992011-02-19 17:20:11 +0000316 }
317 if(quiet)
318 {
DRC2e7b76b2009-04-03 12:04:24 +0000319 printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
DRC2a285992011-02-19 17:20:11 +0000320 printf("%c", quiet==2? '\n':'\t');
DRC2e7b76b2009-04-03 12:04:24 +0000321 printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
DRC2a285992011-02-19 17:20:11 +0000322 printf("%c", quiet==2? '\n':'\t');
DRC2e7b76b2009-04-03 12:04:24 +0000323 }
324 else
325 {
326 if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
327 else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
328 printf("C--> Frame rate: %f fps\n", (double)ITER/elapsed);
329 printf(" Output image size: %d bytes\n", jpgbufsize);
330 printf(" Compression ratio: %f:1\n",
331 (double)(w*h*ps)/(double)jpgbufsize);
332 printf(" Source throughput: %f Megapixels/sec\n",
333 (double)(w*h)/1000000.*(double)ITER/elapsed);
334 printf(" Output bit stream: %f Megabits/sec\n",
335 (double)jpgbufsize*8./1000000.*(double)ITER/elapsed);
336 }
337 if(tilesizex==w && tilesizey==h)
338 {
DRC9e17f7d2010-12-10 04:59:13 +0000339 if(yuv==YUVENCODE)
DRCfbb67472010-11-24 04:02:37 +0000340 sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
341 else
342 sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
DRC2e7b76b2009-04-03 12:04:24 +0000343 if((outfile=fopen(tempstr, "wb"))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000344 _throwunix("opening reference image");
DRC2e7b76b2009-04-03 12:04:24 +0000345 if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
DRCe8ce2e02010-11-12 10:14:11 +0000346 _throwunix("writing reference image");
DRC9e17f7d2010-12-10 04:59:13 +0000347 fclose(outfile); outfile=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000348 if(!quiet) printf("Reference image written to %s\n", tempstr);
349 }
DRC0b11d1c2011-02-24 21:43:35 +0000350 if(yuv==YUVENCODE)
351 {
352 if(quiet==1) printf("\n"); goto bailout;
353 }
DRC2e7b76b2009-04-03 12:04:24 +0000354
355 // Decompression test
DRC993bf0e2011-02-15 21:57:26 +0000356 if(decomptest(srcbuf, jpegbuf, comptilesize, rgbbuf, w, h, jpegsub, qual,
357 filename, tilesizex, tilesizey)==-1)
358 goto bailout;
DRC2e7b76b2009-04-03 12:04:24 +0000359
360 // Cleanup
DRC0f1f60d2011-03-01 20:23:12 +0000361 for(i=0; i<numtilesx*numtilesy; i++)
362 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
363 free(jpegbuf); jpegbuf=NULL;
364 free(comptilesize); comptilesize=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000365 } while(tilesizex<w || tilesizey<h);
366
DRC2e7b76b2009-04-03 12:04:24 +0000367 bailout:
DRC9e17f7d2010-12-10 04:59:13 +0000368 if(outfile) {fclose(outfile); outfile=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000369 if(jpegbuf)
370 {
371 for(i=0; i<numtilesx*numtilesy; i++)
372 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
373 free(jpegbuf); jpegbuf=NULL;
374 }
375 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
376 if(rgbbuf) {free(rgbbuf); rgbbuf=NULL;}
DRCe8ce2e02010-11-12 10:14:11 +0000377 if(hnd) {tjDestroy(hnd); hnd=NULL;}
DRC2e7b76b2009-04-03 12:04:24 +0000378 return;
379}
380
381
DRC993bf0e2011-02-15 21:57:26 +0000382void dodecomptest(char *filename)
DRCe8ce2e02010-11-12 10:14:11 +0000383{
DRC993bf0e2011-02-15 21:57:26 +0000384 FILE *file=NULL; tjhandle hnd=NULL;
DRC890f1e02011-02-26 22:02:37 +0000385 unsigned char **jpegbuf=NULL, *srcbuf=NULL;
386 unsigned long *comptilesize=NULL, srcbufsize, jpgbufsize;
DRC993bf0e2011-02-15 21:57:26 +0000387 int w=0, h=0, jpegsub=-1;
DRC61c15bd2010-11-13 05:31:25 +0000388 char *temp=NULL;
DRC0f1f60d2011-03-01 20:23:12 +0000389 int i, j, tilesizex, tilesizey, numtilesx, numtilesy, retval=0;
DRC890f1e02011-02-26 22:02:37 +0000390 double start, elapsed;
391 int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
392 |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0);
393 int ps=_ps[pf], tilen;
DRCe8ce2e02010-11-12 10:14:11 +0000394
DRC993bf0e2011-02-15 21:57:26 +0000395 useppm=1;
DRCe8ce2e02010-11-12 10:14:11 +0000396
397 if((file=fopen(filename, "rb"))==NULL)
398 _throwunix("opening file");
DRC890f1e02011-02-26 22:02:37 +0000399 if(fseek(file, 0, SEEK_END)<0 || (srcbufsize=ftell(file))<0)
DRCe8ce2e02010-11-12 10:14:11 +0000400 _throwunix("determining file size");
DRC890f1e02011-02-26 22:02:37 +0000401 if((srcbuf=(unsigned char *)malloc(srcbufsize))==NULL)
DRCe8ce2e02010-11-12 10:14:11 +0000402 _throwunix("allocating memory");
403 if(fseek(file, 0, SEEK_SET)<0)
404 _throwunix("setting file position");
DRC890f1e02011-02-26 22:02:37 +0000405 if(fread(srcbuf, srcbufsize, 1, file)<1)
DRCe8ce2e02010-11-12 10:14:11 +0000406 _throwunix("reading JPEG data");
DRCcad1cfe2010-12-14 01:22:00 +0000407 fclose(file); file=NULL;
DRCe8ce2e02010-11-12 10:14:11 +0000408
409 temp=strrchr(filename, '.');
410 if(temp!=NULL) *temp='\0';
411
DRC890f1e02011-02-26 22:02:37 +0000412 if((hnd=tjInitTransform())==NULL) _throwtj("executing tjInitTransform()");
413 if(tjDecompressHeader2(hnd, srcbuf, srcbufsize, &w, &h, &jpegsub)==-1)
DRCcad1cfe2010-12-14 01:22:00 +0000414 _throwtj("executing tjDecompressHeader2()");
DRCe8ce2e02010-11-12 10:14:11 +0000415
DRC890f1e02011-02-26 22:02:37 +0000416 if(yuv) dotile=0;
417
418 if(dotile)
DRCe8ce2e02010-11-12 10:14:11 +0000419 {
DRC890f1e02011-02-26 22:02:37 +0000420 tilesizex=tilesizey=512;
421 if(quiet==1)
422 {
423 printf("All performance values in Mpixels/sec\n\n");
424 printf("Bitmap\tBitmap\tJPEG\tTile Size\tXform\tCompr\tDecomp\n");
425 printf("Format\tOrder\tFormat\t X Y \tPerf \tRatio\tPerf\n\n");
426 }
427 else if(!quiet)
428 {
429 printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
430 bu?"Bottom-up":"Top-down");
431 }
432 do
433 {
434 tilesizex*=2; if(tilesizex>w) tilesizex=w;
435 tilesizey*=2; if(tilesizey>h) tilesizey=h;
436 numtilesx=(w+tilesizex-1)/tilesizex;
437 numtilesy=(h+tilesizey-1)/tilesizey;
438 if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)
439 *numtilesx*numtilesy))==NULL
440 || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)
441 *numtilesx*numtilesy))==NULL)
442 _throwunix("allocating image buffers");
443 memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
444
445 for(i=0; i<numtilesx*numtilesy; i++)
446 {
447 if((jpegbuf[i]=(unsigned char *)malloc(
448 TJBUFSIZE(tilesizex, tilesizey))) == NULL)
449 _throwunix("allocating image buffers");
450 }
451
452 if(quiet==1)
453 {
454 printf("%s\t%s\t%s\t", _pfname[pf], bu?"BU":"TD", _subnamel[jpegsub]);
455 if(tilesizex==w && tilesizey==h) printf("Full \t");
456 else printf("%-4d %-4d\t", tilesizex, tilesizey);
457 }
458
459 start=rrtime();
460 jpgbufsize=0; tilen=0;
461 for(i=0; i<h; i+=tilesizey)
462 {
463 for(j=0; j<w; j+=tilesizex)
464 {
465 int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
466 if(tjTransform(hnd, srcbuf, srcbufsize, jpegbuf[tilen],
467 &comptilesize[tilen], j, i, tempw, temph, TJXFORM_NONE,
468 TJXFORM_CROP, flags)
469 ==-1)
470 _throwtj("executing tjTransform()");
471 jpgbufsize+=comptilesize[tilen];
472 tilen++;
473 }
474 }
475 elapsed=rrtime()-start;
476
477 if(quiet)
478 {
479 printsigfig((double)(w*h)/1000000./elapsed, 4);
480 printf("%c", quiet==2? '\n':'\t');
481 printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
482 printf("%c", quiet==2? '\n':'\t');
483 }
484 else if(!quiet)
485 {
486 if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
487 else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
488 printf("X--> Frame rate: %f fps\n", 1.0/elapsed);
489 printf(" Output image size: %lu bytes\n", jpgbufsize);
490 printf(" Compression ratio: %f:1\n",
491 (double)(w*h*ps)/(double)jpgbufsize);
492 printf(" Source throughput: %f Megapixels/sec\n",
493 (double)(w*h)/1000000./elapsed);
494 printf(" Output bit stream: %f Megabits/sec\n",
495 (double)jpgbufsize*8./1000000./elapsed);
496 }
497
498 if(decomptest(NULL, jpegbuf, comptilesize, NULL, w, h, jpegsub, 0,
499 filename, tilesizex, tilesizey)==-1)
500 goto bailout;
501
502 // Cleanup
503 for(i=0; i<numtilesx*numtilesy; i++)
504 {free(jpegbuf[i]); jpegbuf[i]=NULL;}
505 free(jpegbuf); jpegbuf=NULL;
506 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
507 } while(tilesizex<w || tilesizey<h);
DRCe8ce2e02010-11-12 10:14:11 +0000508 }
DRC993bf0e2011-02-15 21:57:26 +0000509 else
DRCe8ce2e02010-11-12 10:14:11 +0000510 {
DRC890f1e02011-02-26 22:02:37 +0000511 if(quiet==1)
512 {
513 printf("All performance values in Mpixels/sec\n\n");
514 printf("Bitmap\tBitmap\tJPEG\tImage Size\tDecomp\n");
515 printf("Format\tOrder\tFormat\t X Y \tPerf\n\n");
516 printf("%s\t%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD",
517 _subnamel[jpegsub], w, h);
518 }
519 else if(!quiet)
520 {
521 if(yuv==YUVDECODE)
522 printf(">>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]);
523 else
524 printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
525 bu?"Bottom-up":"Top-down");
526 printf("\nImage size: %d x %d", w, h);
DRC109a5782011-03-01 09:53:07 +0000527 if(scale_num!=1 || scale_denom!=1)
528 printf(" --> %d x %d", (w*scale_num+scale_denom-1)/scale_denom,
529 (h*scale_num+scale_denom-1)/scale_denom);
DRC890f1e02011-02-26 22:02:37 +0000530 printf("\n");
531 }
DRCe8ce2e02010-11-12 10:14:11 +0000532
DRC890f1e02011-02-26 22:02:37 +0000533 decomptest(NULL, &srcbuf, &srcbufsize, NULL, w, h, jpegsub, 0, filename,
534 w, h);
535 }
DRCe8ce2e02010-11-12 10:14:11 +0000536
537 bailout:
DRCcad1cfe2010-12-14 01:22:00 +0000538 if(file) {fclose(file); file=NULL;}
DRC890f1e02011-02-26 22:02:37 +0000539 if(jpegbuf)
540 {
541 for(i=0; i<numtilesx*numtilesy; i++)
542 {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
543 free(jpegbuf); jpegbuf=NULL;
544 }
545 if(comptilesize) {free(comptilesize); comptilesize=NULL;}
546 if(srcbuf) {free(srcbuf); srcbuf=NULL;}
DRCe8ce2e02010-11-12 10:14:11 +0000547 if(hnd) {tjDestroy(hnd); hnd=NULL;}
548 return;
549}
550
551
552void usage(char *progname)
553{
DRC109a5782011-03-01 09:53:07 +0000554 int i;
DRCdae3ee92011-02-16 02:08:17 +0000555 printf("USAGE: %s\n", progname);
556 printf(" <Inputfile (BMP|PPM)> <%% Quality> [options]\n\n");
557 printf(" %s\n", progname);
558 printf(" <Inputfile (JPG)> [options]\n\n");
559 printf("Options:\n\n");
560 printf("-tile = Test performance of the codec when the image is encoded as separate\n");
561 printf(" tiles of varying sizes.\n");
562 printf("-forcemmx, -forcesse, -forcesse2, -forcesse3 =\n");
DRC035aac42011-02-19 18:10:05 +0000563 printf(" Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n");
564 printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
DRCdae3ee92011-02-16 02:08:17 +0000565 printf(" Test the specified color conversion path in the codec (default: BGR)\n");
566 printf("-fastupsample = Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n");
567 printf(" YUV decoding in libjpeg decompressor\n");
568 printf("-quiet = Output results in tabular rather than verbose format\n");
569 printf("-yuvencode = Encode RGB input as planar YUV rather than compressing as JPEG\n");
570 printf("-yuvdecode = Decode JPEG image to planar YUV rather than RGB\n");
DRC109a5782011-03-01 09:53:07 +0000571 printf("-scale M/N = scale down the width/height of the decompressed JPEG image by a\n");
572 printf(" factor of M/N (M/N = ");
573 for(i=0; i<nsf; i++)
574 {
575 printf("%d/%d", sf[i].num, sf[i].denom);
576 if(nsf==2 && i!=nsf-1) printf(" or ");
577 else if(nsf>2)
578 {
579 if(i!=nsf-1) printf(", ");
580 if(i==nsf-2) printf("or ");
581 }
582 }
583 printf(")\n\n");
DRCdae3ee92011-02-16 02:08:17 +0000584 printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
585 printf("test will be performed for all quality values in the range.\n\n");
DRCe8ce2e02010-11-12 10:14:11 +0000586 exit(1);
587}
588
589
DRC2e7b76b2009-04-03 12:04:24 +0000590int main(int argc, char *argv[])
591{
DRC109a5782011-03-01 09:53:07 +0000592 unsigned char *bmpbuf=NULL; int w, h, i, j;
DRC17ac3722011-02-26 21:20:46 +0000593 int qual=-1, hiqual=-1; char *temp;
DRC0f1f60d2011-03-01 20:23:12 +0000594 int minarg=2; int retval=0;
DRC2e7b76b2009-04-03 12:04:24 +0000595
DRC109a5782011-03-01 09:53:07 +0000596 if((sf=tjGetScalingFactors(&nsf))==NULL || nsf==0)
597 _throwtj("executing tjGetScalingFactors()");
598
DRCe8ce2e02010-11-12 10:14:11 +0000599 if(argc<minarg) usage(argv[0]);
DRC2e7b76b2009-04-03 12:04:24 +0000600
DRCe8ce2e02010-11-12 10:14:11 +0000601 temp=strrchr(argv[1], '.');
602 if(temp!=NULL)
DRC2e7b76b2009-04-03 12:04:24 +0000603 {
DRCe8ce2e02010-11-12 10:14:11 +0000604 if(!stricmp(temp, ".ppm")) useppm=1;
605 if(!stricmp(temp, ".jpg") || !stricmp(temp, ".jpeg")) decomponly=1;
606 }
607
DRC0b11d1c2011-02-24 21:43:35 +0000608 printf("\n");
609
DRCac08ef62010-12-09 10:01:57 +0000610 if(argc>minarg)
611 {
612 for(i=minarg; i<argc; i++)
613 {
DRC9e17f7d2010-12-10 04:59:13 +0000614 if(!stricmp(argv[i], "-yuvencode"))
DRCac08ef62010-12-09 10:01:57 +0000615 {
DRC0b11d1c2011-02-24 21:43:35 +0000616 printf("Testing YUV planar encoding\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000617 yuv=YUVENCODE; hiqual=qual=100;
618 }
619 if(!stricmp(argv[i], "-yuvdecode"))
620 {
DRC0b11d1c2011-02-24 21:43:35 +0000621 printf("Testing YUV planar decoding\n\n");
DRC9e17f7d2010-12-10 04:59:13 +0000622 yuv=YUVDECODE;
DRCac08ef62010-12-09 10:01:57 +0000623 }
624 }
625 }
626
DRC9e17f7d2010-12-10 04:59:13 +0000627 if(!decomponly && yuv!=YUVENCODE)
DRCe8ce2e02010-11-12 10:14:11 +0000628 {
629 minarg=3;
630 if(argc<minarg) usage(argv[0]);
631 if((qual=atoi(argv[2]))<1 || qual>100)
632 {
633 puts("ERROR: Quality must be between 1 and 100.");
634 exit(1);
635 }
636 if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
637 && sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1
638 && hiqual<=100) {}
639 else hiqual=qual;
640 }
641
642 if(argc>minarg)
643 {
644 for(i=minarg; i<argc; i++)
DRC2e7b76b2009-04-03 12:04:24 +0000645 {
646 if(!stricmp(argv[i], "-tile")) dotile=1;
647 if(!stricmp(argv[i], "-forcesse3"))
648 {
DRC0b11d1c2011-02-24 21:43:35 +0000649 printf("Using SSE3 code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000650 forcesse3=1;
651 }
652 if(!stricmp(argv[i], "-forcesse2"))
653 {
DRC0b11d1c2011-02-24 21:43:35 +0000654 printf("Using SSE2 code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000655 forcesse2=1;
656 }
657 if(!stricmp(argv[i], "-forcesse"))
658 {
DRC0b11d1c2011-02-24 21:43:35 +0000659 printf("Using SSE code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000660 forcesse=1;
661 }
662 if(!stricmp(argv[i], "-forcemmx"))
663 {
DRC0b11d1c2011-02-24 21:43:35 +0000664 printf("Using MMX code\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000665 forcemmx=1;
666 }
DRC61e51f92009-04-05 21:53:20 +0000667 if(!stricmp(argv[i], "-fastupsample"))
668 {
DRC0b11d1c2011-02-24 21:43:35 +0000669 printf("Using fast upsampling code\n\n");
DRC61e51f92009-04-05 21:53:20 +0000670 fastupsample=1;
671 }
DRC2e7b76b2009-04-03 12:04:24 +0000672 if(!stricmp(argv[i], "-rgb")) pf=BMP_RGB;
DRC035aac42011-02-19 18:10:05 +0000673 if(!stricmp(argv[i], "-rgbx")) pf=BMP_RGBX;
DRC2e7b76b2009-04-03 12:04:24 +0000674 if(!stricmp(argv[i], "-bgr")) pf=BMP_BGR;
DRC035aac42011-02-19 18:10:05 +0000675 if(!stricmp(argv[i], "-bgrx")) pf=BMP_BGRX;
676 if(!stricmp(argv[i], "-xbgr")) pf=BMP_XBGR;
677 if(!stricmp(argv[i], "-xrgb")) pf=BMP_XRGB;
DRC2e7b76b2009-04-03 12:04:24 +0000678 if(!stricmp(argv[i], "-bottomup")) bu=1;
679 if(!stricmp(argv[i], "-quiet")) quiet=1;
DRC2a285992011-02-19 17:20:11 +0000680 if(!stricmp(argv[i], "-qq")) quiet=2;
DRCdae3ee92011-02-16 02:08:17 +0000681 if(!stricmp(argv[i], "-scale") && i<argc-1)
682 {
DRC109a5782011-03-01 09:53:07 +0000683 int temp1=0, temp2=0, match=0;
684 if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)==2)
685 {
686 for(j=0; j<nsf; j++)
687 {
688 if(temp1==sf[j].num && temp2==sf[j].denom)
689 {
690 scale_num=temp1; scale_denom=temp2;
691 match=1; break;
692 }
693 }
694 if(!match) usage(argv[0]);
695 }
696 else usage(argv[0]);
DRCdae3ee92011-02-16 02:08:17 +0000697 }
DRC2e7b76b2009-04-03 12:04:24 +0000698 }
699 }
700
DRC109a5782011-03-01 09:53:07 +0000701 if((scale_num!=1 || scale_denom!=1) && dotile)
DRCdae3ee92011-02-16 02:08:17 +0000702 {
703 printf("Disabling tiled compression/decompression tests, because these tests do not\n");
704 printf("work when scaled decompression is enabled.\n");
705 dotile=0;
706 }
707
DRCe8ce2e02010-11-12 10:14:11 +0000708 if(!decomponly)
DRC2e7b76b2009-04-03 12:04:24 +0000709 {
DRCe8ce2e02010-11-12 10:14:11 +0000710 if(loadbmp(argv[1], &bmpbuf, &w, &h, pf, 1, bu)==-1)
711 _throwbmp("loading bitmap");
712 temp=strrchr(argv[1], '.');
713 if(temp!=NULL) *temp='\0';
DRC2e7b76b2009-04-03 12:04:24 +0000714 }
715
DRC2a285992011-02-19 17:20:11 +0000716 if(quiet==1 && !decomponly)
DRC2e7b76b2009-04-03 12:04:24 +0000717 {
DRC0b11d1c2011-02-24 21:43:35 +0000718 printf("All performance values in Mpixels/sec\n\n");
DRC2e7b76b2009-04-03 12:04:24 +0000719 printf("Bitmap\tBitmap\tJPEG\tJPEG\tTile Size\tCompr\tCompr\tDecomp\n");
720 printf("Format\tOrder\tFormat\tQual\t X Y \tPerf \tRatio\tPerf\n\n");
721 }
722
DRCe8ce2e02010-11-12 10:14:11 +0000723 if(decomponly)
724 {
DRC993bf0e2011-02-15 21:57:26 +0000725 dodecomptest(argv[1]);
DRC0b11d1c2011-02-24 21:43:35 +0000726 printf("\n");
DRCe8ce2e02010-11-12 10:14:11 +0000727 goto bailout;
728 }
DRC2e7b76b2009-04-03 12:04:24 +0000729 for(i=hiqual; i>=qual; i--)
DRC993bf0e2011-02-15 21:57:26 +0000730 dotest(bmpbuf, w, h, TJ_GRAYSCALE, i, argv[1]);
DRC0b11d1c2011-02-24 21:43:35 +0000731 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000732 for(i=hiqual; i>=qual; i--)
DRC993bf0e2011-02-15 21:57:26 +0000733 dotest(bmpbuf, w, h, TJ_420, i, argv[1]);
DRC0b11d1c2011-02-24 21:43:35 +0000734 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000735 for(i=hiqual; i>=qual; i--)
DRC993bf0e2011-02-15 21:57:26 +0000736 dotest(bmpbuf, w, h, TJ_422, i, argv[1]);
DRC0b11d1c2011-02-24 21:43:35 +0000737 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000738 for(i=hiqual; i>=qual; i--)
DRC993bf0e2011-02-15 21:57:26 +0000739 dotest(bmpbuf, w, h, TJ_444, i, argv[1]);
DRC0b11d1c2011-02-24 21:43:35 +0000740 printf("\n");
DRC2e7b76b2009-04-03 12:04:24 +0000741
DRC109a5782011-03-01 09:53:07 +0000742 bailout:
743 if(bmpbuf) free(bmpbuf);
DRC0f1f60d2011-03-01 20:23:12 +0000744 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000745}