1 /*------------------------------------------------------------------------
2 * Copyright 2007-2009 (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 <config.h>
25 #ifdef HAVE_INTTYPES_H
26 # include <inttypes.h>
27 #endif
28 #ifdef HAVE_STDLIB_H
29 # include <stdlib.h>
30 #endif
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <assert.h>
35 #ifdef HAVE_SYS_IOCTL_H
36 # include <sys/ioctl.h>
37 #endif
38 #ifdef HAVE_SYS_MMAN_H
39 # include <sys/mman.h>
40 #endif
41 #ifdef HAVE_LIBV4L2_H
42 # include <fcntl.h>
43 # include <libv4l2.h>
44 #else
45 # define v4l2_close close
46 # define v4l2_ioctl ioctl
47 # define v4l2_mmap mmap
48 # define v4l2_munmap munmap
49 #endif
50 #include <linux/videodev2.h>
51
52 #include "video.h"
53 #include "image.h"
54
55 #define V4L2_FORMATS_MAX 64
56 #define V4L2_FORMATS_SIZE_MAX 256
57
58 typedef struct video_controls_priv_s {
59 struct video_controls_s s;
60
61 // Private fields
62 __u32 id;
63 } video_controls_priv_t;
64
v4l2_nq(zbar_video_t * vdo,zbar_image_t * img)65 static int v4l2_nq (zbar_video_t *vdo,
66 zbar_image_t *img)
67 {
68 if(vdo->iomode == VIDEO_READWRITE)
69 return(video_nq_image(vdo, img));
70
71 if(video_unlock(vdo))
72 return(-1);
73
74 struct v4l2_buffer vbuf;
75 memset(&vbuf, 0, sizeof(vbuf));
76 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
77 if(vdo->iomode == VIDEO_MMAP) {
78 vbuf.memory = V4L2_MEMORY_MMAP;
79 vbuf.index = img->srcidx;
80 }
81 else {
82 vbuf.memory = V4L2_MEMORY_USERPTR;
83 vbuf.m.userptr = (unsigned long)img->data;
84 vbuf.length = img->datalen;
85 vbuf.index = img->srcidx; /* FIXME workaround broken drivers */
86 }
87 if(v4l2_ioctl(vdo->fd, VIDIOC_QBUF, &vbuf) < 0)
88 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
89 "queuing video buffer (VIDIOC_QBUF)"));
90 return(0);
91 }
92
v4l2_dq(zbar_video_t * vdo)93 static zbar_image_t *v4l2_dq (zbar_video_t *vdo)
94 {
95 zbar_image_t *img;
96 int fd = vdo->fd;
97
98 if(vdo->iomode != VIDEO_READWRITE) {
99 video_iomode_t iomode = vdo->iomode;
100 if(video_unlock(vdo))
101 return(NULL);
102
103 struct v4l2_buffer vbuf;
104 memset(&vbuf, 0, sizeof(vbuf));
105 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
106 if(iomode == VIDEO_MMAP)
107 vbuf.memory = V4L2_MEMORY_MMAP;
108 else
109 vbuf.memory = V4L2_MEMORY_USERPTR;
110
111 if(v4l2_ioctl(fd, VIDIOC_DQBUF, &vbuf) < 0)
112 return(NULL);
113
114 if(iomode == VIDEO_MMAP) {
115 assert(vbuf.index >= 0);
116 assert(vbuf.index < vdo->num_images);
117 img = vdo->images[vbuf.index];
118 }
119 else {
120 /* reverse map pointer back to image (FIXME) */
121 assert(vbuf.m.userptr >= (unsigned long)vdo->buf);
122 assert(vbuf.m.userptr < (unsigned long)(vdo->buf + vdo->buflen));
123 int i = (vbuf.m.userptr - (unsigned long)vdo->buf) / vdo->datalen;
124 assert(i >= 0);
125 assert(i < vdo->num_images);
126 img = vdo->images[i];
127 assert(vbuf.m.userptr == (unsigned long)img->data);
128 }
129 }
130 else {
131 img = video_dq_image(vdo);
132 if(!img)
133 return(NULL);
134
135 /* FIXME should read entire image */
136 ssize_t datalen = read(fd, (void*)img->data, img->datalen);
137 if(datalen < 0) {
138 perror("v4l2_dq read");
139 return(NULL);
140 }
141 else if(datalen != img->datalen)
142 zprintf(0, "WARNING: read() size mismatch: 0x%lx != 0x%lx\n",
143 datalen, img->datalen);
144 }
145 return(img);
146 }
147
v4l2_start(zbar_video_t * vdo)148 static int v4l2_start (zbar_video_t *vdo)
149 {
150 if(vdo->iomode == VIDEO_READWRITE)
151 return(0);
152
153 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
154 if(v4l2_ioctl(vdo->fd, VIDIOC_STREAMON, &type) < 0)
155 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
156 "starting video stream (VIDIOC_STREAMON)"));
157 return(0);
158 }
159
v4l2_stop(zbar_video_t * vdo)160 static int v4l2_stop (zbar_video_t *vdo)
161 {
162 if(vdo->iomode == VIDEO_READWRITE)
163 return(0);
164
165 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
166 if(v4l2_ioctl(vdo->fd, VIDIOC_STREAMOFF, &type) < 0)
167 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
168 "stopping video stream (VIDIOC_STREAMOFF)"));
169 return(0);
170 }
171
v4l2_cleanup(zbar_video_t * vdo)172 static int v4l2_cleanup (zbar_video_t *vdo)
173 {
174 if(vdo->iomode == VIDEO_READWRITE)
175 return(0);
176
177 struct v4l2_requestbuffers rb;
178 memset(&rb, 0, sizeof(rb));
179 rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
180 if(vdo->iomode == VIDEO_MMAP) {
181 rb.memory = V4L2_MEMORY_MMAP;
182 int i;
183 for(i = 0; i < vdo->num_images; i++) {
184 zbar_image_t *img = vdo->images[i];
185 if(img->data &&
186 v4l2_munmap((void*)img->data, img->datalen))
187 err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__,
188 "unmapping video frame buffers");
189 img->data = NULL;
190 img->datalen = 0;
191 }
192 }
193 else
194 rb.memory = V4L2_MEMORY_USERPTR;
195
196 /* requesting 0 buffers
197 * should implicitly disable streaming
198 */
199 if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0)
200 err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__,
201 "releasing video frame buffers (VIDIOC_REQBUFS)");
202
203
204 /* v4l2_close v4l2_open device */
205 if(vdo->fd >= 0) {
206 v4l2_close(vdo->fd);
207 vdo->fd = -1;
208 }
209 return(0);
210 }
211
v4l2_mmap_buffers(zbar_video_t * vdo)212 static int v4l2_mmap_buffers (zbar_video_t *vdo)
213 {
214
215 struct v4l2_buffer vbuf;
216 memset(&vbuf, 0, sizeof(vbuf));
217 vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
218 vbuf.memory = V4L2_MEMORY_MMAP;
219
220 int i;
221 for(i = 0; i < vdo->num_images; i++) {
222 vbuf.index = i;
223 if(v4l2_ioctl(vdo->fd, VIDIOC_QUERYBUF, &vbuf) < 0)
224 /* FIXME cleanup */
225 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
226 "querying video buffer (VIDIOC_QUERYBUF)"));
227
228 if(vbuf.length < vdo->datalen)
229 fprintf(stderr, "WARNING: insufficient v4l2 video buffer size:\n"
230 "\tvbuf[%d].length=%x datalen=%lx image=%d x %d %.4s(%08x)\n",
231 i, vbuf.length, vdo->datalen, vdo->width, vdo->height,
232 (char*)&vdo->format, vdo->format);
233
234 zbar_image_t *img = vdo->images[i];
235 img->datalen = vbuf.length;
236 img->data = v4l2_mmap(NULL, vbuf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
237 vdo->fd, vbuf.m.offset);
238 if(img->data == MAP_FAILED)
239 /* FIXME cleanup */
240 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
241 "mapping video frame buffers"));
242 zprintf(2, " buf[%d] 0x%lx bytes @%p\n",
243 i, img->datalen, img->data);
244 }
245 return(0);
246 }
247
v4l2_request_buffers(zbar_video_t * vdo,uint32_t num_images)248 static int v4l2_request_buffers (zbar_video_t *vdo, uint32_t num_images)
249 {
250 struct v4l2_requestbuffers rb;
251 memset(&rb, 0, sizeof(rb));
252 rb.count = num_images;
253 rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
254
255 if(vdo->iomode == VIDEO_MMAP)
256 rb.memory = V4L2_MEMORY_MMAP;
257 else
258 rb.memory = V4L2_MEMORY_USERPTR;
259
260 if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0)
261 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
262 "requesting video frame buffers (VIDIOC_REQBUFS)"));
263 if(num_images && rb.count)
264 vdo->num_images = rb.count;
265 return(0);
266 }
267
v4l2_set_format(zbar_video_t * vdo,uint32_t fmt)268 static int v4l2_set_format (zbar_video_t *vdo,
269 uint32_t fmt)
270 {
271 struct v4l2_format vfmt;
272 struct v4l2_pix_format *vpix = &vfmt.fmt.pix;
273 memset(&vfmt, 0, sizeof(vfmt));
274 vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
275 vpix->width = vdo->width;
276 vpix->height = vdo->height;
277 vpix->pixelformat = fmt;
278 vpix->field = V4L2_FIELD_NONE;
279 int rc = 0;
280 if((rc = v4l2_ioctl(vdo->fd, VIDIOC_S_FMT, &vfmt)) < 0) {
281 /* several broken drivers return an error if we request
282 * no interlacing (NB v4l2 spec violation)
283 * ...try again with an interlaced request
284 */
285 zprintf(1, "VIDIOC_S_FMT returned %d(%d), trying interlaced...\n",
286 rc, errno);
287
288 /* FIXME this might be _ANY once we can de-interlace */
289 vpix->field = V4L2_FIELD_INTERLACED;
290
291 if(v4l2_ioctl(vdo->fd, VIDIOC_S_FMT, &vfmt) < 0)
292 return(err_capture_int(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
293 "setting format %x (VIDIOC_S_FMT)", fmt));
294
295 zprintf(0, "WARNING: broken driver returned error when non-interlaced"
296 " format requested\n");
297 }
298
299 struct v4l2_format newfmt;
300 struct v4l2_pix_format *newpix = &newfmt.fmt.pix;
301 memset(&newfmt, 0, sizeof(newfmt));
302 newfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
303 if(v4l2_ioctl(vdo->fd, VIDIOC_G_FMT, &newfmt) < 0)
304 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
305 "querying format (VIDIOC_G_FMT)"));
306
307 if(newpix->field != V4L2_FIELD_NONE)
308 err_capture(vdo, SEV_WARNING, ZBAR_ERR_INVALID, __func__,
309 "video driver only supports interlaced format,"
310 " vertical scanning may not work");
311
312 if(newpix->pixelformat != fmt
313 /* FIXME bpl/bpp checks? */)
314 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
315 "video driver can't provide compatible format"));
316
317 vdo->format = fmt;
318 vdo->width = newpix->width;
319 vdo->height = newpix->height;
320 vdo->datalen = newpix->sizeimage;
321
322 zprintf(1, "set new format: %.4s(%08x) %u x %u (0x%lx)\n",
323 (char*)&vdo->format, vdo->format, vdo->width, vdo->height,
324 vdo->datalen);
325 return(0);
326 }
327
v4l2_init(zbar_video_t * vdo,uint32_t fmt)328 static int v4l2_init (zbar_video_t *vdo,
329 uint32_t fmt)
330 {
331 struct v4l2_requestbuffers rb;
332 if(v4l2_set_format(vdo, fmt))
333 return(-1);
334
335 memset(&rb, 0, sizeof(rb));
336 rb.count = vdo->num_images;
337 rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
338 if(vdo->iomode == VIDEO_MMAP)
339 rb.memory = V4L2_MEMORY_MMAP;
340 else
341 rb.memory = V4L2_MEMORY_USERPTR;
342
343 if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0)
344 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
345 "requesting video frame buffers (VIDIOC_REQBUFS)"));
346
347 if(!rb.count)
348 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
349 "driver returned 0 buffers"));
350
351 if(vdo->num_images > rb.count)
352 vdo->num_images = rb.count;
353
354 zprintf(1, "using %u buffers (of %d requested)\n",
355 rb.count, vdo->num_images);
356
357 if(vdo->iomode == VIDEO_MMAP)
358 return(v4l2_mmap_buffers(vdo));
359 if(vdo->iomode == VIDEO_USERPTR)
360 return(v4l2_request_buffers(vdo, vdo->num_images));
361 return(0);
362 }
363
v4l2_probe_iomode(zbar_video_t * vdo)364 static int v4l2_probe_iomode (zbar_video_t *vdo)
365 {
366 struct v4l2_requestbuffers rb;
367 memset(&rb, 0, sizeof(rb));
368 rb.count = vdo->num_images;
369 rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
370 if(vdo->iomode == VIDEO_MMAP)
371 rb.memory = V4L2_MEMORY_MMAP;
372 else
373 rb.memory = V4L2_MEMORY_USERPTR;
374
375 if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0) {
376 if(vdo->iomode)
377 return(err_capture_int(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__,
378 "unsupported iomode requested (%d)",
379 vdo->iomode));
380 else if(errno != EINVAL)
381 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
382 "querying streaming mode (VIDIOC_REQBUFS)"));
383 #ifdef HAVE_SYS_MMAN_H
384 err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__,
385 "USERPTR failed. Falling back to mmap");
386 vdo->iomode = VIDEO_MMAP;
387 #else
388 return err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
389 "Userptr not supported, and zbar was compiled without mmap support"));
390 #endif
391 }
392 else {
393 if(!vdo->iomode)
394 rb.memory = V4L2_MEMORY_USERPTR;
395 /* Update the num_images with the max supported by the driver */
396 if(rb.count)
397 vdo->num_images = rb.count;
398 else
399 err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__,
400 "Something is wrong: number of buffers returned by REQBUF is zero!");
401
402 /* requesting 0 buffers
403 * This cleans up the buffers allocated previously on probe
404 */
405 rb.count = 0;
406 if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0)
407 err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__,
408 "releasing video frame buffers (VIDIOC_REQBUFS)");
409 }
410 return(0);
411 }
412
413 static inline void v4l2_max_size (zbar_video_t *vdo, uint32_t pixfmt,
414 uint32_t *max_width, uint32_t *max_height)
415 {
416 int mwidth = 0, mheight = 0, i;
417 struct v4l2_frmsizeenum frm;
418
419 for(i = 0; i < V4L2_FORMATS_SIZE_MAX; i++) {
420 memset(&frm, 0, sizeof(frm));
421 frm.index = i;
422 frm.pixel_format = pixfmt;
423
424 if(v4l2_ioctl(vdo->fd, VIDIOC_ENUM_FRAMESIZES, &frm))
425 break;
426
427 switch (frm.type) {
428 case V4L2_FRMSIZE_TYPE_DISCRETE:
429 mwidth = frm.discrete.width;
430 mheight = frm.discrete.height;
431 break;
432 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
433 case V4L2_FRMSIZE_TYPE_STEPWISE:
434 mwidth = frm.stepwise.max_width;
435 mheight = frm.stepwise.max_height;
436 break;
437 default:
438 continue;
439 }
440 if (mwidth > *max_width)
441 *max_width = mwidth;
442 if (mheight > *max_height)
443 *max_height = mheight;
444 }
445 }
446
447 static inline int v4l2_probe_formats (zbar_video_t *vdo)
448 {
449 int n_formats = 0, n_emu_formats = 0;
450 uint32_t max_width = 0, max_height = 0;
451
452 if(vdo->width && vdo->height)
453 zprintf(1, "Caller requested an specific size: %d x %d\n",
454 vdo->width, vdo->height);
455
456 zprintf(2, "enumerating supported formats:\n");
457 struct v4l2_fmtdesc desc;
458 memset(&desc, 0, sizeof(desc));
459 desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
460
461 for(desc.index = 0; desc.index < V4L2_FORMATS_MAX; desc.index++) {
462 if(v4l2_ioctl(vdo->fd, VIDIOC_ENUM_FMT, &desc) < 0)
463 break;
464 zprintf(2, " [%d] %.4s : %s%s%s\n",
465 desc.index, (char*)&desc.pixelformat, desc.description,
466 (desc.flags & V4L2_FMT_FLAG_COMPRESSED) ? " COMPRESSED" : "",
467 (desc.flags & V4L2_FMT_FLAG_EMULATED) ? " EMULATED" : "");
468 if (desc.flags & V4L2_FMT_FLAG_EMULATED) {
469 vdo->emu_formats = realloc(vdo->emu_formats,
470 (n_emu_formats + 2) * sizeof(uint32_t));
471 vdo->emu_formats[n_emu_formats++] = desc.pixelformat;
472 } else {
473 vdo->formats = realloc(vdo->formats,
474 (n_formats + 2) * sizeof(uint32_t));
475 vdo->formats[n_formats++] = desc.pixelformat;
476 }
477
478 if(!vdo->width || !vdo->height)
479 v4l2_max_size(vdo, desc.pixelformat, &max_width, &max_height);
480 }
481
482 if(!vdo->width || !vdo->height) {
483 zprintf(1, "Max supported size: %d x %d\n", max_width, max_height);
484 if (max_width && max_height) {
485 vdo->width = max_width;
486 vdo->height = max_height;
487 } else {
488 /* fallback to large size, driver reduces to max available */
489 vdo->width = 640 * 64;
490 vdo->height = 480 * 64;
491
492 }
493 }
494
495 if(!desc.index)
496 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
497 "enumerating video formats (VIDIOC_ENUM_FMT)"));
498 if(vdo->formats)
499 vdo->formats[n_formats] = 0;
500 if(vdo->emu_formats)
501 vdo->emu_formats[n_emu_formats] = 0;
502 if(!vdo->formats && vdo->emu_formats) {
503 /*
504 * If only emu formats are available, just move them to vdo->formats.
505 * This happens when libv4l detects that the only available fourcc
506 * formats are webcam proprietary formats or bayer formats.
507 */
508 vdo->formats = vdo->emu_formats;
509 vdo->emu_formats = NULL;
510 }
511
512 zprintf(2, "Found %d formats and %d emulated formats.\n",
513 n_formats, n_emu_formats);
514
515 struct v4l2_format fmt;
516 struct v4l2_pix_format *pix = &fmt.fmt.pix;
517 memset(&fmt, 0, sizeof(fmt));
518 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
519 if(v4l2_ioctl(vdo->fd, VIDIOC_G_FMT, &fmt) < 0)
520 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
521 "querying current video format (VIDIO_G_FMT)"));
522
523 zprintf(1, "current format: %.4s(%08x) %u x %u%s (line=0x%x size=0x%x)\n",
524 (char*)&pix->pixelformat, pix->pixelformat,
525 pix->width, pix->height,
526 (pix->field != V4L2_FIELD_NONE) ? " INTERLACED" : "",
527 pix->bytesperline, pix->sizeimage);
528
529 vdo->format = pix->pixelformat;
530 vdo->datalen = pix->sizeimage;
531 if(pix->width == vdo->width && pix->height == vdo->height)
532 return(0);
533
534 struct v4l2_format maxfmt;
535 struct v4l2_pix_format *maxpix = &maxfmt.fmt.pix;
536 memcpy(&maxfmt, &fmt, sizeof(maxfmt));
537 maxpix->width = vdo->width;
538 maxpix->height = vdo->height;
539
540 zprintf(1, "setting requested size: %d x %d\n", vdo->width, vdo->height);
541 if(v4l2_ioctl(vdo->fd, VIDIOC_S_FMT, &maxfmt) < 0) {
542 zprintf(1, "set FAILED...trying to recover original format\n");
543 /* ignore errors (driver broken anyway) */
544 v4l2_ioctl(vdo->fd, VIDIOC_S_FMT, &fmt);
545 }
546
547 memset(&fmt, 0, sizeof(fmt));
548 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
549 if(v4l2_ioctl(vdo->fd, VIDIOC_G_FMT, &fmt) < 0)
550 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
551 "querying current video format (VIDIOC_G_FMT)"));
552
553 zprintf(1, "final format: %.4s(%08x) %u x %u%s (line=0x%x size=0x%x)\n",
554 (char*)&pix->pixelformat, pix->pixelformat,
555 pix->width, pix->height,
556 (pix->field != V4L2_FIELD_NONE) ? " INTERLACED" : "",
557 pix->bytesperline, pix->sizeimage);
558
559 vdo->width = pix->width;
560 vdo->height = pix->height;
561 vdo->datalen = pix->sizeimage;
562 return(0);
563 }
564
565 static inline int v4l2_reset_crop (zbar_video_t *vdo)
566 {
567 /* check cropping */
568 struct v4l2_cropcap ccap;
569 memset(&ccap, 0, sizeof(ccap));
570 ccap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
571 if(v4l2_ioctl(vdo->fd, VIDIOC_CROPCAP, &ccap) < 0)
572 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
573 "querying crop support (VIDIOC_CROPCAP)"));
574
575 zprintf(1, "crop bounds: %d x %d @ (%d, %d)\n",
576 ccap.bounds.width, ccap.bounds.height,
577 ccap.bounds.left, ccap.bounds.top);
578 zprintf(1, "current crop win: %d x %d @ (%d, %d) aspect %d / %d\n",
579 ccap.defrect.width, ccap.defrect.height,
580 ccap.defrect.left, ccap.defrect.top,
581 ccap.pixelaspect.numerator, ccap.pixelaspect.denominator);
582
583 #if 0
584 // This logic causes the device to fallback to the current resolution
585 if(!vdo->width || !vdo->height) {
586 vdo->width = ccap.defrect.width;
587 vdo->height = ccap.defrect.height;
588 }
589 #endif
590
591 /* reset crop parameters */
592 struct v4l2_crop crop;
593 memset(&crop, 0, sizeof(crop));
594 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
595 crop.c = ccap.defrect;
596 if(v4l2_ioctl(vdo->fd, VIDIOC_S_CROP, &crop) < 0 && errno != EINVAL && errno != ENOTTY)
597 return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__,
598 "setting default crop window (VIDIOC_S_CROP)"));
599 return(0);
600 }
601
602 /** locate a control entry
603 */
604 static struct video_controls_priv_s *v4l2_g_control_def(zbar_video_t *vdo,
605 const char *name)
606 {
607 struct video_controls_priv_s *p = (void *)vdo->controls;
608
609 while (p) {
610 if (!strcasecmp(p->s.name, name))
611 break;
612 p = p->s.next;
613 }
614
615 if (!p->s.name) {
616 zprintf(1, "Control not found: %s", name);
617 return NULL;
618 }
619
620 return p;
621 }
622
623 void v4l2_free_controls(zbar_video_t *vdo)
624 {
625 int i;
626
627 if(vdo->controls) {
628 struct video_controls_s *p = vdo->controls;
629 while (p) {
630 free(p->name);
631 free(p->group);
632 if(p->menu) {
633 for (i = 0; i < p->menu_size; i++)
634 free(p->menu[i].name);
635 free(p->menu);
636 }
637 p = p->next;
638 }
639 free(vdo->controls);
640 }
641 vdo->controls = NULL;
642 }
643
644 #ifdef VIDIOC_QUERY_EXT_CTRL
645 static const char *v4l2_ctrl_type(uint32_t type)
646 {
647 switch(type) {
648 // All controls below are available since, at least, Kernel 2.6.31
649 case V4L2_CTRL_TYPE_INTEGER:
650 return "int";
651 case V4L2_CTRL_TYPE_BOOLEAN:
652 return "bool";
653 case V4L2_CTRL_TYPE_MENU:
654 return "menu";
655 case V4L2_CTRL_TYPE_BUTTON:
656 return "button";
657 case V4L2_CTRL_TYPE_INTEGER64:
658 return "int64";
659 case V4L2_CTRL_TYPE_CTRL_CLASS:
660 return "ctrl class";
661 case V4L2_CTRL_TYPE_STRING:
662 return "string";
663 #ifdef V4L2_CTRL_TYPE_INTEGER_MENU
664 case V4L2_CTRL_TYPE_INTEGER_MENU:
665 return "int menu";
666 #endif
667 #ifdef V4L2_CTRL_TYPE_U32
668 // Newer controls. All of them should be there since Kernel 3.16
669 case V4L2_CTRL_TYPE_BITMASK:
670 return "bitmask";
671 case V4L2_CTRL_TYPE_U8:
672 return "compound u8";
673 case V4L2_CTRL_TYPE_U16:
674 return "compound u16";
675 case V4L2_CTRL_TYPE_U32:
676 return "compound 32";
677 #endif
678 default:
679 return "unknown";
680 }
681 }
682
683 static const char *v4l2_ctrl_class(uint32_t class)
684 {
685 switch(class) {
686 // All classes below are available since, at least, Kernel 2.6.31
687 case V4L2_CTRL_CLASS_USER:
688 return "User";
689 case V4L2_CTRL_CLASS_MPEG:
690 return "MPEG-compression";
691 case V4L2_CTRL_CLASS_CAMERA:
692 return "Camera";
693 case V4L2_CTRL_CLASS_FM_TX:
694 return "FM Modulator";
695 #ifdef V4L2_CTRL_CLASS_DETECT
696 // Newer classes added up to Kernel 3.16
697 case V4L2_CTRL_CLASS_FLASH:
698 return "Camera flash";
699 case V4L2_CTRL_CLASS_JPEG:
700 return "JPEG-compression";
701 case V4L2_CTRL_CLASS_IMAGE_SOURCE:
702 return "Image source";
703 case V4L2_CTRL_CLASS_IMAGE_PROC:
704 return "Image processing";
705 case V4L2_CTRL_CLASS_DV:
706 return "Digital Video";
707 case V4L2_CTRL_CLASS_FM_RX:
708 return "FM Receiver";
709 case V4L2_CTRL_CLASS_RF_TUNER:
710 return "RF tuner";
711 case V4L2_CTRL_CLASS_DETECT:
712 return "Detection";
713 #endif
714 default:
715 return "Unknown";
716 }
717 }
718
719 // return values: 1: ignore, 0: added, -1: silently ignore
720 static int v4l2_add_control(zbar_video_t *vdo,
721 struct v4l2_query_ext_ctrl *query,
722 struct video_controls_priv_s **ptr)
723 {
724 // Control is disabled, ignore it. Please notice that disabled controls
725 // can be re-enabled. The right thing here would be to get those too,
726 // and add a logic to
727 if (query->flags & V4L2_CTRL_FLAG_DISABLED)
728 return 1;
729
730 /* Silently ignore control classes */
731 if (query->type == V4L2_CTRL_TYPE_CTRL_CLASS)
732 return -1;
733
734 // There's not much sense on displaying permanent read-only controls
735 if (query->flags & V4L2_CTRL_FLAG_READ_ONLY)
736 return 1;
737
738 // Allocate a new element on the linked list
739 if (!vdo->controls) {
740 *ptr = calloc(1, sizeof(**ptr));
741 vdo->controls = (void *)*ptr;
742 } else {
743 (*ptr)->s.next = calloc(1, sizeof(**ptr));
744 *ptr = (*ptr)->s.next;
745 }
746
747 // Fill control data
748 (*ptr)->id = query->id;
749 (*ptr)->s.name = strdup((const char *)query->name);
750 (*ptr)->s.group = strdup(v4l2_ctrl_class(V4L2_CTRL_ID2CLASS(query->id)));
751 switch (query->type) {
752 case V4L2_CTRL_TYPE_INTEGER:
753 (*ptr)->s.type = VIDEO_CNTL_INTEGER;
754 (*ptr)->s.min = query->minimum;
755 (*ptr)->s.max = query->maximum;
756 (*ptr)->s.def = query->default_value;
757 (*ptr)->s.step = query->step;
758 return(0);
759 case V4L2_CTRL_TYPE_INTEGER64:
760 (*ptr)->s.type = VIDEO_CNTL_INTEGER64;
761 (*ptr)->s.min = query->minimum;
762 (*ptr)->s.max = query->maximum;
763 (*ptr)->s.def = query->default_value;
764 (*ptr)->s.step = query->step;
765 return(0);
766 case V4L2_CTRL_TYPE_BOOLEAN:
767 (*ptr)->s.type = VIDEO_CNTL_BOOLEAN;
768 return(0);
769 case V4L2_CTRL_TYPE_BUTTON:
770 (*ptr)->s.type = VIDEO_CNTL_BUTTON;
771 return (0);
772 case V4L2_CTRL_TYPE_STRING:
773 (*ptr)->s.type = VIDEO_CNTL_STRING;
774 return (0);
775 #ifdef V4L2_CTRL_TYPE_INTEGER_MENU
776 case V4L2_CTRL_TYPE_INTEGER_MENU:
777 #endif
778 case V4L2_CTRL_TYPE_MENU: {
779 struct v4l2_querymenu menu;
780 struct video_control_menu_s *first = NULL, *p;
781 int n_menu = 0;
782
783 memset(&menu, 0, sizeof(menu));
784 menu.id = query->id;
785
786 for (menu.index = query->minimum;
787 menu.index <= query->maximum;
788 menu.index++) {
789 if (!ioctl(vdo->fd, VIDIOC_QUERYMENU, &menu)) {
790 first = realloc(first, (n_menu + 1) * sizeof(*(*ptr)->s.menu));
791
792 p = &first[n_menu];
793 p->value = menu.index;
794
795 #ifdef V4L2_CTRL_TYPE_INTEGER_MENU
796 if (query->type == V4L2_CTRL_TYPE_INTEGER_MENU)
797 asprintf(p->name, "%i", menu.value);
798 else
799 #endif /* V4L2_CTRL_TYPE_INTEGER_MENU */
800 p->name = strdup((const char *)menu.name);
801
802 n_menu++;
803 }
804 }
805 (*ptr)->s.menu = first;
806 (*ptr)->s.menu_size = n_menu;
807 (*ptr)->s.min = query->minimum;
808 (*ptr)->s.max = query->maximum;
809 (*ptr)->s.def = query->default_value;
810 (*ptr)->s.type = VIDEO_CNTL_MENU;
811 return (0);
812 }
813 default:
814 return (1);
815 }
816 }
817
818 static int v4l2_query_controls(zbar_video_t *vdo)
819 {
820 struct video_controls_priv_s *ptr = NULL;
821 struct v4l2_query_ext_ctrl query;
822 int ignore;
823 const char *old_class = NULL;
824
825 // Free controls list if not NULL
826 v4l2_free_controls(vdo);
827
828 memset(&query, 0, sizeof(query));
829 query.id = V4L2_CTRL_FLAG_NEXT_CTRL;
830 while (!v4l2_ioctl(vdo->fd, VIDIOC_QUERY_EXT_CTRL, &query)) {
831 ignore = v4l2_add_control(vdo, &query, &ptr);
832
833 if (ignore >= 0 && _zbar_verbosity) {
834 int i;
835 const char *class = v4l2_ctrl_class(V4L2_CTRL_ID2CLASS(query.id));
836 if (class != old_class)
837 zprintf(1, "Control class %s:\n", class);
838
839 zprintf(1, "%-10s %-32s - 0x%x%s\n",
840 v4l2_ctrl_type(query.type),
841 query.name,
842 query.id,
843 ignore ? " - Ignored" : "");
844
845 for (i = 0; i < ptr->s.menu_size; i++)
846 zprintf(1, " %" PRId64 ": %s\n",
847 ptr->s.menu[i].value, ptr->s.menu[i].name);
848
849 old_class = class;
850 }
851
852 query.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
853 }
854
855 return(0);
856 }
857
858 static int v4l2_s_control(zbar_video_t *vdo,
859 const char *name,
860 void *value)
861 {
862 struct v4l2_ext_controls ctrls;
863 struct v4l2_ext_control c;
864 struct video_controls_priv_s *p;
865
866 p = v4l2_g_control_def(vdo, name);
867 if (!p)
868 return ZBAR_ERR_UNSUPPORTED; // we have no such a control on the list
869
870 memset(&ctrls, 0, sizeof(ctrls));
871 ctrls.count = 1;
872 #ifdef V4L2_CTRL_ID2WHICH
873 ctrls.which = V4L2_CTRL_ID2WHICH(p->id);
874 #else
875 ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
876 #endif
877 ctrls.controls = &c;
878
879 memset(&c, 0, sizeof(c));
880 c.id = p->id;
881
882 switch (p->s.type) {
883 case VIDEO_CNTL_INTEGER:
884 case VIDEO_CNTL_BOOLEAN:
885 case VIDEO_CNTL_BUTTON:
886 case VIDEO_CNTL_MENU:
887 c.value = *(int *)value;
888 break;
889 #if 0
890 //FIXME: Need to check callers with respect bufffer size
891 case VIDEO_CNTL_INTEGER64:
892 c.value64 = *(int64_t *)value;
893 break;
894 #endif
895 default:
896 return ZBAR_ERR_UNSUPPORTED;
897 }
898
899 int rv = v4l2_ioctl(vdo->fd, VIDIOC_S_EXT_CTRLS, &ctrls);
900 if(rv) {
901 zprintf(1, "v4l2 set user control \"%s\" returned %d\n", p->s.name, rv);
902 rv = ZBAR_ERR_INVALID;
903 }
904 zprintf(1, "%-32s id: 0x%x set to value %d\n",
905 name, p->id, *(int*)value);
906
907 return 0;
908 }
909
910 static int v4l2_g_control(zbar_video_t *vdo,
911 const char *name,
912 void *value)
913 {
914 struct v4l2_ext_controls ctrls;
915 struct v4l2_ext_control c;
916 struct video_controls_priv_s *p;
917
918 p = v4l2_g_control_def(vdo, name);
919 if (!p)
920 return ZBAR_ERR_UNSUPPORTED; // we have no such a control on the list
921
922 memset(&ctrls, 0, sizeof(ctrls));
923 ctrls.count = 1;
924 #ifdef V4L2_CTRL_ID2WHICH
925 ctrls.which = V4L2_CTRL_ID2WHICH(p->id);
926 #else
927 ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
928 #endif
929 ctrls.controls = &c;
930
931 memset(&c, 0, sizeof(c));
932 c.id = p->id;
933
934 int rv = v4l2_ioctl(vdo->fd, VIDIOC_G_EXT_CTRLS, &ctrls);
935 if (rv) {
936 zprintf(1, "v4l2 get user control \"%s\" returned %d\n", p->s.name, rv);
937 return ZBAR_ERR_UNSUPPORTED;
938 }
939
940 switch (p->s.type) {
941 case VIDEO_CNTL_INTEGER:
942 case VIDEO_CNTL_BOOLEAN:
943 case VIDEO_CNTL_BUTTON:
944 case VIDEO_CNTL_MENU:
945 *(int *)value = c.value;
946 zprintf(1, "v4l2 get user control \"%s\" = %d\n", p->s.name, c.value);
947 return(0);
948 #if 0
949 //FIXME: Need to check callers with respect bufffer size
950 case VIDEO_CNTL_INTEGER64:
951 *(int64_t *)value = c.value64;
952 return(0);
953 #endif
954 default:
955 return ZBAR_ERR_UNSUPPORTED;
956 }
957 }
958
959 #else /* For very old Kernels < 3.16 (2014) */
960 static void v4l2_add_control(zbar_video_t *vdo,
961 char *group_name,
962 struct v4l2_queryctrl *query,
963 struct video_controls_priv_s **ptr)
964 {
965 // Control is disabled, ignore it. Please notice that disabled controls
966 // can be re-enabled. The right thing here would be to get those too,
967 // and add a logic to
968 if (query->flags & V4L2_CTRL_FLAG_DISABLED)
969 return;
970
971 // FIXME: add support also for other control types
972 if (!((query->type == V4L2_CTRL_TYPE_INTEGER) ||
973 (query->type == V4L2_CTRL_TYPE_BOOLEAN)))
974 return;
975
976 zprintf(1, "%s %s ctrl %-32s id: 0x%x\n",
977 group_name,
978 (query->type == V4L2_CTRL_TYPE_INTEGER) ? "int " :
979 "bool",
980 query->name,
981 query->id);
982
983 // Allocate a new element on the linked list
984 if (!vdo->controls) {
985 *ptr = calloc(1, sizeof(**ptr));
986 vdo->controls = (void *)*ptr;
987 } else {
988 (*ptr)->s.next = calloc(1, sizeof(**ptr));
989 *ptr = (*ptr)->s.next;
990 }
991
992 // Fill control data
993 (*ptr)->id = query->id;
994 (*ptr)->s.name = strdup((const char *)query->name);
995 if (query->type == V4L2_CTRL_TYPE_INTEGER) {
996 (*ptr)->s.type = VIDEO_CNTL_INTEGER;
997 (*ptr)->s.min = query->minimum;
998 (*ptr)->s.max = query->maximum;
999 (*ptr)->s.def = query->default_value;
1000 (*ptr)->s.step = query->step;
1001 } else {
1002 (*ptr)->s.type = VIDEO_CNTL_BOOLEAN;
1003 }
1004 }
1005
1006 static int v4l2_query_controls(zbar_video_t *vdo)
1007 {
1008 int id = 0;
1009 struct video_controls_priv_s *ptr;
1010 struct v4l2_queryctrl query;
1011
1012 // Free controls list if not NULL
1013 ptr = (void *)vdo->controls;
1014 while (ptr) {
1015 free(ptr->s.name);
1016 ptr = ptr->s.next;
1017 }
1018 free(vdo->controls);
1019 vdo->controls = NULL;
1020 ptr = NULL;
1021
1022 id=0;
1023 do {
1024 query.id = id | V4L2_CTRL_FLAG_NEXT_CTRL;
1025 if(v4l2_ioctl(vdo->fd, VIDIOC_QUERYCTRL, &query))
1026 break;
1027
1028 v4l2_add_control(vdo, "extended", &query, &ptr);
1029 id = query.id;
1030 } while (1);
1031
1032 id=V4L2_CID_PRIVATE_BASE;
1033 do {
1034 query.id = id;
1035 if(v4l2_ioctl(vdo->fd, VIDIOC_QUERYCTRL, &query))
1036 break;
1037 v4l2_add_control(vdo, "private", &query, &ptr);
1038 id = query.id;
1039 } while (1);
1040
1041 return(0);
1042 }
1043
1044 static int v4l2_s_control(zbar_video_t *vdo,
1045 const char *name,
1046 void *value)
1047 {
1048 struct v4l2_control cs;
1049 struct video_controls_priv_s *p;
1050
1051 p = v4l2_g_control_def(vdo, name);
1052 if (!p)
1053 return ZBAR_ERR_UNSUPPORTED; // we have no such a control on the list
1054
1055 zprintf(1, "%-32s id: 0x%x set to value %d\n",
1056 name, p->id, *(int*)value);
1057
1058 // FIXME: add support for VIDIOC_S_EXT_CTRL
1059 memset(&cs, 0, sizeof(cs));
1060 cs.id = p->id;
1061 cs.value = *(int*)value;
1062 int rv = v4l2_ioctl(vdo->fd, VIDIOC_S_CTRL, &cs);
1063 if(rv!=0) {
1064 zprintf(1, "v4l2 set user control \"%s\" returned %d\n", p->s.name, rv);
1065 rv = ZBAR_ERR_INVALID;
1066 }
1067 return rv;
1068 }
1069
1070 static int v4l2_g_control(zbar_video_t *vdo,
1071 const char *name,
1072 void *value)
1073 {
1074 struct v4l2_control cs;
1075 struct video_controls_priv_s *p;
1076
1077 p = v4l2_g_control_def(vdo, name);
1078 if (!p)
1079 return ZBAR_ERR_UNSUPPORTED; // we have no such a control on the list
1080
1081 memset(&cs, 0, sizeof(cs));
1082
1083 cs.id = p->id;
1084 cs.value = *(int*)value;
1085 int rv = v4l2_ioctl(vdo->fd, VIDIOC_G_CTRL, &cs);
1086 *(int*)value = cs.value;
1087 if(rv!=0) {
1088 zprintf(1, "v4l2 get user control \"%s\" returned %d\n", p->s.name, rv);
1089 rv = ZBAR_ERR_UNSUPPORTED;
1090 }
1091 return rv;
1092 }
1093 #endif /* VIDIOC_QUERY_EXT_CTRL */
1094
1095 static int v4l2_sort_resolutions(const void *__a, const void *__b)
1096 {
1097 const struct video_resolution_s *a = __a;
1098 const struct video_resolution_s *b = __b;
1099 int r;
1100
1101 r = (int)b->width - a->width;
1102 if (!r)
1103 r = (int)b->height - a->height;
1104
1105 return r;
1106 }
1107
1108 static float v4l2_get_max_fps_discrete(zbar_video_t *vdo,
1109 struct v4l2_frmsizeenum *frmsize)
1110 {
1111 struct v4l2_frmivalenum frmival = { 0 };
1112 float fps, max_fps = -1;
1113
1114 frmival.width = frmsize->discrete.width;
1115 frmival.height = frmsize->discrete.height;
1116 frmival.pixel_format = frmsize->pixel_format;
1117 frmival.index = 0;
1118
1119 for (frmival.index = 0;
1120 !v4l2_ioctl(vdo->fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival);
1121 frmival.index++) {
1122 fps = ((float)frmival.discrete.denominator)/frmival.discrete.numerator;
1123 if (fps > max_fps)
1124 max_fps = fps;
1125 }
1126 return max_fps;
1127 }
1128
1129 static void v4l2_insert_resolution(zbar_video_t *vdo,
1130 unsigned int *n_res,
1131 unsigned int width, unsigned int height,
1132 float max_fps)
1133 {
1134 unsigned int i;
1135
1136 for (i = 0; i < *n_res; i++) {
1137 if (vdo->res[i].width == width && vdo->res[i].height == height)
1138 return;
1139 }
1140
1141 vdo->res = realloc(vdo->res, (*n_res + 1) * sizeof(struct video_resolution_s));
1142
1143 vdo->res[*n_res].width = width;
1144 vdo->res[*n_res].height = height;
1145 vdo->res[*n_res].max_fps = max_fps;
1146
1147 (*n_res)++;
1148 }
1149
1150 static int v4l2_get_supported_resolutions(zbar_video_t *vdo)
1151 {
1152 struct v4l2_fmtdesc fmt = { 0 };
1153 struct v4l2_frmsizeenum frmsize = { 0 };
1154 int i;
1155 unsigned int width, height, n_res = 0;
1156
1157 vdo->res = NULL;
1158
1159 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1160 for (fmt.index = 0;
1161 !v4l2_ioctl(vdo->fd, VIDIOC_ENUM_FMT, &fmt);
1162 fmt.index++) {
1163 if (vdo->format != fmt.pixelformat)
1164 continue;
1165
1166 frmsize.pixel_format = fmt.pixelformat;
1167 frmsize.index = 0;
1168
1169 while (!v4l2_ioctl(vdo->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) {
1170 if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
1171 v4l2_insert_resolution(vdo, &n_res, frmsize.discrete.width,
1172 frmsize.discrete.height,
1173 v4l2_get_max_fps_discrete(vdo, &frmsize));
1174 } else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
1175 for (i = 0; i <= 4; i++) {
1176 width = frmsize.stepwise.min_width +
1177 i * (frmsize.stepwise.max_width -
1178 frmsize.stepwise.min_width) / 4;
1179 height = frmsize.stepwise.min_height +
1180 i * (frmsize.stepwise.max_height -
1181 frmsize.stepwise.min_height) / 4;
1182 v4l2_insert_resolution(vdo, &n_res, width, height, -1);
1183 }
1184 }
1185 frmsize.index++;
1186 }
1187 }
1188 qsort(vdo->res, n_res, sizeof(struct video_resolution_s),
1189 v4l2_sort_resolutions);
1190
1191 for (i = 0; i < n_res; i++) {
1192 zprintf(1, "%dx%d (%0.2f fps)\n",
1193 vdo->res[i].width, vdo->res[i].height, vdo->res[i].max_fps);
1194 }
1195
1196 /* Make the list zero-terminated */
1197 v4l2_insert_resolution(vdo, &n_res, 0, 0, 0);
1198
1199 return 0;
1200 }
1201
1202 int _zbar_v4l2_probe (zbar_video_t *vdo)
1203 {
1204 /* check capabilities */
1205 struct v4l2_capability vcap;
1206 memset(&vcap, 0, sizeof(vcap));
1207 if(v4l2_ioctl(vdo->fd, VIDIOC_QUERYCAP, &vcap) < 0)
1208 return(err_capture(vdo, SEV_WARNING, ZBAR_ERR_UNSUPPORTED, __func__,
1209 "video4linux version 2 not supported (VIDIOC_QUERYCAP)"));
1210
1211
1212 zprintf(1, "%.32s on %.32s driver %.16s (version %u.%u.%u)\n", vcap.card,
1213 (vcap.bus_info[0]) ? (char*)vcap.bus_info : "<unknown>",
1214 vcap.driver, (vcap.version >> 16) & 0xff,
1215 (vcap.version >> 8) & 0xff, vcap.version & 0xff);
1216 zprintf(1, " capabilities:%s%s%s%s\n",
1217 (vcap.device_caps & V4L2_CAP_VIDEO_CAPTURE) ? " CAPTURE" : "",
1218 (vcap.device_caps & V4L2_CAP_VIDEO_OVERLAY) ? " OVERLAY" : "",
1219 (vcap.device_caps & V4L2_CAP_READWRITE) ? " READWRITE" : "",
1220 (vcap.device_caps & V4L2_CAP_STREAMING) ? " STREAMING" : "");
1221
1222 if(!(vcap.device_caps & V4L2_CAP_VIDEO_CAPTURE) ||
1223 !(vcap.device_caps & (V4L2_CAP_READWRITE | V4L2_CAP_STREAMING)))
1224 return(err_capture(vdo, SEV_WARNING, ZBAR_ERR_UNSUPPORTED, __func__,
1225 "v4l2 device does not support usable CAPTURE"));
1226
1227 if(v4l2_reset_crop(vdo))
1228 /* ignoring errors (driver cropping support questionable) */;
1229
1230 if(v4l2_probe_formats(vdo))
1231 return(-1);
1232
1233 if (v4l2_query_controls(vdo))
1234 return(-1);
1235
1236 if (v4l2_get_supported_resolutions(vdo))
1237 return(-1);
1238
1239 /* FIXME report error and fallback to readwrite? (if supported...) */
1240 if(vdo->iomode != VIDEO_READWRITE &&
1241 (vcap.device_caps & V4L2_CAP_STREAMING) &&
1242 v4l2_probe_iomode(vdo))
1243 return(-1);
1244 if(!vdo->iomode)
1245 vdo->iomode = VIDEO_READWRITE;
1246
1247 zprintf(1, "using I/O mode: %s\n",
1248 (vdo->iomode == VIDEO_READWRITE) ? "READWRITE" :
1249 (vdo->iomode == VIDEO_MMAP) ? "MMAP" :
1250 (vdo->iomode == VIDEO_USERPTR) ? "USERPTR" : "<UNKNOWN>");
1251
1252 vdo->intf = VIDEO_V4L2;
1253 vdo->init = v4l2_init;
1254 vdo->cleanup = v4l2_cleanup;
1255 vdo->start = v4l2_start;
1256 vdo->stop = v4l2_stop;
1257 vdo->nq = v4l2_nq;
1258 vdo->dq = v4l2_dq;
1259 vdo->set_control = v4l2_s_control;
1260 vdo->get_control = v4l2_g_control;
1261 vdo->free = v4l2_free_controls;
1262 return(0);
1263 }
1264