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-old.h"
26
27 #include "grab-ng.h"
28
29 /* ---------------------------------------------------------------------- */
30
31 /* open+close */
32 static void* v4l2_open(char *device);
33 static int v4l2_close(void *handle);
34
35 /* attributes */
36 static char* v4l2_devname(void *handle);
37 static int v4l2_flags(void *handle);
38 static struct ng_attribute* v4l2_attrs(void *handle);
39 static int v4l2_read_attr(struct ng_attribute*);
40 static void v4l2_write_attr(struct ng_attribute*, int val);
41
42 /* overlay */
43 static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base);
44 static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
45 struct OVERLAY_CLIP *oc, int count, int aspect);
46
47 /* capture video */
48 static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt);
49 static int v4l2_startvideo(void *handle, int fps, unsigned int buffers);
50 static void v4l2_stopvideo(void *handle);
51 static struct ng_video_buf* v4l2_nextframe(void *handle);
52 static struct ng_video_buf* v4l2_getimage(void *handle);
53
54 /* tuner */
55 static unsigned long v4l2_getfreq(void *handle);
56 static void v4l2_setfreq(void *handle, unsigned long freq);
57 static int v4l2_tuned(void *handle);
58
59 /* ---------------------------------------------------------------------- */
60
61 #define WANTED_BUFFERS 32
62
63 #define MAX_INPUT 16
64 #define MAX_NORM 16
65 #define MAX_FORMAT 32
66 #define MAX_CTRL 32
67
68 struct v4l2_handle {
69 int fd;
70
71 /* device descriptions */
72 unsigned int ninputs,nstds,nfmts;
73 struct v4l2_capability cap;
74 struct v4l2_streamparm streamparm;
75 struct v4l2_input inp[MAX_INPUT];
76 struct v4l2_enumstd std[MAX_NORM];
77 struct v4l2_fmtdesc fmt[MAX_FORMAT];
78 struct v4l2_queryctrl ctl[MAX_CTRL*2];
79
80 /* attributes */
81 int nattr;
82 struct ng_attribute *attr;
83
84 /* capture */
85 int fps,first;
86 long long start;
87 struct v4l2_format fmt_v4l2;
88 struct ng_video_fmt fmt_me;
89 struct v4l2_requestbuffers reqbufs;
90 struct v4l2_buffer buf_v4l2[WANTED_BUFFERS];
91 struct ng_video_buf buf_me[WANTED_BUFFERS];
92 int queue,waiton;
93
94 /* overlay */
95 struct v4l2_framebuffer ov_fb;
96 struct v4l2_window ov_win;
97 struct v4l2_clip ov_clips[256];
98 int ov_error;
99 int ov_enabled;
100 int ov_on;
101 };
102
103 /* ---------------------------------------------------------------------- */
104
105 struct ng_vid_driver v4l2_driver = {
106 name: "v4l2-old",
107 open: v4l2_open,
108 close: v4l2_close,
109
110 get_devname: v4l2_devname,
111 capabilities: v4l2_flags,
112 list_attrs: v4l2_attrs,
113
114 setupfb: v4l2_setupfb,
115 overlay: v4l2_overlay,
116
117 setformat: v4l2_setformat,
118 startvideo: v4l2_startvideo,
119 stopvideo: v4l2_stopvideo,
120 nextframe: v4l2_nextframe,
121 getimage: v4l2_getimage,
122
123 getfreq: v4l2_getfreq,
124 setfreq: v4l2_setfreq,
125 is_tuned: v4l2_tuned,
126 };
127
128 static __u32 xawtv_pixelformat[VIDEO_FMT_COUNT] = {
129 0, /* unused */
130 V4L2_PIX_FMT_HI240, /* RGB8 */
131 V4L2_PIX_FMT_GREY, /* GRAY8 */
132 V4L2_PIX_FMT_RGB555, /* RGB15_LE */
133 V4L2_PIX_FMT_RGB565, /* RGB16_LE */
134 V4L2_PIX_FMT_RGB555X, /* RGB15_BE */
135 V4L2_PIX_FMT_RGB565X, /* RGB16_BE */
136 V4L2_PIX_FMT_BGR24, /* BGR24 */
137 V4L2_PIX_FMT_BGR32, /* BGR32 */
138 V4L2_PIX_FMT_RGB24, /* RGB24 */
139 0, /* RGB32 */
140 0, /* LUT 2 */
141 0, /* LUT 4 */
142 V4L2_PIX_FMT_YUYV, /* YUV422 */
143 V4L2_PIX_FMT_YUV422P, /* YUV422P */
144 V4L2_PIX_FMT_YUV420, /* YUV420P */
145 };
146
147 static struct STRTAB stereo[] = {
148 { V4L2_TUNER_MODE_MONO, "mono" },
149 { V4L2_TUNER_MODE_STEREO, "stereo" },
150 { V4L2_TUNER_MODE_LANG1, "lang1" },
151 { V4L2_TUNER_MODE_LANG2, "lang2" },
152 { -1, NULL },
153 };
154
155 /* ---------------------------------------------------------------------- */
156 /* debug output */
157
158 #define PREFIX "ioctl: "
159
160 static const char *io_names[] = {
161 "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
162 "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
163 "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
164 "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
165 "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
166 "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
167 "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
168 "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
169 "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
170 "S_MODULATOR"
171 };
172 static const int io_count = (sizeof(io_names)/sizeof(char*));
173 #define IONAME(cmd) ((cmd & 0xff) < io_count ? \
174 io_names[cmd & 0xff] : "UNKNOWN")
175
176 static int
177 xioctl(int fd, int cmd, void *arg, int mayfail)
178 {
179 int rc;
180
181 rc = ioctl(fd,cmd,arg);
182 if (0 == rc && ng_debug < 2)
183 return rc;
184 if (mayfail && errno == mayfail && ng_debug < 2)
185 return rc;
186 switch (cmd) {
187 case VIDIOC_QUERYCAP:
188 {
189 struct v4l2_capability *a = arg;
190 fprintf(stderr,PREFIX "VIDIOC_QUERYCAP(%s,type=0x%x,in=%d,out=%d,"
191 "audio=%d,size=%dx%d-%dx%d,fps=%d,flags=0x%x)",
192 a->name,a->type,a->inputs,a->outputs,a->audios,
193 a->minwidth,a->minheight,a->maxwidth,a->maxheight,
194 a->maxframerate,a->flags);
195 break;
196 }
197
198 case VIDIOC_G_FMT:
199 case VIDIOC_S_FMT:
200 {
201 struct v4l2_format *a = arg;
202
203 fprintf(stderr,PREFIX "VIDIOC_%s(type=%d,",IONAME(cmd),a->type);
204 switch (a->type) {
205 case V4L2_BUF_TYPE_CAPTURE:
206 fprintf(stderr,
207 "%dx%d,depth=%d,%c%c%c%c,flags=0x%x,bpl=%d,size=%d)",
208 a->fmt.pix.width,a->fmt.pix.height,a->fmt.pix.depth,
209 a->fmt.pix.pixelformat & 0xff,
210 (a->fmt.pix.pixelformat >> 8) & 0xff,
211 (a->fmt.pix.pixelformat >> 16) & 0xff,
212 (a->fmt.pix.pixelformat >> 24) & 0xff,
213 a->fmt.pix.depth,a->fmt.pix.bytesperline,
214 a->fmt.pix.sizeimage);
215 break;
216 default:
217 fprintf(stderr,"??" "?)"); /* break trigraph */
218 break;
219 }
220 break;
221 }
222 case VIDIOC_REQBUFS:
223 {
224 struct v4l2_requestbuffers *a = arg;
225
226 fprintf(stderr,PREFIX "VIDIOC_REQBUFS(count=%d,type=%d)",
227 a->count,a->type);
228 break;
229 }
230 case VIDIOC_QBUF:
231 case VIDIOC_DQBUF:
232 {
233 struct v4l2_buffer *a = arg;
234
235 fprintf(stderr,PREFIX "VIDIOC_%s(%d,type=%d,off=%d,len=%d,used=%d,"
236 "flags=0x%x,ts=%Ld,seq=%d)",
237 IONAME(cmd),a->index,a->type,a->offset,a->length,
238 a->bytesused,a->flags,a->timestamp,a->sequence);
239 break;
240 }
241
242 case VIDIOC_G_WIN:
243 case VIDIOC_S_WIN:
244 {
245 struct v4l2_window *a = arg;
246
247 fprintf(stderr,PREFIX "VIDIOC_%s(%dx%d+%d+%d,key=0x%x,clips=%d)",
248 IONAME(cmd), a->width, a->height, a->x, a->y,
249 a->chromakey,a->clipcount);
250 break;
251 }
252 case VIDIOC_PREVIEW:
253 {
254 int *a = arg;
255
256 fprintf(stderr,PREFIX "VIDIOC_PREVIEW(%s)",*a ? "on" : "off");
257 break;
258 }
259
260 case VIDIOC_QUERYCTRL:
261 {
262 struct v4l2_queryctrl *a = arg;
263
264 fprintf(stderr,PREFIX "VIDIOC_QUERYCTRL(id=%d,%s,%d-%d/%d,def=%d,"
265 "type=%d,flags=0x%x)",
266 a->id,a->name,a->minimum,a->maximum,a->step,
267 a->default_value,a->type,a->flags);
268 break;
269 }
270 case VIDIOC_QUERYMENU:
271 {
272 struct v4l2_querymenu *a = arg;
273
274 fprintf(stderr,PREFIX "VIDIOC_QUERYMENU(id=%d,index=%d,%s)",
275 a->id,a->index,a->name);
276 break;
277 }
278 case VIDIOC_G_CTRL:
279 case VIDIOC_S_CTRL:
280 {
281 struct v4l2_control *a = arg;
282
283 fprintf(stderr,PREFIX "VIDIOC_%s(id=%d,value=%d)",
284 IONAME(cmd),a->id,a->value);
285 break;
286 }
287
288 default:
289 fprintf(stderr,PREFIX "VIDIOC_%s(cmd=0x%x)",IONAME(cmd),cmd);
290 break;
291 }
292 fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno));
293 return rc;
294 }
295
296 static void
297 print_bits(char *title, char **names, int count, int value)
298 {
299 int i;
300
301 fprintf(stderr,"%s: ",title);
302 for (i = 0; i < count; i++) {
303 if (value & (1 << i))
304 fprintf(stderr,"%s ",names[i]);
305 }
306 fprintf(stderr,"\n");
307 }
308
309 static void
310 print_device_capabilities(struct v4l2_handle *h)
311 {
312 static char *cap_type[] = {
313 "capture",
314 "codec",
315 "output",
316 "fx",
317 "vbi",
318 "vtr",
319 "vtx",
320 "radio",
321 };
322 static char *cap_flags[] = {
323 "read",
324 "write",
325 "streaming",
326 "preview",
327 "select",
328 "tuner",
329 "monochrome",
330 "teletext"
331 };
332 static char *ctl_type[] = {
333 "integer",
334 "boolean",
335 "menu"
336 };
337 static char *cap_parm[] = {
338 "highquality",
339 "vflip",
340 "hflip"
341 };
342
343 unsigned int i;
344
345 fprintf(stderr,"\n*** v4l2: video device capabilities ***\n");
346
347 /* capabilities */
348 fprintf(stderr, "type: %s\n", h->cap.type < SDIMOF(cap_type)
349 ? cap_type[h->cap.type] : "unknown");
350 print_bits("flags",cap_flags,DIMOF(cap_flags),h->cap.flags);
351 fprintf(stderr,"\n");
352 fprintf(stderr,"inputs: %d\naudios: %d\n",h->cap.inputs,h->cap.audios);
353 fprintf(stderr,"size: %dx%d => %dx%d\n",
354 h->cap.minwidth,h->cap.minheight,h->cap.maxwidth,h->cap.maxheight);
355 fprintf(stderr,"fps: %d max\n",h->cap.maxframerate);
356
357 /* inputs */
358 fprintf(stderr,"video inputs:\n");
359 for (i = 0; i < h->ninputs; i++) {
360 printf(" %d: \"%s\", tuner: %s, audio: %s\n", i, h->inp[i].name,
361 (h->inp[i].type == V4L2_INPUT_TYPE_TUNER) ? "yes" : "no",
362 (h->inp[i].capability & V4L2_INPUT_CAP_AUDIO) ? "yes" : "no");
363 }
364
365 /* video standards */
366 fprintf(stderr,"video standards:\n");
367 for (i = 0; i < h->nstds; i++) {
368 printf(" %d: \"%s\"\n", i, h->std[i].std.name);
369 }
370
371 /* capture formats */
372 fprintf(stderr,"capture formats:\n");
373 for (i = 0; i < h->nfmts; i++) {
374 fprintf(stderr," %d: %c%c%c%c, depth=%d,%s \"%s\"\n", i,
375 h->fmt[i].pixelformat & 0xff,
376 (h->fmt[i].pixelformat >> 8) & 0xff,
377 (h->fmt[i].pixelformat >> 16) & 0xff,
378 (h->fmt[i].pixelformat >> 24) & 0xff,
379 h->fmt[i].depth,
380 (h->fmt[i].flags & V4L2_FMT_FLAG_COMPRESSED) ? " compressed" : "",
381 h->fmt[i].description);
382 }
383
384 /* capture parameters */
385 fprintf(stderr,"capture parameters:\n");
386 print_bits(" cap",cap_parm,sizeof(cap_parm)/sizeof(char*),
387 h->streamparm.parm.capture.capability);
388 print_bits(" cur",cap_parm,sizeof(cap_parm)/sizeof(char*),
389 h->streamparm.parm.capture.capturemode);
390 fprintf(stderr," timeperframe=%ld\n",
391 h->streamparm.parm.capture.timeperframe);
392
393 /* controls */
394 fprintf(stderr,"supported controls:\n");
395 for (i = 0; i < MAX_CTRL*2; i++) {
396 if (h->ctl[i].id == UNSET)
397 continue;
398 fprintf(stderr," %2d: \"%s\", [%d .. %d], step=%d, def=%d, type=%s\n",
399 i, h->ctl[i].name,
400 h->ctl[i].minimum,h->ctl[i].maximum,
401 h->ctl[i].step,h->ctl[i].default_value,
402 ctl_type[h->ctl[i].type]);
403 }
404 fprintf(stderr,"\n");
405 }
406
407 static void
408 print_bufinfo(struct v4l2_buffer *buf)
409 {
410 static char *type[] = {
411 "",
412 "capture",
413 "codec in",
414 "codec out",
415 "effects in1",
416 "effects in2",
417 "effects out",
418 "video out"
419 };
420
421 fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n",
422 buf->index,
423 buf->type < sizeof(type)/sizeof(char*) ?
424 type[buf->type] : "unknown",
425 buf->offset,buf->length,buf->bytesused);
426 }
427
428 static void
429 print_fbinfo(struct v4l2_framebuffer *fb)
430 {
431 static char *fb_cap[] = {
432 "extern",
433 "chromakey",
434 "clipping",
435 "scale-up",
436 "scale-down"
437 };
438 static char *fb_flags[] = {
439 "primary",
440 "overlay",
441 "chromakey"
442 };
443
444 /* capabilities */
445 fprintf(stderr,"v4l2: framebuffer info\n");
446 print_bits(" cap",fb_cap,sizeof(fb_cap)/sizeof(char*),fb->capability);
447 print_bits(" flags",fb_cap,sizeof(fb_flags)/sizeof(char*),fb->flags);
448 fprintf(stderr," base: %p %p %p\n",fb->base[0],fb->base[1],fb->base[2]);
449 fprintf(stderr," format: %dx%d, %c%c%c%c, %d byte\n",
450 fb->fmt.width, fb->fmt.height,
451 fb->fmt.pixelformat & 0xff,
452 (fb->fmt.pixelformat >> 8) & 0xff,
453 (fb->fmt.pixelformat >> 16) & 0xff,
454 (fb->fmt.pixelformat >> 24) & 0xff,
455 fb->fmt.sizeimage);
456 }
457
458 /* ---------------------------------------------------------------------- */
459 /* helpers */
460
461 static void
462 get_device_capabilities(struct v4l2_handle *h)
463 {
464 unsigned int i;
465
466 for (h->ninputs = 0; h->ninputs < h->cap.inputs; h->ninputs++) {
467 h->inp[h->ninputs].index = h->ninputs;
468 if (-1 == xioctl(h->fd, VIDIOC_ENUMINPUT, &h->inp[h->ninputs], 0))
469 break;
470 }
471 for (h->nstds = 0; h->nstds < MAX_NORM; h->nstds++) {
472 h->std[h->nstds].index = h->nstds;
473 if (-1 == xioctl(h->fd, VIDIOC_ENUMSTD, &h->std[h->nstds], EINVAL))
474 break;
475 }
476 for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) {
477 h->fmt[h->nfmts].index = h->nfmts;
478 if (-1 == xioctl(h->fd, VIDIOC_ENUM_PIXFMT, &h->fmt[h->nfmts], EINVAL))
479 break;
480 }
481
482 h->streamparm.type = V4L2_BUF_TYPE_CAPTURE;
483 ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm);
484
485 /* controls */
486 for (i = 0; i < MAX_CTRL; i++) {
487 h->ctl[i].id = V4L2_CID_BASE+i;
488 if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) ||
489 (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED))
490 h->ctl[i].id = -1;
491 }
492 for (i = 0; i < MAX_CTRL; i++) {
493 h->ctl[i+MAX_CTRL].id = V4L2_CID_PRIVATE_BASE+i;
494 if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i+MAX_CTRL], EINVAL) ||
495 (h->ctl[i+MAX_CTRL].flags & V4L2_CTRL_FLAG_DISABLED))
496 h->ctl[i+MAX_CTRL].id = -1;
497 }
498 }
499
500 static struct STRTAB *
501 build_norms(struct v4l2_handle *h)
502 {
503 struct STRTAB *norms;
504 unsigned int i;
505
506 norms = malloc(sizeof(struct STRTAB) * (h->nstds+1));
507 for (i = 0; i < h->nstds; i++) {
508 norms[i].nr = i;
509 norms[i].str = h->std[i].std.name;
510 }
511 norms[i].nr = -1;
512 norms[i].str = NULL;
513 return norms;
514 }
515
516 static struct STRTAB *
517 build_inputs(struct v4l2_handle *h)
518 {
519 struct STRTAB *inputs;
520 unsigned int i;
521
522 inputs = malloc(sizeof(struct STRTAB) * (h->ninputs+1));
523 for (i = 0; i < h->ninputs; i++) {
524 inputs[i].nr = i;
525 inputs[i].str = h->inp[i].name;
526 }
527 inputs[i].nr = -1;
528 inputs[i].str = NULL;
529 return inputs;
530 }
531
532 /* ---------------------------------------------------------------------- */
533
534 static struct V4L2_ATTR {
535 unsigned int id;
536 unsigned int v4l2;
537 } v4l2_attr[] = {
538 { ATTR_ID_VOLUME, V4L2_CID_AUDIO_VOLUME },
539 { ATTR_ID_MUTE, V4L2_CID_AUDIO_MUTE },
540 { ATTR_ID_COLOR, V4L2_CID_SATURATION },
541 { ATTR_ID_BRIGHT, V4L2_CID_BRIGHTNESS },
542 { ATTR_ID_HUE, V4L2_CID_HUE },
543 { ATTR_ID_CONTRAST, V4L2_CID_CONTRAST },
544 };
545 #define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR))
546
547 static struct STRTAB*
548 v4l2_menu(int fd, const struct v4l2_queryctrl *ctl)
549 {
550 struct STRTAB *menu;
551 struct v4l2_querymenu item;
552 int i;
553
554 menu = malloc(sizeof(struct STRTAB) * (ctl->maximum-ctl->minimum+2));
555 for (i = ctl->minimum; i <= ctl->maximum; i++) {
556 item.id = ctl->id;
557 item.index = i;
558 if (-1 == xioctl(fd, VIDIOC_QUERYMENU, &item, 0)) {
559 free(menu);
560 return NULL;
561 }
562 menu[i-ctl->minimum].nr = i;
563 menu[i-ctl->minimum].str = strdup(item.name);
564 }
565 menu[i-ctl->minimum].nr = -1;
566 menu[i-ctl->minimum].str = NULL;
567 return menu;
568 }
569
570 static void
571 v4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl,
572 int id, struct STRTAB *choices)
573 {
574 static int private_ids = ATTR_ID_COUNT;
575 unsigned int i;
576
577 h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute));
578 memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2);
579 if (ctl) {
580 for (i = 0; i < NUM_ATTR; i++)
581 if (v4l2_attr[i].v4l2 == ctl->id)
582 break;
583 if (i != NUM_ATTR) {
584 h->attr[h->nattr].id = v4l2_attr[i].id;
585 } else {
586 h->attr[h->nattr].id = private_ids++;
587 }
588 h->attr[h->nattr].name = ctl->name;
589 h->attr[h->nattr].priv = ctl;
590 h->attr[h->nattr].defval = ctl->default_value;
591 switch (ctl->type) {
592 case V4L2_CTRL_TYPE_INTEGER:
593 h->attr[h->nattr].type = ATTR_TYPE_INTEGER;
594 h->attr[h->nattr].defval = ctl->default_value;
595 h->attr[h->nattr].min = ctl->minimum;
596 h->attr[h->nattr].max = ctl->maximum;
597 break;
598 case V4L2_CTRL_TYPE_BOOLEAN:
599 h->attr[h->nattr].type = ATTR_TYPE_BOOL;
600 break;
601 case V4L2_CTRL_TYPE_MENU:
602 h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
603 h->attr[h->nattr].choices = v4l2_menu(h->fd, ctl);
604 break;
605 default:
606 return;
607 }
608 } else {
609 /* for norms + inputs */
610 h->attr[h->nattr].id = id;
611 h->attr[h->nattr].defval = 0;
612 h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
613 h->attr[h->nattr].choices = choices;
614 }
615 if (h->attr[h->nattr].id < ATTR_ID_COUNT)
616 h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id];
617
618 h->attr[h->nattr].read = v4l2_read_attr;
619 h->attr[h->nattr].write = v4l2_write_attr;
620 h->attr[h->nattr].handle = h;
621 h->nattr++;
622 }
623
624 static int v4l2_read_attr(struct ng_attribute *attr)
625 {
626 struct v4l2_handle *h = attr->handle;
627 const struct v4l2_queryctrl *ctl = attr->priv;
628 struct v4l2_control c;
629 struct v4l2_tuner tuner;
630 int value = 0;
631
632 if (NULL != ctl) {
633 c.id = ctl->id;
634 xioctl(h->fd,VIDIOC_G_CTRL,&c,0);
635 value = c.value;
636
637 } else if (attr->id == ATTR_ID_NORM) {
638 value = -1; /* FIXME */
639
640 } else if (attr->id == ATTR_ID_INPUT) {
641 xioctl(h->fd,VIDIOC_G_INPUT,&value,0);
642
643 } else if (attr->id == ATTR_ID_AUDIO_MODE) {
644 memset(&tuner,0,sizeof(tuner));
645 xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
646 value = tuner.audmode;
647 #if 1
648 if (ng_debug) {
649 fprintf(stderr,"v4l2: tuner cap:%s%s%s\n",
650 (tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "",
651 (tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "",
652 (tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : "");
653 fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n",
654 (tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "",
655 (tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "",
656 (tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "",
657 (tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : "");
658 fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n",
659 (tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "",
660 (tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "",
661 (tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "",
662 (tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : "");
663 }
664 #endif
665 }
666 return value;
667 }
668
669 static void v4l2_write_attr(struct ng_attribute *attr, int value)
670 {
671 struct v4l2_handle *h = attr->handle;
672 const struct v4l2_queryctrl *ctl = attr->priv;
673 struct v4l2_control c;
674 struct v4l2_tuner tuner;
675
676 if (NULL != ctl) {
677 c.id = ctl->id;
678 c.value = value;
679 xioctl(h->fd,VIDIOC_S_CTRL,&c,0);
680
681 } else if (attr->id == ATTR_ID_NORM) {
682 xioctl(h->fd,VIDIOC_S_STD,&h->std[value].std,0);
683
684 } else if (attr->id == ATTR_ID_INPUT) {
685 xioctl(h->fd,VIDIOC_S_INPUT,&value,0);
686
687 } else if (attr->id == ATTR_ID_AUDIO_MODE) {
688 memset(&tuner,0,sizeof(tuner));
689 xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
690 tuner.audmode = value;
691 xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0);
692 }
693 }
694
695 /* ---------------------------------------------------------------------- */
696
697 static void*
698 v4l2_open(char *device)
699 {
700 struct v4l2_handle *h;
701 int i;
702
703 h = malloc(sizeof(*h));
704 if (NULL == h)
705 return NULL;
706 memset(h,0,sizeof(*h));
707
708 if (-1 == (h->fd = open(device, O_RDWR))) {
709 fprintf(stderr,"v4l2: open %s: %s\n",device,strerror(errno));
710 goto err;
711 }
712
713 if (-1 == ioctl(h->fd,VIDIOC_QUERYCAP,&h->cap))
714 goto err;
715 if (ng_debug)
716 fprintf(stderr, "v4l2: open\n");
717 fcntl(h->fd,F_SETFD,FD_CLOEXEC);
718 if (ng_debug)
719 fprintf(stderr,"v4l2: device is %s\n",h->cap.name);
720
721 get_device_capabilities(h);
722 if (ng_debug)
723 print_device_capabilities(h);
724
725 /* attributes */
726 v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h));
727 v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h));
728 if (h->cap.flags & V4L2_FLAG_TUNER)
729 v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo);
730 for (i = 0; i < MAX_CTRL*2; i++) {
731 if (h->ctl[i].id == UNSET)
732 continue;
733 v4l2_add_attr(h, &h->ctl[i], 0, NULL);
734 }
735
736 /* capture buffers */
737 for (i = 0; i < WANTED_BUFFERS; i++) {
738 ng_init_video_buf(h->buf_me+i);
739 h->buf_me[i].release = ng_wakeup_video_buf;
740 }
741
742 return h;
743
744 err:
745 if (h->fd != -1)
746 close(h->fd);
747 if (h)
748 free(h);
749 return NULL;
750 }
751
752 static int
753 v4l2_close(void *handle)
754 {
755 struct v4l2_handle *h = handle;
756
757 if (ng_debug)
758 fprintf(stderr, "v4l2: close\n");
759
760 close(h->fd);
761 free(h);
762 return 0;
763 }
764
765 static char*
766 v4l2_devname(void *handle)
767 {
768 struct v4l2_handle *h = handle;
769 return h->cap.name;
770 }
771
772 static int v4l2_flags(void *handle)
773 {
774 struct v4l2_handle *h = handle;
775 int ret = 0;
776
777 if (h->cap.flags & V4L2_FLAG_PREVIEW && !h->ov_error)
778 ret |= CAN_OVERLAY;
779 if ((h->cap.flags & V4L2_FLAG_STREAMING) ||
780 (h->cap.flags & V4L2_FLAG_READ))
781 ret |= CAN_CAPTURE;
782 if (h->cap.flags & V4L2_FLAG_TUNER)
783 ret |= CAN_TUNE;
784 return ret;
785 }
786
787 static struct ng_attribute* v4l2_attrs(void *handle)
788 {
789 struct v4l2_handle *h = handle;
790 return h->attr;
791 }
792
793 /* ---------------------------------------------------------------------- */
794
795 static unsigned long
796 v4l2_getfreq(void *handle)
797 {
798 struct v4l2_handle *h = handle;
799 unsigned long freq;
800
801 xioctl(h->fd, VIDIOC_G_FREQ, &freq, 0);
802 return freq;
803 }
804
805 static void
806 v4l2_setfreq(void *handle, unsigned long freq)
807 {
808 struct v4l2_handle *h = handle;
809
810 if (ng_debug)
811 fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16);
812 xioctl(h->fd, VIDIOC_S_FREQ, &freq, 0);
813 }
814
815 static int
816 v4l2_tuned(void *handle)
817 {
818 struct v4l2_handle *h = handle;
819 struct v4l2_tuner tuner;
820
821 usleep(10000);
822 if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0))
823 return 0;
824 return tuner.signal ? 1 : 0;
825 }
826
827 /* ---------------------------------------------------------------------- */
828 /* overlay */
829
830 static int
831 v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base)
832 {
833 struct v4l2_handle *h = handle;
834
835 if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0))
836 return -1;
837
838 if (1 /* ng_debug */)
839 print_fbinfo(&h->ov_fb);
840
841 /* double-check settings */
842 if (NULL != base && h->ov_fb.base[0] != base) {
843 fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n");
844 fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base);
845 h->ov_error = 1;
846 return -1;
847 }
848 if (h->ov_fb.fmt.width != fmt->width ||
849 h->ov_fb.fmt.height != fmt->height) {
850 fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n");
851 fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n",
852 fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height);
853 h->ov_error = 1;
854 return -1;
855 }
856 if ((h->ov_fb.fmt.flags & V4L2_FMT_FLAG_BYTESPERLINE) &&
857 fmt->bytesperline > 0 &&
858 fmt->bytesperline != h->ov_fb.fmt.bytesperline) {
859 fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n");
860 fprintf(stderr,"v4l2: me=%d v4l=%d\n",
861 fmt->bytesperline,h->ov_fb.fmt.bytesperline);
862 h->ov_error = 1;
863 return -1;
864 }
865 #if 0
866 if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) {
867 fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n");
868 fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n",
869 xawtv_pixelformat[fmt->fmtid] & 0xff,
870 (xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff,
871 (xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff,
872 (xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff,
873 ng_vfmt_to_desc[fmt->fmtid],
874 h->ov_fb.fmt.pixelformat & 0xff,
875 (h->ov_fb.fmt.pixelformat >> 8) & 0xff,
876 (h->ov_fb.fmt.pixelformat >> 16) & 0xff,
877 (h->ov_fb.fmt.pixelformat >> 24) & 0xff);
878 h->ov_error = 1;
879 return -1;
880 }
881 #endif
882 return 0;
883 }
884
885 static int
886 v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
887 struct OVERLAY_CLIP *oc, int count, int aspect)
888 {
889 struct v4l2_handle *h = handle;
890 int rc,i;
891
892 if (h->ov_error)
893 return -1;
894
895 if (NULL == fmt) {
896 if (ng_debug)
897 fprintf(stderr,"v4l2: overlay off\n");
898 if (h->ov_enabled) {
899 h->ov_enabled = 0;
900 h->ov_on = 0;
901 xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
902 }
903 return 0;
904 }
905
906 if (ng_debug)
907 fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n",
908 fmt->width,fmt->height,x,y,count);
909 h->ov_win.x = x;
910 h->ov_win.y = y;
911 h->ov_win.width = fmt->width;
912 h->ov_win.height = fmt->height;
913
914 /* check against max. size */
915 ioctl(h->fd,VIDIOC_QUERYCAP,&h->cap);
916 if (h->ov_win.width > h->cap.maxwidth) {
917 h->ov_win.width = h->cap.maxwidth;
918 h->ov_win.x += (fmt->width - h->ov_win.width)/2;
919 }
920 if (h->ov_win.height > h->cap.maxheight) {
921 h->ov_win.height = h->cap.maxheight;
922 h->ov_win.y += (fmt->height - h->ov_win.height)/2;
923 }
924 if (aspect)
925 ng_ratio_fixup(&h->ov_win.width,&h->ov_win.height,
926 &h->ov_win.x,&h->ov_win.y);
927
928 /* fixups */
929 ng_check_clipping(h->ov_win.width, h->ov_win.height,
930 x - h->ov_win.x, y - h->ov_win.y,
931 oc, &count);
932
933 if (h->ov_fb.capability & V4L2_FBUF_CAP_CLIPPING) {
934 h->ov_win.clips = h->ov_clips;
935 h->ov_win.clipcount = count;
936
937 for (i = 0; i < count; i++) {
938 h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1];
939 h->ov_clips[i].x = oc[i].x1;
940 h->ov_clips[i].y = oc[i].y1;
941 h->ov_clips[i].width = oc[i].x2-oc[i].x1;
942 h->ov_clips[i].height = oc[i].y2-oc[i].y1;
943 }
944 }
945 #if 0
946 if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) {
947 h->ov_win.chromakey = 0; /* FIXME */
948 }
949 #endif
950 rc = xioctl(h->fd, VIDIOC_S_WIN, &h->ov_win, 0);
951
952 h->ov_enabled = (0 == rc) ? 1 : 0;
953 h->ov_on = (0 == rc) ? 1 : 0;
954 xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
955
956 return 0;
957 }
958
959 /* ---------------------------------------------------------------------- */
960 /* capture helpers */
961
962 static int
963 v4l2_queue_buffer(struct v4l2_handle *h)
964 {
965 int frame = h->queue % h->reqbufs.count;
966 int rc;
967
968 if (0 != h->buf_me[frame].refcount) {
969 if (0 != h->queue - h->waiton)
970 return -1;
971 fprintf(stderr,"v4l2: waiting for a free buffer\n");
972 ng_waiton_video_buf(h->buf_me+frame);
973 }
974
975 rc = xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[frame], 0);
976 if (0 == rc)
977 h->queue++;
978 return rc;
979 }
980
981 static void
982 v4l2_queue_all(struct v4l2_handle *h)
983 {
984 for (;;) {
985 if (h->queue - h->waiton >= h->reqbufs.count)
986 return;
987 if (0 != v4l2_queue_buffer(h))
988 return;
989 }
990 }
991
992 static int
993 v4l2_waiton(struct v4l2_handle *h)
994 {
995 struct v4l2_buffer buf;
996 struct timeval tv;
997 fd_set rdset;
998
999 /* wait for the next frame */
1000 again:
1001 tv.tv_sec = 5;
1002 tv.tv_usec = 0;
1003 FD_ZERO(&rdset);
1004 FD_SET(h->fd, &rdset);
1005 switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) {
1006 case -1:
1007 if (EINTR == errno)
1008 goto again;
1009 perror("v4l2: select");
1010 return -1;
1011 case 0:
1012 fprintf(stderr,"v4l2: oops: select timeout\n");
1013 return -1;
1014 }
1015
1016 /* get it */
1017 memset(&buf,0,sizeof(buf));
1018 buf.type = V4L2_BUF_TYPE_CAPTURE;
1019 if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0))
1020 return -1;
1021 h->waiton++;
1022 h->buf_v4l2[buf.index] = buf;
1023 return buf.index;
1024 }
1025
1026 static int
1027 v4l2_start_streaming(struct v4l2_handle *h, int buffers)
1028 {
1029 int disable_overlay = 0;
1030 int i;
1031
1032 /* setup buffers */
1033 h->reqbufs.count = buffers;
1034 h->reqbufs.type = V4L2_BUF_TYPE_CAPTURE;
1035 if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0))
1036 return -1;
1037 for (i = 0; i < h->reqbufs.count; i++) {
1038 h->buf_v4l2[i].index = i;
1039 h->buf_v4l2[i].type = V4L2_BUF_TYPE_CAPTURE;
1040 if (-1 == ioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i]))
1041 return -1;
1042 h->buf_me[i].fmt = h->fmt_me;
1043 h->buf_me[i].size = h->buf_me[i].fmt.bytesperline *
1044 h->buf_me[i].fmt.height;
1045 h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length,
1046 PROT_READ | PROT_WRITE, MAP_SHARED,
1047 h->fd, h->buf_v4l2[i].offset);
1048 if ((void*)-1 == h->buf_me[i].data) {
1049 perror("mmap");
1050 return -1;
1051 }
1052 if (ng_debug)
1053 print_bufinfo(&h->buf_v4l2[i]);
1054 }
1055
1056 /* queue up all buffers */
1057 v4l2_queue_all(h);
1058
1059 try_again:
1060 /* turn off preview (if needed) */
1061 if (disable_overlay) {
1062 h->ov_on = 0;
1063 xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
1064 if (ng_debug)
1065 fprintf(stderr,"v4l2: overlay off (start_streaming)\n");
1066 }
1067
1068 /* start capture */
1069 if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type,
1070 h->ov_on ? EBUSY : 0)) {
1071 if (h->ov_on && errno == EBUSY) {
1072 disable_overlay = 1;
1073 goto try_again;
1074 }
1075 return -1;
1076 }
1077 return 0;
1078 }
1079
1080 static void
1081 v4l2_stop_streaming(struct v4l2_handle *h)
1082 {
1083 int i;
1084
1085 /* stop capture */
1086 if (-1 == ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type))
1087 perror("ioctl VIDIOC_STREAMOFF");
1088
1089 /* free buffers */
1090 for (i = 0; i < h->reqbufs.count; i++) {
1091 if (0 != h->buf_me[i].refcount)
1092 ng_waiton_video_buf(&h->buf_me[i]);
1093 if (-1 == munmap(h->buf_me[i].data,h->buf_me[i].size))
1094 perror("munmap");
1095 }
1096 h->queue = 0;
1097 h->waiton = 0;
1098
1099 /* turn on preview (if needed) */
1100 if (h->ov_on != h->ov_enabled) {
1101 h->ov_on = h->ov_enabled;
1102 xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
1103 if (ng_debug)
1104 fprintf(stderr,"v4l2: overlay on (stop_streaming)\n");
1105 }
1106 }
1107
1108 /* ---------------------------------------------------------------------- */
1109 /* capture interface */
1110
1111 /* set capture parameters */
1112 static int
1113 v4l2_setformat(void *handle, struct ng_video_fmt *fmt)
1114 {
1115 struct v4l2_handle *h = handle;
1116
1117 h->fmt_v4l2.type = V4L2_BUF_TYPE_CAPTURE;
1118 h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid];
1119 h->fmt_v4l2.fmt.pix.flags = V4L2_FMT_FLAG_INTERLACED;
1120 h->fmt_v4l2.fmt.pix.depth = ng_vfmt_to_depth[fmt->fmtid];
1121 h->fmt_v4l2.fmt.pix.width = fmt->width;
1122 h->fmt_v4l2.fmt.pix.height = fmt->height;
1123 h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline;
1124
1125 if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL))
1126 return -1;
1127 if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid])
1128 return -1;
1129 fmt->width = h->fmt_v4l2.fmt.pix.width;
1130 fmt->height = h->fmt_v4l2.fmt.pix.height;
1131 fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline;
1132 if (0 == fmt->bytesperline)
1133 fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
1134 h->fmt_me = *fmt;
1135 if (ng_debug)
1136 fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n",
1137 fmt->width,fmt->height,
1138 h->fmt_v4l2.fmt.pix.pixelformat & 0xff,
1139 (h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff,
1140 (h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff,
1141 (h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff,
1142 h->fmt_v4l2.fmt.pix.sizeimage);
1143 return 0;
1144 }
1145
1146 /* start/stop video */
1147 static int
1148 v4l2_startvideo(void *handle, int fps, unsigned int buffers)
1149 {
1150 struct v4l2_handle *h = handle;
1151
1152 if (0 != h->fps)
1153 fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n");
1154 h->fps = fps;
1155 h->first = 1;
1156 h->start = 0;
1157
1158 if (h->cap.flags & V4L2_FLAG_STREAMING)
1159 return v4l2_start_streaming(h,buffers);
1160 return 0;
1161 }
1162
1163 static void
1164 v4l2_stopvideo(void *handle)
1165 {
1166 struct v4l2_handle *h = handle;
1167
1168 if (0 == h->fps)
1169 fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n");
1170 h->fps = 0;
1171
1172 if (h->cap.flags & V4L2_FLAG_STREAMING)
1173 v4l2_stop_streaming(h);
1174 }
1175
1176 /* read images */
1177 static struct ng_video_buf*
1178 v4l2_nextframe(void *handle)
1179 {
1180 struct v4l2_handle *h = handle;
1181 struct ng_video_buf *buf = NULL;
1182 int rc,size,frame = 0;
1183
1184 if (h->cap.flags & V4L2_FLAG_STREAMING) {
1185 v4l2_queue_all(h);
1186 frame = v4l2_waiton(h);
1187 if (-1 == frame)
1188 return NULL;
1189 h->buf_me[frame].refcount++;
1190 buf = &h->buf_me[frame];
1191 memset(&buf->info,0,sizeof(buf->info));
1192 buf->info.ts = h->buf_v4l2[frame].timestamp;
1193 } else {
1194 size = h->fmt_me.bytesperline * h->fmt_me.height;
1195 buf = ng_malloc_video_buf(&h->fmt_me,size);
1196 rc = read(h->fd,buf->data,size);
1197 if (rc != size) {
1198 if (-1 == rc) {
1199 perror("v4l2: read");
1200 } else {
1201 fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
1202 }
1203 ng_release_video_buf(buf);
1204 return NULL;
1205 }
1206 memset(&buf->info,0,sizeof(buf->info));
1207 buf->info.ts = ng_get_timestamp();
1208 }
1209
1210 if (h->first) {
1211 h->first = 0;
1212 h->start = buf->info.ts;
1213 if (ng_debug)
1214 fprintf(stderr,"v4l2: start ts=%lld\n",h->start);
1215 }
1216 buf->info.ts -= h->start;
1217 return buf;
1218 }
1219
1220 static struct ng_video_buf*
1221 v4l2_getimage(void *handle)
1222 {
1223 struct v4l2_handle *h = handle;
1224 struct ng_video_buf *buf;
1225 int size,frame,rc;
1226
1227 size = h->fmt_me.bytesperline * h->fmt_me.height;
1228 buf = ng_malloc_video_buf(&h->fmt_me,size);
1229 if (h->cap.flags & V4L2_FLAG_READ) {
1230 rc = read(h->fd,buf->data,size);
1231 if (rc != size) {
1232 if (-1 == rc) {
1233 perror("v4l2: read");
1234 } else {
1235 fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
1236 }
1237 ng_release_video_buf(buf);
1238 return NULL;
1239 }
1240 } else {
1241 if (-1 == v4l2_start_streaming(h,1)) {
1242 v4l2_stop_streaming(h);
1243 return NULL;
1244 }
1245 frame = v4l2_waiton(h);
1246 if (-1 == frame) {
1247 v4l2_stop_streaming(h);
1248 return NULL;
1249 }
1250 memcpy(buf->data,h->buf_me[0].data,size);
1251 v4l2_stop_streaming(h);
1252 }
1253 return buf;
1254 }
1255
1256 /* ---------------------------------------------------------------------- */
1257
1258 extern void ng_plugin_init(void);
1259 void ng_plugin_init(void)
1260 {
1261 ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver);
1262 }
1263
|
This page was automatically generated by the
LXR engine.
|