1 /* -*- C++ -*-
2  * File: halt_mt_win32.c
3  * Copyright 2008-2021 LibRaw LLC (info@libraw.org)
4  * Created: Sat Mar  8, 2008
5  *
6  * LibRaw  C API mutithreaded sample:  emulates call to "dcraw  -h [-w] [-a]
7 [-v]"
8  * Win32 version
9 
10 LibRaw is free software; you can redistribute it and/or modify
11 it under the terms of the one of two licenses as you choose:
12 
13 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
14    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
15 
16 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
17    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
18 
19 
20  */
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <math.h>
25 #include <windows.h>
26 #include "libraw/libraw.h"
27 
28 #ifdef LIBRAW_WIN32_CALLS
29 #define snprintf _snprintf
30 #endif
31 
32 #define HANDLE_ERRORS(ret)                                                     \
33   do                                                                           \
34   {                                                                            \
35     if (ret)                                                                   \
36     {                                                                          \
37       fprintf(stderr, "%s: %s\n", fn, libraw_strerror(ret));                   \
38       if (LIBRAW_FATAL_ERROR(ret))                                             \
39       {                                                                        \
40         libraw_close(iprc);                                                    \
41         return -1;                                                             \
42       }                                                                        \
43     }                                                                          \
44   } while (0)
45 
46 // global settings
47 int verbose = 0, use_camera_wb = 0, use_auto_wb = 0, tiff_mode = 0;
48 
49 // global file queue
50 HANDLE qmutex;
51 char **queue = NULL;
52 size_t qsize = 0, qptr = 0;
53 
get_next_file()54 char *get_next_file()
55 {
56   char *ret;
57   DWORD dwWaitResult;
58   if (!queue)
59     return NULL;
60   if (qptr >= qsize)
61     return NULL;
62 
63   dwWaitResult = WaitForSingleObject(qmutex,    // handle to mutex
64                                      INFINITE); // no time-out interval
65   switch (dwWaitResult)
66   {
67   // The thread got ownership of the mutex
68   case WAIT_OBJECT_0:
69     ret = queue[qptr++];
70     ReleaseMutex(qmutex);
71     break;
72   case WAIT_ABANDONED:
73     return NULL; // cannot obtain the lock
74   };
75   return ret;
76 }
77 
78 // thread routine
process_files(void * q)79 int process_files(void *q)
80 {
81   int ret;
82   int count = 0;
83   char outfn[1024], *fn;
84   libraw_data_t *iprc = libraw_init(0);
85 
86   if (!iprc)
87   {
88     fprintf(stderr, "Cannot create libraw handle\n");
89     return -1;
90   }
91 
92   while ((fn = get_next_file()))
93   {
94 
95     iprc->params.half_size = 1; /* dcraw -h */
96     iprc->params.use_camera_wb = use_camera_wb;
97     iprc->params.use_auto_wb = use_auto_wb;
98     iprc->params.output_tiff = tiff_mode;
99 
100     ret = libraw_open_file(iprc, fn);
101     if (verbose)
102       fprintf(stderr, "%s: %s/%s\n", fn, iprc->idata.make, iprc->idata.model);
103     HANDLE_ERRORS(ret);
104 
105     ret = libraw_unpack(iprc);
106     HANDLE_ERRORS(ret);
107 
108     ret = libraw_dcraw_process(iprc);
109     HANDLE_ERRORS(ret);
110 
111     snprintf(outfn, 1023, "%s.%s", fn, tiff_mode ? "tif" : "ppm");
112 
113     if (verbose)
114       fprintf(stderr, "Writing file %s\n", outfn);
115     ret = libraw_dcraw_ppm_tiff_writer(iprc, outfn);
116     HANDLE_ERRORS(ret);
117     count++;
118   }
119   libraw_close(iprc);
120   printf("Processed %d files\n", count);
121   return 0;
122 }
123 
usage(const char * p)124 void usage(const char *p)
125 {
126   printf("Options:\n"
127          "-J n  - set parallel job count (default 2)\n"
128          "-v    - verbose\n"
129          "-w    - use camera white balance\n"
130          "-T    - output TIFF instead of PPM\n"
131          "-a    - average image for white balance\n");
132   exit(1);
133 }
134 
show_files(void * q)135 int show_files(void *q)
136 {
137   char *p;
138   int cnt = 0;
139   while (p = get_next_file())
140   {
141     printf("%s\n", p);
142     cnt++;
143   }
144   return cnt;
145 }
146 
main(int ac,char * av[])147 int main(int ac, char *av[])
148 {
149   int i, max_threads = 2;
150   HANDLE *threads;
151   DWORD ThreadID;
152 
153   if (ac < 2)
154     usage(av[0]);
155 
156   queue = calloc(ac - 1, sizeof(queue[0]));
157 
158   for (i = 1; i < ac; i++)
159   {
160     if (av[i][0] == '-')
161     {
162       if (av[i][1] == 'w')
163         use_camera_wb = 1;
164       if (av[i][1] == 'a')
165         use_auto_wb = 1;
166       if (av[i][1] == 'v')
167         verbose = 1;
168       if (av[i][1] == 'T')
169         tiff_mode = 1;
170       if (av[i][1] == 'J')
171       {
172         max_threads = atoi(av[++i]);
173         if (max_threads < 1)
174         {
175           fprintf(stderr, "Job count should be at least 1\n");
176           exit(1);
177         }
178       }
179     }
180     else
181       queue[qsize++] = av[i];
182   }
183   qmutex = CreateMutex(NULL, FALSE, NULL);
184   threads = calloc(max_threads, sizeof(threads[0]));
185   for (i = 0; i < max_threads; i++)
186   {
187 
188     if (NULL ==
189         (threads[i] = CreateThread(NULL, // default security attributes
190                                    0,    // default stack size
191                                    (LPTHREAD_START_ROUTINE)process_files,
192                                    NULL,      // no thread function arguments
193                                    0,         // default creation flags
194                                    &ThreadID) // receive thread identifier
195          ))
196     {
197       printf("CreateThread error: %d\n", GetLastError());
198       return 1;
199     }
200   }
201 
202   WaitForMultipleObjects(max_threads, threads, TRUE, INFINITE);
203 
204   // Close thread and mutex handles
205 
206   for (i = 0; i < max_threads; i++)
207     CloseHandle(threads[i]);
208 
209   CloseHandle(qmutex);
210 
211   return 0;
212 }
213