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 return;
346 }
347 } else {
348 /* for norms + inputs */
349 h->attr[h->nattr].id = id;
350 if (-1 == h->attr[h->nattr].id)
351 h->attr[h->nattr].id = private_ids++;
352 h->attr[h->nattr].defval = 0;
353 h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
354 h->attr[h->nattr].choices = choices;
355 }
356 if (h->attr[h->nattr].id < ATTR_ID_COUNT)
357 h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id];
358
359 h->attr[h->nattr].read = v4l2_read_attr;
360 h->attr[h->nattr].write = v4l2_write_attr;
361 h->attr[h->nattr].handle = h;
362 h->nattr++;
363 }
364
365 static int v4l2_read_attr(struct ng_attribute *attr)
366 {
367 struct v4l2_handle *h = attr->handle;
368 const struct v4l2_queryctrl *ctl = attr->priv;
369 struct v4l2_control c;
370 struct v4l2_tuner tuner;
371 v4l2_std_id std;
372 int value = 0;
373 int i;
374
375 if (NULL != ctl) {
376 c.id = ctl->id;
377 xioctl(h->fd,VIDIOC_G_CTRL,&c,0);
378 value = c.value;
379
380 } else if (attr->id == ATTR_ID_NORM) {
381 value = -1;
382 xioctl(h->fd,VIDIOC_G_STD,&std,0);
383 for (i = 0; i < h->nstds; i++)
384 if (std & h->std[i].id)
385 value = i;
386
387 } else if (attr->id == ATTR_ID_INPUT) {
388 xioctl(h->fd,VIDIOC_G_INPUT,&value,0);
389
390 } else if (attr->id == ATTR_ID_AUDIO_MODE) {
391 memset(&tuner,0,sizeof(tuner));
392 xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
393 value = tuner.audmode;
394 #if 1
395 if (ng_debug) {
396 fprintf(stderr,"v4l2: tuner cap:%s%s%s\n",
397 (tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "",
398 (tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "",
399 (tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : "");
400 fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n",
401 (tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "",
402 (tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "",
403 (tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "",
404 (tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : "");
405 fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n",
406 (tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "",
407 (tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "",
408 (tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "",
409 (tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : "");
410 }
411 #endif
412 }
413 return value;
414 }
415
416 static void v4l2_write_attr(struct ng_attribute *attr, int value)
417 {
418 struct v4l2_handle *h = attr->handle;
419 const struct v4l2_queryctrl *ctl = attr->priv;
420 struct v4l2_control c;
421 struct v4l2_tuner tuner;
422
423 if (NULL != ctl) {
424 c.id = ctl->id;
425 c.value = value;
426 xioctl(h->fd,VIDIOC_S_CTRL,&c,0);
427
428 } else if (attr->id == ATTR_ID_NORM) {
429 xioctl(h->fd,VIDIOC_S_STD,&h->std[value].id,0);
430
431 } else if (attr->id == ATTR_ID_INPUT) {
432 xioctl(h->fd,VIDIOC_S_INPUT,&value,0);
433
434 } else if (attr->id == ATTR_ID_AUDIO_MODE) {
435 memset(&tuner,0,sizeof(tuner));
436 xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
437 tuner.audmode = value;
438 xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0);
439 }
440 }
441
442 /* ---------------------------------------------------------------------- */
443
444 static void*
445 v4l2_open(char *device)
446 {
447 struct v4l2_handle *h;
448 int i;
449
450 h = malloc(sizeof(*h));
451 if (NULL == h)
452 return NULL;
453 memset(h,0,sizeof(*h));
454
455 if (-1 == (h->fd = open(device, O_RDWR))) {
456 fprintf(stderr,"v4l2: open %s: %s\n",device,strerror(errno));
457 goto err;
458 }
459
460 if (-1 == xioctl(h->fd,VIDIOC_QUERYCAP,&h->cap,EINVAL))
461 goto err;
462 if (ng_debug)
463 fprintf(stderr, "v4l2: open\n");
464 fcntl(h->fd,F_SETFD,FD_CLOEXEC);
465 if (ng_debug)
466 fprintf(stderr,"v4l2: device info:\n"
467 " %s %d.%d.%d / %s @ %s\n",
468 h->cap.driver,
469 (h->cap.version >> 16) & 0xff,
470 (h->cap.version >> 8) & 0xff,
471 h->cap.version & 0xff,
472 h->cap.card,h->cap.bus_info);
473 get_device_capabilities(h);
474
475 /* attributes */
476 v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h));
477 v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h));
478 if (h->cap.capabilities & V4L2_CAP_TUNER)
479 v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo);
480 for (i = 0; i < MAX_CTRL*2; i++) {
481 if (h->ctl[i].id == UNSET)
482 continue;
483 v4l2_add_attr(h, &h->ctl[i], 0, NULL);
484 }
485
486 /* capture buffers */
487 for (i = 0; i < WANTED_BUFFERS; i++) {
488 ng_init_video_buf(h->buf_me+i);
489 h->buf_me[i].release = ng_wakeup_video_buf;
490 }
491
492 return h;
493
494 err:
495 if (h->fd != -1)
496 close(h->fd);
497 if (h)
498 free(h);
499 return NULL;
500 }
501
502 static int
503 v4l2_close(void *handle)
504 {
505 struct v4l2_handle *h = handle;
506
507 if (ng_debug)
508 fprintf(stderr, "v4l2: close\n");
509
510 close(h->fd);
511 free(h);
512 return 0;
513 }
514
515 static char*
516 v4l2_devname(void *handle)
517 {
518 struct v4l2_handle *h = handle;
519 return h->cap.card;
520 }
521
522 static int v4l2_flags(void *handle)
523 {
524 struct v4l2_handle *h = handle;
525 int ret = 0;
526
527 if (h->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY && !h->ov_error)
528 ret |= CAN_OVERLAY;
529 if (h->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
530 ret |= CAN_CAPTURE;
531 if (h->cap.capabilities & V4L2_CAP_TUNER)
532 ret |= CAN_TUNE;
533 return ret;
534 }
535
536 static struct ng_attribute* v4l2_attrs(void *handle)
537 {
538 struct v4l2_handle *h = handle;
539 return h->attr;
540 }
541
542 /* ---------------------------------------------------------------------- */
543
544 static unsigned long
545 v4l2_getfreq(void *handle)
546 {
547 struct v4l2_handle *h = handle;
548 struct v4l2_frequency f;
549
550 memset(&f,0,sizeof(f));
551 xioctl(h->fd, VIDIOC_G_FREQUENCY, &f, 0);
552 return f.frequency;
553 }
554
555 static void
556 v4l2_setfreq(void *handle, unsigned long freq)
557 {
558 struct v4l2_handle *h = handle;
559 struct v4l2_frequency f;
560
561 if (ng_debug)
562 fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16);
563 memset(&f,0,sizeof(f));
564 f.type = V4L2_TUNER_ANALOG_TV;
565 f.frequency = freq;
566 xioctl(h->fd, VIDIOC_S_FREQUENCY, &f, 0);
567 }
568
569 static int
570 v4l2_tuned(void *handle)
571 {
572 struct v4l2_handle *h = handle;
573 struct v4l2_tuner tuner;
574
575 usleep(10000);
576 memset(&tuner,0,sizeof(tuner));
577 if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0))
578 return 0;
579 return tuner.signal ? 1 : 0;
580 }
581
582 /* ---------------------------------------------------------------------- */
583 /* overlay */
584
585 static int
586 v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base)
587 {
588 struct v4l2_handle *h = handle;
589
590 if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0))
591 return -1;
592
593 /* double-check settings */
594 if (NULL != base && h->ov_fb.base != base) {
595 fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n");
596 fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base);
597 h->ov_error = 1;
598 return -1;
599 }
600 if (h->ov_fb.fmt.width != fmt->width ||
601 h->ov_fb.fmt.height != fmt->height) {
602 fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n");
603 fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n",
604 fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height);
605 h->ov_error = 1;
606 return -1;
607 }
608 if (fmt->bytesperline > 0 &&
609 fmt->bytesperline != h->ov_fb.fmt.bytesperline) {
610 fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n");
611 fprintf(stderr,"v4l2: me=%d v4l=%d\n",
612 fmt->bytesperline,h->ov_fb.fmt.bytesperline);
613 h->ov_error = 1;
614 return -1;
615 }
616 #if 0
617 if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) {
618 fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n");
619 fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n",
620 xawtv_pixelformat[fmt->fmtid] & 0xff,
621 (xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff,
622 (xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff,
623 (xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff,
624 ng_vfmt_to_desc[fmt->fmtid],
625 h->ov_fb.fmt.pixelformat & 0xff,
626 (h->ov_fb.fmt.pixelformat >> 8) & 0xff,
627 (h->ov_fb.fmt.pixelformat >> 16) & 0xff,
628 (h->ov_fb.fmt.pixelformat >> 24) & 0xff);
629 h->ov_error = 1;
630 return -1;
631 }
632 #endif
633 return 0;
634 }
635
636 static int
637 v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
638 struct OVERLAY_CLIP *oc, int count, int aspect)
639 {
640 struct v4l2_handle *h = handle;
641 struct v4l2_format win;
642 int rc,i;
643
644 if (h->ov_error)
645 return -1;
646
647 if (NULL == fmt) {
648 if (ng_debug)
649 fprintf(stderr,"v4l2: overlay off\n");
650 if (h->ov_enabled) {
651 h->ov_enabled = 0;
652 h->ov_on = 0;
653 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
654 }
655 return 0;
656 }
657
658 if (ng_debug)
659 fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n",
660 fmt->width,fmt->height,x,y,count);
661 memset(&win,0,sizeof(win));
662 win.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
663 win.fmt.win.w.left = x;
664 win.fmt.win.w.top = y;
665 win.fmt.win.w.width = fmt->width;
666 win.fmt.win.w.height = fmt->height;
667
668 /* check against max. size */
669 xioctl(h->fd,VIDIOC_TRY_FMT,&win,0);
670 if (win.fmt.win.w.width != (int)fmt->width)
671 win.fmt.win.w.left = x + (fmt->width - win.fmt.win.w.width)/2;
672 if (win.fmt.win.w.height != (int)fmt->height)
673 win.fmt.win.w.top = y + (fmt->height - win.fmt.win.w.height)/2;
674 if (aspect)
675 ng_ratio_fixup(&win.fmt.win.w.width,&win.fmt.win.w.height,
676 &win.fmt.win.w.left,&win.fmt.win.w.top);
677
678 /* fixups */
679 ng_check_clipping(win.fmt.win.w.width, win.fmt.win.w.height,
680 x - win.fmt.win.w.left, y - win.fmt.win.w.top,
681 oc, &count);
682
683 h->ov_win = win;
684 if (h->ov_fb.capability & V4L2_FBUF_CAP_LIST_CLIPPING) {
685 h->ov_win.fmt.win.clips = h->ov_clips;
686 h->ov_win.fmt.win.clipcount = count;
687
688 for (i = 0; i < count; i++) {
689 h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1];
690 h->ov_clips[i].c.left = oc[i].x1;
691 h->ov_clips[i].c.top = oc[i].y1;
692 h->ov_clips[i].c.width = oc[i].x2-oc[i].x1;
693 h->ov_clips[i].c.height = oc[i].y2-oc[i].y1;
694 }
695 }
696 #if 0
697 if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) {
698 h->ov_win.chromakey = 0; /* FIXME */
699 }
700 #endif
701 rc = xioctl(h->fd, VIDIOC_S_FMT, &h->ov_win, 0);
702
703 h->ov_enabled = (0 == rc) ? 1 : 0;
704 h->ov_on = (0 == rc) ? 1 : 0;
705 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
706
707 return 0;
708 }
709
710 /* ---------------------------------------------------------------------- */
711 /* capture helpers */
712
713 static int
714 v4l2_queue_buffer(struct v4l2_handle *h)
715 {
716 int frame = h->queue % h->reqbufs.count;
717 int rc;
718
719 if (0 != h->buf_me[frame].refcount) {
720 if (0 != h->queue - h->waiton)
721 return -1;
722 fprintf(stderr,"v4l2: waiting for a free buffer\n");
723 ng_waiton_video_buf(h->buf_me+frame);
724 }
725
726 rc = xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[frame], 0);
727 if (0 == rc)
728 h->queue++;
729 return rc;
730 }
731
732 static void
733 v4l2_queue_all(struct v4l2_handle *h)
734 {
735 for (;;) {
736 if (h->queue - h->waiton >= h->reqbufs.count)
737 return;
738 if (0 != v4l2_queue_buffer(h))
739 return;
740 }
741 }
742
743 static int
744 v4l2_waiton(struct v4l2_handle *h)
745 {
746 struct v4l2_buffer buf;
747 struct timeval tv;
748 fd_set rdset;
749
750 /* wait for the next frame */
751 again:
752 tv.tv_sec = 5;
753 tv.tv_usec = 0;
754 FD_ZERO(&rdset);
755 FD_SET(h->fd, &rdset);
756 switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) {
757 case -1:
758 if (EINTR == errno)
759 goto again;
760 perror("v4l2: select");
761 return -1;
762 case 0:
763 fprintf(stderr,"v4l2: oops: select timeout\n");
764 return -1;
765 }
766
767 /* get it */
768 memset(&buf,0,sizeof(buf));
769 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
770 if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0))
771 return -1;
772 h->waiton++;
773 h->buf_v4l2[buf.index] = buf;
774
775 #if 0
776 if (1) {
777 /* for driver debugging */
778 static const char *fn[] = {
779 "any", "none", "top", "bottom",
780 "interlaced", "tb", "bt", "alternate",
781 };
782 static struct timeval last;
783 signed long diff;
784
785 diff = (buf.timestamp.tv_sec - last.tv_sec) * 1000000;
786 diff += buf.timestamp.tv_usec - last.tv_usec;
787 fprintf(stderr,"\tdiff %6.1f ms buf %d field %d [%s]\n",
788 diff/1000.0, buf.index, buf.field, fn[buf.field%8]);
789 last = buf.timestamp;
790 }
791 #endif
792
793 return buf.index;
794 }
795
796 static int
797 v4l2_start_streaming(struct v4l2_handle *h, int buffers)
798 {
799 int disable_overlay = 0;
800 unsigned int i;
801
802 /* setup buffers */
803 h->reqbufs.count = buffers;
804 h->reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
805 h->reqbufs.memory = V4L2_MEMORY_MMAP;
806 if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0))
807 return -1;
808 for (i = 0; i < h->reqbufs.count; i++) {
809 h->buf_v4l2[i].index = i;
810 h->buf_v4l2[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
811 h->buf_v4l2[i].memory = V4L2_MEMORY_MMAP;
812 if (-1 == xioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i], 0))
813 return -1;
814 h->buf_me[i].fmt = h->fmt_me;
815 h->buf_me[i].size = h->buf_me[i].fmt.bytesperline *
816 h->buf_me[i].fmt.height;
817 h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length,
818 PROT_READ | PROT_WRITE, MAP_SHARED,
819 h->fd, h->buf_v4l2[i].m.offset);
820 if (MAP_FAILED == h->buf_me[i].data) {
821 perror("mmap");
822 return -1;
823 }
824 if (ng_debug)
825 print_bufinfo(&h->buf_v4l2[i]);
826 }
827
828 /* queue up all buffers */
829 v4l2_queue_all(h);
830
831 try_again:
832 /* turn off preview (if needed) */
833 if (disable_overlay) {
834 h->ov_on = 0;
835 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
836 if (ng_debug)
837 fprintf(stderr,"v4l2: overlay off (start_streaming)\n");
838 }
839
840 /* start capture */
841 if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type,
842 h->ov_on ? EBUSY : 0)) {
843 if (h->ov_on && errno == EBUSY) {
844 disable_overlay = 1;
845 goto try_again;
846 }
847 return -1;
848 }
849 return 0;
850 }
851
852 static void
853 v4l2_stop_streaming(struct v4l2_handle *h)
854 {
855 unsigned int i;
856
857 /* stop capture */
858 if (-1 == ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type))
859 perror("ioctl VIDIOC_STREAMOFF");
860
861 /* free buffers */
862 for (i = 0; i < h->reqbufs.count; i++) {
863 if (0 != h->buf_me[i].refcount)
864 ng_waiton_video_buf(&h->buf_me[i]);
865 if (ng_debug)
866 print_bufinfo(&h->buf_v4l2[i]);
867 if (-1 == munmap(h->buf_me[i].data,h->buf_me[i].size))
868 perror("munmap");
869 }
870 h->queue = 0;
871 h->waiton = 0;
872
873 /* turn on preview (if needed) */
874 if (h->ov_on != h->ov_enabled) {
875 h->ov_on = h->ov_enabled;
876 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
877 if (ng_debug)
878 fprintf(stderr,"v4l2: overlay on (stop_streaming)\n");
879 }
880 }
881
882 /* ---------------------------------------------------------------------- */
883 /* capture interface */
884
885 /* set capture parameters */
886 static int
887 v4l2_setformat(void *handle, struct ng_video_fmt *fmt)
888 {
889 struct v4l2_handle *h = handle;
890
891 h->fmt_v4l2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
892 h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid];
893 h->fmt_v4l2.fmt.pix.width = fmt->width;
894 h->fmt_v4l2.fmt.pix.height = fmt->height;
895 h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ANY;
896 //h->fmt_v4l2.fmt.pix.field = V4L2_FIELD_ALTERNATE;
897 if (fmt->bytesperline != fmt->width * ng_vfmt_to_depth[fmt->fmtid]/8)
898 h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline;
899 else
900 h->fmt_v4l2.fmt.pix.bytesperline = 0;
901
902 if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL))
903 return -1;
904 if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid])
905 return -1;
906 fmt->width = h->fmt_v4l2.fmt.pix.width;
907 fmt->height = h->fmt_v4l2.fmt.pix.height;
908 fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline;
909 if (0 == fmt->bytesperline)
910 fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
911 h->fmt_me = *fmt;
912 if (ng_debug)
913 fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n",
914 fmt->width,fmt->height,
915 h->fmt_v4l2.fmt.pix.pixelformat & 0xff,
916 (h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff,
917 (h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff,
918 (h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff,
919 h->fmt_v4l2.fmt.pix.sizeimage);
920 return 0;
921 }
922
923 /* start/stop video */
924 static int
925 v4l2_startvideo(void *handle, int fps, unsigned int buffers)
926 {
927 struct v4l2_handle *h = handle;
928
929 if (0 != h->fps)
930 fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n");
931 h->fps = fps;
932 h->first = 1;
933 h->start = 0;
934
935 if (h->cap.capabilities & V4L2_CAP_STREAMING)
936 return v4l2_start_streaming(h,buffers);
937 return 0;
938 }
939
940 static void
941 v4l2_stopvideo(void *handle)
942 {
943 struct v4l2_handle *h = handle;
944
945 if (0 == h->fps)
946 fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n");
947 h->fps = 0;
948
949 if (h->cap.capabilities & V4L2_CAP_STREAMING)
950 v4l2_stop_streaming(h);
951 }
952
953 /* read images */
954 static struct ng_video_buf*
955 v4l2_nextframe(void *handle)
956 {
957 struct v4l2_handle *h = handle;
958 struct ng_video_buf *buf = NULL;
959 int rc,size,frame = 0;
960
961 if (h->cap.capabilities & V4L2_CAP_STREAMING) {
962 v4l2_queue_all(h);
963 frame = v4l2_waiton(h);
964 if (-1 == frame)
965 return NULL;
966 h->buf_me[frame].refcount++;
967 buf = &h->buf_me[frame];
968 memset(&buf->info,0,sizeof(buf->info));
969 buf->info.ts = ng_tofday_to_timestamp(&h->buf_v4l2[frame].timestamp);
970 } else {
971 size = h->fmt_me.bytesperline * h->fmt_me.height;
972 buf = ng_malloc_video_buf(&h->fmt_me,size);
973 rc = read(h->fd,buf->data,size);
974 if (rc != size) {
975 if (-1 == rc) {
976 perror("v4l2: read");
977 } else {
978 fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
979 }
980 ng_release_video_buf(buf);
981 return NULL;
982 }
983 memset(&buf->info,0,sizeof(buf->info));
984 buf->info.ts = ng_get_timestamp();
985 }
986
987 if (h->first) {
988 h->first = 0;
989 h->start = buf->info.ts;
990 if (ng_debug)
991 fprintf(stderr,"v4l2: start ts=%lld\n",h->start);
992 }
993 buf->info.ts -= h->start;
994 return buf;
995 }
996
997 static struct ng_video_buf*
998 v4l2_getimage(void *handle)
999 {
1000 struct v4l2_handle *h = handle;
1001 struct ng_video_buf *buf;
1002 int size,frame,rc;
1003
1004 size = h->fmt_me.bytesperline * h->fmt_me.height;
1005 buf = ng_malloc_video_buf(&h->fmt_me,size);
1006 if (h->cap.capabilities & V4L2_CAP_READWRITE) {
1007 rc = read(h->fd,buf->data,size);
1008 if (-1 == rc && EBUSY == errno && h->ov_on) {
1009 h->ov_on = 0;
1010 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
1011 rc = read(h->fd,buf->data,size);
1012 h->ov_on = 1;
1013 xioctl(h->fd, VIDIOC_OVERLAY, &h->ov_on, 0);
1014 }
1015 if (rc != size) {
1016 if (-1 == rc) {
1017 perror("v4l2: read");
1018 } else {
1019 fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
1020 }
1021 ng_release_video_buf(buf);
1022 return NULL;
1023 }
1024 } else {
1025 if (-1 == v4l2_start_streaming(h,1)) {
1026 v4l2_stop_streaming(h);
1027 return NULL;
1028 }
1029 frame = v4l2_waiton(h);
1030 if (-1 == frame) {
1031 v4l2_stop_streaming(h);
1032 return NULL;
1033 }
1034 memcpy(buf->data,h->buf_me[0].data,size);
1035 v4l2_stop_streaming(h);
1036 }
1037 return buf;
1038 }
1039
1040 /* ---------------------------------------------------------------------- */
1041
1042 extern void ng_plugin_init(void);
1043 void ng_plugin_init(void)
1044 {
1045 ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver);
1046 }
1047
|
This page was automatically generated by the
LXR engine.
|