Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.