1 /* -*- C++ -*-
2  * File: halt_mt.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  *
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 <pthread.h>
26 
27 #include "libraw/libraw.h"
28 
29 #define HANDLE_ERRORS(ret)                                                     \
30   do                                                                           \
31   {                                                                            \
32     if (ret)                                                                   \
33     {                                                                          \
34       fprintf(stderr, "%s: %s\n", fn, libraw_strerror(ret));                   \
35       if (LIBRAW_FATAL_ERROR(ret))                                             \
36       {                                                                        \
37         libraw_close(iprc);                                                    \
38         return NULL;                                                           \
39       }                                                                        \
40     }                                                                          \
41   } while (0)
42 
43 int verbose = 0, use_camera_wb = 0, use_auto_wb = 0, tiff_mode = 0;
44 
45 pthread_mutex_t qm;
46 char **queue = NULL;
47 size_t qsize = 0, qptr = 0;
48 
get_next_file()49 char *get_next_file()
50 {
51   char *ret;
52   if (!queue)
53     return NULL;
54   if (qptr >= qsize)
55     return NULL;
56   pthread_mutex_lock(&qm);
57   ret = queue[qptr++];
58   pthread_mutex_unlock(&qm);
59   return ret;
60 }
61 
process_files(void * q)62 void *process_files(void *q)
63 {
64   int ret;
65   int count = 0;
66   char outfn[1024], *fn;
67   libraw_data_t *iprc = libraw_init(0);
68 
69   if (!iprc)
70   {
71     fprintf(stderr, "Cannot create libraw handle\n");
72     return NULL;
73   }
74 
75   while ((fn = get_next_file()))
76   {
77 
78     iprc->params.half_size = 1; /* dcraw -h */
79     iprc->params.use_camera_wb = use_camera_wb;
80     iprc->params.use_auto_wb = use_auto_wb;
81     iprc->params.output_tiff = tiff_mode;
82 
83     ret = libraw_open_file(iprc, fn);
84     if (verbose)
85       fprintf(stderr, "%s: %s/%s\n", fn, iprc->idata.make, iprc->idata.model);
86     HANDLE_ERRORS(ret);
87 
88     ret = libraw_unpack(iprc);
89     HANDLE_ERRORS(ret);
90 
91     ret = libraw_dcraw_process(iprc);
92     HANDLE_ERRORS(ret);
93 
94     snprintf(outfn, 1023, "%s.%s", fn, tiff_mode ? "tiff" : "ppm");
95 
96     if (verbose)
97       fprintf(stderr, "Writing file %s\n", outfn);
98     ret = libraw_dcraw_ppm_tiff_writer(iprc, outfn);
99     HANDLE_ERRORS(ret);
100     count++;
101   }
102   libraw_close(iprc);
103   return NULL;
104 }
105 
usage(const char * p)106 void usage(const char *p)
107 {
108   printf("%s: Multi-threaded LibRaw sample app. Emulates dcraw -h [-w] [-a]\n",
109          p);
110   printf("Options:\n"
111          "-J n  - set parallel job count (default 2)\n"
112          "-v    - verbose\n"
113          "-w    - use camera white balance\n"
114          "-a    - average image for white balance\n");
115   exit(1);
116 }
117 
show_files(void * q)118 int show_files(void *q)
119 {
120   char *p;
121   int cnt = 0;
122   while ((p = get_next_file()))
123   {
124     printf("%s\n", p);
125     cnt++;
126   }
127   return cnt;
128 }
129 
main(int ac,char * av[])130 int main(int ac, char *av[])
131 {
132   int i, max_threads = 2;
133   pthread_t *threads;
134   if (ac < 2)
135     usage(av[0]);
136 
137   queue = calloc(ac - 1, sizeof(queue[0]));
138 
139   for (i = 1; i < ac; i++)
140   {
141     if (av[i][0] == '-')
142     {
143       if (av[i][1] == 'w')
144         use_camera_wb = 1;
145       if (av[i][1] == 'a')
146         use_auto_wb = 1;
147       if (av[i][1] == 'v')
148         verbose = 1;
149       if (av[i][1] == 'T')
150         tiff_mode = 1;
151       if (av[i][1] == 'J')
152       {
153         max_threads = atoi(av[++i]);
154         if (max_threads < 1)
155         {
156           fprintf(stderr, "Job count should be at least 1\n");
157           exit(1);
158         }
159       }
160     }
161     else
162       queue[qsize++] = av[i];
163   }
164   pthread_mutex_init(&qm, NULL);
165   threads = calloc(max_threads, sizeof(threads[0]));
166   for (i = 0; i < max_threads; i++)
167     pthread_create(&threads[i], NULL, process_files, NULL);
168   for (i = 0; i < max_threads; i++)
169   {
170     int *iptr;
171     if (threads[i])
172     {
173       pthread_join(threads[i], (void *)&iptr);
174     }
175   }
176 
177   return 0;
178 }
179