1 /*
2 * interface to the v4l2 driver
3 *
4 * (c) 1998-2002 Gerd Knorr <kraxel@bytesex.org>
5 *
6 */
7 #include "config.h"
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <math.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <sys/types.h>
18 #include <sys/time.h>
19 #include <sys/ioctl.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <pthread.h>
23
24 #include <asm/types.h> /* XXX glibc */
25 #include "videodev2.h"
26
27 #include "grab-ng.h"
28
29 #include "struct-dump.h"
30 #include "struct-v4l2.h"
31
32 /* ---------------------------------------------------------------------- */
33
34 /* open+close */
35 static void* v4l2_open(char *device);
36 static int v4l2_close(void *handle);
37
38 /* attributes */
39 static char* v4l2_devname(void *handle);
40 static int v4l2_flags(void *handle);
41 static struct ng_attribute* v4l2_attrs(void *handle);
42 static int v4l2_read_attr(struct ng_attribute*);
43 static void v4l2_write_attr(struct ng_attribute*, int val);
44
45 /* overlay */
46 static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base);
47 static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
48 struct OVERLAY_CLIP *oc, int count, int aspect);
49
50 /* capture video */
51 static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt);
52 static int v4l2_startvideo(void *handle, int fps, unsigned int buffers);
53 static void v4l2_stopvideo(void *handle);
54 static struct ng_video_buf* v4l2_nextframe(void *handle);
55 static struct ng_video_buf* v4l2_getimage(void *handle);
56
57 /* tuner */
58 static unsigned long v4l2_getfreq(void *handle);
59 static void v4l2_setfreq(void *handle, unsigned long freq);
60 static int v4l2_tuned(void *handle);
61
62 /* ---------------------------------------------------------------------- */
63
64 #define WANTED_BUFFERS 32
65
66 #define MAX_INPUT 16
67 #define MAX_NORM 16
68 #define MAX_FORMAT 32
69 #define MAX_CTRL 32
70
71 struct v4l2_handle {
72 int fd;
73
74 /* device descriptions */
75 int ninputs,nstds,nfmts;
76 struct v4l2_capability cap;
77 struct v4l2_streamparm streamparm;
78 struct v4l2_input inp[MAX_INPUT];
79 struct v4l2_standard std[MAX_NORM];
80 struct v4l2_fmtdesc fmt[MAX_FORMAT];
81 struct v4l2_queryctrl ctl[MAX_CTRL*2];
82
83 /* attributes */
84 int nattr;
85 struct ng_attribute *attr;
86
87 /* capture */
88 int fps,first;
89 long long start;
90 struct v4l2_format fmt_v4l2;
91 struct ng_video_fmt fmt_me;
92 struct v4l2_requestbuffers reqbufs;
93 struct v4l2_buffer buf_v4l2[WANTED_BUFFERS];
94 struct ng_video_buf buf_me[WANTED_BUFFERS];
95 unsigned int queue,waiton;
96
97 /* overlay */
98 struct v4l2_framebuffer ov_fb;
99 struct v4l2_format ov_win;
100 struct v4l2_clip ov_clips[256];
101 #if 0
102 enum v4l2_field ov_fields;
103 #endif
104 int ov_error;
105 int ov_enabled;
106 int ov_on;
107 };
108
109 /* ---------------------------------------------------------------------- */
110
111 struct ng_vid_driver v4l2_driver = {
112 name: "v4l2",
113 open: v4l2_open,
114 close: v4l2_close,
115
116 get_devname: v4l2_devname,
117 capabilities: v4l2_flags,
118 list_attrs: v4l2_attrs,
119
120 setupfb: v4l2_setupfb,
121 overlay: v4l2_overlay,
122
123 setformat: v4l2_setformat,
124 startvideo: v4l2_startvideo,
125 stopvideo: v4l2_stopvideo,
126 nextframe: v4l2_nextframe,
127 getimage: v4l2_getimage,
128
129 getfreq: v4l2_getfreq,
130 setfreq: v4l2_setfreq,
131 is_tuned: v4l2_tuned,
132 };
133
134 static __u32 xawtv_pixelformat[VIDEO_FMT_COUNT] = {
135 [ VIDEO_RGB08 ] = V4L2_PIX_FMT_HI240,
136 [ VIDEO_GRAY ] = V4L2_PIX_FMT_GREY,
137 [ VIDEO_RGB15_LE ] = V4L2_PIX_FMT_RGB555,
138 [ VIDEO_RGB16_LE ] = V4L2_PIX_FMT_RGB565,
139 [ VIDEO_RGB15_BE ] = V4L2_PIX_FMT_RGB555X,
140 [ VIDEO_RGB16_BE ] = V4L2_PIX_FMT_RGB565X,
141 [ VIDEO_BGR24 ] = V4L2_PIX_FMT_BGR24,
142 [ VIDEO_BGR32 ] = V4L2_PIX_FMT_BGR32,
143 [ VIDEO_RGB24 ] = V4L2_PIX_FMT_RGB24,
144 [ VIDEO_YUYV ] = V4L2_PIX_FMT_YUYV,
145 [ VIDEO_UYVY ] = V4L2_PIX_FMT_UYVY,
146 [ VIDEO_YUV422P ] = V4L2_PIX_FMT_YUV422P,
147 [ VIDEO_YUV420P ] = V4L2_PIX_FMT_YUV420,
148 };
149
150 static struct STRTAB stereo[] = {
151 { V4L2_TUNER_MODE_MONO, "mono" },
152 { V4L2_TUNER_MODE_STEREO, "stereo" },
153 { V4L2_TUNER_MODE_LANG1, "lang1" },
154 { V4L2_TUNER_MODE_LANG2, "lang2" },
155 { -1, NULL },
156 };
157
158 /* ---------------------------------------------------------------------- */
159 /* debug output */
160
161 #define PREFIX "ioctl: "
162
163 static int
164 xioctl(int fd, int cmd, void *arg, int mayfail)
165 {
166 int rc;
167
168 rc = ioctl(fd,cmd,arg);
169 if (0 == rc && ng_debug < 2)
170 return rc;
171 if (mayfail && errno == mayfail && ng_debug < 2)
172 return rc;
173 print_ioctl(stderr,ioctls_v4l2,PREFIX,cmd,arg);
174 fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno));
175 return rc;
176 }
177
178 static void
179 print_bufinfo(struct v4l2_buffer *buf)
180 {
181 static char *type[] = {
182 [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
183 [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
184 [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
185 [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
186 [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
187 };
188
189 fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n",
190 buf->index,
191 buf->type < sizeof(type)/sizeof(char*)
192 ? type[buf->type] : "unknown",
193 buf->m.offset,buf->length,buf->bytesused);
194 }
195
196 /* ---------------------------------------------------------------------- */
197 /* helpers */
198
199 static void
200 get_device_capabilities(struct v4l2_handle *h)
201 {
202 int i;
203
204 for (h->ninputs = 0; h->ninputs < MAX_INPUT; h->ninputs++) {
205 h->inp[h->ninputs].index = h->ninputs;
206 if (-1 == xioctl(h->fd, VIDIOC_ENUMINPUT, &h->inp[h->ninputs], EINVAL))
207 break;
208 }
209 for (h->nstds = 0; h->nstds < MAX_NORM; h->nstds++) {
210 h->std[h->nstds].index = h->nstds;
211 if (-1 == xioctl(h->fd, VIDIOC_ENUMSTD, &h->std[h->nstds], EINVAL))
212 break;
213 }
214 for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) {
215 h->fmt[h->nfmts].index = h->nfmts;
216 h->fmt[h->nfmts].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
217 if (-1 == xioctl(h->fd, VIDIOC_ENUM_FMT, &h->fmt[h->nfmts], EINVAL))
218 break;
219 }
220
221 h->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
222 ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm);
223
224 /* controls */
225 for (i = 0; i < MAX_CTRL; i++) {
226 h->ctl[i].id = V4L2_CID_BASE+i;
227 if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) ||
228 (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED))
229 h->ctl[i].id = -1;
230 }
231 for (i = 0; i < MAX_CTRL; i++) {
232 h->ctl[i+MAX_CTRL].id = V4L2_CID_PRIVATE_BASE+i;
233 if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i+MAX_CTRL], EINVAL) ||
234 (h->ctl[i+MAX_CTRL].flags & V4L2_CTRL_FLAG_DISABLED))
235 h->ctl[i+MAX_CTRL].id = -1;
236 }
237 }
238
239 static struct STRTAB *
240 build_norms(struct v4l2_handle *h)
241 {
242 struct STRTAB *norms;
243 int i;
244
245 norms = malloc(sizeof(struct STRTAB) * (h->nstds+1));
246 for (i = 0; i < h->nstds; i++) {
247 norms[i].nr = i;
248 norms[i].str = h->std[i].name;
249 }
250 norms[i].nr = -1;
251 norms[i].str = NULL;
252 return norms;
253 }
254
255 static struct STRTAB *
256 build_inputs(struct v4l2_handle *h)
257 {
258 struct STRTAB *inputs;
259 int i;
260
261 inputs = malloc(sizeof(struct STRTAB) * (h->ninputs+1));
262 for (i = 0; i < h->ninputs; i++) {
263 inputs[i].nr = i;
264 inputs[i].str = h->inp[i].name;
265 }
266 inputs[i].nr = -1;
267 inputs[i].str = NULL;
268 return inputs;
269 }
270
271 /* ---------------------------------------------------------------------- */
272
273 static struct V4L2_ATTR {
274 unsigned int id;
275 unsigned int v4l2;
276 } v4l2_attr[] = {
277 { ATTR_ID_VOLUME, V4L2_CID_AUDIO_VOLUME },
278 { ATTR_ID_MUTE, V4L2_CID_AUDIO_MUTE },
279 { ATTR_ID_COLOR, V4L2_CID_SATURATION },
280 { ATTR_ID_BRIGHT, V4L2_CID_BRIGHTNESS },
281 { ATTR_ID_HUE, V4L2_CID_HUE },
282 { ATTR_ID_CONTRAST, V4L2_CID_CONTRAST },
283 };
284 #define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR))
285
286 static struct STRTAB*
287 v4l2_menu(int fd, const struct v4l2_queryctrl *ctl)
288 {
289 struct STRTAB *menu;
290 struct v4l2_querymenu item;
291 int i;
292
293 menu = malloc(sizeof(struct STRTAB) * (ctl->maximum-ctl->minimum+2));
294 for (i = ctl->minimum; i <= ctl->maximum; i++) {
295 item.id = ctl->id;
296 item.index = i;
297 if (-1 == xioctl(fd, VIDIOC_QUERYMENU, &item, 0)) {
298 free(menu);
299 return NULL;
300 }
301 menu[i-ctl->minimum].nr = i;
302 menu[i-ctl->minimum].str = strdup(item.name);
303 }
304 menu[i-ctl->minimum].nr = -1;
305 menu[i-ctl->minimum].str = NULL;
306 return menu;
307 }
308
309 static void
310 v4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl,
311 int id, struct STRTAB *choices)
312 {
313 static int private_ids = ATTR_ID_COUNT;
314 unsigned int i;
315
316 h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute));
317 memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2);
318 if (ctl) {
319 for (i = 0; i < NUM_ATTR; i++)
320 if (v4l2_attr[i].v4l2 == ctl->id)
321 break;
322 if (i != NUM_ATTR) {
323 h->attr[h->nattr].id = v4l2_attr[i].id;
324 } else {
325 h->attr[h->nattr].id = private_ids++;
326 }
327 h->attr[h->nattr].name = ctl->name;
328 h->attr[h->nattr].priv = ctl;
329 h->attr[h->nattr].defval = ctl->default_value;
330 switch (ctl->type) {
331 case V4L2_CTRL_TYPE_INTEGER:
332 h->attr[h->nattr].type = ATTR_TYPE_INTEGER;
333 h->attr[h->nattr].defval = ctl->default_value;
334 h->attr[h->nattr].min = ctl->minimum;
335 h->attr[h->nattr].max = ctl->maximum;
336 break;
337 case V4L2_CTRL_TYPE_BOOLEAN:
338 h->attr[h->nattr].type = ATTR_TYPE_BOOL;
339 break;
340 case V4L2_CTRL_TYPE_MENU:
341 h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
342 h->attr[h->nattr].choices = v4l2_menu(h->fd, ctl);
343 break;
344 default:
345 memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2);
346 return;
347 }
348 } else {
349 /* for norms + inputs */
350 h->attr[h->nattr].id = id;
351 if (-1 == h->attr[h->nattr].id)
352 h->attr[h->nattr].id = private_ids++;
353 h->attr[h->nattr].defval = 0;
354 h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
355 h->attr[h->nattr].choices = choices;
356 }
357 if (h->attr[h->nattr].id < ATTR_ID_COUNT)
358 h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id];
359
360 h->attr[h->nattr].read = v4l2_read_attr;
361 h->attr[h->nattr].write = v4l2_write_attr;
362 h->attr[h->nattr].handle = h;
363 h->nattr++;
364 }
365
366 static int v4l2_read_attr(struct ng_attribute *attr)
367 {
368 struct v4l2_handle *h = attr->handle;
369 const struct v4l2_queryctrl *ctl = attr->priv;
370 struct v4l2_control c;
371 struct v4l2_tuner tuner;
372 v4l2_std_id std;
373 int value = 0;
374 int i;
375
376 if (NULL != ctl) {
377 c.id = ctl->id;
378 xioctl(h->fd,VIDIOC_G_CTRL,&c,0);
379 value = c.value;
380
381 } else if (attr->id == ATTR_ID_NORM) {
382 value = -1;
383 xioctl(h->fd,VIDIOC_G_STD,&std,0);
384 for (i = 0; i < h->nstds; i++)
385 if (std & h->std[i].id)
386 value = i;
387
388 } else if (attr->id == ATTR_ID_INPUT) {
389 xioctl(h->fd,VIDIOC_G_INPUT,&value,0);
390
391 } else if (attr->id == ATTR_ID_AUDIO_MODE) {
392 memset(&tuner,0,sizeof(tuner));
393 xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
394 value = tuner.audmode;
395 #if 1
396 if (ng_debug) {
397 fprintf(stderr,"v4l2: tuner cap:%s%s%s\n",
398 (tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "",
399 (tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "",
400 (tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : "");
401 fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n",
402 (tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "",
403 (tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "",
404 (tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "",
405 (tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : "");
406 fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n",
407 (tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "",
408 (tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "",
409 (tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "",
410 (tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : "");
411 }
412 #endif
413 }
414 return value;
415 }
416
417 static void v4l2_write_attr(struct ng_attribute *attr, int value)
418 {
419 struct v4l2_handle *h = attr->handle;
420 const struct v4l2_queryctrl *ctl = attr->priv;
421 struct v4l2_control c;
422 struct v4l2_tuner tuner;
423
424 if (NULL != ctl) {
425 c.id = ctl->id;
426 c.value = value;
427 xioctl(h->fd,VIDIOC_S_CTRL,&c,0);
428
429 } else if (attr->id == ATTR_ID_NORM) {
430 xioctl(h->fd,VIDIOC_S_STD,&h->std[value].id,0);
431
432 } else if (attr->id == ATTR_ID_INPUT) {
433 xioctl(h->fd,VIDIOC_S_INPUT,&value,0);
434
435 } else if (attr->id == ATTR_ID_AUDIO_MODE) {
436 memset(&tuner,0,sizeof(tuner));
437 xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
438 tuner.audmode = value;
439 xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0);
440 }
441 }
442
443 /* ---------------------------------------------------------------------- */
444
445 static void*
446 v4l2_open(char *device)
447 {
448 struct v4l2_handle *h;
449 int i;
450
451 h = malloc(sizeof(*h));
452 if (NULL == h)
453 return NULL;
454 memset(h,0,sizeof(*h));
455
456 if (-1 == (h->fd = open(device, O_RDWR))) {
457 fprintf(stderr,"v4l2: open %s: %s\n",device,strerror(errno));
458 goto err;
459 }
460
461 if (-1 == xioctl(h->fd,VIDIOC_QUERYCAP,&h->cap,EINVAL))
462 goto err;
463 if (ng_debug)
464 fprintf(stderr, "v4l2: open\n");
465 fcntl(h->fd,F_SETFD,FD_CLOEXEC);
466 if (ng_debug)
467 fprintf(stderr,"v4l2: device info:\n"
468 " %s %d.%d.%d / %s @ %s\n",
469 h->cap.driver,
470 (h->cap.version >> 16) & 0xff,
471 (h->cap.version >> 8) & 0xff,
472 h->cap.version & 0xff,
473 h->cap.card,h->cap.bus_info);
474 get_device_capabilities(h);
475
476 /* attributes */
477 v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h));
478 v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h));
479 if (h->cap.capabilities & V4L2_CAP_TUNER)
480 v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo);
481 for (i = 0; i < MAX_CTRL*2; i++) {
482 if (h->ctl[i].id == UNSET)
483 continue;
484 v4l2_add_attr(h, &h->ctl[i], 0, NULL);
485 }
486
487 /* capture buffers */
488 for (i = 0; i < WANTED_BUFFERS; i++) {
489 ng_init_video_buf(h->buf_me+i);
490 h->buf_me[i].release = ng_wakeup_video_buf;
491 }
492
493 return h;
494
495 err:
496 if (h->fd != -1)
497 close(h->fd);
498 if (h)
499 free(h);
500 return NULL;
501 }
502
503 static int
504 v4l2_close(void *handle)
505 {
506 struct v4l2_handle *h = handle;
507
508 if (ng_debug)
509 fprintf(stderr, "v4l2: close\n");
510
511 close(h->fd);
512 free(h);
513 return 0;
514 }
515
516 static char*
517 v4l2_devname(void *handle)
518 {
519 struct v4l2_handle *h = handle;
520 return h->cap.card;
521 }
522
523 static int v4l2_flags(void *handle)
524 {
525 struct v4l2_handle *h = handle;
526 int ret = 0;
527
528 if (h->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY && !h->ov_error)
529 ret |= CAN_OVERLAY;
530 if (h->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
531 ret |= CAN_CAPTURE;
532 if (h->cap.capabilities & V4L2_CAP_TUNER)
533 ret |= CAN_TUNE;
534 return ret;
535 }
536
537 static struct ng_attribute* v4l2_attrs(void *handle)
538 {
539 struct v4l2_handle *h = handle;
540 return h->attr;
541 }
542
543 /* ---------------------------------------------------------------------- */
544
545 static unsigned long
546 v4l2_getfreq(void *handle)
547 {
548 struct v4l2_handle *h = handle;
549 struct v4l2_frequency f;
550
551 memset(&f,0,sizeof(f));
552 xioctl(h->fd, VIDIOC_G_FREQUENCY, &f, 0);
553 return f.frequency;
554 }
555
556 static void
557 v4l2_setfreq(void *handle, unsigned long freq)
558 {
559 struct v4l2_handle *h = handle;
560 struct v4l2_frequency f;
561
562 if (ng_debug)
563 fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16);
564 memset(&f,0,sizeof(f));
565 f.type = V4L2_TUNER_ANALOG_TV;
566 f.frequency = freq;
567 xioctl(h->fd, VIDIOC_S_FREQUENCY, &f, 0);
568 }
569
570 static int
571 v4l2_tuned(void *handle)
572 {
573 struct v4l2_handle *h = handle;
574 struct v4l2_tuner tuner;
575
576 usleep(10000);
577 memset(&tuner,0,sizeof(tuner));
578 if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0))
579 return 0;
580 return tuner.signal ? 1 : 0;
581 }
582
583 /* ---------------------------------------------------------------------- */
584 /* overlay */
585
586 static int
587 v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base)
588 {
589 struct v4l2_handle *h = handle;
590
591 if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0))
592 return -1;
593
594 /* double-check settings */
595 if (NULL != base && h->ov_fb.base != base) {
596 fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n");
597 fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base);
598 h->ov_error = 1;
599 return -1;
600 }
601 if (h->ov_fb.fmt.width != fmt->width ||
602 h->ov_fb.fmt.height != fmt->height) {
603 fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n");
604 fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n",
605 fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height);
606 h->ov_error = 1;
607 return -1;
608 }
609 if (fmt->bytesperline > 0 &&
610 fmt->bytesperline != h->ov_fb.fmt.bytesperline) {
611 fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n");
612 fprintf(stderr,"v4l2: me=%d v4l=%d\n",
613 fmt->bytesperline,h->ov_fb.fmt.bytesperline);
614 h->ov_error = 1;
615 return -1;
616 }
617 #if 0
618 if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) {
619 fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n");
620 fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n",
621 xawtv_pixelformat[fmt->fmtid] & 0xff,
622 (xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff,
623 (xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff,
624 (xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff,
625 ng_vfmt_to_desc[fmt->fmtid],
626 h->ov_fb.fmt.pixelformat & 0xff,
627 (h->ov_fb.fmt.pixelformat >> 8) & 0xff,
628 (h->ov_fb.fmt.pixelformat >> 16) & 0xff,
629 (h->ov_fb.fmt.pixelformat >> 24) & 0xff);
630 h->ov_error = 1;
631 return -1;
632 }
633 #endif
634 return 0;
635 }
636
637 static int
638 v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
639 struct OVERLAY_CLIP *oc, int count, int aspect)
640 {
641 struct v4l2_handle *h = handle;
642 struct v4l2_format win;
643 int rc,i;
644
645 if (h->ov_error)
646 return -1;
647
648 if (NULL == fmt) {
649 if (ng_debug)
650 fprintf(stderr,"v4l2: overlay off\n");
651 if (h->ov_enabled) {
652 h->ov_enabled = 0;
653 h->ov_on = 0;
654 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
655 }
656 return 0;
657 }
658
659 if (ng_debug)
660 fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n",
661 fmt->width,fmt->height,x,y,count);
662 memset(&win,0,sizeof(win));
663 win.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
664 win.fmt.win.w.left = x;
665 win.fmt.win.w.top = y;
666 win.fmt.win.w.width = fmt->width;
667 win.fmt.win.w.height = fmt->height;
668
669 /* check against max. size */
670 xioctl(h->fd,VIDIOC_TRY_FMT,&win,0);
671 if (win.fmt.win.w.width != (int)fmt->width)
672 win.fmt.win.w.left = x + (fmt->width - win.fmt.win.w.width)/2;
673 if (win.fmt.win.w.height != (int)fmt->height)
674 win.fmt.win.w.top = y + (fmt->height - win.fmt.win.w.height)/2;
675 if (aspect)
676 ng_ratio_fixup(&win.fmt.win.w.width,&win.fmt.win.w.height,
677 &win.fmt.win.w.left,&win.fmt.win.w.top);
678
679 /* fixups */
680 ng_check_clipping(win.fmt.win.w.width, win.fmt.win.w.height,
681 x - win.fmt.win.w.left, y - win.fmt.win.w.top,
682 oc, &count);
683
684 h->ov_win = win;
685 if (h->ov_fb.capability & V4L2_FBUF_CAP_LIST_CLIPPING) {
686 h->ov_win.fmt.win.clips = h->ov_clips;
687 h->ov_win.fmt.win.clipcount = count;
688
689 for (i = 0; i < count; i++) {
690 h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1];
691 h->ov_clips[i].c.left = oc[i].x1;
692 h->ov_clips[i].c.top = oc[i].y1;
693 h->ov_clips[i].c.width = oc[i].x2-oc[i].x1;
694 h->ov_clips[i].c.height = oc[i].y2-oc[i].y1;
695 }
696 }
697 #if 0
698 if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) {
699 h->ov_win.chromakey = 0; /* FIXME */
700 }
701 #endif
702 rc = xioctl(h->fd, VIDIOC_S_FMT, &h->ov_win, 0);
703
704 h->ov_enabled = (0 == rc) ? 1 : 0;
705 h->ov_on = (0 == rc) ? 1 : 0;
706 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
707
708 return 0;
709 }
710
711 /* ---------------------------------------------------------------------- */
712 /* capture helpers */
713
714 static int
715 v4l2_queue_buffer(struct v4l2_handle *h)
716 {
717 int frame = h->queue % h->reqbufs.count;
718 int rc;
719
720 if (0 != h->buf_me[frame].refcount) {
721 if (0 != h->queue - h->waiton)
722 return -1;
723 fprintf(stderr,"v4l2: waiting for a free buffer\n");
724 ng_waiton_video_buf(h->buf_me+frame);
725 }
726
727 rc = xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[frame], 0);
728 if (0 == rc)
729 h->queue++;
730 return rc;
731 }
732
733 static void
734 v4l2_queue_all(struct v4l2_handle *h)
735 {
736 for (;;) {
737 if (h->queue - h->waiton >= h->reqbufs.count)
738 return;
739 if (0 != v4l2_queue_buffer(h))
740 return;
741 }
742 }
743
744 static int
745 v4l2_waiton(struct v4l2_handle *h)
746 {
747 struct v4l2_buffer buf;
748 struct timeval tv;
749 fd_set rdset;
750
751 /* wait for the next frame */
752 again:
753 tv.tv_sec = 5;
754 tv.tv_usec = 0;
755 FD_ZERO(&rdset);
756 FD_SET(h->fd, &rdset);
757 switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) {
758 case -1:
759 if (EINTR == errno)
760 goto again;
761 perror("v4l2: select");
762 return -1;
763 case 0:
764 fprintf(stderr,"v4l2: oops: select timeout\n");
765 return -1;
766 }
767
768 /* get it */
769 memset(&buf,0,sizeof(buf));
770 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
771 if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0))
772 return -1;
773 h->waiton++;
774 h->buf_v4l2[buf.index] = buf;
775
776 #if 0
777 if (1) {
778 /* for driver debugging */
779 static const char *fn[] = {
780 "any", "none", "top", "bottom",
781 "interlaced", "tb", "bt", "alternate",
782 };
783 static struct timeval last;
784 signed long diff;
785
786 diff = (buf.timestamp.tv_sec - last.tv_sec) * 1000000;
787 diff += buf.timestamp.tv_usec - last.tv_usec;
788 fprintf(stderr,"\tdiff %6.1f ms buf %d field %d [%s]\n",
789 diff/1000.0, buf.index, buf.field, fn[buf.field%8]);
790 last = buf.timestamp;
791 }
792 #endif
793
794 return buf.index;
795 }
796
797 static int
798 v4l2_start_streaming(struct v4l2_handle *h, int buffers)
799 {
800 int disable_overlay = 0;
801 unsigned int i;
802
803 /* setup buffers */
804 h->reqbufs.count = buffers;
805 h->reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
806 h->reqbufs.memory = V4L2_MEMORY_MMAP;
807 if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0))
808 return -1;
809 for (i = 0; i < h->reqbufs.count; i++) {
810 h->buf_v4l2[i].index = i;
811 h->buf_v4l2[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
812 h->buf_v4l2[i].memory = V4L2_MEMORY_MMAP;
813 if (-1 == xioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i], 0))
814 return -1;
815 h->buf_me[i].fmt = h->fmt_me;
816 h->buf_me[i].size = h->buf_me[i].fmt.bytesperline *
817 h->buf_me[i].fmt.height;
818 h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length,
819 PROT_READ | PROT_WRITE, MAP_SHARED,
820 h->fd, h->buf_v4l2[i].m.offset);
821 if (MAP_FAILED == h->buf_me[i].data) {
822 perror("mmap");
823 return -1;
824 }
825 if (ng_debug)
826 print_bufinfo(&h->buf_v4l2[i]);
827 }
828
829 /* queue up all buffers */
830 v4l2_queue_all(h);
831
832 try_again:
833 /* turn off preview (if needed) */
834 if (disable_overlay) {
835 h->ov_on = 0;
836 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
837 if (ng_debug)
838 fprintf(stderr,"v4l2: overlay off (start_streaming)\n");
839 }
840
841 /* start capture */
842 if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type,
843 h->ov_on ? EBUSY : 0)) {
844 if (h->ov_on && errno == EBUSY) {
845 disable_overlay = 1;
846 goto try_again;
847 }
848 return -1;
849 }
850 return 0;
851 }
852
853 static void
854 v4l2_stop_streaming(struct v4l2_handle *h)
855 {
856 unsigned int i;
857
858 /* stop capture */
859 if (-1 == ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type))
860 perror("ioctl VIDIOC_STREAMOFF");
861
862 /* free buffers */
863 for (i = 0; i < h->reqbufs.count; i++) {
864 if (0 != h->buf_me[i].refcount)
865 ng_waiton_video_buf(&h->buf_me[i]);
866 if (ng_debug)
867 print_bufinfo(&h->buf_v4l2[i]);
868 if (-1 == munmap(h->buf_me[i].data,h->buf_me[i].size))
869 perror("munmap");
870 }
871 h->queue = 0;
872 h->waiton = 0;
873
874 /* turn on preview (if needed) */
875 if (h->ov_on != h->ov_enabled) {
876 h->ov_on = h->ov_enabled;
877 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
878 if (ng_debug)
879 fprintf(stderr,"v4l2: overlay on (stop_streaming)\n");
880 }
881 }
882
883 /* ---------------------------------------------------------------------- */
884 /* capture interface */
885
886 /* set capture parameters */
887 static int
888 v4l2_setformat(void *handle, struct ng_video_fmt *fmt)
889 {
890 struct v4l2_handle *h = handle;
891
892 h->fmt_v4l2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
893 h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid];
894 h->fmt_v4l2.fmt.pix.width = fmt->width;
895 h->fmt_v4l2.fmt.pix.height = fmt->height;
896 h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ANY;
897 //h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ALTERNATE;
898 if (fmt->bytesperline != fmt->width * ng_vfmt_to_depth[fmt->fmtid]/8)
899 h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline;
900 else
901 h->fmt_v4l2.fmt.pix.bytesperline = 0;
902
903 if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL))
904 return -1;
905 if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid])
906 return -1;
907 fmt->width = h->fmt_v4l2.fmt.pix.width;
908 fmt->height = h->fmt_v4l2.fmt.pix.height;
909 fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline;
910 if (0 == fmt->bytesperline)
911 fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
912 h->fmt_me = *fmt;
913 if (ng_debug)
914 fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n",
915 fmt->width,fmt->height,
916 h->fmt_v4l2.fmt.pix.pixelformat & 0xff,
917 (h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff,
918 (h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff,
919 (h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff,
920 h->fmt_v4l2.fmt.pix.sizeimage);
921 return 0;
922 }
923
924 /* start/stop video */
925 static int
926 v4l2_startvideo(void *handle, int fps, unsigned int buffers)
927 {
928 struct v4l2_handle *h = handle;
929
930 if (0 != h->fps)
931 fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n");
932 h->fps = fps;
933 h->first = 1;
934 h->start = 0;
935
936 if (h->cap.capabilities & V4L2_CAP_STREAMING)
937 return v4l2_start_streaming(h,buffers);
938 return 0;
939 }
940
941 static void
942 v4l2_stopvideo(void *handle)
943 {
944 struct v4l2_handle *h = handle;
945
946 if (0 == h->fps)
947 fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n");
948 h->fps = 0;
949
950 if (h->cap.capabilities & V4L2_CAP_STREAMING)
951 v4l2_stop_streaming(h);
952 }
953
954 /* read images */
955 static struct ng_video_buf*
956 v4l2_nextframe(void *handle)
957 {
958 struct v4l2_handle *h = handle;
959 struct ng_video_buf *buf = NULL;
960 int rc,size,frame = 0;
961
962 if (h->cap.capabilities & V4L2_CAP_STREAMING) {
963 v4l2_queue_all(h);
964 frame = v4l2_waiton(h);
965 if (-1 == frame)
966 return NULL;
967 h->buf_me[frame].refcount++;
968 buf = &h->buf_me[frame];
969 memset(&buf->info,0,sizeof(buf->info));
970 buf->info.ts = ng_tofday_to_timestamp(&h->buf_v4l2[frame].timestamp);
971 } else {
972 size = h->fmt_me.bytesperline * h->fmt_me.height;
973 buf = ng_malloc_video_buf(&h->fmt_me,size);
974 rc = read(h->fd,buf->data,size);
975 if (rc != size) {
976 if (-1 == rc) {
977 perror("v4l2: read");
978 } else {
979 fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
980 }
981 ng_release_video_buf(buf);
982 return NULL;
983 }
984 memset(&buf->info,0,sizeof(buf->info));
985 buf->info.ts = ng_get_timestamp();
986 }
987
988 if (h->first) {
989 h->first = 0;
990 h->start = buf->info.ts;
991 if (ng_debug)
992 fprintf(stderr,"v4l2: start ts=%lld\n",h->start);
993 }
994 buf->info.ts -= h->start;
995 return buf;
996 }
997
998 static struct ng_video_buf*
999 v4l2_getimage(void *handle)
1000 {
1001 struct v4l2_handle *h = handle;
1002 struct ng_video_buf *buf;
1003 int size,frame,rc;
1004
1005 size = h->fmt_me.bytesperline * h->fmt_me.height;
1006 buf = ng_malloc_video_buf(&h->fmt_me,size);
1007 if (h->cap.capabilities & V4L2_CAP_READWRITE) {
1008 rc = read(h->fd,buf->data,size);
1009 if (-1 == rc && EBUSY == errno && h->ov_on) {
1010 h->ov_on = 0;
1011 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
1012 rc = read(h->fd,buf->data,size);
1013 h->ov_on = 1;
1014 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
1015 }
1016 if (rc != size) {
1017 if (-1 == rc) {
1018 perror("v4l2: read");
1019 } else {
1020 fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
1021 }
1022 ng_release_video_buf(buf);
1023 return NULL;
1024 }
1025 } else {
1026 if (-1 == v4l2_start_streaming(h,1)) {
1027 v4l2_stop_streaming(h);
1028 return NULL;
1029 }
1030 frame = v4l2_waiton(h);
1031 if (-1 == frame) {
1032 v4l2_stop_streaming(h);
1033 return NULL;
1034 }
1035 memcpy(buf->data,h->buf_me[0].data,size);
1036 v4l2_stop_streaming(h);
1037 }
1038 return buf;
1039 }
1040
1041 /* ---------------------------------------------------------------------- */
1042
1043 extern void ng_plugin_init(void);
1044 void ng_plugin_init(void)
1045 {
1046 ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver);
1047 }
1048
|
This page was automatically generated by the
LXR engine.
|