1 /* -*- C++ -*-
2  * File: postprocessing_benchmark.cpp
3  * Copyright 2008-2021 LibRaw LLC (info@libraw.org)
4  * Created: Jul 13, 2011
5  *
6  * LibRaw simple C++ API:  creates 8 different renderings from 1 source file.
7 The 1st and 4th one should be identical
8 
9 LibRaw is free software; you can redistribute it and/or modify
10 it under the terms of the one of two licenses as you choose:
11 
12 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
13    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
14 
15 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
16    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
17 
18  */
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 
23 #include "libraw/libraw.h"
24 
25 #ifndef LIBRAW_WIN32_CALLS
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #else
30 #include <winsock2.h>
31 #endif
32 
33 #include "libraw/libraw.h"
34 
35 void timerstart(void);
36 float timerend(void);
37 
main(int argc,char * argv[])38 int main(int argc, char *argv[])
39 {
40   int i, ret, rep = 1;
41   LibRaw RawProcessor;
42 #ifdef OUT
43 #undef OUT
44 #endif
45 #define OUT RawProcessor.imgdata.params
46 #define OUTR RawProcessor.imgdata.rawparams
47 #define S RawProcessor.imgdata.sizes
48 
49   if (argc < 2)
50   {
51     printf(
52         "postprocessing benchmark: LibRaw %s sample, %d cameras supported\n"
53         "Measures postprocessing speed with different options\n"
54         "Usage: %s [-a] [-H N] [-q N] [-h] [-m N] [-n N] [-s N] [-B x y w h] "
55         "[-R N]\n"
56         "-a             average image for white balance\n"
57         "-H <num>       Highlight mode (0=clip, 1=unclip, 2=blend, "
58         "3+=rebuild)\n"
59         "-q <num>       Set the interpolation quality\n"
60         "-h             Half-size color image\n"
61         "-m <num>       Apply a num-passes 3x3 median filter to R-G and B-G\n"
62         "-n <num>       Set threshold for wavelet denoising\n"
63         "-s <num>       Select one raw image from input file\n"
64         "-B <x y w h>   Crop output image\n"
65         "-R <num>       Number of repetitions\n"
66         "-c             Do not use rawspeed\n",
67         LibRaw::version(), LibRaw::cameraCount(), argv[0]);
68     return 0;
69   }
70   char opm, opt, *cp, *sp;
71   int arg, c;
72   int shrink = 0;
73 
74   argv[argc] = (char *)"";
75   for (arg = 1; (((opm = argv[arg][0]) - 2) | 2) == '+';)
76   {
77     char *optstr = argv[arg];
78     opt = argv[arg++][1];
79     if ((cp = strchr(sp = (char *)"HqmnsBR", opt)) != 0)
80       for (i = 0; i < "1111141"[cp - sp] - '0'; i++)
81         if (!isdigit(argv[arg + i][0]) && !optstr[2])
82         {
83           fprintf(stderr, "Non-numeric argument to \"-%c\"\n", opt);
84           return 1;
85         }
86     switch (opt)
87     {
88     case 'a':
89       OUT.use_auto_wb = 1;
90       break;
91     case 'H':
92       OUT.highlight = atoi(argv[arg++]);
93       break;
94     case 'q':
95       OUT.user_qual = atoi(argv[arg++]);
96       break;
97     case 'h':
98       OUT.half_size = 1;
99       OUT.four_color_rgb = 1;
100       shrink = 1;
101       break;
102     case 'm':
103       OUT.med_passes = atoi(argv[arg++]);
104       break;
105     case 'n':
106       OUT.threshold = (float)atof(argv[arg++]);
107       break;
108     case 's':
109       OUTR.shot_select = abs(atoi(argv[arg++]));
110       break;
111     case 'B':
112       for (c = 0; c < 4; c++)
113         OUT.cropbox[c] = atoi(argv[arg++]);
114       break;
115     case 'R':
116       rep = abs(atoi(argv[arg++]));
117       if (rep < 1)
118         rep = 1;
119       break;
120     case 'c':
121       RawProcessor.imgdata.rawparams.use_rawspeed = 0;
122       break;
123     default:
124       fprintf(stderr, "Unknown option \"-%c\".\n", opt);
125       return 1;
126     }
127   }
128   for (; arg < argc; arg++)
129   {
130     printf("Processing file %s\n", argv[arg]);
131     timerstart();
132     if ((ret = RawProcessor.open_file(argv[arg])) != LIBRAW_SUCCESS)
133     {
134       fprintf(stderr, "Cannot open_file %s: %s\n", argv[arg],
135               libraw_strerror(ret));
136       continue; // no recycle b/c open file will recycle itself
137     }
138 
139     if ((ret = RawProcessor.unpack()) != LIBRAW_SUCCESS)
140     {
141       fprintf(stderr, "Cannot unpack %s: %s\n", argv[arg],
142               libraw_strerror(ret));
143       continue;
144     }
145     float qsec = timerend();
146     printf("\n%.1f msec for unpack\n", qsec);
147     float mpix, rmpix;
148     timerstart();
149     for (c = 0; c < rep; c++)
150     {
151       if ((ret = RawProcessor.dcraw_process()) != LIBRAW_SUCCESS)
152       {
153         fprintf(stderr, "Cannot postprocess %s: %s\n", argv[arg],
154                 libraw_strerror(ret));
155         break;
156       }
157       libraw_processed_image_t *p = RawProcessor.dcraw_make_mem_image();
158       if (p)
159         RawProcessor.dcraw_clear_mem(p);
160       RawProcessor.free_image();
161     }
162     float msec = timerend() / (float)rep;
163 
164     if ((ret = RawProcessor.adjust_sizes_info_only()) != LIBRAW_SUCCESS)
165     {
166       fprintf(stderr, "Cannot adjust sizes for %s: %s\n", argv[arg],
167               libraw_strerror(ret));
168       break;
169     }
170     rmpix = (S.iwidth * S.iheight) / 1000000.0f;
171 
172     if (c == rep) // no failure
173     {
174       unsigned int crop[4];
175       for (int i = 0; i < 4; i++)
176         crop[i] = (OUT.cropbox[i]) >> shrink;
177       if (crop[0] + crop[2] > S.iwidth)
178         crop[2] = S.iwidth - crop[0];
179       if (crop[1] + crop[3] > S.iheight)
180         crop[3] = S.iheight - crop[1];
181 
182       mpix = float(crop[2] * crop[3]) / 1000000.0f;
183       float mpixsec = mpix * 1000.0f / msec;
184 
185       printf("Performance: %.2f Mpix/sec\n"
186              "File: %s, Frame: %d %.1f total Mpix, %.1f msec\n"
187              "Params:      WB=%s Highlight=%d Qual=%d HalfSize=%s Median=%d "
188              "Wavelet=%.0f\n"
189              "Crop:        %u-%u:%ux%u, active Mpix: %.2f, %.1f frames/sec\n",
190              mpixsec, argv[arg], OUTR.shot_select, rmpix, msec,
191              OUT.use_auto_wb ? "auto" : "default", OUT.highlight, OUT.user_qual,
192              OUT.half_size ? "YES" : "No", OUT.med_passes, OUT.threshold,
193              crop[0], crop[1], crop[2], crop[3], mpix, 1000.0f / msec);
194     }
195   }
196 
197   return 0;
198 }
199 
200 #ifndef LIBRAW_WIN32_CALLS
201 static struct timeval start, end;
timerstart(void)202 void timerstart(void) { gettimeofday(&start, NULL); }
timerend(void)203 float timerend(void)
204 {
205   gettimeofday(&end, NULL);
206   float msec = (end.tv_sec - start.tv_sec) * 1000.0f +
207                (end.tv_usec - start.tv_usec) / 1000.0f;
208   return msec;
209 }
210 #else
211 LARGE_INTEGER start;
timerstart(void)212 void timerstart(void) { QueryPerformanceCounter(&start); }
timerend()213 float timerend()
214 {
215   LARGE_INTEGER unit, end;
216   QueryPerformanceCounter(&end);
217   QueryPerformanceFrequency(&unit);
218   float msec = (float)(end.QuadPart - start.QuadPart);
219   msec /= (float)unit.QuadPart / 1000.0f;
220   return msec;
221 }
222 
223 #endif
224