1 /*------------------------------------------------------------------------
2  *  Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
3  *
4  *  This file is part of the ZBar Bar Code Reader.
5  *
6  *  The ZBar Bar Code Reader is free software; you can redistribute it
7  *  and/or modify it under the terms of the GNU Lesser Public License as
8  *  published by the Free Software Foundation; either version 2.1 of
9  *  the License, or (at your option) any later version.
10  *
11  *  The ZBar Bar Code Reader is distributed in the hope that it will be
12  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13  *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser Public License
17  *  along with the ZBar Bar Code Reader; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  *  Boston, MA  02110-1301  USA
20  *
21  *  http://sourceforge.net/projects/zbar
22  *------------------------------------------------------------------------*/
23 
24 #include "video.h"
25 #include "image.h"
26 
27 
28 #ifdef HAVE_LIBJPEG
29 extern struct jpeg_decompress_struct *_zbar_jpeg_decomp_create(void);
30 extern void _zbar_jpeg_decomp_destroy(struct jpeg_decompress_struct *cinfo);
31 #endif
32 
_zbar_video_recycle_image(zbar_image_t * img)33 static void _zbar_video_recycle_image (zbar_image_t *img)
34 {
35     zbar_video_t *vdo = img->src;
36     assert(vdo);
37     assert(img->srcidx >= 0);
38     video_lock(vdo);
39     if(vdo->images[img->srcidx] != img)
40         vdo->images[img->srcidx] = img;
41     if(vdo->active)
42         vdo->nq(vdo, img);
43     else
44         video_unlock(vdo);
45 }
46 
_zbar_video_recycle_shadow(zbar_image_t * img)47 static void _zbar_video_recycle_shadow (zbar_image_t *img)
48 {
49     zbar_video_t *vdo = img->src;
50     assert(vdo);
51     assert(img->srcidx == -1);
52     video_lock(vdo);
53     img->next = vdo->shadow_image;
54     vdo->shadow_image = img;
55     video_unlock(vdo);
56 }
57 
zbar_video_create()58 zbar_video_t *zbar_video_create ()
59 {
60     zbar_video_t *vdo = calloc(1, sizeof(zbar_video_t));
61     int i;
62     if(!vdo)
63         return(NULL);
64     err_init(&vdo->err, ZBAR_MOD_VIDEO);
65     vdo->fd = -1;
66 
67     (void)_zbar_mutex_init(&vdo->qlock);
68 
69     /* pre-allocate images */
70     vdo->num_images = ZBAR_VIDEO_IMAGES_MAX;
71     vdo->images = calloc(ZBAR_VIDEO_IMAGES_MAX, sizeof(zbar_image_t*));
72     if(!vdo->images) {
73         zbar_video_destroy(vdo);
74         return(NULL);
75     }
76 
77     for(i = 0; i < ZBAR_VIDEO_IMAGES_MAX; i++) {
78         zbar_image_t *img = vdo->images[i] = zbar_image_create();
79         if(!img) {
80             zbar_video_destroy(vdo);
81             return(NULL);
82         }
83         img->refcnt = 0;
84         img->cleanup = _zbar_video_recycle_image;
85         img->srcidx = i;
86         img->src = vdo;
87     }
88 
89     return(vdo);
90 }
91 
zbar_video_destroy(zbar_video_t * vdo)92 void zbar_video_destroy (zbar_video_t *vdo)
93 {
94     if(vdo->intf != VIDEO_INVALID)
95         zbar_video_open(vdo, NULL);
96     if(vdo->images) {
97         int i;
98         for(i = 0; i < ZBAR_VIDEO_IMAGES_MAX; i++)
99             if(vdo->images[i])
100                 _zbar_image_free(vdo->images[i]);
101         free(vdo->images);
102     }
103     while(vdo->shadow_image) {
104         zbar_image_t *img = vdo->shadow_image;
105         vdo->shadow_image = img->next;
106         free((void*)img->data);
107         img->data = NULL;
108         free(img);
109     }
110     if(vdo->buf)
111         free(vdo->buf);
112     if(vdo->formats)
113         free(vdo->formats);
114     if(vdo->emu_formats)
115         free(vdo->emu_formats);
116 
117     if(vdo->free)
118         vdo->free(vdo);
119 
120     err_cleanup(&vdo->err);
121     _zbar_mutex_destroy(&vdo->qlock);
122 
123 #ifdef HAVE_LIBJPEG
124     if(vdo->jpeg_img) {
125         zbar_image_destroy(vdo->jpeg_img);
126         vdo->jpeg_img = NULL;
127     }
128     if(vdo->jpeg) {
129         _zbar_jpeg_decomp_destroy(vdo->jpeg);
130         vdo->jpeg = NULL;
131     }
132 #endif
133     free(vdo);
134 }
135 
zbar_video_open(zbar_video_t * vdo,const char * dev)136 int zbar_video_open (zbar_video_t *vdo,
137                      const char *dev)
138 {
139     char *ldev = NULL;
140     int rc;
141     zbar_video_enable(vdo, 0);
142     video_lock(vdo);
143     if(vdo->intf != VIDEO_INVALID) {
144         if(vdo->cleanup) {
145             vdo->cleanup(vdo);
146             vdo->cleanup = NULL;
147         }
148         zprintf(1, "closed camera (fd=%d)\n", vdo->fd);
149         vdo->intf = VIDEO_INVALID;
150     }
151     video_unlock(vdo);
152 
153     if(!dev)
154         return(0);
155 
156     if((unsigned char)dev[0] < 0x10) {
157         /* default linux device, overloaded for other platforms */
158         int id = dev[0];
159         dev = ldev = strdup("/dev/video0");
160         ldev[10] = '0' + id;
161     }
162 
163     rc = _zbar_video_open(vdo, dev);
164 
165     if(ldev)
166         free(ldev);
167     return(rc);
168 }
169 
zbar_video_get_fd(const zbar_video_t * vdo)170 int zbar_video_get_fd (const zbar_video_t *vdo)
171 {
172     if(vdo->intf == VIDEO_INVALID)
173         return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
174                            "video device not opened"));
175     if(vdo->intf != VIDEO_V4L2)
176         return(err_capture(vdo, SEV_WARNING, ZBAR_ERR_UNSUPPORTED, __func__,
177                            "video driver does not support polling"));
178     return(vdo->fd);
179 }
180 
zbar_video_request_size(zbar_video_t * vdo,unsigned width,unsigned height)181 int zbar_video_request_size (zbar_video_t *vdo,
182                              unsigned width,
183                              unsigned height)
184 {
185     if(vdo->initialized)
186         /* FIXME re-init different format? */
187         return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
188                            "already initialized, unable to resize"));
189 
190     vdo->width = width;
191     vdo->height = height;
192     zprintf(1, "request size: %d x %d\n", width, height);
193     return(0);
194 }
195 
zbar_video_request_interface(zbar_video_t * vdo,int ver)196 int zbar_video_request_interface (zbar_video_t *vdo,
197                                   int ver)
198 {
199     if(vdo->intf != VIDEO_INVALID)
200         return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
201                          "device already opened, unable to change interface"));
202     vdo->intf = (video_interface_t)ver;
203     zprintf(1, "request interface version %d\n", vdo->intf);
204     return(0);
205 }
206 
zbar_video_request_iomode(zbar_video_t * vdo,int iomode)207 int zbar_video_request_iomode (zbar_video_t *vdo,
208                                int iomode)
209 {
210     if(vdo->intf != VIDEO_INVALID)
211         return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
212                          "device already opened, unable to change iomode"));
213     if(iomode < 0 || iomode > VIDEO_USERPTR)
214         return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
215                          "invalid iomode requested"));
216     vdo->iomode = iomode;
217     return(0);
218 }
219 
zbar_video_get_width(const zbar_video_t * vdo)220 int zbar_video_get_width (const zbar_video_t *vdo)
221 {
222     return(vdo->width);
223 }
224 
zbar_video_get_height(const zbar_video_t * vdo)225 int zbar_video_get_height (const zbar_video_t *vdo)
226 {
227     return(vdo->height);
228 }
229 
zbar_video_get_format(const zbar_video_t * vdo)230 uint32_t zbar_video_get_format (const zbar_video_t *vdo)
231 {
232     return(vdo->format);
233 }
234 
video_init_images(zbar_video_t * vdo)235 static inline int video_init_images (zbar_video_t *vdo)
236 {
237     int i;
238     assert(vdo->datalen);
239     if(vdo->iomode != VIDEO_MMAP) {
240         assert(!vdo->buf);
241         vdo->buflen = vdo->num_images * vdo->datalen;
242         vdo->buf = calloc(1, vdo->buflen);
243         if(!vdo->buf)
244             return(err_capture(vdo, SEV_FATAL, ZBAR_ERR_NOMEM, __func__,
245                                "unable to allocate image buffers"));
246         zprintf(1, "pre-allocated %d %s buffers size=0x%lx\n", vdo->num_images,
247                 (vdo->iomode == VIDEO_READWRITE) ? "READ" : "USERPTR",
248                 vdo->buflen);
249     }
250     for(i = 0; i < vdo->num_images; i++) {
251         zbar_image_t *img = vdo->images[i];
252         img->format = vdo->format;
253         zbar_image_set_size(img, vdo->width, vdo->height);
254         if(vdo->iomode != VIDEO_MMAP) {
255             unsigned long offset = i * vdo->datalen;
256             img->datalen = vdo->datalen;
257             img->data = (uint8_t*)vdo->buf + offset;
258             zprintf(2, "    [%02d] @%08lx\n", i, offset);
259         }
260     }
261     return(0);
262 }
263 
zbar_video_init(zbar_video_t * vdo,unsigned long fmt)264 int zbar_video_init (zbar_video_t *vdo,
265                      unsigned long fmt)
266 {
267 #ifdef HAVE_LIBJPEG
268     const zbar_format_def_t *vidfmt;
269 #endif
270     if(vdo->initialized)
271         /* FIXME re-init different format? */
272         return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
273                            "already initialized, re-init unimplemented"));
274 
275     if(vdo->init(vdo, fmt))
276         return(-1);
277     vdo->format = fmt;
278     if(video_init_images(vdo))
279         return(-1);
280 #ifdef HAVE_LIBJPEG
281     vidfmt = _zbar_format_lookup(fmt);
282     if(vidfmt && vidfmt->group == ZBAR_FMT_JPEG) {
283         zbar_image_t *img;
284         /* prepare for decoding */
285         if(!vdo->jpeg)
286             vdo->jpeg = _zbar_jpeg_decomp_create();
287         if(vdo->jpeg_img)
288             zbar_image_destroy(vdo->jpeg_img);
289 
290         /* create intermediate image for decoder to use*/
291         img = vdo->jpeg_img = zbar_image_create();
292         img->format = fourcc('Y','8','0','0');
293         zbar_image_set_size(img, vdo->width, vdo->height);
294         img->datalen = vdo->width * vdo->height;
295     }
296 #endif
297     vdo->initialized = 1;
298     return(0);
299 }
300 
zbar_video_enable(zbar_video_t * vdo,int enable)301 int zbar_video_enable (zbar_video_t *vdo,
302                        int enable)
303 {
304     if(vdo->active == enable)
305         return(0);
306 
307     if(enable) {
308         if(vdo->intf == VIDEO_INVALID)
309             return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
310                                "video device not opened"));
311 
312         if(!vdo->initialized &&
313            zbar_negotiate_format(vdo, NULL))
314             return(-1);
315     }
316 
317     if(video_lock(vdo))
318         return(-1);
319     vdo->active = enable;
320     if(enable) {
321         /* enqueue all buffers */
322         int i;
323         for(i = 0; i < vdo->num_images; i++)
324             if(vdo->nq(vdo, vdo->images[i]) ||
325                ((i + 1 < vdo->num_images) && video_lock(vdo)))
326                 return(-1);
327 
328         return(vdo->start(vdo));
329     }
330     else {
331         int i;
332         for(i = 0; i < vdo->num_images; i++)
333             vdo->images[i]->next = NULL;
334         vdo->nq_image = vdo->dq_image = NULL;
335         if(video_unlock(vdo))
336             return(-1);
337 
338         return(vdo->stop(vdo));
339     }
340 }
341 
zbar_video_next_image(zbar_video_t * vdo)342 zbar_image_t *zbar_video_next_image (zbar_video_t *vdo)
343 {
344     unsigned frame;
345     zbar_image_t *img;
346 
347     if(video_lock(vdo))
348         return(NULL);
349     if(!vdo->active) {
350         video_unlock(vdo);
351         return(NULL);
352     }
353 
354     frame = vdo->frame++;
355     img = vdo->dq(vdo);
356     if(img) {
357         img->seq = frame;
358         if(vdo->num_images < 2) {
359             /* return a *copy* of the video image and immediately recycle
360              * the driver's buffer to avoid deadlocking the resources
361              */
362             zbar_image_t *tmp = img;
363             video_lock(vdo);
364             img = vdo->shadow_image;
365             vdo->shadow_image = (img) ? img->next : NULL;
366             video_unlock(vdo);
367 
368             if(!img) {
369                 img = zbar_image_create();
370                 assert(img);
371                 img->refcnt = 0;
372                 img->src = vdo;
373                 /* recycle the shadow images */
374 
375                 img->format = vdo->format;
376                 zbar_image_set_size(img, vdo->width, vdo->height);
377                 img->datalen = vdo->datalen;
378                 img->data = malloc(vdo->datalen);
379             }
380             img->cleanup = _zbar_video_recycle_shadow;
381             img->seq = frame;
382             memcpy((void*)img->data, tmp->data, img->datalen);
383             _zbar_video_recycle_image(tmp);
384         }
385         else
386             img->cleanup = _zbar_video_recycle_image;
387         _zbar_image_refcnt(img, 1);
388     }
389     return(img);
390 }
391 
392 /** @brief return if fun unsupported, otherwise continue */
393 #define return_if_not_supported(fun, name) \
394 { \
395     if(!(fun)) { \
396         zprintf(1, "video driver does not implement %s\n", name); \
397         return ZBAR_ERR_UNSUPPORTED; \
398     } \
399 }
400 #define return_if_non_zero(a) { int rv=a; if (rv!=0) return(rv); }
401 
zbar_video_set_control(zbar_video_t * vdo,const char * control_name,int value)402 int zbar_video_set_control (zbar_video_t *vdo,
403                             const char *control_name,
404                             int value)
405 {
406     int loc_value, rv;
407     return_if_not_supported(vdo->set_control, "set_control");
408     loc_value = value;
409 
410     rv = vdo->set_control(vdo, control_name, &loc_value);
411 
412     if(rv==0)
413         zprintf(1, "value of %s set to: %d\n", control_name, loc_value);
414     return(rv);
415 }
416 
zbar_video_get_control(zbar_video_t * vdo,const char * control_name,int * value)417 int zbar_video_get_control (zbar_video_t *vdo,
418                             const char *control_name,
419                             int *value)
420 {
421     return_if_not_supported(vdo->get_control, "get_control");
422     return(vdo->get_control(vdo, control_name, value));
423 }
424 
zbar_video_get_controls(const zbar_video_t * vdo,int index)425 struct video_controls_s *zbar_video_get_controls (const zbar_video_t *vdo,
426                                                   int index)
427 {
428     int i = 0;
429     struct video_controls_s *p = vdo->controls;
430 
431     while (p && i != index) {
432         i++;
433         p = p->next;
434     }
435 
436     if (!p)
437         return NULL;
438 
439     return p;
440 }
441 
zbar_video_get_resolutions(const zbar_video_t * vdo,int index)442 struct video_resolution_s *zbar_video_get_resolutions (const zbar_video_t *vdo,
443                                                        int index)
444 {
445     int i = 0;
446     struct video_resolution_s *p = vdo->res;
447 
448     while (i != index) {
449         if (!p->width || !p->height)
450             return NULL;
451         i++;
452         p++;
453     }
454 
455     if (!p->width || !p->height)
456        return NULL;
457 
458     return p;
459 }
460