first batch
authorThomas Vander Stichele <thomas@apestaart.org>
Mon, 17 Dec 2001 19:03:14 +0000 (19:03 +0000)
committerThomas Vander Stichele <thomas@apestaart.org>
Mon, 17 Dec 2001 19:03:14 +0000 (19:03 +0000)
Original commit message from CVS:
first batch

sys/Makefile.am [new file with mode: 0644]
sys/v4l/Makefile.am [new file with mode: 0644]
sys/v4l/grab-v4l.c [new file with mode: 0644]
sys/v4l/grab.h [new file with mode: 0644]
sys/v4l/gstv4lsrc.c [new file with mode: 0644]
sys/v4l/gstv4lsrc.h [new file with mode: 0644]

diff --git a/sys/Makefile.am b/sys/Makefile.am
new file mode 100644 (file)
index 0000000..101ea5a
--- /dev/null
@@ -0,0 +1,5 @@
+### use HAVE_ stuff to decide on dirs
+DIRS=qcam v4l vcdsrc vgasink xvideosink
+
+DIST_SUBDIRS=qcam v4l vcdsrc vgasink xvideosink
+
diff --git a/sys/v4l/Makefile.am b/sys/v4l/Makefile.am
new file mode 100644 (file)
index 0000000..b99e2d4
--- /dev/null
@@ -0,0 +1,12 @@
+plugindir = $(libdir)/gst
+
+plugin_LTLIBRARIES = libv4lsrc.la
+
+libv4lsrc_la_SOURCES = \
+                   gstv4lsrc.c \
+                   grab-v4l.c
+
+## FIXME : do we need -O2 ? libv4lsrc_la_CFLAGS = -O2 $(GST_CFLAGS)
+libv4lsrc_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstv4lsrc.h grab.h
diff --git a/sys/v4l/grab-v4l.c b/sys/v4l/grab-v4l.c
new file mode 100644 (file)
index 0000000..6c05950
--- /dev/null
@@ -0,0 +1,973 @@
+/*
+ * interface to the v4l driver
+ *
+ *   (c) 1997-99 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <endian.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <X11/Intrinsic.h>
+
+#include <asm/types.h>         /* XXX glibc */
+#include <linux/videodev.h>
+
+#include "grab.h"
+
+#define SYNC_TIMEOUT 1
+
+/* ---------------------------------------------------------------------- */
+
+/* experimental, interface might change */
+#ifndef VIDIOCSWIN2
+#define VIDIOCSWIN2 _IOW('v',28,struct video_window2)
+struct video_window2
+{
+    __u16   palette;                /* Palette (aka video format) in use */
+    __u32   start;                  /* start address, relative to video_buffer.base */
+    __u32   pitch;
+    __u32   width;
+    __u32   height;
+    __u32   flags;
+    
+    struct video_clip *clips;
+    int clipcount;
+};
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+/* open+close */
+static int   grab_open(struct GRABBER *grab_v4l, char *filename);
+static int   grab_close(struct GRABBER *grab_v4l);
+
+/* overlay */
+static int   grab_setupfb(struct GRABBER *grab_v4l, int sw, int sh, int format, void *base, int width);
+static int   grab_overlay(struct GRABBER *grab_v4l, int x, int y, int width, int height, int format,
+                          OverlayClip *oc, int count);
+static int   grab_offscreen(struct GRABBER *grab_v4l, int start, int pitch, int width, int height,
+                            int format);
+
+/* capture */
+static int   grab_mm_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height,
+                               int *linelength);
+static void* grab_mm_capture(struct GRABBER *grab_v4l, int single);
+static void  grab_mm_cleanup(struct GRABBER *grab_v4l);
+static int   grab_read_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height,
+                                 int *linelength);
+static void* grab_read_capture(struct GRABBER *grab_v4l, int single);
+static void  grab_read_cleanup(struct GRABBER *grab_v4l);
+
+/* control */
+static int   grab_tune(struct GRABBER *grab_v4l, unsigned long freq);
+static int   grab_tuned(struct GRABBER *grab_v4l);
+static int   grab_input(struct GRABBER *grab_v4l, int input, int norm);
+static int   grab_hasattr(struct GRABBER *grab_v4l, int id);
+static int   grab_getattr(struct GRABBER *grab_v4l, int id);
+static int   grab_setattr(struct GRABBER *grab_v4l, int id, int val);
+
+/* internal helpers */
+static int   grab_wait(struct GRABBER *grab_v4l, struct video_mmap *gb);
+
+/* ---------------------------------------------------------------------- */
+
+static const char *device_cap[] = {
+  "capture", "tuner", "teletext", "overlay", "chromakey", "clipping",
+  "frameram", "scales", "monochrome", NULL
+};
+
+static const char *device_pal[] = {
+  "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15",
+  "yuv422", "yuyv", "uyvy", "yuv420", "yuv411", "raw",
+  "yuv422p", "yuv411p", "yuv420p", "yuv410p"
+};
+#define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN")
+
+static const struct STRTAB stereo[] = {
+                                  {  0, "auto"    },
+                                  {  1, "mono"    },
+                                  {  2, "stereo"  },
+                                  {  4, "lang1"   },
+                                  {  8, "lang2"   },
+                                  { -1, NULL,     },
+                                };
+static struct STRTAB norms[] = {
+                                 {  0, "PAL" },
+                                 {  1, "NTSC" },
+                                 {  2, "SECAM" },
+                                 {  3, "AUTO" },
+                                 { -1, NULL }
+                               };
+static const struct STRTAB norms_bttv[] = {
+                                      {  0, "PAL" },
+                                      {  1, "NTSC" },
+                                      {  2, "SECAM" },
+                                      {  3, "PAL-NC" },
+                                      {  4, "PAL-M" },
+                                      {  5, "PAL-N" },
+                                      {  6, "NTSC-JP" },
+                                      { -1, NULL }
+                                    };
+static int gb_pal[] = {
+  0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0
+};
+
+static const unsigned short format2palette[] = {
+  0,/* unused */
+  VIDEO_PALETTE_HI240,/* RGB8   */
+  VIDEO_PALETTE_GREY,/* GRAY8  */
+#if __BYTE_ORDER == __BIG_ENDIAN
+  0,
+  0,
+  VIDEO_PALETTE_RGB555,/* RGB15_BE  */
+  VIDEO_PALETTE_RGB565,/* RGB16_BE  */
+  0,
+  0,
+  VIDEO_PALETTE_RGB24,/* RGB24     */
+  VIDEO_PALETTE_RGB32,/* RGB32     */
+#else
+  VIDEO_PALETTE_RGB555,/* RGB15_LE  */
+  VIDEO_PALETTE_RGB565,/* RGB16_LE  */
+  0,
+  0,
+  VIDEO_PALETTE_RGB24,/* BGR24     */
+  VIDEO_PALETTE_RGB32,/* BGR32     */
+  0,
+  0,
+#endif
+  0,                          /* LUT 2    */
+  0,                          /* LUT 4    */
+  VIDEO_PALETTE_YUV422,       /* YUV422   */
+  VIDEO_PALETTE_YUV422P,      /* YUV422P  */
+  VIDEO_PALETTE_YUV420P,      /* YUV420P  */
+};
+
+static const unsigned int format2depth[] = {
+  0,               /* unused   */
+  8,               /* RGB8     */
+  8,               /* GRAY8    */
+  16,              /* RGB15 LE */
+  16,              /* RGB16 LE */
+  16,              /* RGB15 BE */
+  16,              /* RGB16 BE */
+  24,              /* BGR24    */
+  32,              /* BGR32    */
+  24,              /* RGB24    */
+  32,              /* RGB32    */
+  16,              /* LUT2     */
+  32,              /* LUT4     */
+  16,          /* YUV422   */
+  16,          /* YUV422P  */
+  12,          /* YUV420P  */
+  0,           /* MJPEG    */
+};
+
+static const unsigned char* format_desc[] = {
+  "",
+  "8 bit PseudoColor (dithering)",
+  "8 bit StaticGray",
+  "15 bit TrueColor (LE)",
+  "16 bit TrueColor (LE)",
+  "15 bit TrueColor (BE)",
+  "16 bit TrueColor (BE)",
+  "24 bit TrueColor (LE: bgr)",
+  "32 bit TrueColor (LE: bgr-)",
+  "24 bit TrueColor (BE: rgb)",
+  "32 bit TrueColor (BE: -rgb)",
+  "16 bit TrueColor (lut)",
+  "32 bit TrueColor (lut)",
+  "16 bit YUV 4:2:2",
+  "16 bit YUV 4:2:2 (planar)",
+  "12 bit YUV 4:2:0 (planar)",
+  "MJPEG"
+};
+
+
+/* pass 0/1 by reference */
+static const int                      one = 1, zero = 0;
+
+/* ---------------------------------------------------------------------- */
+static const struct GRAB_ATTR init_grab_attr[] = 
+               { 
+                  { GRAB_ATTR_VOLUME,   1, VIDIOCGAUDIO, VIDIOCSAUDIO, NULL },
+                 { GRAB_ATTR_MUTE,     1, VIDIOCGAUDIO, VIDIOCSAUDIO, NULL },
+                 { GRAB_ATTR_MODE,     1, VIDIOCGAUDIO, VIDIOCSAUDIO, NULL },
+
+                  { GRAB_ATTR_COLOR,    1, VIDIOCGPICT,  VIDIOCSPICT,  NULL },
+                  { GRAB_ATTR_BRIGHT,   1, VIDIOCGPICT,  VIDIOCSPICT,  NULL },
+                  { GRAB_ATTR_HUE,      1, VIDIOCGPICT,  VIDIOCSPICT,  NULL },
+                  { GRAB_ATTR_CONTRAST, 1, VIDIOCGPICT,  VIDIOCSPICT,  NULL },
+               };
+
+struct GRABBER *grab_init()
+{
+  struct GRABBER *new_grabber;
+
+  new_grabber = malloc(sizeof(struct GRABBER));
+
+  new_grabber->name = "v4l";
+  new_grabber->flags = 0;
+  new_grabber->norms = norms;
+  new_grabber->inputs = NULL;
+  new_grabber->opened = 0;
+  new_grabber->fd = -1;
+  new_grabber->overlay = 0;
+  new_grabber->audio_modes = stereo;
+  new_grabber->grab_open = grab_open;
+  new_grabber->grab_close = grab_close;
+  new_grabber->grab_setupfb = grab_setupfb;
+  new_grabber->grab_overlay = NULL;
+  new_grabber->grab_offscreen = NULL;
+  new_grabber->grab_setparams = NULL;
+  new_grabber->grab_capture = NULL;
+  new_grabber->grab_cleanup = NULL;
+  new_grabber->grab_tune = grab_tune;
+  new_grabber->grab_tuned = grab_tuned;
+  new_grabber->grab_input = grab_input;
+  new_grabber->grab_hasattr = grab_hasattr;
+  new_grabber->grab_getattr = grab_getattr;
+  new_grabber->grab_setattr = grab_setattr;
+
+  memcpy(new_grabber->grab_attr, init_grab_attr, sizeof(init_grab_attr));
+
+  new_grabber->grab_attr[0].arg = &new_grabber->audio;
+  new_grabber->grab_attr[1].arg = &new_grabber->audio;
+  new_grabber->grab_attr[2].arg = &new_grabber->audio;
+  new_grabber->grab_attr[3].arg = &new_grabber->pict;
+  new_grabber->grab_attr[4].arg = &new_grabber->pict;
+  new_grabber->grab_attr[5].arg = &new_grabber->pict;
+  new_grabber->grab_attr[6].arg = &new_grabber->pict;
+
+  return new_grabber;
+}
+
+/* FIXME this isn't used (yet?)
+static void grab_cleanup(struct GRABBER *grab_v4l)
+{
+}
+*/
+
+static int grab_open(struct GRABBER *grab_v4l, char *filename)
+{
+  int i;
+
+  if (-1 != grab_v4l->fd)
+    goto err;
+
+  if (-1 == (grab_v4l->fd = open(filename ? filename : "/dev/video",O_RDWR))) {
+    fprintf(stderr,"v4l: open %s: %s\n",
+            filename ? filename : "/dev/video",strerror(errno));
+    goto err;
+  }
+
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability)) {
+    perror("v4l: open\n");
+    goto err;
+       }
+
+  fprintf(stderr, "v4l: open\n");
+
+  fcntl(grab_v4l->fd,F_SETFD,FD_CLOEXEC);
+
+  fprintf(stderr,"v4l: device is %s\n",grab_v4l->capability.name); 
+
+  sprintf(grab_v4l->name = malloc(strlen(grab_v4l->capability.name)+8),
+          "v4l: %s",grab_v4l->capability.name);
+
+  fprintf(stderr,"v4l: capabilities: ");
+  for (i = 0; device_cap[i] != NULL; i++)
+    if (grab_v4l->capability.type & (1 << i))
+      fprintf(stderr," %s",device_cap[i]);
+  fprintf(stderr,"\n");
+
+  /* input sources */
+  fprintf(stderr,"v4l:   channels: %d\n",grab_v4l->capability.channels);
+
+  grab_v4l->channels = malloc(sizeof(struct video_channel)*grab_v4l->capability.channels);
+  memset(grab_v4l->channels,0,sizeof(struct video_channel)*grab_v4l->capability.channels);
+
+  grab_v4l->inputs = malloc(sizeof(struct STRTAB)*(grab_v4l->capability.channels+1));
+  memset(grab_v4l->inputs,0,sizeof(struct STRTAB)*(grab_v4l->capability.channels+1));
+
+  for (i = 0; i < grab_v4l->capability.channels; i++) {
+    grab_v4l->channels[i].channel = i;
+    if (-1 == ioctl(grab_v4l->fd,VIDIOCGCHAN,&grab_v4l->channels[i]))
+      perror("v4l: ioctl VIDIOCGCHAN"), exit(0);
+    grab_v4l->inputs[i].nr  = i;
+    grab_v4l->inputs[i].str = grab_v4l->channels[i].name;
+    fprintf(stderr,"v4l:    %s: %d %s%s %s%s\n",
+              grab_v4l->channels[i].name,
+              grab_v4l->channels[i].tuners,
+              (grab_v4l->channels[i].flags & VIDEO_VC_TUNER)   ? "tuner "  : "",
+              (grab_v4l->channels[i].flags & VIDEO_VC_AUDIO)   ? "audio "  : "",
+              (grab_v4l->channels[i].type & VIDEO_TYPE_TV)     ? "tv "     : "",
+              (grab_v4l->channels[i].type & VIDEO_TYPE_CAMERA) ? "camera " : "");
+  }
+  grab_v4l->inputs[i].nr  = -1;
+  grab_v4l->inputs[i].str = NULL;
+
+  /* ioctl probe, switch to input 0 */
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCSCHAN,&grab_v4l->channels[0])) {
+    fprintf(stderr,"v4l: you need a newer bttv version (>= 0.5.14)\n");
+    goto err;
+  }
+
+  /* audios */
+  fprintf(stderr,"v4l:  audios  : %d\n",grab_v4l->capability.audios);
+
+  if (grab_v4l->capability.audios) {
+    grab_v4l->audio.audio = 0;
+    if (-1 == ioctl(grab_v4l->fd,VIDIOCGAUDIO,&grab_v4l->audio))
+      perror("v4l: ioctl VIDIOCGCAUDIO") /* , exit(0) */ ;
+    fprintf(stderr,"v4l:    %d (%s): ",i,grab_v4l->audio.name);
+    if (grab_v4l->audio.flags & VIDEO_AUDIO_MUTABLE)
+      fprintf(stderr,"muted=%s ",
+              (grab_v4l->audio.flags&VIDEO_AUDIO_MUTE) ? "yes":"no");
+    if (grab_v4l->audio.flags & VIDEO_AUDIO_VOLUME)
+      fprintf(stderr,"volume=%d ",grab_v4l->audio.volume);
+    if (grab_v4l->audio.flags & VIDEO_AUDIO_BASS)
+      fprintf(stderr,"bass=%d ",grab_v4l->audio.bass);
+    if (grab_v4l->audio.flags & VIDEO_AUDIO_TREBLE)
+      fprintf(stderr,"treble=%d ",grab_v4l->audio.treble);
+    fprintf(stderr,"\n");
+
+    if (!(grab_v4l->audio.flags & VIDEO_AUDIO_VOLUME)) {
+      grab_v4l->grab_attr[0].have = 0; /* volume     */
+    }
+  } else {
+    grab_v4l->grab_attr[0].have = 0; /* volume     */
+    grab_v4l->grab_attr[1].have = 0; /* mute       */
+    grab_v4l->grab_attr[2].have = 0; /* audio mode */
+  }
+
+  fprintf(stderr,"v4l:  size    : %dx%d => %dx%d\n",
+            grab_v4l->capability.minwidth,grab_v4l->capability.minheight,
+            grab_v4l->capability.maxwidth,grab_v4l->capability.maxheight);
+
+  /* tuner (more than one???) */
+  if (grab_v4l->capability.type & VID_TYPE_TUNER) {
+    grab_v4l->tuner = malloc(sizeof(struct video_tuner));
+    memset(grab_v4l->tuner,0,sizeof(struct video_tuner));
+    if (-1 == ioctl(grab_v4l->fd,VIDIOCGTUNER,grab_v4l->tuner))
+      perror("v4l: ioctl VIDIOCGTUNER");
+    fprintf(stderr,"v4l:  tuner   : %s %lu-%lu",
+              grab_v4l->tuner->name,grab_v4l->tuner->rangelow,grab_v4l->tuner->rangehigh);
+    for (i = 0; norms[i].str != NULL; i++) {
+      if (grab_v4l->tuner->flags & (1<<i)) {
+        fprintf(stderr," %s",norms[i].str);
+      } else
+        norms[i].nr = -1;
+    }
+    fprintf(stderr,"\n");
+  } else {
+    struct video_channel vchan;
+
+    memcpy(&vchan, &grab_v4l->channels[0], sizeof(struct video_channel));
+    for (i = 0; norms[i].str != NULL; i++) {
+      vchan.norm = i;
+      if (-1 == ioctl(grab_v4l->fd,VIDIOCSCHAN,&vchan))
+        norms[i].nr = -1;
+      fprintf(stderr," %s",norms[i].str);
+    }
+    fprintf(stderr,"\n");
+    if (-1 == ioctl(grab_v4l->fd,VIDIOCSCHAN,&grab_v4l->channels[0])) {
+      fprintf(stderr,"v4l: you need a newer bttv version (>= 0.5.14)\n");
+      goto err;
+    }
+    grab_v4l->grab_tune  = NULL;
+    grab_v4l->grab_tuned = NULL;
+  }
+#if 1
+#define BTTV_VERSION           _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+  /* dirty hack time / v4l design flaw -- works with bttv only
+   * this adds support for a few less common PAL versions */
+  if (-1 != ioctl(grab_v4l->fd,BTTV_VERSION,0)) {
+    grab_v4l->norms = norms_bttv;
+  }
+#endif
+   
+  /* frame buffer */
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGFBUF,&grab_v4l->ov_fbuf))
+    perror("v4l: ioctl VIDIOCGFBUF");
+  fprintf(stderr,"v4l:  fbuffer : base=0x%p size=%dx%d depth=%d bpl=%d\n",
+            grab_v4l->ov_fbuf.base, grab_v4l->ov_fbuf.width, grab_v4l->ov_fbuf.height,
+            grab_v4l->ov_fbuf.depth, grab_v4l->ov_fbuf.bytesperline);
+
+  /* picture parameters */
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGPICT,&grab_v4l->pict))
+    perror("v4l: ioctl VIDIOCGPICT");
+
+  fprintf(stderr,
+          "v4l:  picture : brightness=%d hue=%d colour=%d contrast=%d\n",
+          grab_v4l->pict.brightness, grab_v4l->pict.hue, grab_v4l->pict.colour, grab_v4l->pict.contrast);
+  fprintf(stderr,
+            "v4l:  picture : whiteness=%d depth=%d palette=%s\n",
+            grab_v4l->pict.whiteness, grab_v4l->pict.depth, PALETTE(grab_v4l->pict.palette));
+
+  /* map grab buffer */
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGMBUF,&grab_v4l->gb_buffers)) {
+    perror("v4l: ioctl VIDIOCGMBUF");
+  }
+  grab_v4l->map = mmap(0,grab_v4l->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,grab_v4l->fd,0);
+  if ((char*)-1 != grab_v4l->map) {
+    grab_v4l->grab_setparams = grab_mm_setparams;
+    grab_v4l->grab_capture   = grab_mm_capture;
+    grab_v4l->grab_cleanup   = grab_mm_cleanup;
+  } else {
+    perror("v4l: mmap");
+    grab_v4l->grab_setparams = grab_read_setparams;
+    grab_v4l->grab_capture   = grab_read_capture;
+    grab_v4l->grab_cleanup   = grab_read_cleanup;
+  }
+       grab_v4l->opened = 1;
+
+  return grab_v4l->fd;
+
+  err:
+  if (grab_v4l->fd != -1) {
+    close(grab_v4l->fd);
+    grab_v4l->fd = -1;
+  }
+  return -1;
+}
+
+static int
+  grab_close(struct GRABBER *grab_v4l)
+{
+  if (-1 == grab_v4l->fd)
+    return 0;
+
+  if (grab_v4l->gb_grab > grab_v4l->gb_sync)
+    grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
+
+  if ((char*)-1 != grab_v4l->map)
+    munmap(grab_v4l->map,grab_v4l->gb_buffers.size);
+
+  fprintf(stderr, "v4l: close\n");
+
+  close(grab_v4l->fd);
+  grab_v4l->fd = -1;
+       grab_v4l->opened = 0;
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* do overlay                                                             */
+
+static int
+  grab_setupfb(struct GRABBER *grab_v4l, int sw, int sh, int format, void *base, int bpl)
+{
+  int settings_ok = 1;
+  grab_v4l->swidth  = sw;
+  grab_v4l->sheight = sh;
+
+  /* double-check settings */
+  fprintf(stderr,"v4l: %dx%d, %d bit/pixel, %d byte/scanline\n",
+          grab_v4l->ov_fbuf.width,grab_v4l->ov_fbuf.height,
+          grab_v4l->ov_fbuf.depth,grab_v4l->ov_fbuf.bytesperline);
+  if ((bpl > 0 && grab_v4l->ov_fbuf.bytesperline != bpl) ||
+      (grab_v4l->ov_fbuf.width  != sw) ||
+      (grab_v4l->ov_fbuf.height != sh)) {
+    fprintf(stderr,"v4l: WARNING: v4l and dga disagree about the screen size\n");
+    fprintf(stderr,"v4l: WARNING: Is v4l-conf installed correctly?\n");
+    settings_ok = 0;
+  }
+  if (format2depth[format] != ((grab_v4l->ov_fbuf.depth+7)&0xf8)) {
+    fprintf(stderr,"v4l: WARNING: v4l and dga disagree about the color depth\n");
+    fprintf(stderr,"v4l: WARNING: Is v4l-conf installed correctly?\n");
+    fprintf(stderr,"%d %d\n",format2depth[format],grab_v4l->ov_fbuf.depth);
+    settings_ok = 0;
+  }
+  if (settings_ok) {
+    grab_v4l->grab_overlay   = grab_overlay;
+    grab_v4l->grab_offscreen = grab_offscreen;
+    return 0;
+  } else {
+    fprintf(stderr,"v4l: WARNING: overlay mode disabled\n");
+    return -1;
+  }
+}
+
+static int
+  grab_overlay(struct GRABBER *grab_v4l, int x, int y, int width, int height, int format,
+               OverlayClip *oc, int count)
+  {
+      int i,xadjust=0,yadjust=0;
+
+      //fprintf(stderr,"v4l: overlay %d %d\n", x, y);
+
+      if (width == 0 || height == 0) {
+        //fprintf(stderr,"v4l: overlay off\n");
+        ioctl(grab_v4l->fd, VIDIOCCAPTURE, &zero);
+        grab_v4l->overlay = 0;
+        return 0;
+      }
+
+      grab_v4l->ov_win.x          = x;
+      grab_v4l->ov_win.y          = y;
+      grab_v4l->ov_win.width      = width;
+      grab_v4l->ov_win.height     = height;
+      grab_v4l->ov_win.flags      = 0;
+
+      /* check against max. size */
+      ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability);
+      if (grab_v4l->ov_win.width > grab_v4l->capability.maxwidth) {
+        grab_v4l->ov_win.width = grab_v4l->capability.maxwidth;
+        grab_v4l->ov_win.x += (width - grab_v4l->ov_win.width)/2;
+      }
+      if (grab_v4l->ov_win.height > grab_v4l->capability.maxheight) {
+        grab_v4l->ov_win.height = grab_v4l->capability.maxheight;
+        grab_v4l->ov_win.y +=  (height - grab_v4l->ov_win.height)/2;
+      }
+
+      /* pass aligned values -- the driver does'nt get it right yet */
+      grab_v4l->ov_win.width  &= ~3;
+      grab_v4l->ov_win.height &= ~3;
+      grab_v4l->ov_win.x      &= ~3;
+      if (grab_v4l->ov_win.x              < x)        grab_v4l->ov_win.x     += 4;
+      if (grab_v4l->ov_win.x+grab_v4l->ov_win.width > x+width)  grab_v4l->ov_win.width -= 4;
+
+      /* fixups */
+      xadjust = grab_v4l->ov_win.x - x;
+      yadjust = grab_v4l->ov_win.y - y;
+
+      if (grab_v4l->capability.type & VID_TYPE_CLIPPING) {
+        grab_v4l->ov_win.clips      = grab_v4l->ov_clips;
+        grab_v4l->ov_win.clipcount  = count;
+        
+        for (i = 0; i < count; i++) {
+          grab_v4l->ov_clips[i].x      = oc[i].x1 - xadjust;
+          grab_v4l->ov_clips[i].y      = oc[i].y1 - yadjust;
+          grab_v4l->ov_clips[i].width  = oc[i].x2-oc[i].x1 /* XXX */;
+          grab_v4l->ov_clips[i].height = oc[i].y2-oc[i].y1;
+          //fprintf(stderr,"v4l: clip=%dx%d+%d+%d\n",
+                    //grab_v4l->ov_clips[i].width,grab_v4l->ov_clips[i].height,
+                    //grab_v4l->ov_clips[i].x,grab_v4l->ov_clips[i].y);
+        }
+      }
+      if (grab_v4l->capability.type & VID_TYPE_CHROMAKEY) {
+        grab_v4l->ov_win.chromakey  = 0;    /* XXX */
+      }
+      if (-1 == ioctl(grab_v4l->fd, VIDIOCSWIN, &grab_v4l->ov_win))
+        perror("v4l: ioctl VIDIOCSWIN");
+
+      if (!grab_v4l->overlay) {
+        grab_v4l->pict.palette =
+          (format < sizeof(format2palette)/sizeof(unsigned short))?
+          format2palette[format]: 0;
+        if(grab_v4l->pict.palette == 0) {
+          fprintf(stderr,"v4l: unsupported overlay video format: %s\n",
+                  format_desc[format]);
+          return -1;
+        }
+        if (-1 == ioctl(grab_v4l->fd,VIDIOCSPICT,&grab_v4l->pict))
+          perror("v4l: ioctl VIDIOCSPICT");
+        if (-1 == ioctl(grab_v4l->fd, VIDIOCCAPTURE, &one))
+          perror("v4l: ioctl VIDIOCCAPTURE");
+        grab_v4l->overlay = 1;
+      }
+
+      //fprintf(stderr,"v4l: overlay win=%dx%d+%d+%d, %d clips\n",
+        //       width,height,x,y, count);
+
+      return 0;
+  }
+
+static int
+  grab_offscreen(struct GRABBER *grab_v4l, int start, int pitch, int width, int height, int format)
+{
+  struct video_window2 vo;
+
+  if (width == 0 || height == 0) {
+    fprintf(stderr,"v4l: offscreen off\n");
+    ioctl(grab_v4l->fd, VIDIOCCAPTURE, &zero);
+    grab_v4l->overlay = 0;
+    return 0;
+  }
+
+  vo.palette   = VIDEO_PALETTE_YUV422; /* FIXME */
+  vo.start     = start;
+  vo.pitch     = pitch;
+  vo.width     = width;
+  vo.height    = height;
+  vo.flags     = 0;
+  vo.clips     = NULL;
+  vo.clipcount = 0;
+   
+  if (-1 == ioctl(grab_v4l->fd_grab,VIDIOCSWIN2,&vo))
+    perror("v4l: ioctl VIDIOCSOFFSCREEN");
+  if (-1 == ioctl(grab_v4l->fd_grab,VIDIOCCAPTURE,&one))
+    perror("v4l: ioctl VIDIOCCAPTURE");
+  fprintf(stderr,"v4l: offscreen size=%dx%d\n",
+            width,height);
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* capture using mmaped buffers (with double-buffering, ...)              */
+
+static int
+  grab_queue(struct GRABBER *grab_v4l, struct video_mmap *gb, int probe)
+{
+  //fprintf(stderr,"g%d",gb->frame);
+#if 0
+  /* might be useful for debugging driver problems */
+  memset(map + grab_v4l->gb_buffers.offsets[gb->frame],0,
+         grab_v4l->gb_buffers.size/grab_v4l->gb_buffers.frames);
+#endif
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCMCAPTURE,gb)) {
+    if (errno == EAGAIN)
+      fprintf(stderr,"v4l: grabber chip can't sync (no station tuned in?)\n");
+    else
+      if (!probe)
+        fprintf(stderr,"v4l: ioctl VIDIOCMCAPTURE(%d,%s,%dx%d): %s\n",
+                gb->frame,PALETTE(gb->format),gb->width,gb->height,
+                strerror(errno));
+    return -1;
+  }
+  //fprintf(stderr,"* ");
+  grab_v4l->gb_grab++;
+  return 0;
+}
+
+static int
+  grab_wait(struct GRABBER *grab_v4l, struct video_mmap *gb)
+{
+  int ret = 0;
+   
+  //alarm(SYNC_TIMEOUT);
+  //fprintf(stderr,"s%d",gb->frame);
+
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCSYNC,&(gb->frame))) {
+    //perror("v4l: ioctl VIDIOCSYNC");
+    ret = -1;
+  }
+  grab_v4l->gb_sync++;
+  //fprintf(stderr,"* ");
+  //alarm(0);
+  return ret;
+}
+
+static int
+  grab_probe(struct GRABBER *grab_v4l, int format)
+{
+  struct video_mmap gb;
+
+  if (0 != gb_pal[format])
+    goto done;
+
+  gb.frame  = 0;
+  gb.width  = 64;
+  gb.height = 48;
+
+  fprintf(stderr, "v4l: capture probe %s...\t", device_pal[format]);
+  gb.format = format;
+  if (-1 == grab_queue(grab_v4l, &gb,1)) {
+    gb_pal[format] = 2;
+    goto done;
+  }
+  if (-1 == grab_wait(grab_v4l, &gb)) {
+    gb_pal[format] = 2;
+    goto done;
+  }
+  gb_pal[format] = 1;
+  fprintf(stderr, "ok\n");
+
+  done:
+  return gb_pal[format] == 1;
+}
+
+static int
+  grab_mm_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height, int *linelength)
+{
+  //if (!grab_v4l->opened) return -1;
+
+  /* finish old stuff */
+  if (grab_v4l->gb_grab > grab_v4l->gb_sync)
+    grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
+
+  /* verify parameters */
+  ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability);
+  if (*width > grab_v4l->capability.maxwidth)
+    *width = grab_v4l->capability.maxwidth;
+  if (*height > grab_v4l->capability.maxheight)
+    *height = grab_v4l->capability.maxheight; 
+  *linelength = *width * format2depth[format] / 8;
+
+#if 1
+  /* XXX bttv bug workaround - it returns a larger size than it can handle */
+  if (*width > 768+76) {
+    *width = 768+76;
+    *linelength = *width * format2depth[format] / 8;
+  }
+#endif
+
+  /* initialize everything */
+  grab_v4l->gb_even.format = grab_v4l->gb_odd.format =
+                     (format < sizeof(format2palette)/sizeof(unsigned short)) ?
+                     format2palette[format] : 0;
+  if (grab_v4l->gb_even.format == 0 || !grab_probe(grab_v4l, grab_v4l->gb_even.format)) {
+    return -1;
+  }
+  grab_v4l->pixmap_bytes   = format2depth[format] / 8;
+  grab_v4l->gb_even.frame  = 0;
+  grab_v4l->gb_odd.frame   = 1;
+  grab_v4l->gb_even.width  = *width;
+  grab_v4l->gb_even.height = *height;
+  grab_v4l->gb_odd.width   = *width;
+  grab_v4l->gb_odd.height  = *height;
+  grab_v4l->even = 0;
+
+  return 0;
+}
+
+static void*
+  grab_mm_capture(struct GRABBER *grab_v4l, int single)
+{
+  void *buf;
+
+  if (!single && grab_v4l->gb_grab == grab_v4l->gb_sync)
+    /* streaming capture started */
+    if (-1 == grab_queue(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd,0))
+      return NULL;
+
+  if (single && grab_v4l->gb_grab > grab_v4l->gb_sync)
+    /* clear streaming capture */
+    grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
+
+  /* queue */
+  if (-1 == grab_queue(grab_v4l, grab_v4l->even ? &grab_v4l->gb_odd : &grab_v4l->gb_even,0))
+    return NULL;
+  if (grab_v4l->gb_grab > grab_v4l->gb_sync+1) {
+    /* wait -- streaming */
+         //fprintf(stderr, "v4lsrc: 1 %d %d\n", grab_v4l->gb_grab, gb_sync);
+    grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
+    buf = grab_v4l->map + grab_v4l->gb_buffers.offsets[grab_v4l->even ? 0 : 1];
+  } else {
+    /* wait -- single */
+         //fprintf(stderr, "v4lsrc: 2 %d %d %d\n", grab_v4l->gb_grab, gb_sync, even);
+    grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_odd : &grab_v4l->gb_even);
+    buf = grab_v4l->map + grab_v4l->gb_buffers.offsets[grab_v4l->even ? 1 : 0];
+  }
+  grab_v4l->even = !grab_v4l->even;
+       //fprintf(stderr, "v4lsrc: even %d\n", even);
+
+  return buf;
+}
+
+static void
+  grab_mm_cleanup(struct GRABBER *grab_v4l)
+{
+  if (grab_v4l->gb_grab > grab_v4l->gb_sync)
+    grab_wait(grab_v4l, grab_v4l->even ? &grab_v4l->gb_even : &grab_v4l->gb_odd);
+}
+
+/* ---------------------------------------------------------------------- */
+/* capture using simple read()                                            */
+
+static int
+  grab_read_setparams(struct GRABBER *grab_v4l, int format, int *width, int *height, int *linelength)
+{
+  struct video_window win;
+   
+  grab_v4l->pict.depth   = format2depth[format];
+  grab_v4l->pict.palette = format2palette[format];
+
+  /* set format */
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCSPICT,&grab_v4l->pict)) {
+    perror("v4l: ioctl VIDIOCSPICT");
+    return -1;
+  }
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGPICT,&grab_v4l->pict)) {
+    perror("v4l: ioctl VIDIOCGPICT");
+    return -1;
+  }
+  
+  /* set size */
+  ioctl(grab_v4l->fd,VIDIOCGCAP,&grab_v4l->capability);
+  if (*width > grab_v4l->capability.maxwidth)
+    *width = grab_v4l->capability.maxwidth;
+  if (*height > grab_v4l->capability.maxheight)
+    *height = grab_v4l->capability.maxheight;
+  memset(&win,0,sizeof(struct video_window));
+  win.width  = *width;
+  win.height = *height;
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCSWIN,&win)) {
+    perror("v4l: ioctl VIDIOCSWIN");
+    return -1;
+  }
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGWIN,&win)) {
+    perror("v4l: ioctl VIDIOCGWIN");
+    return -1;
+  }
+
+  *width  = win.width;
+  *height = win.height;
+  *linelength = *width * format2depth[format] / 8;
+
+  /* alloc buffer */
+  grab_v4l->grab_read_size = *linelength * *height;
+  if (grab_v4l->grab_read_buf)
+    free(grab_v4l->grab_read_buf);
+  grab_v4l->grab_read_buf = malloc(grab_v4l->grab_read_size);
+  if (NULL == grab_v4l->grab_read_buf)
+    return -1;
+
+   
+  return 0;
+}
+
+static void*
+grab_read_capture(struct GRABBER *grab_v4l, int single)
+{
+   int rc;
+
+   rc = read(grab_v4l->fd,grab_v4l->grab_read_buf,grab_v4l->grab_read_size);
+   if (grab_v4l->grab_read_size != rc) {
+          fprintf(stderr,"v4l: grabber read error (rc=%d)\n",rc);
+     return NULL;
+   }
+   return grab_v4l->grab_read_buf;
+}
+
+static void
+grab_read_cleanup(struct GRABBER *grab_v4l)
+{
+   if (grab_v4l->grab_read_buf) {
+     free(grab_v4l->grab_read_buf);
+     grab_v4l->grab_read_buf = NULL;
+   }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int
+  grab_tune(struct GRABBER *grab_v4l, unsigned long freq)
+{
+  freq = freq*16/1000;
+  fprintf(stderr,"v4l: freq: %.3f\n",(float)freq/16);
+  if (-1 == ioctl(grab_v4l->fd, VIDIOCSFREQ, &freq))
+    perror("v4l: ioctl VIDIOCSFREQ");
+  return 0;
+}
+
+static int
+  grab_tuned(struct GRABBER *grab_v4l)
+{
+  usleep(10000);
+  if (-1 == ioctl(grab_v4l->fd,VIDIOCGTUNER,grab_v4l->tuner)) {
+    perror("v4l: ioctl VIDIOCGTUNER");
+    return 0;
+  }
+  return grab_v4l->tuner->signal ? 1 : 0;
+}
+
+static int
+  grab_input(struct GRABBER *grab_v4l, int input, int norm)
+{
+  if (-1 != input) {
+    fprintf(stderr,"v4l: input: %d\n",input);
+    grab_v4l->cur_input = input;
+  }
+  if (-1 != norm) {
+    fprintf(stderr,"v4l: norm : %d\n",norm);
+    grab_v4l->cur_norm = norm;
+  }
+
+  grab_v4l->channels[grab_v4l->cur_input].norm = grab_v4l->cur_norm;
+  if (-1 == ioctl(grab_v4l->fd, VIDIOCSCHAN, &grab_v4l->channels[grab_v4l->cur_input]))
+    perror("v4l: ioctl VIDIOCSCHAN");
+  return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int grab_hasattr(struct GRABBER *grab_v4l, int id)
+{
+  int i;
+
+  for (i = 0; i < NUM_ATTR; i++)
+    if (id == grab_v4l->grab_attr[i].id && grab_v4l->grab_attr[i].have)
+      break;
+  if (i == NUM_ATTR)
+    return 0;
+  return 1;
+}
+
+int grab_getattr(struct GRABBER *grab_v4l, int id)
+{
+  int i;
+
+  for (i = 0; i < NUM_ATTR; i++)
+    if (id == grab_v4l->grab_attr[i].id && grab_v4l->grab_attr[i].have)
+      break;
+  if (i == NUM_ATTR)
+    return -1;
+  if (-1 == ioctl(grab_v4l->fd,grab_v4l->grab_attr[i].get,grab_v4l->grab_attr[i].arg))
+    perror("v4l: ioctl get");
+
+  switch (id) {
+    case GRAB_ATTR_VOLUME:   return grab_v4l->audio.volume;
+    case GRAB_ATTR_MUTE:     return grab_v4l->audio.flags & VIDEO_AUDIO_MUTE;
+    case GRAB_ATTR_MODE:     return grab_v4l->audio.mode;
+    case GRAB_ATTR_COLOR:    return grab_v4l->pict.contrast;
+    case GRAB_ATTR_BRIGHT:   return grab_v4l->pict.contrast;
+    case GRAB_ATTR_HUE:      return grab_v4l->pict.contrast;
+    case GRAB_ATTR_CONTRAST: return grab_v4l->pict.contrast;
+      default: return -1;
+  }
+}
+
+int grab_setattr(struct GRABBER *grab_v4l, int id, int val)
+{
+  int i;
+   
+  /* read ... */
+  for (i = 0; i < NUM_ATTR; i++)
+    if (id == grab_v4l->grab_attr[i].id && grab_v4l->grab_attr[i].have)
+      break;
+  if (i == NUM_ATTR)
+    return -1;
+  if (-1 == ioctl(grab_v4l->fd,grab_v4l->grab_attr[i].set,grab_v4l->grab_attr[i].arg))
+    perror("v4l: ioctl get");
+
+  /* ... modify ... */
+  switch (id) {
+    case GRAB_ATTR_VOLUME:   grab_v4l->audio.volume = val; break;
+    case GRAB_ATTR_MUTE:
+      if (val)
+        grab_v4l->audio.flags |= VIDEO_AUDIO_MUTE;
+      else
+        grab_v4l->audio.flags &= ~VIDEO_AUDIO_MUTE;
+      break;
+    case GRAB_ATTR_MODE:     grab_v4l->audio.mode      = val; break;
+    case GRAB_ATTR_COLOR:    grab_v4l->pict.colour     = val; break;
+    case GRAB_ATTR_BRIGHT:   grab_v4l->pict.brightness = val; break;
+    case GRAB_ATTR_HUE:      grab_v4l->pict.hue        = val; break;
+    case GRAB_ATTR_CONTRAST: grab_v4l->pict.contrast   = val; break;
+      default: return -1;
+  }
+
+  /* ... write */
+  if (-1 == ioctl(grab_v4l->fd,grab_v4l->grab_attr[i].set,grab_v4l->grab_attr[i].arg))
+    perror("v4l: ioctl set");
+  return 0;
+}
+
diff --git a/sys/v4l/grab.h b/sys/v4l/grab.h
new file mode 100644 (file)
index 0000000..0eafe76
--- /dev/null
@@ -0,0 +1,121 @@
+#define VIDEO_RGB08          1  /* bt848 dithered */
+#define VIDEO_GRAY           2
+#define VIDEO_RGB15_LE       3  /* 15 bpp little endian */
+#define VIDEO_RGB16_LE       4  /* 16 bpp little endian */
+#define VIDEO_RGB15_BE       5  /* 15 bpp big endian */
+#define VIDEO_RGB16_BE       6  /* 16 bpp big endian */
+#define VIDEO_BGR24          7  /* bgrbgrbgrbgr (LE) */
+#define VIDEO_BGR32          8  /* bgr-bgr-bgr- (LE) */
+#define VIDEO_RGB24          9  /* rgbrgbrgbrgb (BE)*/
+#define VIDEO_RGB32         10  /* -rgb-rgb-rgb (BE)*/
+#define VIDEO_LUT2          11  /* lookup-table 2 byte depth */
+#define VIDEO_LUT4          12  /* lookup-table 4 byte depth */
+#define VIDEO_YUV422       13  /* YUV 4:2:2 */
+#define VIDEO_YUV422P       14  /* YUV 4:2:2 (planar) */
+#define VIDEO_YUV420P      15  /* YUV 4:2:0 (planar) */
+#define VIDEO_MJPEG        16  /* MJPEG */
+
+#define CAN_AUDIO_VOLUME     1
+
+#define GRAB_ATTR_VOLUME     1
+#define GRAB_ATTR_MUTE       2
+#define GRAB_ATTR_MODE       3
+
+#define GRAB_ATTR_COLOR     11
+#define GRAB_ATTR_BRIGHT    12
+#define GRAB_ATTR_HUE       13
+#define GRAB_ATTR_CONTRAST  14
+
+#define TRAP(txt) fprintf(stderr,"%s:%d:%s\n",__FILE__,__LINE__,txt);exit(1);
+
+/* ------------------------------------------------------------------------- */
+
+struct STRTAB {
+    long nr;
+    char *str;
+};
+
+typedef struct _OverlayClip OverlayClip;
+
+struct _OverlayClip {
+         int x1, x2, y1, y2;
+};
+
+struct GRAB_ATTR {
+         int   id;
+         int   have;
+         int   get;
+         int   set;
+         void  *arg;
+};
+
+struct GRABBER {
+    char            *name;
+    int             flags;
+    const struct STRTAB   *norms;
+    struct STRTAB   *inputs;
+    const struct STRTAB   *audio_modes;
+               int             opened;
+               char            *map;
+               int             fd, fd_grab;
+
+               /* generic informations */
+               struct video_capability  capability;
+               struct video_channel     *channels;
+               struct video_audio       audio;
+               struct video_tuner       *tuner;
+               struct video_picture     pict;
+#define NUM_ATTR 7
+               struct GRAB_ATTR         grab_attr[NUM_ATTR];
+
+               int                      cur_input;
+               int                      cur_norm;
+               int   grab_read_size;
+               char *grab_read_buf;
+
+               /* overlay */
+               struct video_window      ov_win;
+               struct video_clip        ov_clips[32];
+               struct video_buffer      ov_fbuf;
+
+               /* screen grab */
+               struct video_mmap        gb_even;
+               struct video_mmap        gb_odd;
+               int                      even,pixmap_bytes;
+               int                      gb_grab,gb_sync;
+               struct video_mbuf        gb_buffers;
+
+
+               /* state */
+               int                      overlay, swidth, sheight;
+
+    int   (*grab_open)(struct GRABBER *grab_v4l, char *opt);
+    int   (*grab_close)(struct GRABBER *grab_v4l);
+
+    int   (*grab_setupfb)(struct GRABBER *grab_v4l, int sw, int sh, int format, void *base, int bpl);
+    int   (*grab_overlay)(struct GRABBER *grab_v4l, int x, int y, int width, int height, int format,
+                                                  OverlayClip *oc, int count);
+    int   (*grab_offscreen)(struct GRABBER *grab_v4l, int start, int pitch, int width, int height,
+                                            int format);
+
+               int   (*grab_setparams)(struct GRABBER *grab_v4l, int format, int *width, int *height, int *linelength);
+               void* (*grab_capture)(struct GRABBER *grab_v4l, int single);
+               void  (*grab_cleanup)(struct GRABBER *grab_v4l);
+
+    int   (*grab_tune)(struct GRABBER *grab_v4l, unsigned long freq);
+               int   (*grab_tuned)(struct GRABBER *grab_v4l);
+               int   (*grab_input)(struct GRABBER *grab_v4l, int input, int norm);
+
+#if 0
+               int   (*grab_picture)(int color, int bright, int hue, int contrast);
+         int   (*grab_audio)(int mute, int volume, int *mode);
+#else
+         int   (*grab_hasattr)(struct GRABBER *grab_v4l, int id);
+         int   (*grab_getattr)(struct GRABBER *grab_v4l, int id);
+         int   (*grab_setattr)(struct GRABBER *grab_v4l, int id, int val);
+#endif
+};
+
+/* ------------------------------------------------------------------------- */
+
+struct GRABBER *grab_init();
diff --git a/sys/v4l/gstv4lsrc.c b/sys/v4l/gstv4lsrc.c
new file mode 100644 (file)
index 0000000..fc847c8
--- /dev/null
@@ -0,0 +1,629 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <string.h>
+
+//#define DEBUG_ENABLED
+#include <gstv4lsrc.h>
+
+#include <linux/videodev.h>
+
+static GstElementDetails gst_v4lsrc_details = {
+  "Video (v4l) Source",
+  "Source/Video",
+  "Read from a Video for Linux capture device",
+  VERSION,
+  "Wim Taymans <wim.taymans@tvd.be>",
+  "(C) 2000",
+};
+
+/* V4lSrc signals and args */
+enum {
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+  ARG_WIDTH,
+  ARG_HEIGHT,
+  ARG_FORMAT,
+  ARG_TUNE,
+  ARG_TUNED,
+  ARG_INPUT,
+  ARG_NORM,
+  ARG_VOLUME,
+  ARG_MUTE,
+  ARG_AUDIO_MODE,
+  ARG_COLOR,
+  ARG_BRIGHT,
+  ARG_HUE,
+  ARG_CONTRAST,
+  ARG_DEVICE,
+};
+
+
+static void                    gst_v4lsrc_class_init   (GstV4lSrcClass *klass);
+static void                    gst_v4lsrc_init         (GstV4lSrc *v4lsrc);
+
+static void                    gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void                    gst_v4lsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static GstElementStateReturn   gst_v4lsrc_change_state (GstElement *element);
+static void                    gst_v4lsrc_close_v4l    (GstV4lSrc *src);
+static gboolean                        gst_v4lsrc_open_v4l     (GstV4lSrc *src);
+
+static GstBuffer*              gst_v4lsrc_get          (GstPad *pad);
+static GstPadNegotiateReturn   gst_v4lsrc_negotiate    (GstPad *pad, GstCaps **caps, gpointer *user_data);
+
+static gboolean                        gst_v4lsrc_sync_parms   (GstV4lSrc *v4lsrc);
+
+static GstElementClass *parent_class = NULL;
+////static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_v4lsrc_get_type (void)
+{
+  static GType v4lsrc_type = 0;
+
+  if (!v4lsrc_type) {
+    static const GTypeInfo v4lsrc_info = {
+      sizeof(GstV4lSrcClass),      NULL,
+      NULL,
+      (GClassInitFunc)gst_v4lsrc_class_init,
+      NULL,
+      NULL,
+      sizeof(GstV4lSrc),
+      0,
+      (GInstanceInitFunc)gst_v4lsrc_init,
+      NULL
+    };
+    v4lsrc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
+  }
+  return v4lsrc_type;
+}
+
+static void
+gst_v4lsrc_class_init (GstV4lSrcClass *klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
+    g_param_spec_int("width","width","width",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
+    g_param_spec_int("height","height","height",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
+    g_param_spec_int("format","format","format",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TUNE,
+    g_param_spec_ulong("tune","tune","tune",
+                       0,G_MAXULONG,0,G_PARAM_WRITABLE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TUNED,
+    g_param_spec_boolean("tuned","tuned","tuned",
+                         TRUE,G_PARAM_READABLE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_INPUT,
+    g_param_spec_int("input","input","input",
+                     G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM,
+    g_param_spec_int("norm","norm","norm",
+                     G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
+    g_param_spec_int("volume","volume","volume",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
+    g_param_spec_boolean("mute","mute","mute",
+                         TRUE,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_AUDIO_MODE,
+    g_param_spec_int("mode","mode","mode",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_COLOR,
+    g_param_spec_int("color","color","color",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHT,
+    g_param_spec_int("bright","bright","bright",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HUE,
+    g_param_spec_int("hue","hue","hue",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CONTRAST,
+    g_param_spec_int("contrast","contrast","contrast",
+                     G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
+    g_param_spec_string("device","device","device",
+                        NULL, G_PARAM_READWRITE)); // CHECKME
+
+  gobject_class->set_property = gst_v4lsrc_set_property;
+  gobject_class->get_property = gst_v4lsrc_get_property;
+
+  gstelement_class->change_state = gst_v4lsrc_change_state;
+}
+
+static void
+gst_v4lsrc_init (GstV4lSrc *v4lsrc)
+{
+  v4lsrc->srcpad = gst_pad_new("src",GST_PAD_SRC);
+  gst_element_add_pad(GST_ELEMENT(v4lsrc),v4lsrc->srcpad);
+
+  gst_pad_set_get_function (v4lsrc->srcpad,gst_v4lsrc_get);
+  gst_pad_set_negotiate_function (v4lsrc->srcpad,gst_v4lsrc_negotiate);
+
+  /* if the destination cannot say what it wants, we give this */
+  v4lsrc->width = 100;
+  v4lsrc->height = 100;
+  v4lsrc->format = 0;
+  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 3;
+  // make a grbber
+  v4lsrc->grabber = grab_init();
+  v4lsrc->device = NULL;
+  v4lsrc->init = TRUE;
+}
+
+static GstPadNegotiateReturn
+gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data) 
+{
+  GstV4lSrc *v4lsrc;
+
+  GST_DEBUG (0, "v4lsrc: negotiate %p\n", user_data); 
+
+  v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
+
+  if (!*caps) {
+    return GST_PAD_NEGOTIATE_FAIL;
+  }
+  else {
+    gint width, height;
+    gulong format;
+
+    GST_DEBUG (0, "%08lx\n", gst_caps_get_fourcc_int (*caps, "format"));
+
+    width  = gst_caps_get_int (*caps, "width");
+    height = gst_caps_get_int (*caps, "height");
+
+    format =  gst_caps_get_fourcc_int (*caps, "format");
+
+    g_print ("v4lsrc: got format %08lx\n", format);
+
+    switch (format) {
+      case GST_MAKE_FOURCC ('R','G','B',' '):
+      {
+        gint depth, endianness, bpp;
+
+        depth = gst_caps_get_int (*caps, "depth");
+        bpp = gst_caps_get_int (*caps, "bpp");
+        endianness = gst_caps_get_int (*caps, "endianness");
+
+        GST_DEBUG (0, "%d\n", depth);
+        g_print ("v4lsrc: got depth %d, bpp %d, endianness %d\n", depth, bpp, endianness);
+       switch (depth) {
+          case 15:
+            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
+                    VIDEO_RGB15_LE:
+                    VIDEO_RGB15_BE);
+            v4lsrc->buffer_size = width * height * 2;
+            break;
+          case 16:
+            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
+                    VIDEO_RGB16_LE:
+                    VIDEO_RGB16_BE);
+            v4lsrc->buffer_size = width * height * 2;
+            break;
+          case 24:
+            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
+                    VIDEO_BGR24:
+                    VIDEO_RGB24);
+            v4lsrc->buffer_size = width * height * 3;
+            break;
+          case 32:
+            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
+                    VIDEO_BGR32:
+                    VIDEO_RGB32);
+            v4lsrc->buffer_size = width * height * 4;
+            break;
+          default:
+            *caps = NULL;
+            return GST_PAD_NEGOTIATE_TRY;
+       }
+       break;
+      }
+      case GST_MAKE_FOURCC ('I','4','2','0'):
+        v4lsrc->format = VIDEO_YUV420P;
+        v4lsrc->buffer_size = width * height +
+                             width * height / 2;
+       break;
+      case GST_MAKE_FOURCC ('U','Y','V','Y'):
+       if (G_BYTE_ORDER == G_BIG_ENDIAN) {
+          v4lsrc->format = VIDEO_YUV422;
+          v4lsrc->buffer_size = width * height * 2;
+         break;
+       }
+       else {
+          *caps = NULL;
+          return GST_PAD_NEGOTIATE_TRY;
+       }
+      case GST_MAKE_FOURCC ('Y','U','Y','2'):
+       if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
+          v4lsrc->format = VIDEO_YUV422;
+          v4lsrc->buffer_size = width * height * 2;
+         break;
+       }
+       else {
+          *caps = NULL;
+          return GST_PAD_NEGOTIATE_TRY;
+       }
+      default:
+        *caps = NULL;
+        return GST_PAD_NEGOTIATE_TRY;
+    }
+    v4lsrc->width  = width;
+    v4lsrc->height = height;
+
+    if (gst_v4lsrc_sync_parms (v4lsrc)) {
+      return GST_PAD_NEGOTIATE_AGREE;
+    }
+    else {
+      *caps = NULL;
+      return GST_PAD_NEGOTIATE_TRY;
+    }
+  }
+
+  return GST_PAD_NEGOTIATE_FAIL;
+}
+
+static GstCaps*
+gst_v4lsrc_create_caps (GstV4lSrc *src)
+{
+  GstCaps *caps;
+  gulong fourcc = 0;
+  gint width, height;
+
+  width = src->width;
+  height = src->height;
+
+  switch (src->format) {
+    case VIDEO_RGB08:
+    case VIDEO_GRAY:
+    case VIDEO_LUT2:
+    case VIDEO_LUT4:
+      caps = NULL;
+      break;
+    case VIDEO_RGB15_LE:
+    case VIDEO_RGB16_LE:
+    case VIDEO_RGB15_BE:
+    case VIDEO_RGB16_BE:
+    case VIDEO_BGR24:
+    case VIDEO_BGR32:
+    case VIDEO_RGB24:
+    case VIDEO_RGB32:
+      caps = NULL;
+      break;
+    case VIDEO_YUV422:
+    case VIDEO_YUV422P:
+    case VIDEO_YUV420P: {
+
+      if (src->format == VIDEO_YUV422) {
+        fourcc = GST_STR_FOURCC ("YUY2");
+        src->buffer_size = width * height * 2;
+      }
+      else if (src->format == VIDEO_YUV422P) {
+        fourcc = GST_STR_FOURCC ("YV12");
+        src->buffer_size = width * height * 2;
+      }
+      else if (src->format == VIDEO_YUV420P) {
+        fourcc = GST_STR_FOURCC ("I420");
+        src->buffer_size = width * height +
+                             width * height / 2;
+      }
+      
+      caps = GST_CAPS_NEW (
+                     "v4lsrc_caps",
+                     "video/raw",
+                       "format",       GST_PROPS_FOURCC (fourcc),
+                       "width",        GST_PROPS_INT (src->width),
+                       "height",       GST_PROPS_INT (src->height)
+                       );
+      break;
+    }
+    default:
+      caps = NULL;
+      break;
+  }
+
+  return caps;
+}
+
+static GstBuffer*
+gst_v4lsrc_get (GstPad *pad)
+{
+  GstV4lSrc *v4lsrc;
+  GstBuffer *buf = NULL;
+  guint8 *grab_buf;
+
+  g_return_val_if_fail (pad != NULL, NULL);
+
+  v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
+
+  if (v4lsrc->format && v4lsrc->init) {
+    gst_pad_set_caps (v4lsrc->srcpad, gst_v4lsrc_create_caps (v4lsrc));
+    v4lsrc->init = FALSE;
+  }
+  else {
+    if (!gst_pad_get_caps (v4lsrc->srcpad) && 
+        !gst_pad_renegotiate (v4lsrc->srcpad)) {
+      return NULL;
+    }
+  }
+
+  buf = gst_buffer_new();
+  GST_BUFFER_DATA(buf) = g_malloc(v4lsrc->buffer_size);
+  GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
+  GST_DEBUG (0,"v4lsrc: making new buffer %p\n", GST_BUFFER_DATA(buf));
+
+  GST_DEBUG (0,"v4lsrc: request buffer\n");
+  // request a buffer from the grabber
+  grab_buf = v4lsrc->grabber->grab_capture(v4lsrc->grabber, 0);
+  //meta_pull->overlay_info->did_overlay = FALSE;
+
+  g_assert(buf != NULL);
+
+  GST_DEBUG (0,"v4lsrc: sending %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
+  // copy the buffer
+  memcpy(GST_BUFFER_DATA(buf), grab_buf, GST_BUFFER_SIZE(buf));
+
+  GST_DEBUG (0,"v4lsrc: sent %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
+
+  return buf;
+}
+
+static void
+gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+  GstV4lSrc *src;
+  int ret = 0;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_V4LSRC(object));
+  src = GST_V4LSRC(object);
+
+  switch (prop_id) {
+    case ARG_WIDTH:
+      src->width = g_value_get_int (value);
+      gst_v4lsrc_sync_parms(src);
+      break;
+    case ARG_HEIGHT:
+      src->height = g_value_get_int (value);
+      gst_v4lsrc_sync_parms(src);
+      break;
+    case ARG_FORMAT:
+      src->format = g_value_get_int (value);
+      break;
+    case ARG_TUNE:
+      src->tune = g_value_get_ulong (value);
+      ret = src->grabber->grab_tune(src->grabber, src->tune);
+      break;
+    case ARG_INPUT:
+      src->input = g_value_get_int (value);
+      ret = src->grabber->grab_input(src->grabber, src->input, -1);
+      break;
+    case ARG_NORM:
+      src->norm = g_value_get_int (value);
+      ret = src->grabber->grab_input(src->grabber, -1, src->norm);
+      break;
+    case ARG_VOLUME:
+      src->volume = g_value_get_int (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_VOLUME, src->volume);
+      break;
+    case ARG_MUTE:
+      src->mute = g_value_get_boolean (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_MUTE, src->mute);
+      break;
+    case ARG_AUDIO_MODE:
+      src->audio_mode = g_value_get_int (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_MODE, src->audio_mode);
+      break;
+    case ARG_COLOR:
+      src->color = g_value_get_int (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_COLOR, src->color);
+      break;
+    case ARG_BRIGHT:
+      src->bright = g_value_get_int (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_BRIGHT, src->bright);
+      break;
+    case ARG_HUE:
+      src->hue = g_value_get_int (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_HUE, src->hue);
+      break;
+    case ARG_CONTRAST:
+      src->contrast = g_value_get_int (value);
+      ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_CONTRAST, src->contrast);
+      break;
+    case ARG_DEVICE:
+      if (src->device)
+       g_free (src->device);
+      src->device = g_strdup (g_value_get_string (value));
+      break;
+    default:
+      ret = -1;
+      break;
+  }
+  if (ret == -1) {
+    fprintf(stderr, "v4lsrc: error setting property\n");
+  }
+}
+
+static void
+gst_v4lsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+  GstV4lSrc *src;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_V4LSRC(object));
+  src = GST_V4LSRC(object);
+
+  g_print ("get arg\n");
+
+  switch (prop_id) {
+    case ARG_WIDTH:
+      g_value_set_int (value, src->width);
+      break;
+    case ARG_HEIGHT:
+      g_value_set_int (value, src->height);
+      break;
+    case ARG_TUNED:
+      g_value_set_boolean (value, src->grabber->grab_tuned(src->grabber));
+      break;
+    case ARG_VOLUME:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_VOLUME));
+      break;
+    case ARG_MUTE:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_MUTE));
+      break;
+    case ARG_AUDIO_MODE:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_MODE));
+      break;
+    case ARG_COLOR:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_COLOR));
+      break;
+    case ARG_BRIGHT:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_BRIGHT));
+      break;
+    case ARG_HUE:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_HUE));
+      break;
+    case ARG_CONTRAST:
+      g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_CONTRAST));
+      break;
+    case ARG_DEVICE:
+      g_value_set_string (value, src->device);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstElementStateReturn
+gst_v4lsrc_change_state (GstElement *element)
+{
+  g_return_val_if_fail(GST_IS_V4LSRC(element), FALSE);
+
+  /* if going down into NULL state, close the file if it's open */
+  if (GST_STATE_PENDING(element) == GST_STATE_NULL) {
+    if (GST_FLAG_IS_SET(element,GST_V4LSRC_OPEN))
+      gst_v4lsrc_close_v4l(GST_V4LSRC(element));
+  /* otherwise (READY or higher) we need to open the sound card */
+  } else {
+    gst_info ("v4lsrc: opening\n");
+    if (!GST_FLAG_IS_SET(element,GST_V4LSRC_OPEN)) {
+      if (!gst_v4lsrc_open_v4l(GST_V4LSRC(element))) {
+       gst_info ("v4lsrc: open failed\n");
+        return GST_STATE_FAILURE;
+      }
+    }
+  }
+
+  if (GST_ELEMENT_CLASS(parent_class)->change_state)
+    return GST_ELEMENT_CLASS(parent_class)->change_state(element);
+
+  return GST_STATE_SUCCESS;
+}
+
+static gboolean
+gst_v4lsrc_sync_parms (GstV4lSrc *src)
+{
+  gint linelength;
+  gboolean success;
+
+  g_return_val_if_fail(src != NULL, FALSE);
+  g_return_val_if_fail(GST_IS_V4LSRC(src), FALSE);
+
+  GST_DEBUG (0,"v4lsrc: resync %d %d %d\n", src->width, src->height, src->format);
+
+  if (!src->grabber->opened) 
+    return FALSE;
+
+  if (src->grabber->grab_setparams(src->grabber, src->format, &src->width, &src->height, &linelength) != 0) {
+    fprintf(stderr, "v4lsrc: error setting params\n");
+    success = FALSE;
+  }
+  else {
+    GST_DEBUG (0,"v4lsrc: resynced to %d %d %d\n", src->width, src->height, src->buffer_size);
+    success = TRUE;
+  }
+  return success;
+}
+
+static gboolean
+gst_v4lsrc_open_v4l (GstV4lSrc *src)
+{
+  g_return_val_if_fail(src->grabber != NULL, FALSE);
+  g_return_val_if_fail(!src->grabber->opened, FALSE);
+
+  if (src->grabber->grab_open(src->grabber, src->device) != -1) {
+    gst_v4lsrc_sync_parms(src);
+    GST_FLAG_SET(src, GST_V4LSRC_OPEN);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static void
+gst_v4lsrc_close_v4l (GstV4lSrc *src)
+{
+  g_return_if_fail(src->grabber != NULL);
+  g_return_if_fail(src->grabber->opened);
+
+  src->grabber->grab_close(src->grabber);
+  GST_FLAG_UNSET(src, GST_V4LSRC_OPEN);
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+  GstElementFactory *factory;
+
+  /* create an elementfactory for the v4lsrcparse element */
+  factory = gst_elementfactory_new("v4lsrc",GST_TYPE_V4LSRC,
+                                   &gst_v4lsrc_details);
+  g_return_val_if_fail(factory != NULL, FALSE);
+  gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+  return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+  GST_VERSION_MAJOR,
+  GST_VERSION_MINOR,
+  "v4lsrc",
+  plugin_init
+};
+
diff --git a/sys/v4l/gstv4lsrc.h b/sys/v4l/gstv4lsrc.h
new file mode 100644 (file)
index 0000000..8411e9d
--- /dev/null
@@ -0,0 +1,97 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_V4LSRC_H__
+#define __GST_V4LSRC_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+#include <linux/videodev.h>
+
+#include "grab.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_V4LSRC \
+  (gst_v4lsrc_get_type())
+#define GST_V4LSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LSRC,GstV4lSrc))
+#define GST_V4LSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LSRC,GstV4lSrcClass))
+#define GST_IS_V4LSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LSRC))
+#define GST_IS_V4LSRC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LSRC))
+
+// NOTE: per-element flags start with 16 for now
+typedef enum {
+  GST_V4LSRC_OPEN            = GST_ELEMENT_FLAG_LAST,
+
+  GST_V4LSRC_FLAG_LAST       = GST_ELEMENT_FLAG_LAST+2,
+} GstV4lSrcFlags;
+
+typedef struct _GstV4lSrc GstV4lSrc;
+typedef struct _GstV4lSrcClass GstV4lSrcClass;
+
+struct _GstV4lSrc {
+  GstElement element;
+
+  /* pads */
+  GstPad *srcpad;
+
+  /* video device */
+  struct GRABBER *grabber;
+  gboolean init;
+
+  gint width;
+  gint height;
+  guint16 format;
+  guint32 buffer_size;
+  gulong tune;
+  gboolean tuned;
+  gint input;
+  gint norm;
+  gint volume;
+  gboolean mute;
+  gint audio_mode;
+  gint color;
+  gint bright;
+  gint hue;
+  gint contrast;
+  gchar *device;
+};
+
+struct _GstV4lSrcClass {
+  GstElementClass parent_class;
+};
+
+GType gst_v4lsrc_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_V4LSRC_H__ */