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 v4l driver
  3  *
  4  *   (c) 1997-2001 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 <pthread.h>
 18 #include <sys/types.h>
 19 #include <sys/time.h>
 20 #include <sys/ioctl.h>
 21 #include <sys/stat.h>
 22 #include <sys/mman.h>
 23 
 24 #include "videodev.h"
 25 
 26 #include "grab-ng.h"
 27 
 28 #include "struct-dump.h"
 29 #include "struct-v4l.h"
 30 
 31 #define SYNC_TIMEOUT 5
 32 
 33 /* ---------------------------------------------------------------------- */
 34 
 35 /* open+close */
 36 static void*   v4l_open(char *device);
 37 static int     v4l_close(void *handle);
 38 
 39 /* attributes */
 40 static char*   v4l_devname(void *handle);
 41 static int     v4l_flags(void *handle);
 42 static struct ng_attribute* v4l_attrs(void *handle);
 43 static int     v4l_read_attr(struct ng_attribute*);
 44 static void    v4l_write_attr(struct ng_attribute*, int val);
 45 
 46 /* overlay */
 47 static int   v4l_setupfb(void *handle, struct ng_video_fmt *fmt, void *base);
 48 static int   v4l_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
 49                          struct OVERLAY_CLIP *oc, int count, int aspect);
 50 
 51 /* capture video */
 52 static int v4l_setformat(void *handle, struct ng_video_fmt *fmt);
 53 static int v4l_startvideo(void *handle, int fps, unsigned int buffers);
 54 static void v4l_stopvideo(void *handle);
 55 static struct ng_video_buf* v4l_nextframe(void *handle);
 56 static struct ng_video_buf* v4l_getimage(void *handle);
 57 
 58 /* tuner */
 59 static unsigned long v4l_getfreq(void *handle);
 60 static void v4l_setfreq(void *handle, unsigned long freq);
 61 static int v4l_tuned(void *handle);
 62 
 63 /* ---------------------------------------------------------------------- */
 64 
 65 static const char *device_cap[] = {
 66     "capture", "tuner", "teletext", "overlay", "chromakey", "clipping",
 67     "frameram", "scales", "monochrome", NULL
 68 };
 69 
 70 static const char *device_pal[] = {
 71     "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15",
 72     "yuv422", "yuyv", "uyvy", "yuv420", "yuv411", "raw",
 73     "yuv422p", "yuv411p", "yuv420p", "yuv410p"
 74 };
 75 #define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN")
 76 
 77 static struct STRTAB stereo[] = {
 78     {  0,                  "auto"    },
 79     {  VIDEO_SOUND_MONO,   "mono"    },
 80     {  VIDEO_SOUND_STEREO, "stereo"  },
 81     {  VIDEO_SOUND_LANG1,  "lang1"   },
 82     {  VIDEO_SOUND_LANG2,  "lang2"   },
 83     { -1, NULL },
 84 };
 85 static struct STRTAB norms_v4l[] = {
 86     {  VIDEO_MODE_PAL,     "PAL"   },
 87     {  VIDEO_MODE_NTSC,    "NTSC"  },
 88     {  VIDEO_MODE_SECAM,   "SECAM" },
 89     {  VIDEO_MODE_AUTO,    "AUTO"  },
 90     { -1, NULL }
 91 };
 92 static struct STRTAB norms_bttv[] = {
 93     {  VIDEO_MODE_PAL,   "PAL"     },
 94     {  VIDEO_MODE_NTSC,  "NTSC"    },
 95     {  VIDEO_MODE_SECAM, "SECAM"   },
 96     {  3,                "PAL-NC"  },
 97     {  4,                "PAL-M"   },
 98     {  5,                "PAL-N"   },
 99     {  6,                "NTSC-JP" },
100     { -1, NULL }
101 };
102 
103 static unsigned short format2palette[VIDEO_FMT_COUNT] = {
104     [ VIDEO_RGB08 ]    = VIDEO_PALETTE_HI240,
105     [ VIDEO_GRAY ]     = VIDEO_PALETTE_GREY,
106     [ VIDEO_RGB15_LE ] = VIDEO_PALETTE_RGB555,
107     [ VIDEO_RGB16_LE ] = VIDEO_PALETTE_RGB565,
108     [ VIDEO_BGR24 ]    = VIDEO_PALETTE_RGB24,
109     [ VIDEO_BGR32 ]    = VIDEO_PALETTE_RGB32,
110     [ VIDEO_YUYV ]     = VIDEO_PALETTE_YUV422,
111     [ VIDEO_UYVY ]     = VIDEO_PALETTE_UYVY,
112     [ VIDEO_YUV422P ]  = VIDEO_PALETTE_YUV422P,
113     [ VIDEO_YUV420P ]  = VIDEO_PALETTE_YUV420P,
114 };
115 
116 /* pass 0/1 by reference */
117 static int                      one = 1, zero = 0;
118 
119 /* ---------------------------------------------------------------------- */
120 
121 struct v4l_handle {
122     int                      fd;
123 
124     /* general informations */
125     struct video_capability  capability;
126     struct video_channel     *channels;
127     struct video_tuner       tuner;
128     struct video_audio       audio;
129     struct video_picture     pict;
130 
131     /* attributes */
132     int                      nattr;
133     struct ng_attribute      *attr;
134     int                      input;
135     int                      audio_mode;
136     
137     /* overlay */
138     struct video_buffer      fbuf;
139     struct video_window      win;
140     int                      ov_error;
141     unsigned int             ov_fmtid;
142     int                      ov_enabled;
143     int                      ov_on;
144 
145     /* capture */
146     int                      use_read;
147     struct ng_video_fmt      fmt;
148     long long                start;
149     int                      fps;
150     
151     /* capture via read() */
152     struct ng_video_fmt      rd_fmt;
153     struct video_window      rd_win;
154     unsigned int             rd_fmtid;
155     
156     /* capture to mmap()'ed buffers */
157     struct video_mbuf        mbuf;
158     unsigned char            *mmap;
159     unsigned int             nbuf;
160     unsigned int             queue;
161     unsigned int             waiton;
162     int                      probe[VIDEO_FMT_COUNT];
163     struct video_mmap        *buf_v4l;
164     struct ng_video_buf      *buf_me;
165 };
166 
167 struct ng_vid_driver v4l_driver = {
168     name:          "v4l",
169     open:          v4l_open,
170     close:         v4l_close,
171 
172     get_devname:   v4l_devname,
173     capabilities:  v4l_flags,
174     list_attrs:    v4l_attrs,
175 
176     setupfb:       v4l_setupfb,
177     overlay:       v4l_overlay,
178 
179     setformat:     v4l_setformat,
180     startvideo:    v4l_startvideo,
181     stopvideo:     v4l_stopvideo,
182     nextframe:     v4l_nextframe,
183     getimage:      v4l_getimage,
184     
185     getfreq:       v4l_getfreq,
186     setfreq:       v4l_setfreq,
187     is_tuned:      v4l_tuned,
188 };
189 
190 /* ---------------------------------------------------------------------- */
191 
192 static int alarms;
193 
194 static void
195 sigalarm(int signal)
196 {
197     alarms++;
198     fprintf(stderr,"v4l: timeout (got SIGALRM), hardware/driver problems?\n");
199 }
200 
201 static void
202 siginit(void)
203 {
204     struct sigaction act,old;
205     
206     memset(&act,0,sizeof(act));
207     act.sa_handler  = sigalarm;
208     sigemptyset(&act.sa_mask);
209     sigaction(SIGALRM,&act,&old);
210 }
211 
212 /* ---------------------------------------------------------------------- */
213 
214 #define PREFIX "ioctl: "
215 
216 static int
217 xioctl(int fd, int cmd, void *arg)
218 {
219     int rc;
220 
221     rc = ioctl(fd,cmd,arg);
222     if (0 == rc && ng_debug < 2)
223         return 0;
224     print_ioctl(stderr,ioctls_v4l1,PREFIX,cmd,arg);
225     fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno));
226     return rc;
227 }
228 
229 /* ---------------------------------------------------------------------- */
230 
231 static void
232 v4l_add_attr(struct v4l_handle *h, int id, int type,
233              int defval, struct STRTAB *choices)
234 {
235     h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute));
236     memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2);
237     h->attr[h->nattr].id      = id;
238     h->attr[h->nattr].type    = type;
239     h->attr[h->nattr].defval  = defval;
240     h->attr[h->nattr].choices = choices;
241     if (ATTR_TYPE_INTEGER == type) {
242         h->attr[h->nattr].min = 0;
243         h->attr[h->nattr].max = 65535;
244     }
245     if (id < ATTR_ID_COUNT)
246         h->attr[h->nattr].name = ng_attr_to_desc[id];
247 
248     h->attr[h->nattr].read    = v4l_read_attr;
249     h->attr[h->nattr].write   = v4l_write_attr;
250     h->attr[h->nattr].handle  = h;
251     h->nattr++;
252 }
253 
254 static void*
255 v4l_open(char *device)
256 {
257     struct v4l_handle *h;
258     struct STRTAB *inputs;
259     struct STRTAB *norms;
260     unsigned int i;
261     int rc;
262 
263     h = malloc(sizeof(*h));
264     if (NULL == h)
265         return NULL;
266     memset(h,0,sizeof(*h));
267 
268     /* open device */
269     if (-1 == (h->fd = open(device,O_RDWR))) {
270         fprintf(stderr,"v4l: open %s: %s\n",device,strerror(errno));
271         goto err;
272     }
273     if (-1 == ioctl(h->fd,VIDIOCGCAP,&h->capability))
274         goto err;
275 
276     if (ng_debug)
277         fprintf(stderr, "v4l: open: %s (%s)\n",device,h->capability.name);
278     fcntl(h->fd,F_SETFD,FD_CLOEXEC);
279     siginit();
280     if (ng_debug) {
281         fprintf(stderr,"  capabilities: ");
282         for (i = 0; device_cap[i] != NULL; i++)
283             if (h->capability.type & (1 << i))
284                 fprintf(stderr," %s",device_cap[i]);
285         fprintf(stderr,"\n");
286         fprintf(stderr,"  size    : %dx%d => %dx%d\n",
287                 h->capability.minwidth,h->capability.minheight,
288                 h->capability.maxwidth,h->capability.maxheight);
289     }
290 
291     /* input sources */
292     if (ng_debug)
293         fprintf(stderr,"  channels: %d\n",h->capability.channels);
294     h->channels = malloc(sizeof(struct video_channel)*h->capability.channels);
295     memset(h->channels,0,sizeof(struct video_channel)*h->capability.channels);
296     inputs = malloc(sizeof(struct STRTAB)*(h->capability.channels+1));
297     memset(inputs,0,sizeof(struct STRTAB)*(h->capability.channels+1));
298     for (i = 0; i < h->capability.channels; i++) {
299         h->channels[i].channel = i;
300         xioctl(h->fd,VIDIOCGCHAN,&(h->channels[i]));
301         inputs[i].nr  = i;
302         inputs[i].str = h->channels[i].name;
303         if (ng_debug)
304             fprintf(stderr,"    %s: %d %s%s %s%s\n",
305                     h->channels[i].name,
306                     h->channels[i].tuners,
307                     (h->channels[i].flags & VIDEO_VC_TUNER)   ? "tuner "  : "",
308                     (h->channels[i].flags & VIDEO_VC_AUDIO)   ? "audio "  : "",
309                     (h->channels[i].type & VIDEO_TYPE_TV)     ? "tv "     : "",
310                     (h->channels[i].type & VIDEO_TYPE_CAMERA) ? "camera " : "");
311     }
312     inputs[i].nr  = -1;
313     inputs[i].str = NULL;
314     v4l_add_attr(h,ATTR_ID_INPUT,ATTR_TYPE_CHOICE,0,inputs);
315     
316     /* audios */
317     if (ng_debug)
318         fprintf(stderr,"  audios  : %d\n",h->capability.audios);
319     if (h->capability.audios) {
320         h->audio.audio = 0;
321         xioctl(h->fd,VIDIOCGAUDIO,&h->audio);
322         if (ng_debug) {
323             fprintf(stderr,"    %d (%s): ",i,h->audio.name);
324             if (h->audio.flags & VIDEO_AUDIO_MUTABLE)
325                 fprintf(stderr,"muted=%s ",
326                         (h->audio.flags&VIDEO_AUDIO_MUTE) ? "yes":"no");
327             if (h->audio.flags & VIDEO_AUDIO_VOLUME)
328                 fprintf(stderr,"volume=%d ",h->audio.volume);
329             if (h->audio.flags & VIDEO_AUDIO_BASS)
330                 fprintf(stderr,"bass=%d ",h->audio.bass);
331             if (h->audio.flags & VIDEO_AUDIO_TREBLE)
332                 fprintf(stderr,"treble=%d ",h->audio.treble);
333             fprintf(stderr,"\n");
334         }
335         v4l_add_attr(h,ATTR_ID_MUTE,ATTR_TYPE_BOOL,0,NULL);
336         v4l_add_attr(h,ATTR_ID_AUDIO_MODE,ATTR_TYPE_CHOICE,0,stereo);
337         if (h->audio.flags & VIDEO_AUDIO_VOLUME)
338             v4l_add_attr(h,ATTR_ID_VOLUME,ATTR_TYPE_INTEGER,0,NULL);
339     }
340 
341     /* tv norms / tuner */
342     norms = malloc(sizeof(norms_v4l));
343     memcpy(norms,norms_v4l,sizeof(norms_v4l));
344     if (h->capability.type & VID_TYPE_TUNER) {
345         /* have tuner */
346         xioctl(h->fd,VIDIOCGTUNER,&h->tuner);
347         if (ng_debug)
348             fprintf(stderr,"  tuner   : %s %lu-%lu",
349                     h->tuner.name,h->tuner.rangelow,h->tuner.rangehigh);
350         for (i = 0; norms[i].str != NULL; i++) {
351             if (h->tuner.flags & (1<<i)) {
352                 if (ng_debug)
353                     fprintf(stderr," %s",norms[i].str);
354             } else
355                 norms[i].nr = -1;
356         }
357         if (ng_debug)
358             fprintf(stderr,"\n");
359     } else {
360         /* no tuner */
361         struct video_channel vchan;
362         memcpy(&vchan, &h->channels[0], sizeof(struct video_channel));
363         for (i = 0; norms[i].str != NULL; i++) {
364             vchan.norm = i;
365             if (-1 == xioctl(h->fd,VIDIOCSCHAN,&vchan))
366                 norms[i].nr = -1;
367             else if (ng_debug)
368                 fprintf(stderr," %s",norms[i].str);
369         }
370         /* restore settings after probe */
371         memcpy(&vchan, &h->channels[0], sizeof(struct video_channel));
372         xioctl(h->fd,VIDIOCSCHAN,&vchan);
373         if (ng_debug)
374             fprintf(stderr,"\n");
375     }
376     
377 #if 1
378 #define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
379     /* dirty hack time / v4l design flaw -- works with bttv only
380      * this adds support for a few less common PAL versions */
381     if (-1 != (rc = ioctl(h->fd,BTTV_VERSION,&i))) {
382         norms = norms_bttv;
383         if (ng_debug || rc < 0x000700)
384             fprintf(stderr,"v4l: bttv version %d.%d.%d\n",
385                     (rc >> 16) & 0xff,
386                     (rc >> 8)  & 0xff,
387                     rc         & 0xff);
388         if (rc < 0x000700)
389             fprintf(stderr,
390                     "v4l: prehistoric bttv version found, please try to\n"
391                     "     upgrade the driver before mailing bug reports\n");
392     }
393 #endif
394     v4l_add_attr(h,ATTR_ID_NORM,ATTR_TYPE_CHOICE,0,norms);
395     
396     /* frame buffer */
397     xioctl(h->fd,VIDIOCGFBUF,&h->fbuf);
398     if (ng_debug)
399         fprintf(stderr,"  fbuffer : base=0x%p size=%dx%d depth=%d bpl=%d\n",
400                 h->fbuf.base, h->fbuf.width, h->fbuf.height,
401                 h->fbuf.depth, h->fbuf.bytesperline);
402 
403     /* picture parameters */
404     xioctl(h->fd,VIDIOCGPICT,&h->pict);
405     v4l_add_attr(h,ATTR_ID_BRIGHT,  ATTR_TYPE_INTEGER,0,NULL);
406     v4l_add_attr(h,ATTR_ID_HUE,     ATTR_TYPE_INTEGER,0,NULL);
407     v4l_add_attr(h,ATTR_ID_COLOR,   ATTR_TYPE_INTEGER,0,NULL);
408     v4l_add_attr(h,ATTR_ID_CONTRAST,ATTR_TYPE_INTEGER,0,NULL);
409     if (ng_debug) {
410         fprintf(stderr,
411                 "  picture : brightness=%d hue=%d colour=%d contrast=%d\n",
412                 h->pict.brightness, h->pict.hue,
413                 h->pict.colour, h->pict.contrast);
414         fprintf(stderr,
415                 "  picture : whiteness=%d depth=%d palette=%s\n",
416                 h->pict.whiteness, h->pict.depth, PALETTE(h->pict.palette));
417     }
418 
419     if (h->capability.type & VID_TYPE_CAPTURE) {
420         /* map grab buffer */
421         if (0 == xioctl(h->fd,VIDIOCGMBUF,&h->mbuf)) {
422             if (ng_debug)
423                 fprintf(stderr,"  mbuf: size=%d frames=%d\n",
424                         h->mbuf.size,h->mbuf.frames);
425             h->mmap = mmap(0,h->mbuf.size,PROT_READ|PROT_WRITE,
426                            MAP_SHARED,h->fd,0);
427             if ((unsigned char*)-1 == h->mmap)
428                 perror("mmap");
429         } else {
430             h->mmap = (unsigned char*)-1;
431         }
432         if ((unsigned char*)-1 != h->mmap) {
433             if (ng_debug)
434                 fprintf(stderr,"  v4l: using mapped buffers for capture\n");
435             h->use_read = 0;
436             h->nbuf = h->mbuf.frames;
437             h->buf_v4l = malloc(h->nbuf * sizeof(struct video_mmap));
438             memset(h->buf_v4l,0,h->nbuf * sizeof(struct video_mmap));
439             h->buf_me = malloc(h->nbuf * sizeof(struct ng_video_buf));
440             for (i = 0; i < h->nbuf; i++) {
441                 ng_init_video_buf(h->buf_me+i);
442                 h->buf_me[i].release = ng_wakeup_video_buf;
443             }
444         } else {
445             if (ng_debug)
446                 fprintf(stderr,"  v4l: using read() for capture\n");
447             h->use_read = 1;
448         }
449     }
450 
451     return h;
452 
453 err:
454     if (h->fd != -1)
455         close(h->fd);
456     free(h);
457     return NULL;
458 }
459 
460 static int
461 v4l_close(void *handle)
462 {
463     struct v4l_handle *h = handle;
464     
465     if (ng_debug)
466         fprintf(stderr, "v4l: close\n");
467 
468     if ((unsigned char*)-1 != h->mmap)
469         munmap(h->mmap,h->mbuf.size);
470     
471     close(h->fd);
472     free(h);
473     return 0;
474 }
475 
476 /* ---------------------------------------------------------------------- */
477 
478 static char*
479 v4l_devname(void *handle)
480 {
481     struct v4l_handle *h = handle;
482     return h->capability.name;
483 }
484 
485 static int v4l_flags(void *handle)
486 {
487     struct v4l_handle *h = handle;
488     int ret = 0;
489 
490     if (h->capability.type & VID_TYPE_OVERLAY)
491         ret |= CAN_OVERLAY;
492     if (h->capability.type & VID_TYPE_CAPTURE &&
493         !h->ov_error)
494         ret |= CAN_CAPTURE;
495     if (h->capability.type & VID_TYPE_TUNER)
496         ret |= CAN_TUNE;
497     if (h->capability.type & VID_TYPE_CHROMAKEY)
498         ret |= NEEDS_CHROMAKEY;
499     return ret;
500 }
501 
502 static struct ng_attribute* v4l_attrs(void *handle)
503 {
504     struct v4l_handle *h = handle;
505     return h->attr;
506 }
507 
508 static int audio_mode_mask2bit(int mode)
509 {
510     if (mode & VIDEO_SOUND_STEREO)
511         return VIDEO_SOUND_STEREO;
512     if (mode & VIDEO_SOUND_LANG1)
513         return VIDEO_SOUND_LANG1;
514     if (mode & VIDEO_SOUND_LANG2)
515         return VIDEO_SOUND_LANG2;
516     if (mode & VIDEO_SOUND_MONO)
517         return VIDEO_SOUND_MONO;
518     return 0;
519 }
520 
521 static int v4l_read_attr(struct ng_attribute *attr)
522 {
523     struct v4l_handle *h = attr->handle;
524 
525     switch (attr->id) {
526     case ATTR_ID_INPUT:
527         return -1;
528     case ATTR_ID_NORM:
529         xioctl(h->fd, VIDIOCGCHAN, &h->channels[h->input]);
530         return h->channels[h->input].norm;
531     case ATTR_ID_MUTE:
532         xioctl(h->fd, VIDIOCGAUDIO, &h->audio);
533         return h->audio.flags & VIDEO_AUDIO_MUTE;
534     case ATTR_ID_VOLUME:
535         xioctl(h->fd, VIDIOCGAUDIO, &h->audio);
536         return h->audio.volume;
537     case ATTR_ID_AUDIO_MODE:
538         xioctl(h->fd, VIDIOCGAUDIO, &h->audio);
539         return audio_mode_mask2bit(h->audio.mode);
540     case ATTR_ID_COLOR:
541         xioctl(h->fd, VIDIOCGPICT, &h->pict);
542         return h->pict.colour;
543     case ATTR_ID_BRIGHT:
544         xioctl(h->fd, VIDIOCGPICT, &h->pict);
545         return h->pict.brightness;
546     case ATTR_ID_HUE:
547         xioctl(h->fd, VIDIOCGPICT, &h->pict);
548         return h->pict.hue;
549     case ATTR_ID_CONTRAST:
550         xioctl(h->fd, VIDIOCGPICT, &h->pict);
551         return h->pict.contrast;
552     }
553     return -1;
554 }
555 
556 static void v4l_write_attr(struct ng_attribute *attr, int val)
557 {
558     struct v4l_handle *h = attr->handle;
559 
560     /* read ... */
561     switch (attr->id) {
562     case ATTR_ID_INPUT:
563         /* nothing */
564         break;
565     case ATTR_ID_NORM:
566         xioctl(h->fd, VIDIOCGCHAN, &h->channels[h->input]);
567         break;
568     case ATTR_ID_MUTE:
569     case ATTR_ID_VOLUME:
570     case ATTR_ID_AUDIO_MODE:
571         xioctl(h->fd, VIDIOCGAUDIO, &h->audio);
572         break;
573     case ATTR_ID_COLOR:
574     case ATTR_ID_BRIGHT:
575     case ATTR_ID_HUE:
576     case ATTR_ID_CONTRAST:
577         xioctl(h->fd, VIDIOCGPICT, &h->pict);
578         break;
579     }
580 
581     /* ... modify ... */
582     switch (attr->id) {
583     case ATTR_ID_INPUT:
584         h->input = val;
585         h->audio_mode = 0;
586         break;
587     case ATTR_ID_NORM:
588         h->channels[h->input].norm = val;
589         h->audio_mode = 0;
590         break;
591     case ATTR_ID_MUTE:
592         if (val)
593             h->audio.flags |= VIDEO_AUDIO_MUTE;
594         else
595             h->audio.flags &= ~VIDEO_AUDIO_MUTE;
596         break;
597     case ATTR_ID_VOLUME:
598         h->audio.volume = val;
599         break;
600     case ATTR_ID_AUDIO_MODE:
601         h->audio_mode = val;
602         break;
603     case ATTR_ID_COLOR:
604         h->pict.colour = val;
605         break;
606     case ATTR_ID_BRIGHT:
607         h->pict.brightness = val;
608         break;
609     case ATTR_ID_HUE:
610         h->pict.hue = val;
611         break;
612     case ATTR_ID_CONTRAST:
613         h->pict.contrast = val;
614         break;
615     }
616     /* have to set that all the time as read and write have
617        slightly different semantics:
618           read  == bitmask with all available modes flagged
619           write == one bit set (for the selected mode, zero is autodetect)
620     */
621     h->audio.mode = h->audio_mode;
622 
623     /* ... write */
624     switch (attr->id) {
625     case ATTR_ID_INPUT:
626     case ATTR_ID_NORM:
627         xioctl(h->fd, VIDIOCSCHAN, &h->channels[h->input]);
628         break;
629     case ATTR_ID_MUTE:
630     case ATTR_ID_VOLUME:
631     case ATTR_ID_AUDIO_MODE:
632         xioctl(h->fd, VIDIOCSAUDIO, &h->audio);
633         break;
634     case ATTR_ID_COLOR:
635     case ATTR_ID_BRIGHT:
636     case ATTR_ID_HUE:
637     case ATTR_ID_CONTRAST:
638         xioctl(h->fd, VIDIOCSPICT, &h->pict);
639         break;
640     }
641 }
642 
643 static unsigned long
644 v4l_getfreq(void *handle)
645 {
646     struct v4l_handle *h = handle;
647     unsigned long freq;
648 
649     xioctl(h->fd, VIDIOCGFREQ, &freq);
650     return freq;
651 }
652 
653 static void
654 v4l_setfreq(void *handle, unsigned long freq)
655 {
656     struct v4l_handle *h = handle;
657 
658     if (ng_debug)
659         fprintf(stderr,"v4l: freq: %.3f\n",(float)freq/16);
660     xioctl(h->fd, VIDIOCSFREQ, &freq);
661     h->audio_mode = 0;
662 }
663 
664 static int
665 v4l_tuned(void *handle)
666 {
667     struct v4l_handle *h = handle;
668 
669     /* usleep(10000); */
670     if (-1 == xioctl(h->fd,VIDIOCGTUNER,&h->tuner))
671         return 0;
672     return h->tuner.signal ? 1 : 0;
673 }
674 
675 
676 /* ---------------------------------------------------------------------- */
677 /* do overlay                                                             */
678 
679 int
680 v4l_setupfb(void *handle, struct ng_video_fmt *fmt, void *base)
681 {
682     struct v4l_handle *h = handle;
683 
684     /* overlay supported ?? */
685     if (!(h->capability.type & VID_TYPE_OVERLAY)) {
686         if (ng_debug)
687             fprintf(stderr,"v4l: device has no overlay support\n");
688         return -1;
689     }
690 
691     /* double-check settings */
692     if (ng_debug)
693         fprintf(stderr,"v4l: %dx%d, %d bit/pixel, %d byte/scanline\n",
694                 h->fbuf.width,h->fbuf.height,
695                 h->fbuf.depth,h->fbuf.bytesperline);
696     if ((fmt->bytesperline > 0 &&
697          h->fbuf.bytesperline != fmt->bytesperline) ||
698         (h->fbuf.width  != fmt->width) ||
699         (h->fbuf.height != fmt->height)) {
700         fprintf(stderr,
701                 "WARNING: v4l and x11 disagree about the screen size\n"
702                 "WARNING: Is v4l-conf installed correctly?\n");
703         h->ov_error = 1;
704     }
705     if (ng_vfmt_to_depth[fmt->fmtid] != ((h->fbuf.depth+7)&0xf8)) {
706         fprintf(stderr,
707                 "WARNING: v4l and x11 disagree about the color depth\n"
708                 "WARNING: fbuf.depth=%d, x11 depth=%d\n"
709                 "WARNING: Is v4l-conf installed correctly?\n",
710                 h->fbuf.depth,ng_vfmt_to_depth[fmt->fmtid]);
711         h->ov_error = 1;
712     }
713     if (NULL != base) {
714         /* XXX: minor differences are legal... (matrox problems) */
715         if ((void*)((unsigned long)h->fbuf.base & 0xfffff000) !=
716             (void*)((unsigned long)base         & 0xfffff000)) {
717             fprintf(stderr,
718                     "WARNING: v4l and dga disagree about the framebuffer base\n"
719                     "WARNING: fbuf.base=%p, dga=%p\n"
720                     "WARNING: Is v4l-conf installed correctly?\n",
721                     h->fbuf.base,base);
722             h->ov_error = 1;
723         }
724     }
725     if (h->ov_error) {
726         fprintf(stderr,"WARNING: overlay mode disabled\n");
727         return -1;
728     }
729     return 0;
730 }
731 
732 static void
733 v4l_overlay_set(struct v4l_handle *h, int state)
734 {
735     int rc;
736     
737     if (0 == state) {
738         /* off */
739         if (0 == h->ov_on)
740             return;
741         xioctl(h->fd, VIDIOCCAPTURE, &zero);
742         h->ov_on = 0;
743     } else {
744         /* on */
745         h->pict.depth   = ng_vfmt_to_depth[h->ov_fmtid];
746         h->pict.palette = GETELEM(format2palette,h->ov_fmtid,0);
747         xioctl(h->fd, VIDIOCSPICT, &h->pict);
748         rc = xioctl(h->fd, VIDIOCSWIN, &h->win);
749         if (0 == rc) {
750             if (0 != h->ov_on)
751                 return;
752             xioctl(h->fd, VIDIOCCAPTURE, &one);
753             h->ov_on = 1;
754         } else {
755             /* disable overlay on SWIN failure */
756             xioctl(h->fd, VIDIOCCAPTURE, &zero);
757             h->ov_on = 0;
758         }
759     }
760 }
761 
762 int
763 v4l_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
764             struct OVERLAY_CLIP *oc, int count, int aspect)
765 {
766     struct v4l_handle *h = handle;
767     int i;
768 
769     if (h->ov_error)
770         return -1;
771     
772     if (NULL == fmt) {
773         if (ng_debug)
774             fprintf(stderr,"v4l: overlay off\n");
775         h->ov_enabled = 0;
776         v4l_overlay_set(h,h->ov_enabled);
777         return 0;
778     }
779 
780     h->win.x          = x;
781     h->win.y          = y;
782     h->win.width      = fmt->width;
783     h->win.height     = fmt->height;
784     h->win.flags      = 0;
785     h->win.chromakey  = 0;
786 
787     /* check against max. size */
788     xioctl(h->fd,VIDIOCGCAP,&h->capability);
789     if (h->win.width > h->capability.maxwidth) {
790         h->win.width = h->capability.maxwidth;
791         h->win.x += (fmt->width - h->win.width)/2;
792     }
793     if (h->win.height > h->capability.maxheight) {
794         h->win.height = h->capability.maxheight;
795         h->win.y +=  (fmt->height - h->win.height)/2;
796     }
797     if (aspect)
798         ng_ratio_fixup(&h->win.width,&h->win.height,&h->win.x,&h->win.y);
799 
800 #if 0
801     /* pass aligned values -- the driver does'nt get it right yet */
802     h->win.width  &= ~3;
803     h->win.height &= ~3;
804     h->win.x      &= ~3;
805     if (h->win.x < x)
806         h->win.x     += 4;
807     if (h->win.x+h->win.width > x+fmt->width)
808         h->win.width -= 4;
809 #endif
810 
811     /* fixups */
812     ng_check_clipping(h->win.width, h->win.height,
813                       x - h->win.x, y - h->win.y,
814                       oc, &count);
815 
816     /* handle clipping */
817     if (h->win.clips) {
818         free(h->win.clips);
819         h->win.clips = NULL;
820     }
821     h->win.clipcount = 0;
822     if (h->capability.type & VID_TYPE_CLIPPING && count > 0) {
823         h->win.clipcount  = count;
824         h->win.clips      = malloc(count * sizeof(struct video_clip));
825         for (i = 0; i < count; i++) {
826             h->win.clips[i].x      = oc[i].x1;
827             h->win.clips[i].y      = oc[i].y1;
828             h->win.clips[i].width  = oc[i].x2-oc[i].x1;
829             h->win.clips[i].height = oc[i].y2-oc[i].y1;
830         }
831     }
832     if (h->capability.type & VID_TYPE_CHROMAKEY)
833         h->win.chromakey = ng_chromakey;
834     h->ov_enabled = 1;
835     h->ov_fmtid = fmt->fmtid;
836     v4l_overlay_set(h,h->ov_enabled);
837 
838     if (ng_debug)
839         fprintf(stderr,"v4l: overlay win=%dx%d+%d+%d, %d clips\n",
840                 fmt->width,fmt->height,x,y,count);
841     return 0;
842 }
843 
844 /* ---------------------------------------------------------------------- */
845 
846 static int
847 mm_queue(struct v4l_handle *h)
848 {
849     int frame = h->queue % h->nbuf;
850     int rc;
851 
852     if (0 != h->buf_me[frame].refcount) {
853         if (0 != h->queue - h->waiton)
854             return -1;
855         fprintf(stderr,"v4l: waiting for a free buffer\n");
856         ng_waiton_video_buf(h->buf_me+frame);
857     }
858 
859     rc = xioctl(h->fd,VIDIOCMCAPTURE,h->buf_v4l+frame);
860     if (0 == rc)
861         h->queue++;
862     return rc;
863 }
864 
865 static void
866 mm_queue_all(struct v4l_handle *h)
867 {
868     for (;;) {
869         if (h->queue - h->waiton >= h->nbuf)
870             return;
871         if (0 != mm_queue(h))
872             return;
873     }
874 }
875 
876 static int
877 mm_waiton(struct v4l_handle *h)
878 {
879     int frame = h->waiton % h->nbuf;
880     int rc;
881     
882     if (0 == h->queue - h->waiton)
883         return -1;
884     h->waiton++;
885     
886     alarms=0;
887     alarm(SYNC_TIMEOUT);
888 
889  retry:
890     if (-1 == (rc = xioctl(h->fd,VIDIOCSYNC,h->buf_v4l+frame))) {
891         if (errno == EINTR && !alarms)
892             goto retry;
893     }
894     alarm(0);
895     if (-1 == rc)
896         return -1;
897     return frame;
898 }
899 
900 static void
901 mm_clear(struct v4l_handle *h)
902 {
903     while (h->queue > h->waiton)
904         mm_waiton(h);
905     h->queue  = 0;
906     h->waiton = 0;
907 }
908 
909 static int
910 mm_probe(struct v4l_handle *h, unsigned int fmtid)
911 {
912     if (0 != h->probe[fmtid])
913         goto done;
914 
915     if (ng_debug)
916         fprintf(stderr, "v4l: capture probe %s...\t",
917                 ng_vfmt_to_desc[fmtid]);
918 
919     h->buf_v4l[0].frame  = 0;
920     h->buf_v4l[0].width  = h->capability.minwidth;
921     h->buf_v4l[0].height = h->capability.minheight;
922     h->buf_v4l[0].format = GETELEM(format2palette,fmtid,0);
923 #if 1 /* bug compatibility: bttv up to 0.7.67 reports wrong minwidth */
924     if (h->buf_v4l[0].width == 32)
925         h->buf_v4l[0].width = 48;
926 #endif
927 
928     if (0 == h->buf_v4l[0].format)
929         goto fail;
930     if (-1 == mm_queue(h))
931         goto fail;
932     if (-1 == mm_waiton(h))
933         goto fail;
934 
935     if (ng_debug)
936         fprintf(stderr, "ok\n");
937     h->probe[fmtid] = 1;
938     goto done;
939 
940  fail:
941     if (ng_debug)
942         fprintf(stderr, "failed\n");
943     h->probe[fmtid] = 2;
944 
945  done:
946     mm_clear(h);
947     return h->probe[fmtid] == 1;
948 }
949 
950 static int
951 mm_setparams(struct v4l_handle *h, struct ng_video_fmt *fmt)
952 {
953     unsigned int i;
954 
955     /* buffers available ? */
956     if (h->mbuf.frames < 1)
957         return -1;
958     
959     /* verify parameters */
960     xioctl(h->fd,VIDIOCGCAP,&h->capability);
961     if (fmt->width > h->capability.maxwidth)
962         fmt->width = h->capability.maxwidth;
963     if (fmt->height > h->capability.maxheight)
964         fmt->height = h->capability.maxheight;    
965     fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
966 
967     /* check if we can handle the format */
968     if (!mm_probe(h,fmt->fmtid))
969         return -1;
970 
971     /* initialize everything */
972     h->nbuf = h->mbuf.frames;
973     for (i = 0; i < h->nbuf; i++) {
974         h->buf_v4l[i].format = GETELEM(format2palette,fmt->fmtid,0);
975         h->buf_v4l[i].frame  = i;
976         h->buf_v4l[i].width  = fmt->width;
977         h->buf_v4l[i].height = fmt->height;
978         h->buf_me[i].fmt  = *fmt;
979         h->buf_me[i].data = h->mmap + h->mbuf.offsets[i];
980         h->buf_me[i].size = fmt->height * fmt->bytesperline;
981     }
982     return 0;
983 }
984 
985 /* ---------------------------------------------------------------------- */
986 
987 static int
988 read_setformat(struct v4l_handle *h, struct ng_video_fmt *fmt)
989 {
990     xioctl(h->fd,VIDIOCGCAP,&h->capability);
991     if (fmt->width > h->capability.maxwidth)
992         fmt->width = h->capability.maxwidth;
993     if (fmt->height > h->capability.maxheight)
994         fmt->height = h->capability.maxheight;    
995     fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
996 
997     h->rd_win.width  = fmt->width;
998     h->rd_win.height = fmt->height;
999     h->rd_fmtid = fmt->fmtid;
1000 
1001     h->pict.depth   = ng_vfmt_to_depth[h->rd_fmtid];
1002     h->pict.palette = GETELEM(format2palette,h->rd_fmtid,0);
1003     if (-1 == xioctl(h->fd, VIDIOCSPICT, &h->pict))
1004         return -1;
1005     if (-1 == xioctl(h->fd, VIDIOCSWIN,  &h->rd_win))
1006         return -1;
1007 
1008     fmt->width  = h->rd_win.width;
1009     fmt->height = h->rd_win.height;
1010     fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
1011     h->rd_fmt = *fmt;
1012     return 0;
1013 }
1014 
1015 static struct ng_video_buf*
1016 read_getframe(struct v4l_handle *h)
1017 {
1018     struct ng_video_buf* buf;
1019     int size;
1020 
1021     h->pict.depth   = ng_vfmt_to_depth[h->rd_fmtid];
1022     h->pict.palette = GETELEM(format2palette,h->rd_fmtid,0);
1023     xioctl(h->fd, VIDIOCSPICT, &h->pict);
1024     xioctl(h->fd, VIDIOCSWIN,  &h->rd_win);
1025     size = h->rd_fmt.bytesperline * h->rd_fmt.height;
1026     buf = ng_malloc_video_buf(&h->rd_fmt, size);
1027     if (NULL == buf)
1028         return NULL;
1029     if (size != read(h->fd,buf->data,size)) {
1030         ng_release_video_buf(buf);
1031         return NULL;
1032     }
1033     return buf;
1034 }
1035 
1036 /* ---------------------------------------------------------------------- */
1037 
1038 int
1039 v4l_setformat(void *handle, struct ng_video_fmt *fmt)
1040 {
1041     struct v4l_handle *h = handle;
1042     int rc;
1043 
1044 #if 0
1045     /* for debugging color space conversion functions:
1046        force xawtv to capture some specific format */
1047     if (fmt->fmtid != VIDEO_YUV420P)
1048         return -1;
1049 #endif
1050     
1051     if (ng_debug)
1052         fprintf(stderr,"v4l: setformat\n");
1053     if (h->use_read) {
1054         v4l_overlay_set(h,0);
1055         rc = read_setformat(h,fmt);
1056         v4l_overlay_set(h,h->ov_enabled);
1057     } else {
1058         if (h->queue != h->waiton)
1059             fprintf(stderr,"v4l: Huh? setformat: found queued buffers (%d %d)\n",
1060                     h->queue, h->waiton);
1061         mm_clear(h);
1062         rc = mm_setparams(h,fmt);
1063     }
1064     return rc;
1065 }
1066 
1067 int
1068 v4l_startvideo(void *handle, int fps, unsigned int buffers)
1069 {
1070     struct v4l_handle *h = handle;
1071 
1072     if (ng_debug)
1073         fprintf(stderr,"v4l: startvideo\n");
1074     if (0 != h->fps)
1075         fprintf(stderr,"v4l: Huh? start: fps != 0\n");
1076     if (!h->use_read) {
1077         if (h->nbuf > buffers)
1078             h->nbuf = buffers;
1079         mm_queue_all(h);
1080     }
1081     h->start = ng_get_timestamp();
1082     h->fps = fps;
1083     return 0;
1084 }
1085 
1086 void
1087 v4l_stopvideo(void *handle)
1088 {
1089     struct v4l_handle *h = handle;
1090 
1091     if (ng_debug)
1092         fprintf(stderr,"v4l: stopvideo\n");
1093     if (0 == h->fps)
1094         fprintf(stderr,"v4l: Huh? stop: fps == 0\n");
1095     if (!h->use_read)
1096         mm_clear(h);
1097     h->fps = 0;
1098 }
1099 
1100 struct ng_video_buf*
1101 v4l_nextframe(void *handle)
1102 {
1103     struct v4l_handle *h = handle;
1104     struct ng_video_buf* buf = NULL;
1105     int frame = 0;
1106 
1107     if (ng_debug > 1)
1108         fprintf(stderr,"v4l: getimage\n");
1109 
1110     if (0 == h->fps) {
1111         fprintf(stderr,"v4l: nextframe: fps == 0\n");
1112         return NULL;
1113     }
1114 
1115     if (h->use_read) {
1116         if (buf)
1117             ng_release_video_buf(buf);
1118         v4l_overlay_set(h,0);
1119         buf = read_getframe(h);
1120         v4l_overlay_set(h,h->ov_enabled);
1121         if (NULL == buf)
1122             return NULL;
1123         memset(&buf->info,0,sizeof(buf->info));
1124         buf->info.ts = ng_get_timestamp() - h->start;
1125         return buf;
1126     } else {
1127         mm_queue_all(h);
1128         frame = mm_waiton(h);
1129         if (-1 == frame)
1130             return NULL;
1131         memset(&h->buf_me[frame].info,0,sizeof(h->buf_me[frame].info));
1132         h->buf_me[frame].refcount++;
1133         h->buf_me[frame].info.ts = ng_get_timestamp() - h->start;
1134         return h->buf_me+frame;
1135     }
1136 }
1137 
1138 /* ---------------------------------------------------------------------- */
1139 
1140 struct ng_video_buf*
1141 v4l_getimage(void *handle)
1142 {
1143     struct v4l_handle *h = handle;
1144     struct ng_video_buf* buf = NULL;
1145     int frame;
1146 
1147     if (ng_debug)
1148         fprintf(stderr,"v4l: getimage\n");
1149         
1150     if (0 != h->fps) {
1151         fprintf(stderr,"v4l: getimage: fps != 0\n");
1152         return NULL;
1153     }
1154     if (h->use_read) {
1155         v4l_overlay_set(h,0);
1156         buf = read_getframe(h);
1157         v4l_overlay_set(h,h->ov_enabled);
1158         return buf;
1159     } else {
1160         mm_queue(h);
1161         frame = mm_waiton(h);
1162         if (-1 == frame)
1163             return NULL;
1164         h->buf_me[frame].refcount++;
1165         return h->buf_me+frame;
1166     }
1167 }
1168 
1169 /* ---------------------------------------------------------------------- */
1170 
1171 extern void ng_plugin_init(void);
1172 void ng_plugin_init(void)
1173 {
1174     ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l_driver);
1175 }
1176 
  This page was automatically generated by the LXR engine.