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