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-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.