New video4linux plugins, can also handle hardware JPEG devices. First check-in, proba...
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sun, 23 Dec 2001 15:31:15 +0000 (15:31 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Sun, 23 Dec 2001 15:31:15 +0000 (15:31 +0000)
Original commit message from CVS:
New video4linux plugins, can also handle hardware JPEG devices. First check-in, probably has lots of bugs which will be fixed when we find them

16 files changed:
sys/v4l/Makefile.am
sys/v4l/README [new file with mode: 0644]
sys/v4l/TODO [new file with mode: 0644]
sys/v4l/gstv4lelement.c [new file with mode: 0644]
sys/v4l/gstv4lelement.h [new file with mode: 0644]
sys/v4l/gstv4lmjpegsrc.c [new file with mode: 0644]
sys/v4l/gstv4lmjpegsrc.h [new file with mode: 0644]
sys/v4l/gstv4lsrc.c
sys/v4l/gstv4lsrc.h
sys/v4l/v4l_calls.c [new file with mode: 0644]
sys/v4l/v4l_calls.h [new file with mode: 0644]
sys/v4l/v4lmjpegsrc_calls.c [new file with mode: 0644]
sys/v4l/v4lmjpegsrc_calls.h [new file with mode: 0644]
sys/v4l/v4lsrc_calls.c [new file with mode: 0644]
sys/v4l/v4lsrc_calls.h [new file with mode: 0644]
sys/v4l/videodev_mjpeg.h [new file with mode: 0644]

index b99e2d4..914df99 100644 (file)
@@ -1,12 +1,40 @@
-plugindir = $(libdir)/gst
+filterdir = $(libdir)/gst
 
-plugin_LTLIBRARIES = libv4lsrc.la
+filter_LTLIBRARIES = libv4lelement.la libv4lsrc.la \
+       libv4lmjpegsrc.la
+#libv4lmjpegsink.la
 
-libv4lsrc_la_SOURCES = \
-                   gstv4lsrc.c \
-                   grab-v4l.c
+libv4lelement_la_SOURCES = \
+               gstv4lelement.c \
+               v4l_calls.c
+libv4lelement_la_CFLAGS = \
+               $(GST_CFLAGS)
 
-## FIXME : do we need -O2 ? libv4lsrc_la_CFLAGS = -O2 $(GST_CFLAGS)
-libv4lsrc_la_CFLAGS = $(GST_CFLAGS)
+libv4lsrc_la_SOURCES = \
+               gstv4lsrc.c \
+               v4lsrc_calls.c
+libv4lsrc_la_LIBADD = \
+               libv4lelement.la
+libv4lsrc_la_CFLAGS = \
+               $(GST_CFLAGS)
 
-noinst_HEADERS = gstv4lsrc.h grab.h
+libv4lmjpegsrc_la_SOURCES = \
+               gstv4lmjpegsrc.c \
+               v4lmjpegsrc_calls.c
+libv4lmjpegsrc_la_LIBADD = \
+               libv4lelement.la
+libv4lmjpegsrc_la_CFLAGS = \
+               $(GST_CFLAGS)
+
+#libv4lmjpegsink_la_SOURCED = \
+#              gstv4lmjpegsink.c \
+#              v4lmjpegsikn_calls.c
+#libv4lmjpegsink_la_LIBADD = \
+#              libv4lelement.la
+#libv4lmjpegsink_la_CFLAGS = \
+#              $(GST_CFLAGS)
+
+noinst_HEADERS = gstv4lelement.h v4l_calls.h \
+               gstv4lsrc.h v4lsrc_calls.h \
+               gstv4lmjpegsrc.h v4lmjpegsrc_calls.h
+#gstv4lmjpegsink.h v4lmjpegsink_calls.h
diff --git a/sys/v4l/README b/sys/v4l/README
new file mode 100644 (file)
index 0000000..2df87fa
--- /dev/null
@@ -0,0 +1,22 @@
+General idea:
+
+                            /     gstv4lsrc.[ch]
+                       /          v4lsrc_calls.[ch]
+                    /
+gstv4lelement.[ch] -------------  gstv4lmjpegsrc.[ch]
+v4l_calls.[ch]     -------------  v4lmjpegsrc_calls.[ch]
+                    \
+                       \          gstv4lmjpegsink.[ch]
+                            \     v4lmjpegsink_calls.[ch]
+
+
+I.e., all the files on thei right are child classes of
+the v4lelement 'parent' on the left.mjpegsink is still
+todo.
+
+Generic idea:
+* v4lelement handles generic v4l stuff (picture settings,
+    audio, norm/input setting, open()/close())
+* v4lsrc, v4lmjpegsrc handle the capture specific
+    functions. Maybe we'd need a v4lmpegsrc too
+* v4lmjpegsink handles mjpeg hardware playback of video
diff --git a/sys/v4l/TODO b/sys/v4l/TODO
new file mode 100644 (file)
index 0000000..efda739
--- /dev/null
@@ -0,0 +1,5 @@
+* v4lmjpegsrc: integrate input/norm autodetection
+* v4lmjpegsink: build
+* v4lsrc: threaded sync()
+* v4lsrc: threaded wait-for-sync()-until-queue()
+* BSD-src: build (based on Bt848/Bt878/Meteor API)
diff --git a/sys/v4l/gstv4lelement.c b/sys/v4l/gstv4lelement.c
new file mode 100644 (file)
index 0000000..9b05546
--- /dev/null
@@ -0,0 +1,479 @@
+/* G-Streamer generic V4L element - generic V4L calls handling
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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 "v4l_calls.h"
+
+#if 0
+static GstElementDetails gst_v4lelement_details = {
+  "Generic video4linux Element",
+  "None/Video",
+  "Generic plugin for handling common video4linux calls",
+  VERSION,
+  "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+  "(C) 2001",
+};
+#endif
+
+/* V4lElement signals and args */
+enum {
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+  ARG_CHANNEL,
+  ARG_NORM,
+  ARG_HAS_TUNER,
+  ARG_FREQUENCY,
+  ARG_HAS_AUDIO,
+  ARG_MUTE,
+  ARG_MODE,
+  ARG_VOLUME,
+  ARG_HUE,
+  ARG_BRIGHTNESS,
+  ARG_CONTRAST,
+  ARG_SATURATION,
+  ARG_DEVICE
+};
+
+
+static void                  gst_v4lelement_class_init   (GstV4lElementClass *klass);
+static void                  gst_v4lelement_init         (GstV4lElement      *v4lelement);
+static void                  gst_v4lelement_set_property (GObject            *object,
+                                                          guint              prop_id,
+                                                          const GValue       *value,
+                                                          GParamSpec         *pspec);
+static void                  gst_v4lelement_get_property (GObject            *object,
+                                                          guint              prop_id,
+                                                          GValue             *value,
+                                                          GParamSpec         *pspec);
+static GstElementStateReturn gst_v4lelement_change_state (GstElement         *element);
+static gboolean              plugin_init                 (GModule            *module,
+                                                          GstPlugin          *plugin);
+
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_v4lelement_signals[LAST_SIGNAL] = { 0 };
+
+
+GType
+gst_v4lelement_get_type (void)
+{
+  static GType v4lelement_type = 0;
+
+  if (!v4lelement_type) {
+    static const GTypeInfo v4lelement_info = {
+      sizeof(GstV4lElementClass),
+      NULL,
+      NULL,
+      (GClassInitFunc)gst_v4lelement_class_init,
+      NULL,
+      NULL,
+      sizeof(GstV4lElement),
+      0,
+      (GInstanceInitFunc)gst_v4lelement_init,
+      NULL
+    };
+    v4lelement_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lElement", &v4lelement_info, 0);
+  }
+  return v4lelement_type;
+}
+
+
+
+static void
+gst_v4lelement_class_init (GstV4lElementClass *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_CHANNEL,
+    g_param_spec_int("channel","channel","channel",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+  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_READWRITE));
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_TUNER,
+    g_param_spec_boolean("has_tuner","has_tuner","has_tuner",0,G_PARAM_READABLE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
+    g_param_spec_ulong("frequency","frequency","frequency",0,G_MAXULONG,0,G_PARAM_READWRITE));
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_AUDIO,
+    g_param_spec_boolean("has_audio","has_audio","has_audio",0,G_PARAM_READABLE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
+    g_param_spec_boolean("mute","mute","mute",0,G_PARAM_READWRITE));
+  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));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MODE,
+    g_param_spec_int("mode","mode","mode",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+
+  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));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHTNESS,
+    g_param_spec_int("brightness","brightness","brightness",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+  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));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SATURATION,
+    g_param_spec_int("saturation","saturation","saturation",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
+    g_param_spec_string("device","device","device", NULL, G_PARAM_READWRITE));
+
+  gobject_class->set_property = gst_v4lelement_set_property;
+  gobject_class->get_property = gst_v4lelement_get_property;
+
+  gstelement_class->change_state = gst_v4lelement_change_state;
+}
+
+
+static void
+gst_v4lelement_init (GstV4lElement *v4lelement)
+{
+  /* some default values */
+  v4lelement->video_fd = -1;
+  v4lelement->buffer = NULL;
+  v4lelement->videodev = NULL;
+
+  v4lelement->norm = -1;
+  v4lelement->channel = 0; /* the first channel */
+
+  v4lelement->frequency = 0;
+
+  v4lelement->mute = -1;
+  v4lelement->volume = -1;
+  v4lelement->mode = -1;
+
+  v4lelement->brightness = -1;
+  v4lelement->hue = -1;
+  v4lelement->contrast = -1;
+  v4lelement->saturation = -1;
+}
+
+
+static void
+gst_v4lelement_set_property (GObject      *object,
+                             guint        prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GstV4lElement *v4lelement;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_V4LELEMENT(object));
+  v4lelement = GST_V4LELEMENT(object);
+
+  switch (prop_id)
+  {
+    case ARG_CHANNEL:
+      v4lelement->channel = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
+      {
+        if (v4lelement->norm >= 0)
+          if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
+            return;
+      }
+      break;
+    case ARG_NORM:
+      v4lelement->norm = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
+      {
+        if (v4lelement->norm >= 0)
+          if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
+            return;
+      }
+      break;
+    case ARG_FREQUENCY:
+      v4lelement->frequency = g_value_get_ulong(value);
+      if (GST_V4L_IS_ACTIVE(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
+      {
+        if (!gst_v4l_set_frequency(v4lelement, v4lelement->frequency))
+          return;
+      }
+      break;
+    case ARG_MUTE:
+      v4lelement->mute = g_value_get_boolean(value)?1:0;
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_MUTE, v4lelement->mute))
+          return;
+      }
+      break;
+    case ARG_MODE:
+      v4lelement->mode = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_MODE, v4lelement->mute))
+          return;
+      }
+      break;
+    case ARG_VOLUME:
+      v4lelement->volume = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_VOLUME, v4lelement->volume))
+          return;
+      }
+      break;
+    case ARG_HUE:
+      v4lelement->hue = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_HUE, v4lelement->hue))
+          return;
+      }
+      break;
+    case ARG_BRIGHTNESS:
+      v4lelement->brightness = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_BRIGHTNESS, v4lelement->brightness))
+          return;
+      }
+      break;
+    case ARG_CONTRAST:
+      v4lelement->contrast = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_CONTRAST, v4lelement->contrast))
+          return;
+      }
+      break;
+    case ARG_SATURATION:
+      v4lelement->saturation = g_value_get_int(value);
+      if (GST_V4L_IS_OPEN(v4lelement))
+      {
+        if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_SATURATION, v4lelement->saturation))
+          return;
+      }
+      break;
+    case ARG_DEVICE:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        break; /* only set when *not* open */
+      if (v4lelement->videodev)
+        g_free(v4lelement->videodev);
+      v4lelement->videodev = g_strdup(g_value_get_string(value));
+      break;
+    default:
+      //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_v4lelement_get_property (GObject    *object,
+                             guint      prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  GstV4lElement *v4lelement;
+  gint temp_i = 0;
+  gulong temp_ul = 0;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_V4LELEMENT(object));
+  v4lelement = GST_V4LELEMENT(object);
+
+  switch (prop_id)
+  {
+    case ARG_CHANNEL:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_chan_norm(v4lelement, &temp_i, NULL);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_NORM:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_chan_norm(v4lelement, NULL, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_HAS_TUNER:
+      g_value_set_boolean(value, FALSE);
+      if (GST_V4L_IS_OPEN(v4lelement))
+        if (gst_v4l_has_tuner(v4lelement))
+          g_value_set_boolean(value, TRUE);
+      break;
+    case ARG_FREQUENCY:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_frequency(v4lelement, &temp_ul);
+      g_value_set_ulong(value, temp_ul);
+      break;
+    case ARG_HAS_AUDIO:
+      g_value_set_boolean(value, FALSE);
+      if (GST_V4L_IS_OPEN(v4lelement))
+        if (gst_v4l_has_audio(v4lelement))
+          g_value_set_boolean(value, TRUE);
+      break;
+    case ARG_MUTE:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        if (gst_v4l_has_tuner(v4lelement))
+          gst_v4l_get_audio(v4lelement, V4L_AUDIO_MUTE, &temp_i);
+      g_value_set_int(value, temp_i?TRUE:FALSE);
+      break;
+    case ARG_MODE:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        if (gst_v4l_has_tuner(v4lelement))
+          gst_v4l_get_audio(v4lelement, V4L_AUDIO_MODE, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_VOLUME:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        if (gst_v4l_has_tuner(v4lelement))
+          gst_v4l_get_audio(v4lelement, V4L_AUDIO_VOLUME, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_HUE:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_picture(v4lelement, V4L_PICTURE_HUE, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_BRIGHTNESS:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_picture(v4lelement, V4L_PICTURE_BRIGHTNESS, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_CONTRAST:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_picture(v4lelement, V4L_PICTURE_CONTRAST, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_SATURATION:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        gst_v4l_get_picture(v4lelement, V4L_PICTURE_SATURATION, &temp_i);
+      g_value_set_int(value, temp_i);
+      break;
+    case ARG_DEVICE:
+      g_value_set_string(value, v4lelement->videodev?v4lelement->videodev:"/dev/video");
+      break;
+    default:
+      //G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static GstElementStateReturn
+gst_v4lelement_change_state (GstElement *element)
+{
+  GstV4lElement *v4lelement;
+  
+  g_return_val_if_fail(GST_IS_V4LELEMENT(element), FALSE);
+  
+  v4lelement = GST_V4LELEMENT(element);
+
+  /* if going down into NULL state, close the device if it's open
+   * if going to READY, open the device (and set some options)
+   */
+  switch (GST_STATE_PENDING(element))
+  {
+    case GST_STATE_NULL:
+      if (GST_V4L_IS_OPEN(v4lelement))
+        if (!gst_v4l_close(v4lelement))
+          return GST_STATE_FAILURE;
+      break;
+    case GST_STATE_READY:
+      if (!GST_V4L_IS_OPEN(v4lelement))
+      {
+        int n, temp;
+
+        if (!gst_v4l_open(v4lelement))
+          return GST_STATE_FAILURE;
+
+        /* now, sync options */
+        if (v4lelement->norm >= VIDEO_MODE_PAL &&
+           v4lelement->norm < VIDEO_MODE_AUTO &&
+           v4lelement->channel >= 0)
+        {
+          if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
+            return GST_STATE_FAILURE;
+        }
+        if (v4lelement->frequency > 0 && gst_v4l_has_tuner(v4lelement))
+        {
+          if (!gst_v4l_set_frequency(v4lelement, v4lelement->frequency))
+            return GST_STATE_FAILURE;
+        }
+        for (n=V4L_AUDIO_VOLUME;n<=V4L_AUDIO_MODE;n++)
+        {
+          switch (n)
+          {
+            case V4L_AUDIO_MUTE:   temp = v4lelement->mute;   break;
+            case V4L_AUDIO_VOLUME: temp = v4lelement->volume; break;
+            case V4L_AUDIO_MODE:   temp = v4lelement->mode;   break;
+          }
+          if (temp >= 0 && gst_v4l_has_audio(v4lelement))
+          {
+            if (!gst_v4l_set_audio(v4lelement, n, temp))
+              return GST_STATE_FAILURE;
+          }
+        }
+        for (n=V4L_PICTURE_HUE;n<=V4L_PICTURE_SATURATION;n++)
+        {
+          switch (n)
+          {
+            case V4L_PICTURE_HUE:        temp = v4lelement->hue;        break;
+            case V4L_PICTURE_BRIGHTNESS: temp = v4lelement->brightness; break;
+            case V4L_PICTURE_SATURATION: temp = v4lelement->saturation; break;
+            case V4L_PICTURE_CONTRAST:   temp = v4lelement->contrast;   break;
+          }
+          if (temp >= 0)
+          {
+            if (!gst_v4l_set_picture(v4lelement, n, temp))
+              return GST_STATE_FAILURE;
+          }
+        }
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS(parent_class)->change_state)
+    return GST_ELEMENT_CLASS(parent_class)->change_state(element);
+
+  return GST_STATE_SUCCESS;
+}
+
+
+static gboolean
+plugin_init (GModule   *module,
+             GstPlugin *plugin)
+{
+#if 0
+  GstElementFactory *factory;
+
+  /* create an elementfactory for the v4lelement */
+  factory = gst_elementfactory_new("v4lelement",GST_TYPE_V4LELEMENT,
+                                   &gst_v4lelement_details);
+  g_return_val_if_fail(factory != NULL, FALSE);
+  gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+#endif
+  return TRUE;
+}
+
+
+GstPluginDesc plugin_desc = {
+  GST_VERSION_MAJOR,
+  GST_VERSION_MINOR,
+  "v4lelement",
+  plugin_init
+};
diff --git a/sys/v4l/gstv4lelement.h b/sys/v4l/gstv4lelement.h
new file mode 100644 (file)
index 0000000..62c973b
--- /dev/null
@@ -0,0 +1,84 @@
+/* G-Streamer generic V4L element - generic V4L calls handling
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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_V4LELEMENT_H__
+#define __GST_V4LELEMENT_H__
+
+#include <config.h>
+#include <gst/gst.h>
+#include <sys/types.h>
+#include <linux/videodev.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GST_TYPE_V4LELEMENT \
+  (gst_v4lelement_get_type())
+#define GST_V4LELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LELEMENT,GstV4lElement))
+#define GST_V4LELEMENT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LELEMENT,GstV4lElementClass))
+#define GST_IS_V4LELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LELEMENT))
+#define GST_IS_V4LELEMENT_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LELEMENT))
+
+typedef struct _GstV4lElement GstV4lElement;
+typedef struct _GstV4lElementClass GstV4lElementClass;
+
+struct _GstV4lElement {
+  GstElement element;
+
+  /* the video device */
+  char *videodev;
+
+  /* the video-device's file descriptor */
+  gint video_fd;
+
+  /* the video buffer (mmap()'ed) */
+  guint8 *buffer;
+
+  /* the video-device's capabilities */
+  struct video_capability vcap;
+
+  /* caching values */
+  gint channel;
+  gint norm;
+  gulong frequency;
+  gint mute;
+  gint volume;
+  gint mode;
+  gint brightness;
+  gint hue;
+  gint contrast;
+  gint saturation;
+};
+
+struct _GstV4lElementClass {
+  GstElementClass parent_class;
+};
+
+GType gst_v4lelement_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GST_V4LELEMENT_H__ */
diff --git a/sys/v4l/gstv4lmjpegsrc.c b/sys/v4l/gstv4lmjpegsrc.c
new file mode 100644 (file)
index 0000000..eca922b
--- /dev/null
@@ -0,0 +1,488 @@
+/* G-Streamer hardware MJPEG video source plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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 <string.h>
+#include "v4lmjpegsrc_calls.h"
+
+static GstElementDetails gst_v4lmjpegsrc_details = {
+  "Video (video4linux/MJPEG) Source",
+  "Source/Video",
+  "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
+  VERSION,
+  "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+  "(C) 2001",
+};
+
+/* V4lMjpegSrc signals and args */
+enum {
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+/* arguments */
+enum {
+  ARG_0,
+  ARG_X_OFFSET,
+  ARG_Y_OFFSET,
+  ARG_F_WIDTH,
+  ARG_F_HEIGHT,
+  ARG_H_DECIMATION,
+  ARG_V_DECIMATION,
+  ARG_WIDTH,
+  ARG_HEIGHT,
+  ARG_QUALITY,
+  ARG_NUMBUFS,
+  ARG_BUFSIZE
+};
+
+
+/* init functions */
+static void                  gst_v4lmjpegsrc_class_init   (GstV4lMjpegSrcClass *klass);
+static void                  gst_v4lmjpegsrc_init         (GstV4lMjpegSrc *v4lmjpegsrc);
+
+/* pad/buffer functions */
+static GstPadNegotiateReturn gst_v4lmjpegsrc_negotiate    (GstPad         *pad,
+                                                           GstCaps        **caps,
+                                                           gpointer       *user_data);
+static GstCaps*              gst_v4lmjpegsrc_create_caps  (GstV4lMjpegSrc *v4lmjpegsrc);
+static GstBuffer*            gst_v4lmjpegsrc_get          (GstPad         *pad);
+
+/* get/set params */
+static void                  gst_v4lmjpegsrc_set_property (GObject        *object,
+                                                           guint          prop_id,
+                                                           const GValue   *value,
+                                                           GParamSpec     *pspec);
+static void                  gst_v4lmjpegsrc_get_property (GObject        *object,
+                                                           guint          prop_id,
+                                                           GValue         *value,
+                                                           GParamSpec     *pspec);
+
+/* state handling */
+static GstElementStateReturn gst_v4lmjpegsrc_change_state (GstElement     *element);
+
+/* bufferpool functions */
+static GstBuffer*            gst_v4lmjpegsrc_buffer_new   (GstBufferPool  *pool,
+                                                           gint64         location,
+                                                           gint           size,
+                                                           gpointer       user_data);
+static GstBuffer*            gst_v4lmjpegsrc_buffer_copy  (GstBuffer      *srcbuf);
+static void                  gst_v4lmjpegsrc_buffer_free  (GstBuffer      *buf);
+
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 };
+
+
+GType
+gst_v4lmjpegsrc_get_type (void)
+{
+  static GType v4lmjpegsrc_type = 0;
+
+  if (!v4lmjpegsrc_type) {
+    static const GTypeInfo v4lmjpegsrc_info = {
+      sizeof(GstV4lMjpegSrcClass),
+      NULL,
+      NULL,
+      (GClassInitFunc)gst_v4lmjpegsrc_class_init,
+      NULL,
+      NULL,
+      sizeof(GstV4lMjpegSrc),
+      0,
+      (GInstanceInitFunc)gst_v4lmjpegsrc_init,
+      NULL
+    };
+    v4lmjpegsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", &v4lmjpegsrc_info, 0);
+  }
+  return v4lmjpegsrc_type;
+}
+
+
+static void
+gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+
+  gobject_class = (GObjectClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_X_OFFSET,
+    g_param_spec_int("x_offset","x_offset","x_offset",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_Y_OFFSET,
+    g_param_spec_int("y_offset","y_offset","y_offset",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_WIDTH,
+    g_param_spec_int("frame_width","frame_width","frame_width",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_HEIGHT,
+    g_param_spec_int("frame_height","frame_height","frame_height",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_H_DECIMATION,
+    g_param_spec_int("h_decimation","h_decimation","h_decimation",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_V_DECIMATION,
+    g_param_spec_int("v_decimation","v_decimation","v_decimation",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+
+  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_READABLE));
+  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_READABLE));
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_QUALITY,
+    g_param_spec_int("quality","quality","quality",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
+
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
+    g_param_spec_int("num_buffers","num_buffers","num_buffers",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
+    g_param_spec_int("buffer_size","buffer_size","buffer_size",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+
+  gobject_class->set_property = gst_v4lmjpegsrc_set_property;
+  gobject_class->get_property = gst_v4lmjpegsrc_get_property;
+
+  gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
+}
+
+
+static void
+gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
+{
+  v4lmjpegsrc->srcpad = gst_pad_new("src", GST_PAD_SRC);
+  gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad);
+
+  gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
+  gst_pad_set_negotiate_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_negotiate);
+
+  v4lmjpegsrc->bufferpool = gst_buffer_pool_new();
+  gst_buffer_pool_set_buffer_new_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_new);
+  gst_buffer_pool_set_buffer_copy_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_copy);
+  gst_buffer_pool_set_buffer_free_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_free);
+  gst_buffer_pool_set_user_data(v4lmjpegsrc->bufferpool, v4lmjpegsrc);
+
+  v4lmjpegsrc->frame_width = 0;
+  v4lmjpegsrc->frame_height = 0;
+  v4lmjpegsrc->x_offset = -1;
+  v4lmjpegsrc->y_offset = -1;
+
+  v4lmjpegsrc->horizontal_decimation = 4;
+  v4lmjpegsrc->vertical_decimation = 4;
+
+  v4lmjpegsrc->end_width = 0;
+  v4lmjpegsrc->end_height = 0;
+
+  v4lmjpegsrc->quality = 50;
+
+  v4lmjpegsrc->numbufs = 64;
+  v4lmjpegsrc->bufsize = 256 * 1024;
+
+  v4lmjpegsrc->init = TRUE;
+}
+
+
+
+static GstPadNegotiateReturn
+gst_v4lmjpegsrc_negotiate (GstPad   *pad,
+                           GstCaps  **caps,
+                           gpointer *user_data) 
+{
+  GstV4lMjpegSrc *v4lmjpegsrc;
+
+  v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
+
+  if (!*caps) {
+    return GST_PAD_NEGOTIATE_FAIL;
+  }
+  else {
+    return GST_PAD_NEGOTIATE_AGREE;
+  }
+
+  return GST_PAD_NEGOTIATE_FAIL;
+}
+
+
+static GstCaps*
+gst_v4lmjpegsrc_create_caps (GstV4lMjpegSrc *v4lmjpegsrc)
+{
+  GstCaps *caps;
+
+  caps = GST_CAPS_NEW (
+    "v4lmjpegsrc_caps",
+    "video/jpeg", 
+    "width",            GST_PROPS_INT(v4lmjpegsrc->end_width),
+    "height",           GST_PROPS_INT(v4lmjpegsrc->end_height)
+  );
+
+  return caps;
+}
+
+
+static GstBuffer*
+gst_v4lmjpegsrc_get (GstPad *pad)
+{
+  GstV4lMjpegSrc *v4lmjpegsrc;
+  GstBuffer *buf;
+  gint num;
+
+  g_return_val_if_fail (pad != NULL, NULL);
+
+  v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
+
+  if (v4lmjpegsrc->init) {
+    gst_pad_set_caps (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_create_caps (v4lmjpegsrc));
+    v4lmjpegsrc->init = FALSE;
+  }
+  else {
+    if (!gst_pad_get_caps (v4lmjpegsrc->srcpad) && 
+        !gst_pad_renegotiate (v4lmjpegsrc->srcpad)) {
+      return NULL;
+    }
+  }
+
+  buf = gst_buffer_new_from_pool(v4lmjpegsrc->bufferpool, 0, 0);
+  if (!buf)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Failed to create a new GstBuffer");
+    return NULL;
+  }
+
+  /* grab a frame from the device */
+  if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &(GST_BUFFER_SIZE(buf))))
+    return NULL;
+  GST_BUFFER_DATA(buf) = gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, num);
+  buf->timestamp = v4lmjpegsrc->bsync.timestamp.tv_sec * 1000000000 +
+    v4lmjpegsrc->bsync.timestamp.tv_usec * 1000;
+
+  return buf;
+}
+
+
+static void
+gst_v4lmjpegsrc_set_property (GObject      *object,
+                              guint        prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GstV4lMjpegSrc *v4lmjpegsrc;
+
+  g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
+  v4lmjpegsrc = GST_V4LMJPEGSRC(object);
+
+  switch (prop_id) {
+    case ARG_X_OFFSET:
+      v4lmjpegsrc->x_offset = g_value_get_int(value);
+      break;
+    case ARG_Y_OFFSET:
+      v4lmjpegsrc->y_offset = g_value_get_int(value);
+      break;
+    case ARG_F_WIDTH:
+      v4lmjpegsrc->frame_width = g_value_get_int(value);
+      break;
+    case ARG_F_HEIGHT:
+      v4lmjpegsrc->frame_height = g_value_get_int(value);
+      break;
+    case ARG_H_DECIMATION:
+      v4lmjpegsrc->horizontal_decimation = g_value_get_int(value);
+      break;
+    case ARG_V_DECIMATION:
+      v4lmjpegsrc->vertical_decimation = g_value_get_int(value);
+      break;
+    case ARG_QUALITY:
+      v4lmjpegsrc->quality = g_value_get_int(value);
+      break;
+    case ARG_NUMBUFS:
+      v4lmjpegsrc->numbufs = g_value_get_int(value);
+      break;
+    case ARG_BUFSIZE:
+      v4lmjpegsrc->bufsize = g_value_get_int(value);
+      break;
+    default:
+      parent_class->set_property(object, prop_id, value, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_v4lmjpegsrc_get_property (GObject    *object,
+                              guint      prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  GstV4lMjpegSrc *v4lmjpegsrc;
+
+  g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
+  v4lmjpegsrc = GST_V4LMJPEGSRC(object);
+
+  switch (prop_id) {
+    case ARG_WIDTH:
+      g_value_set_int(value, v4lmjpegsrc->end_width);
+      break;
+    case ARG_HEIGHT:
+      g_value_set_int(value, v4lmjpegsrc->end_height);
+      break;
+    case ARG_NUMBUFS:
+      g_value_set_int(value, v4lmjpegsrc->breq.count);
+      break;
+    case ARG_BUFSIZE:
+      g_value_set_int(value, v4lmjpegsrc->breq.size);
+      break;
+    default:
+      parent_class->get_property(object, prop_id, value, pspec);
+      break;
+  }
+}
+
+
+static GstElementStateReturn
+gst_v4lmjpegsrc_change_state (GstElement *element)
+{
+  GstV4lMjpegSrc *v4lmjpegsrc;
+  
+  g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), FALSE);
+  
+  v4lmjpegsrc = GST_V4LMJPEGSRC(element);
+
+  switch (GST_STATE_PENDING(element)) {
+    case GST_STATE_READY:
+      if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc))) {
+        /* stop capturing, unmap all buffers */
+        if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
+          return GST_STATE_FAILURE;
+      }
+      break;
+    case GST_STATE_PAUSED:
+      if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc))) {
+        /* set buffer info */
+        if (!gst_v4lmjpegsrc_set_buffer(v4lmjpegsrc, v4lmjpegsrc->numbufs, v4lmjpegsrc->bufsize))
+          return GST_STATE_FAILURE;
+        /* set capture parameters and mmap the buffers */
+        if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height &&
+            v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 &&
+            v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation)
+        {
+          if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
+              v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
+            return GST_STATE_FAILURE;
+        }
+        else
+        {
+          if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
+              v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset,
+              v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height,
+              v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->vertical_decimation,
+              v4lmjpegsrc->quality))
+            return GST_STATE_FAILURE;
+        }
+        v4lmjpegsrc->init = TRUE;
+        if (!gst_v4lmjpegsrc_capture_init(v4lmjpegsrc))
+          return GST_STATE_FAILURE;
+      }
+      else {
+        /* de-queue all queued buffers */
+        if (!gst_v4lmjpegsrc_capture_stop(v4lmjpegsrc))
+          return GST_STATE_FAILURE;
+      }
+      break;
+    case GST_STATE_PLAYING:
+      /* queue all buffer, start streaming capture */
+      if (!gst_v4lmjpegsrc_capture_start(v4lmjpegsrc))
+        return GST_STATE_FAILURE;
+      break;
+  }
+
+  if (GST_ELEMENT_CLASS(parent_class)->change_state)
+    return GST_ELEMENT_CLASS(parent_class)->change_state(element);
+
+  return GST_STATE_SUCCESS;
+}
+
+
+static GstBuffer*
+gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
+                            gint64        location,
+                            gint          size,
+                            gpointer      user_data)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_new();
+  if (!buffer) return NULL;
+  buffer->pool_private = user_data;
+
+  /* TODO: add interlacing info to buffer as metadata */
+
+  return buffer;
+}
+
+
+static GstBuffer*
+gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbuf)
+{
+  GstBuffer *buffer;
+
+  buffer = gst_buffer_new();
+  if (!buffer) return NULL;
+  GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
+  if (!GST_BUFFER_DATA(buffer)) return NULL;
+  GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
+  memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
+  GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
+
+  return buffer;
+}
+
+
+static void
+gst_v4lmjpegsrc_buffer_free (GstBuffer *buf)
+{
+  GstV4lMjpegSrc *v4lmjpegsrc = buf->pool_private;
+  int n;
+
+  for (n=0;n<v4lmjpegsrc->breq.count;n++)
+    if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
+    {
+      gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
+      return;
+    }
+
+  gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+    "Couldn't find the buffer");
+}
+
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+  GstElementFactory *factory;
+
+  /* create an elementfactory for the v4lmjpegsrcparse element */
+  factory = gst_elementfactory_new("v4lmjpegsrc",GST_TYPE_V4LMJPEGSRC,
+                                   &gst_v4lmjpegsrc_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,
+  "v4lmjpegsrc",
+  plugin_init
+};
diff --git a/sys/v4l/gstv4lmjpegsrc.h b/sys/v4l/gstv4lmjpegsrc.h
new file mode 100644 (file)
index 0000000..e05a58d
--- /dev/null
@@ -0,0 +1,86 @@
+/* G-Streamer hardware MJPEG video source plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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_V4LMJPEGSRC_H__
+#define __GST_V4LMJPEGSRC_H__
+
+#include <gstv4lelement.h>
+#include <sys/time.h>
+#include <videodev_mjpeg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GST_TYPE_V4LMJPEGSRC \
+  (gst_v4lmjpegsrc_get_type())
+#define GST_V4LMJPEGSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrc))
+#define GST_V4LMJPEGSRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrcClass))
+#define GST_IS_V4LMJPEGSRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LMJPEGSRC))
+#define GST_IS_V4LMJPEGSRC_CLASS(obj) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LMJPEGSRC))
+
+typedef struct _GstV4lMjpegSrc GstV4lMjpegSrc;
+typedef struct _GstV4lMjpegSrcClass GstV4lMjpegSrcClass;
+
+struct _GstV4lMjpegSrc {
+  GstV4lElement v4lelement;
+
+  /* pads */
+  GstPad *srcpad;
+
+  /* the bufferpool */
+  GstBufferPool *bufferpool;
+
+  /* buffer/capture info */
+  struct mjpeg_sync bsync;
+  struct mjpeg_requestbuffers breq;
+
+  /* caching values */
+  gint x_offset;
+  gint y_offset;
+  gint frame_width;
+  gint frame_height;
+  gint horizontal_decimation;
+  gint vertical_decimation;
+
+  gint end_width;
+  gint end_height;
+
+  gint quality;
+  gint numbufs;
+  gint bufsize;
+
+  gboolean init;
+};
+
+struct _GstV4lMjpegSrcClass {
+  GstV4lElementClass parent_class;
+};
+
+GType gst_v4lmjpegsrc_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GST_V4LMJPEGSRC_H__ */
index fc847c8..d12afdc 100644 (file)
@@ -1,5 +1,5 @@
-/* Gnome-Streamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+/* G-Streamer BT8x8/V4L frame grabber plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * 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>
+#include <sys/time.h>
+#include "v4lsrc_calls.h"
 
-//#define DEBUG_ENABLED
-#include <gstv4lsrc.h>
-
-#include <linux/videodev.h>
 
 static GstElementDetails gst_v4lsrc_details = {
-  "Video (v4l) Source",
+  "Video (video4linux/raw) Source",
   "Source/Video",
-  "Read from a Video for Linux capture device",
+  "Reads raw frames from a video4linux (BT8x8) device",
   VERSION,
-  "Wim Taymans <wim.taymans@tvd.be>",
-  "(C) 2000",
+  "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+  "(C) 2001",
 };
 
 /* V4lSrc signals and args */
@@ -44,43 +37,51 @@ enum {
   LAST_SIGNAL
 };
 
+/* arguments */
 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,
+  ARG_PALETTE
 };
 
 
-static void                    gst_v4lsrc_class_init   (GstV4lSrcClass *klass);
-static void                    gst_v4lsrc_init         (GstV4lSrc *v4lsrc);
+/* init functions */
+static void                  gst_v4lsrc_class_init   (GstV4lSrcClass *klass);
+static void                  gst_v4lsrc_init         (GstV4lSrc      *v4lsrc);
+
+/* pad/buffer functions */
+static GstPadNegotiateReturn gst_v4lsrc_negotiate    (GstPad         *pad,
+                                                      GstCaps        **caps,
+                                                      gpointer       *user_data);
+static GstCaps*              gst_v4lsrc_create_caps  (GstV4lSrc      *v4lsrc);
+static GstBuffer*            gst_v4lsrc_get          (GstPad         *pad);
 
-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);
+/* get/set params */
+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);
+/* state handling */
+static GstElementStateReturn gst_v4lsrc_change_state (GstElement     *element);
 
-static GstBuffer*              gst_v4lsrc_get          (GstPad *pad);
-static GstPadNegotiateReturn   gst_v4lsrc_negotiate    (GstPad *pad, GstCaps **caps, gpointer *user_data);
+/* bufferpool functions */
+static GstBuffer*            gst_v4lsrc_buffer_new   (GstBufferPool  *pool,
+                                                      gint64         location,
+                                                      gint           size,
+                                                      gpointer       user_data);
+static GstBuffer*            gst_v4lsrc_buffer_copy  (GstBuffer      *srcbuf);
+static void                  gst_v4lsrc_buffer_free  (GstBuffer      *buf);
 
-static gboolean                        gst_v4lsrc_sync_parms   (GstV4lSrc *v4lsrc);
 
-static GstElementClass *parent_class = NULL;
-////static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
+static GstElementClass *parent_class = NULL;\
+//static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
+
 
 GType
 gst_v4lsrc_get_type (void)
@@ -89,7 +90,8 @@ gst_v4lsrc_get_type (void)
 
   if (!v4lsrc_type) {
     static const GTypeInfo v4lsrc_info = {
-      sizeof(GstV4lSrcClass),      NULL,
+      sizeof(GstV4lSrcClass),
+      NULL,
       NULL,
       (GClassInitFunc)gst_v4lsrc_class_init,
       NULL,
@@ -99,11 +101,12 @@ gst_v4lsrc_get_type (void)
       (GInstanceInitFunc)gst_v4lsrc_init,
       NULL
     };
-    v4lsrc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
+    v4lsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
   }
   return v4lsrc_type;
 }
 
+
 static void
 gst_v4lsrc_class_init (GstV4lSrcClass *klass)
 {
@@ -113,54 +116,14 @@ gst_v4lsrc_class_init (GstV4lSrcClass *klass)
   gobject_class = (GObjectClass*)klass;
   gstelement_class = (GstElementClass*)klass;
 
-  parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+  parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
 
   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_param_spec_int("width","width","width",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
   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
+    g_param_spec_int("height","height","height",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+  g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE,
+    g_param_spec_int("palette","palette","palette",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
 
   gobject_class->set_property = gst_v4lsrc_set_property;
   gobject_class->get_property = gst_v4lsrc_get_property;
@@ -168,33 +131,38 @@ gst_v4lsrc_class_init (GstV4lSrcClass *klass)
   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->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);
+
+  v4lsrc->bufferpool = gst_buffer_pool_new();
+  gst_buffer_pool_set_buffer_new_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_new);
+  gst_buffer_pool_set_buffer_copy_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_copy);
+  gst_buffer_pool_set_buffer_free_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_free);
+  gst_buffer_pool_set_user_data(v4lsrc->bufferpool, v4lsrc);
+
+  v4lsrc->palette = VIDEO_PALETTE_YUV420P;
+  v4lsrc->width = 160;
+  v4lsrc->height = 120;
+  v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
+
   v4lsrc->init = TRUE;
 }
 
+
 static GstPadNegotiateReturn
-gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data) 
+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) {
@@ -204,175 +172,181 @@ gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data)
     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);
+    format = gst_caps_get_fourcc_int (*caps, "format");
 
     switch (format) {
       case GST_MAKE_FOURCC ('R','G','B',' '):
       {
-        gint depth, endianness, bpp;
+        gint depth;
 
         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) {
+        switch (depth) {
           case 15:
-            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
-                    VIDEO_RGB15_LE:
-                    VIDEO_RGB15_BE);
+            v4lsrc->palette = VIDEO_PALETTE_RGB555;
             v4lsrc->buffer_size = width * height * 2;
             break;
           case 16:
-            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
-                    VIDEO_RGB16_LE:
-                    VIDEO_RGB16_BE);
+            v4lsrc->palette = VIDEO_PALETTE_RGB565;
             v4lsrc->buffer_size = width * height * 2;
             break;
           case 24:
-            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
-                    VIDEO_BGR24:
-                    VIDEO_RGB24);
+            v4lsrc->palette = VIDEO_PALETTE_RGB24;
             v4lsrc->buffer_size = width * height * 3;
             break;
           case 32:
-            v4lsrc->format = (endianness == G_LITTLE_ENDIAN ? 
-                    VIDEO_BGR32:
-                    VIDEO_RGB32);
+            v4lsrc->palette = VIDEO_PALETTE_RGB32;
             v4lsrc->buffer_size = width * height * 4;
             break;
           default:
             *caps = NULL;
             return GST_PAD_NEGOTIATE_TRY;
-       }
-       break;
+        }
+
+        break;
       }
+
       case GST_MAKE_FOURCC ('I','4','2','0'):
-        v4lsrc->format = VIDEO_YUV420P;
-        v4lsrc->buffer_size = width * height +
-                             width * height / 2;
-       break;
+        v4lsrc->palette = VIDEO_PALETTE_YUV420P;
+        v4lsrc->buffer_size = width * height * 1.5;
+        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;
-       }
+        v4lsrc->palette = VIDEO_PALETTE_UYVY; //YUV422?;
+        v4lsrc->buffer_size = width * height * 2;
+        break;
+
       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;
-       }
+        v4lsrc->palette = VIDEO_PALETTE_YUYV; //YUV422?;
+        v4lsrc->buffer_size = width * height * 2;
+        break;
+
+      /* TODO: add YUV4:2:2 planar and YUV4:2:0 packed, maybe also YUV4:1:1? */
+
       default:
         *caps = NULL;
         return GST_PAD_NEGOTIATE_TRY;
+
     }
+
+    /* if we get here, it's okay */
     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_AGREE;
   }
 
   return GST_PAD_NEGOTIATE_FAIL;
 }
 
+
 static GstCaps*
-gst_v4lsrc_create_caps (GstV4lSrc *src)
+gst_v4lsrc_create_caps (GstV4lSrc *v4lsrc)
 {
-  GstCaps *caps;
+  GstCaps *caps = NULL;
   gulong fourcc = 0;
-  gint width, height;
 
-  width = src->width;
-  height = src->height;
+  switch (v4lsrc->palette) {
+    case VIDEO_PALETTE_RGB555:
+    case VIDEO_PALETTE_RGB565:
+    case VIDEO_PALETTE_RGB24:
+    case VIDEO_PALETTE_RGB32:
+    {
+      int depth=0, bpp=0;
+
+      fourcc = GST_STR_FOURCC ("RGB ");
+
+      switch (v4lsrc->palette) {
+        case VIDEO_PALETTE_RGB555:
+          depth = 15;
+          bpp = 2;
+          break;
+        case VIDEO_PALETTE_RGB565:
+          depth = 16;
+          bpp = 2;
+          break;
+        case VIDEO_PALETTE_RGB24:
+          depth = 24;
+          bpp = 3;
+          break;
+        case VIDEO_PALETTE_RGB32:
+          depth = 32;
+          bpp = 4;
+          break;
+      }
+
+      caps = GST_CAPS_NEW (
+        "v4lsrc_caps",
+        "video/raw",
+        "format",      GST_PROPS_FOURCC (fourcc),
+        "width",       GST_PROPS_INT (v4lsrc->width),
+        "height",      GST_PROPS_INT (v4lsrc->height),
+        "bpp",         GST_PROPS_INT (bpp),
+        "depth",       GST_PROPS_INT (depth)
+      );
+
+      v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * bpp;
 
-  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;
+    case VIDEO_PALETTE_YUV422:
+    case VIDEO_PALETTE_YUV420P:
+    {
+      switch (v4lsrc->palette) {
+        case VIDEO_PALETTE_YUV422:
+          fourcc = (G_BYTE_ORDER == G_BIG_ENDIAN) ?
+            GST_STR_FOURCC("UYVY") : GST_STR_FOURCC("YUY2");
+          v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
+          break;
+        case VIDEO_PALETTE_YUYV:
+          fourcc = GST_STR_FOURCC("YUY2");
+          v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
+          break;
+        case VIDEO_PALETTE_UYVY:
+          fourcc = GST_STR_FOURCC("UYVY");
+          v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
+          break;
+        case VIDEO_PALETTE_YUV420P:
+          fourcc = GST_STR_FOURCC("I420");
+          v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
+          break;
       }
-      
+
       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)
-                       );
+        "v4lsrc_caps",
+        "video/raw",
+        "format",      GST_PROPS_FOURCC (fourcc),
+        "width",       GST_PROPS_INT (v4lsrc->width),
+        "height",      GST_PROPS_INT (v4lsrc->height)
+      );
+
       break;
     }
+
     default:
-      caps = NULL;
-      break;
+      return NULL;
   }
 
   return caps;
 }
 
+
 static GstBuffer*
 gst_v4lsrc_get (GstPad *pad)
 {
   GstV4lSrc *v4lsrc;
-  GstBuffer *buf = NULL;
-  guint8 *grab_buf;
+  GstBuffer *buf;
+  gint num;
+  struct timeval timestamp;
 
   g_return_val_if_fail (pad != NULL, NULL);
 
   v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
 
-  if (v4lsrc->format && v4lsrc->init) {
+  if (v4lsrc->init) {
     gst_pad_set_caps (v4lsrc->srcpad, gst_v4lsrc_create_caps (v4lsrc));
     v4lsrc->init = FALSE;
   }
@@ -383,172 +357,125 @@ gst_v4lsrc_get (GstPad *pad)
     }
   }
 
-  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));
+  buf = gst_buffer_new_from_pool(v4lsrc->bufferpool, 0, 0);
+  if (!buf)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Failed to create a new GstBuffer");
+    return NULL;
+  }
 
-  GST_DEBUG (0,"v4lsrc: sent %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
+  /* grab a frame from the device */
+  if (!gst_v4lsrc_grab_frame(v4lsrc, &num))
+    return NULL;
+  gettimeofday(&timestamp, 0); /* TODO: threaded sync() */
+  GST_BUFFER_DATA(buf) = gst_v4lsrc_get_buffer(v4lsrc, num);
+  GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
+  buf->timestamp = timestamp.tv_sec * 1000000000 + timestamp.tv_usec * 1000;
 
   return buf;
 }
 
+
 static void
-gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+gst_v4lsrc_set_property (GObject      *object,
+                         guint        prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
 {
-  GstV4lSrc *src;
-  int ret = 0;
+  GstV4lSrc *v4lsrc;
 
-  /* 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);
+  v4lsrc = GST_V4LSRC(object);
 
   switch (prop_id) {
     case ARG_WIDTH:
-      src->width = g_value_get_int (value);
-      gst_v4lsrc_sync_parms(src);
+      v4lsrc->width = g_value_get_int(value);
       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);
+      v4lsrc->height = g_value_get_int(value);
       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));
+
+    case ARG_PALETTE:
+      v4lsrc->palette = g_value_get_int(value);
       break;
+
     default:
-      ret = -1;
+      parent_class->set_property(object, prop_id, value, pspec);
       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)
+gst_v4lsrc_get_property (GObject    *object,
+                         guint      prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
 {
-  GstV4lSrc *src;
+  GstV4lSrc *v4lsrc;
 
-  /* 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");
+  v4lsrc = GST_V4LSRC(object);
 
   switch (prop_id) {
     case ARG_WIDTH:
-      g_value_set_int (value, src->width);
+      g_value_set_int(value, v4lsrc->mmap.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));
+      g_value_set_int(value, v4lsrc->mmap.height);
       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);
+
+    case ARG_PALETTE:
+      g_value_set_int(value, v4lsrc->mmap.format);
       break;
+
     default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      parent_class->get_property(object, prop_id, value, pspec);
       break;
   }
 }
 
+
 static GstElementStateReturn
 gst_v4lsrc_change_state (GstElement *element)
 {
+  GstV4lSrc *v4lsrc;
+  
   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;
+  
+  v4lsrc = GST_V4LSRC(element);
+
+  switch (GST_STATE_PENDING(element)) {
+    case GST_STATE_READY:
+      if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc))) {
+        /* stop capturing, unmap all buffers */
+        if (!gst_v4lsrc_capture_deinit(v4lsrc))
+          return GST_STATE_FAILURE;
       }
-    }
+      break;
+    case GST_STATE_PAUSED:
+      if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc))) {
+        /* set capture parameters and mmap the buffers */
+        if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, v4lsrc->palette))
+          return GST_STATE_FAILURE;
+        v4lsrc->init = TRUE;
+        if (!gst_v4lsrc_capture_init(v4lsrc))
+          return GST_STATE_FAILURE;
+      }
+      else {
+        /* de-queue all queued buffers */
+        if (!gst_v4lsrc_capture_stop(v4lsrc))
+          return GST_STATE_FAILURE;
+      }
+      break;
+    case GST_STATE_PLAYING:
+      /* queue all buffer, start streaming capture */
+      if (!gst_v4lsrc_capture_start(v4lsrc))
+        return GST_STATE_FAILURE;
+      break;
   }
 
   if (GST_ELEMENT_CLASS(parent_class)->change_state)
@@ -557,61 +484,67 @@ gst_v4lsrc_change_state (GstElement *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);
+static GstBuffer*
+gst_v4lsrc_buffer_new (GstBufferPool *pool,
+                       gint64        location,
+                       gint          size,
+                       gpointer      user_data)
+{
+  GstBuffer *buffer;
 
-  GST_DEBUG (0,"v4lsrc: resync %d %d %d\n", src->width, src->height, src->format);
+  buffer = gst_buffer_new();
+  if (!buffer) return NULL;
+  buffer->pool_private = user_data;
 
-  if (!src->grabber->opened) 
-    return FALSE;
+  /* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
 
-  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;
+  return buffer;
 }
 
-static gboolean
-gst_v4lsrc_open_v4l (GstV4lSrc *src)
+
+static GstBuffer*
+gst_v4lsrc_buffer_copy (GstBuffer *srcbuf)
 {
-  g_return_val_if_fail(src->grabber != NULL, FALSE);
-  g_return_val_if_fail(!src->grabber->opened, FALSE);
+  GstBuffer *buffer;
 
-  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;
+  buffer = gst_buffer_new();
+  if (!buffer) return NULL;
+  GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
+  if (!GST_BUFFER_DATA(buffer)) return NULL;
+  GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
+  memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
+  GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
+
+  return buffer;
 }
 
+
 static void
-gst_v4lsrc_close_v4l (GstV4lSrc *src)
+gst_v4lsrc_buffer_free (GstBuffer *buf)
 {
-  g_return_if_fail(src->grabber != NULL);
-  g_return_if_fail(src->grabber->opened);
+  GstV4lSrc *v4lsrc = buf->pool_private;
+  int n;
+
+  for (n=0;n<v4lsrc->mbuf.frames;n++)
+    if (GST_BUFFER_DATA(buf) == gst_v4lsrc_get_buffer(v4lsrc, n))
+    {
+      gst_v4lsrc_requeue_frame(v4lsrc, n);
+      return;
+    }
 
-  src->grabber->grab_close(src->grabber);
-  GST_FLAG_UNSET(src, GST_V4LSRC_OPEN);
+  gst_element_error(GST_ELEMENT(v4lsrc),
+    "Couldn't find the buffer");
 }
 
+
 static gboolean
-plugin_init (GModule *module, GstPlugin *plugin)
+plugin_init (GModule   *module,
+             GstPlugin *plugin)
 {
   GstElementFactory *factory;
 
-  /* create an elementfactory for the v4lsrcparse element */
+  /* create an elementfactory for the v4lsrc */
   factory = gst_elementfactory_new("v4lsrc",GST_TYPE_V4LSRC,
                                    &gst_v4lsrc_details);
   g_return_val_if_fail(factory != NULL, FALSE);
@@ -620,10 +553,10 @@ plugin_init (GModule *module, GstPlugin *plugin)
   return TRUE;
 }
 
+
 GstPluginDesc plugin_desc = {
   GST_VERSION_MAJOR,
   GST_VERSION_MINOR,
   "v4lsrc",
   plugin_init
 };
-
index 8411e9d..ab68742 100644 (file)
@@ -1,5 +1,5 @@
-/* Gnome-Streamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+/* G-Streamer BT8x8/V4L frame grabber plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * 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"
+#include <gstv4lelement.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-
 #define GST_TYPE_V4LSRC \
   (gst_v4lsrc_get_type())
 #define GST_V4LSRC(obj) \
@@ -45,46 +37,36 @@ extern "C" {
 #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;
+  GstV4lElement v4lelement;
 
   /* pads */
   GstPad *srcpad;
 
-  /* video device */
-  struct GRABBER *grabber;
+  /* bufferpool for the buffers we're gonna use */
+  GstBufferPool *bufferpool;
+
+  /* whether we need to reset the GstPad */
   gboolean init;
 
+  /* capture/buffer info */
+  struct video_mmap mmap;
+  struct video_mbuf mbuf;
+  gint sync_frame;
+  gboolean *frame_queued;
+  guint buffer_size;
+
+  /* caching values */
   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;
+  gint palette;
 };
 
 struct _GstV4lSrcClass {
-  GstElementClass parent_class;
+  GstV4lElementClass parent_class;
 };
 
 GType gst_v4lsrc_get_type(void);
@@ -93,5 +75,4 @@ GType gst_v4lsrc_get_type(void);
 }
 #endif /* __cplusplus */
 
-
 #endif /* __GST_V4LSRC_H__ */
diff --git a/sys/v4l/v4l_calls.c b/sys/v4l/v4l_calls.c
new file mode 100644 (file)
index 0000000..062cd8f
--- /dev/null
@@ -0,0 +1,573 @@
+/* G-Streamer generic V4L element - generic V4L calls handling
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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.
+ */
+
+//#define DEBUG
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include "v4l_calls.h"
+
+
+char *picture_name[] = { "Hue", "Brightness", "Contrast", "Saturation" };
+
+char *audio_name[] = { "Volume", "Mute", "Mode" };
+
+char *norm_name[] = { "PAL", "NTSC", "SECAM", "Autodetect" };
+
+/******************************************************
+ * gst_v4l_get_capabilities():
+ *   get the device's capturing capabilities
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4l_get_capabilities (GstV4lElement *v4lelement)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_get_capabilities()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGCAP, &(v4lelement->vcap)) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting \'%s\' capabilities: %s",
+      v4lelement->videodev, sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_open():
+ *   open the video device (v4lelement->videodev)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_open (GstV4lElement *v4lelement)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_open()\n");
+#endif
+
+  GST_V4L_CHECK_NOT_OPEN(v4lelement);
+  GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
+
+  /* be sure we have a device */
+  if (!v4lelement->videodev)
+    v4lelement->videodev = g_strdup("/dev/video");
+
+  /* open the device */
+  v4lelement->video_fd = open(v4lelement->videodev, O_RDONLY);
+  if (!GST_V4L_IS_OPEN(v4lelement))
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Failed to open device (\'%s\'): %s",
+      v4lelement->videodev, sys_errlist[errno]);
+    return FALSE;
+  }
+
+  /* get capabilities */
+  if (!gst_v4l_get_capabilities(v4lelement))
+  {
+    close(v4lelement->video_fd);
+    v4lelement->video_fd = -1;
+    return FALSE;
+  }
+
+  gst_element_info(GST_ELEMENT(v4lelement),
+    "Opened device \'%s\' (\'%s\') successfully",
+    v4lelement->vcap.name, v4lelement->videodev);
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_close():
+ *   close the video device (v4lelement->video_fd)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_close (GstV4lElement *v4lelement)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_close()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+  GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
+
+  close(v4lelement->video_fd);
+  v4lelement->video_fd = -1;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_get_num_chans()
+ * return value: the numver of video input channels
+ ******************************************************/
+
+gint
+gst_v4l_get_num_chans (GstV4lElement *v4lelement)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_get_num_chans()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  return v4lelement->vcap.channels;
+}
+
+
+/******************************************************
+ * gst_v4l_get_chan_norm():
+ *   get the currently active video-channel and it's
+ *   norm (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO})
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_get_chan_norm (GstV4lElement *v4lelement,
+                       gint          *channel,
+                       gint          *norm)
+{
+  struct video_channel vchan;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_get_chan_norm()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting the channel/norm settings: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  if (channel)
+    *channel = vchan.channel;
+  if (norm)
+    *norm = vchan.norm;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_set_chan_norm():
+ *   set a new active channel and it's norm
+ *   (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO})
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_set_chan_norm (GstV4lElement *v4lelement,
+                       gint          channel,
+                       gint          norm)
+{
+  struct video_channel vchan;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_set_chan_norm(), channel = %d, norm = %d (%s)\n",
+    channel, norm, norm_name[norm]);
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+  GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
+
+//  if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0)
+//  {
+//    gst_error("V4lElement - Error getting the channel/norm settings: %s",
+//      sys_errlist[errno]);
+//    return FALSE;
+//  }
+
+  vchan.channel = channel;
+  vchan.norm = norm;
+
+  if (ioctl(v4lelement->video_fd, VIDIOCSCHAN, &vchan) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error setting the channel/norm settings: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_has_tuner():
+ * return value: TRUE if it has a tuner, else FALSE
+ ******************************************************/
+
+gboolean
+gst_v4l_has_tuner (GstV4lElement *v4lelement)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_has_tuner()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  return (v4lelement->vcap.type & VID_TYPE_TUNER);
+}
+
+
+/******************************************************
+ * gst_v4l_get_frequency():
+ *   get the current frequency
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_get_frequency (GstV4lElement *v4lelement,
+                       gulong        *frequency)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_get_frequency()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (!gst_v4l_has_tuner(v4lelement))
+    return FALSE;
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGFREQ, frequency) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting tuner frequency: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_set_frequency():
+ *   set frequency
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_set_frequency (GstV4lElement *v4lelement,
+                       gulong        frequency)
+{
+#ifdef DEBUG
+  fprintf(stderr, "gst_v4l_set_frequency(), frequency = %ul\n",
+    frequency);
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+  GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
+
+  if (!gst_v4l_has_tuner(v4lelement))
+    return FALSE;
+
+  if (ioctl(v4lelement->video_fd, VIDIOCSFREQ, &frequency) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error setting tuner frequency: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_get_picture():
+ *   get a picture value
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_get_picture (GstV4lElement     *v4lelement,
+                     GstV4lPictureType type,
+                     gint              *value)
+{
+  struct video_picture vpic;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_get_picture(), type = %d (%s)\n",
+    type, picture_name[type]);
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting picture parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  switch (type)
+  {
+    case V4L_PICTURE_HUE:
+      *value = vpic.hue;
+      break;
+    case V4L_PICTURE_BRIGHTNESS:
+      *value = vpic.brightness;
+      break;
+    case V4L_PICTURE_CONTRAST:
+      *value = vpic.contrast;
+      break;
+    case V4L_PICTURE_SATURATION:
+      *value = vpic.colour;
+      break;
+    default:
+      gst_element_error(GST_ELEMENT(v4lelement),
+        "Error getting picture parameters: unknown type %d",
+        type);
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_set_picture():
+ *   set a picture value
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_set_picture (GstV4lElement     *v4lelement,
+                     GstV4lPictureType type,
+                     gint              value)
+{
+  struct video_picture vpic;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_set_picture(), type = %d (%s), value = %d\n",
+    type, picture_name[type], value);
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting picture parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  switch (type)
+  {
+    case V4L_PICTURE_HUE:
+      vpic.hue = value;
+      break;
+    case V4L_PICTURE_BRIGHTNESS:
+      vpic.brightness = value;
+      break;
+    case V4L_PICTURE_CONTRAST:
+      vpic.contrast = value;
+      break;
+    case V4L_PICTURE_SATURATION:
+      vpic.colour = value;
+      break;
+    default:
+      gst_element_error(GST_ELEMENT(v4lelement),
+        "Error setting picture parameters: unknown type %d",
+        type);
+      return FALSE;
+  }
+
+  if (ioctl(v4lelement->video_fd, VIDIOCSPICT, &vpic) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error setting picture parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_has_audio():
+ * return value: TRUE if it can do audio, else FALSE
+ ******************************************************/
+
+gboolean
+gst_v4l_has_audio (GstV4lElement *v4lelement)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4L: gst_v4l_has_audio()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  return (v4lelement->vcap.audios > 0);
+}
+
+
+/******************************************************
+ * gst_v4l_get_audio():
+ *   get some audio value
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_get_audio (GstV4lElement   *v4lelement,
+                   GstV4lAudioType type,
+                   gint            *value)
+{
+  struct video_audio vau;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4L: v4l_gst_get_audio(), type = %d (%s)\n",
+    type, audio_name[type]);
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (!gst_v4l_has_audio(v4lelement))
+    return FALSE;
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting audio parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  switch (type)
+  {
+    case V4L_AUDIO_MUTE:
+      *value = (vau.flags & VIDEO_AUDIO_MUTE);
+      break;
+    case V4L_AUDIO_VOLUME:
+      *value = vau.volume;
+      break;
+    case V4L_AUDIO_MODE:
+      *value = vau.mode;
+      break;
+    default:
+      gst_element_error(GST_ELEMENT(v4lelement),
+        "Error getting audio parameters: unknown type %d",
+        type);
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_set_audio():
+ *   set some audio value
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l_set_audio (GstV4lElement   *v4lelement,
+                   GstV4lAudioType type,
+                   gint            value)
+{
+  struct video_audio vau;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4L: v4l_gst_set_audio(), type = %d (%s), value = %d\n",
+    type, audio_name[type], value);
+#endif
+
+  GST_V4L_CHECK_OPEN(v4lelement);
+
+  if (!gst_v4l_has_audio(v4lelement))
+    return FALSE;
+
+  if (ioctl(v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error getting audio parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  switch (type)
+  {
+    case V4L_AUDIO_MUTE:
+      if (!(vau.flags & VIDEO_AUDIO_MUTABLE))
+      {
+        gst_element_error(GST_ELEMENT(v4lelement),
+          "Error setting audio mute: (un)setting mute is not supported");
+        return FALSE;
+      }
+      if (value)
+        vau.flags |= VIDEO_AUDIO_MUTE;
+      else
+        vau.flags &= ~VIDEO_AUDIO_MUTE;
+      break;
+    case V4L_AUDIO_VOLUME:
+      if (!(vau.flags & VIDEO_AUDIO_VOLUME))
+      {
+        gst_element_error(GST_ELEMENT(v4lelement),
+          "Error setting audio volume: setting volume is not supported");
+        return FALSE;
+      }
+      vau.volume = value;
+      break;
+    case V4L_AUDIO_MODE:
+      vau.mode = value;
+      break;
+    default:
+      gst_element_error(GST_ELEMENT(v4lelement),
+        "Error setting audio parameters: unknown type %d",
+        type);
+      return FALSE;
+  }
+
+  if (ioctl(v4lelement->video_fd, VIDIOCSAUDIO, &vau) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lelement),
+      "Error setting audio parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
diff --git a/sys/v4l/v4l_calls.h b/sys/v4l/v4l_calls.h
new file mode 100644 (file)
index 0000000..01038d6
--- /dev/null
@@ -0,0 +1,123 @@
+/* G-Streamer generic V4L element - generic V4L calls handling
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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 __V4L_CALLS_H__
+#define __V4L_CALLS_H__
+
+#include "gstv4lelement.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* simple check whether the device is open */
+#define GST_V4L_IS_OPEN(v4lelement) \
+  (v4lelement->video_fd > 0)
+
+/* check whether the device is 'active' */
+#define GST_V4L_IS_ACTIVE(v4lelement) \
+  (v4lelement->buffer != NULL)
+
+/* checks whether the current v4lelement has already been open()'ed or not */
+#define GST_V4L_CHECK_OPEN(v4lelement) \
+  if (v4lelement->video_fd <= 0)               \
+  {                                            \
+    gst_element_error(GST_ELEMENT(v4lelement), \
+      "Device is not open");                   \
+    return FALSE;                              \
+  }
+
+/* checks whether the current v4lelement is close()'ed or whether it is still open */
+#define GST_V4L_CHECK_NOT_OPEN(v4lelement) \
+  if (v4lelement->video_fd != -1)              \
+  {                                            \
+    gst_element_error(GST_ELEMENT(v4lelement), \
+      "Device is open");                       \
+    return FALSE;                              \
+  }
+
+/* checks whether we're in capture mode or not */
+#define GST_V4L_CHECK_ACTIVE(v4lelement) \
+  if (v4lelement->buffer == NULL)              \
+  {                                            \
+    gst_element_error(GST_ELEMENT(v4lelement), \
+      "Device is not in streaming mode");      \
+    return FALSE;                              \
+  }
+
+/* checks whether we're out of capture mode or not */
+#define GST_V4L_CHECK_NOT_ACTIVE(v4lelement) \
+  if (v4lelement->buffer != NULL)              \
+  {                                            \
+    gst_element_error(GST_ELEMENT(v4lelement), \
+      "Device is in streaming mode");          \
+    return FALSE;                              \
+  }
+
+
+typedef enum {
+  V4L_PICTURE_HUE,
+  V4L_PICTURE_BRIGHTNESS,
+  V4L_PICTURE_CONTRAST,
+  V4L_PICTURE_SATURATION,
+} GstV4lPictureType;
+
+extern char *picture_name[];
+
+typedef enum {
+  V4L_AUDIO_VOLUME,
+  V4L_AUDIO_MUTE,
+  V4L_AUDIO_MODE, /* stereo, mono, ... (see videodev.h) */
+} GstV4lAudioType;
+
+extern char *audio_name[];
+
+extern char *norm_name[];
+
+
+/* open/close the device */
+gboolean gst_v4l_open           (GstV4lElement *v4lelement);
+gboolean gst_v4l_close          (GstV4lElement *v4lelement);
+
+/* norm control (norm = VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) */
+gint     gst_v4l_get_num_chans  (GstV4lElement *v4lelement);
+gboolean gst_v4l_get_chan_norm  (GstV4lElement *v4lelement, gint *channel,          gint *norm);
+gboolean gst_v4l_set_chan_norm  (GstV4lElement *v4lelement, gint  channel,          gint  norm);
+
+/* frequency control */
+gboolean gst_v4l_has_tuner      (GstV4lElement *v4lelement);
+gboolean gst_v4l_get_frequency  (GstV4lElement *v4lelement, gulong *frequency);
+gboolean gst_v4l_set_frequency  (GstV4lElement *v4lelement, gulong  frequency);
+
+/* picture control */
+gboolean gst_v4l_get_picture    (GstV4lElement *v4lelement, GstV4lPictureType type, gint *value);
+gboolean gst_v4l_set_picture    (GstV4lElement *v4lelement, GstV4lPictureType type, gint  value);
+
+/* audio control */
+gboolean gst_v4l_has_audio      (GstV4lElement *v4lelement);
+gboolean gst_v4l_get_audio      (GstV4lElement *v4lelement, GstV4lAudioType type,   gint *value);
+gboolean gst_v4l_set_audio      (GstV4lElement *v4lelement, GstV4lAudioType type,   gint  value);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __V4L_CALLS_H__ */
diff --git a/sys/v4l/v4lmjpegsrc_calls.c b/sys/v4l/v4lmjpegsrc_calls.c
new file mode 100644 (file)
index 0000000..345ae8e
--- /dev/null
@@ -0,0 +1,595 @@
+/* G-Streamer hardware MJPEG video source plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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.
+ */
+
+//#define DEBUG
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include "v4lmjpegsrc_calls.h"
+
+/* On some systems MAP_FAILED seems to be missing */
+#ifndef MAP_FAILED
+#define MAP_FAILED ( (caddr_t) -1 )
+#endif
+
+char *input_name[] = { "Composite", "S-Video", "TV-Tuner", "Autodetect" };
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_queue_frame():
+ *   queue a frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4lmjpegsrc_queue_frame (GstV4lMjpegSrc *v4lmjpegsrc,
+                             gint           num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_queue_frame(), num = %d\n",
+    num);
+#endif
+
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_QBUF_CAPT, &num) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error queueing a buffer (%d): %s",
+      num, sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_sync_next_frame():
+ *   sync on the next frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4lmjpegsrc_sync_next_frame (GstV4lMjpegSrc *v4lmjpegsrc,
+                                 gint           *num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_sync_frame(), num = %d\n",
+    num);
+#endif
+
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_SYNC, &(v4lmjpegsrc->bsync)) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error syncing on a buffer (%ld): %s",
+      v4lmjpegsrc->bsync.frame, sys_errlist[errno]);
+    return FALSE;
+  }
+
+  *num = v4lmjpegsrc->bsync.frame;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_set_input_norm():
+ *   set input/norm (includes autodetection), norm is
+ *   VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_set_input_norm (GstV4lMjpegSrc       *v4lmjpegsrc,
+                                GstV4lMjpegInputType input,
+                                gint                 norm)
+{
+  struct mjpeg_status bstat;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_input_norm(), input = %d (%s), norm = %d (%s)\n",
+    input, input_name[input], norm, norm_name[norm]);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  if (input == V4L_MJPEG_INPUT_AUTO)
+  {
+    int n;
+
+    for (n=V4L_MJPEG_INPUT_COMPOSITE;n<V4L_MJPEG_INPUT_AUTO;n++)
+    {
+      gst_element_info(GST_ELEMENT(v4lmjpegsrc),
+        "Trying %s as input...",
+        input_name[n]);
+      bstat.input = n;
+
+      if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_STATUS, &bstat) < 0)
+      {
+        gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+          "Error getting device status: %s",
+          sys_errlist[errno]);
+        return FALSE;
+      }
+
+      if (bstat.signal)
+      {
+        input = bstat.input;
+        if (norm == VIDEO_MODE_AUTO)
+          norm = bstat.norm;
+        gst_element_info(GST_ELEMENT(v4lmjpegsrc),
+          "Signal found: on input %s, norm %s",
+          input_name[bstat.input], norm_name[bstat.norm]);
+        break;
+      }
+    }
+  }
+  else if (norm == VIDEO_MODE_AUTO && input)
+  {
+    bstat.input = input;
+
+    if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_STATUS, &bstat) < 0)
+    {
+      gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+        "Error getting device status: %s",
+        sys_errlist[errno]);
+      return FALSE;
+    }
+
+    if (bstat.signal)
+    {
+      norm = bstat.norm;
+      gst_element_info(GST_ELEMENT(v4lmjpegsrc),
+        "Norm %s detected on input %s",
+        norm_name[bstat.norm], input_name[input]);
+    }
+    else
+    {
+      gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+        "No signal found on input %s",
+        input_name[input]);
+      return FALSE;
+    }
+  }
+
+  return gst_v4l_set_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), input, norm);
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_set_buffer():
+ *   set buffer parameters (size/count)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc *v4lmjpegsrc,
+                            gint           numbufs,
+                            gint           bufsize)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_buffer(), numbufs = %d, bufsize = %d\n",
+    numbufs, bufsize);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  v4lmjpegsrc->breq.size = bufsize;
+  v4lmjpegsrc->breq.count = numbufs;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_set_capture():
+ *   set capture parameters (simple)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc *v4lmjpegsrc,
+                             gint           decimation,
+                             gint           quality)
+{
+  int norm, input, mw;
+  struct mjpeg_params bparm;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_capture(), decimation = %d, quality = %d\n",
+    decimation, quality);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), &input, &norm);
+
+  /* Query params for capture */
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS, &bparm) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error getting video parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  bparm.decimation = decimation;
+  bparm.quality = quality;
+  bparm.norm = norm;
+  bparm.input = input;
+  bparm.APP_len = 0; /* no JPEG markers - TODO: this is definately not right for decimation==1 */
+
+  mw = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth;
+  if (mw != 768 && mw != 640)
+  {
+    if (decimation == 1)
+      mw = 720;
+    else
+      mw = 704;
+  }
+  v4lmjpegsrc->end_width = mw / decimation;
+  v4lmjpegsrc->end_height = (norm==VIDEO_MODE_NTSC?480:576) / decimation;
+
+  /* TODO: interlacing */
+
+  /* Set params for capture */
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS, &bparm) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error setting video parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_set_capture_m():
+ *   set capture parameters (advanced)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc *v4lmjpegsrc,
+                                        gint           x_offset,
+                                        gint           y_offset,
+                                        gint           width,
+                                        gint           height,
+                                        gint           h_decimation,
+                                        gint           v_decimation,
+                                        gint           quality)
+{
+  gint norm, input;
+  gint maxwidth;
+  struct mjpeg_params bparm;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_capture_m(), x_offset = %d, y_offset = %d, "
+    "width = %d, height = %d, h_decimation = %d, v_decimation = %d, quality = %d\n",
+    x_offset, y_offset, width, height, h_decimation, v_decimation, quality);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), &input, &norm);
+
+  if (GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth != 768 &&
+    GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth != 640)
+    maxwidth = 720;
+  else
+    maxwidth = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth;
+
+  /* Query params for capture */
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS, &bparm) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error getting video parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  bparm.decimation = 0;
+  bparm.quality = quality;
+  bparm.norm = norm;
+  bparm.input = input;
+  bparm.APP_len = 0; /* no JPEG markers - TODO: this is definately not right for decimation==1 */
+
+  if (width <= 0)
+  {
+    if (x_offset < 0) x_offset = 0;
+    width = (maxwidth==720&&h_decimation!=1)?704:maxwidth - 2*x_offset;
+  }
+  else
+  {
+    if (x_offset < 0)
+      x_offset = (maxwidth - width)/2;
+  }
+
+  if (height <= 0)
+  {
+    if (y_offset < 0) y_offset = 0;
+    height = (norm==VIDEO_MODE_NTSC)?480:576 - 2*y_offset;
+  }
+  else
+  {
+    if (y_offset < 0)
+      y_offset = ((norm==VIDEO_MODE_NTSC)?480:576 - height)/2;
+  }
+
+  if (width + x_offset > maxwidth)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Image width+offset (%d) bigger than maximum (%d)",
+      width + x_offset, maxwidth);
+    return FALSE;
+  }
+  if ((width%(bparm.HorDcm*16))!=0) 
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Image width (%d) not multiple of %d (required for JPEG)",
+      width, bparm.HorDcm*16);
+    return FALSE;
+  }
+  if (height + y_offset > (norm==VIDEO_MODE_NTSC ? 480 : 576)) 
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Image height+offset (%d) bigger than maximum (%d)",
+      height + y_offset, (norm==VIDEO_MODE_NTSC ? 480 : 576));
+    return FALSE;
+  }
+  /* RJ: Image height must only be a multiple of 8, but geom_height
+   * is double the field height
+   */
+  if ((height%(bparm.VerDcm*16))!=0) 
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Image height (%d) not multiple of %d (required for JPEG)",
+      height, bparm.VerDcm*16);
+    return FALSE;
+  }
+
+  bparm.img_x = x_offset;
+  bparm.img_width = width;
+  bparm.img_y = y_offset;
+  bparm.img_height = height;
+  bparm.HorDcm = h_decimation;
+  bparm.VerDcm = (v_decimation==4) ? 2 : 1;
+  bparm.TmpDcm = (v_decimation==1) ? 1 : 2;
+  bparm.field_per_buff = (v_decimation==1) ? 2 : 1;
+
+  v4lmjpegsrc->end_width = width / h_decimation;
+  v4lmjpegsrc->end_width = height / v_decimation;
+
+  /* TODO: interlacing */
+
+  /* Set params for capture */
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS, &bparm) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error setting video parameters: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_capture_init():
+ *   initialize the capture system
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc *v4lmjpegsrc)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_init()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  /* Request buffers */
+  if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_REQBUFS, &(v4lmjpegsrc->breq)) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error requesting video buffers: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  gst_element_info(GST_ELEMENT(v4lmjpegsrc),
+    "Got %ld buffers of size %ld KB",
+    v4lmjpegsrc->breq.count, v4lmjpegsrc->breq.size/1024);
+
+  /* Map the buffers */
+  GST_V4LELEMENT(v4lmjpegsrc)->buffer = mmap(0, v4lmjpegsrc->breq.count * v4lmjpegsrc->breq.size, 
+    PROT_READ, MAP_SHARED, GST_V4LELEMENT(v4lmjpegsrc)->video_fd, 0);
+  if (GST_V4LELEMENT(v4lmjpegsrc)->buffer == MAP_FAILED)
+  {
+    gst_element_error(GST_ELEMENT(v4lmjpegsrc),
+      "Error mapping video buffers: %s",
+      sys_errlist[errno]);
+    GST_V4LELEMENT(v4lmjpegsrc)->buffer = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_capture_start():
+ *   start streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc *v4lmjpegsrc)
+{
+  int n;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_start()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  /* queue'ing the buffers starts streaming capture */
+  for (n=0;n<v4lmjpegsrc->breq.count;n++)
+    if (!gst_v4lmjpegsrc_queue_frame(v4lmjpegsrc, n))
+      return FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_grab_frame():
+ *   grab one frame during streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc *v4lmjpegsrc,
+                            gint           *num,
+                            gint           *size)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_grab_frame()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  /* syncing on the buffer grabs it */
+  if (!gst_v4lmjpegsrc_sync_next_frame(v4lmjpegsrc, num))
+    return FALSE;
+
+  *size = v4lmjpegsrc->bsync.length;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_get_buffer():
+ *   get the memory address of a single buffer
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+guint8 *
+gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc *v4lmjpegsrc,
+                            gint           num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_get_buffer(), num = %d\n",
+    num);
+#endif
+
+  if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
+    return NULL;
+
+  return GST_V4LELEMENT(v4lmjpegsrc)->buffer+(v4lmjpegsrc->breq.size*num);
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_requeue_frame():
+ *   requeue a frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc *v4lmjpegsrc,
+                               gint           num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_requeue_frame(), num = %d\n",
+    num);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  if (!gst_v4lmjpegsrc_queue_frame(v4lmjpegsrc, num))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_capture_stop():
+ *   stop streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc *v4lmjpegsrc)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_stop()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  /* unqueue the buffers */
+  if (!gst_v4lmjpegsrc_queue_frame(v4lmjpegsrc, -1))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lmjpegsrc_capture_deinit():
+ *   deinitialize the capture system
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc *v4lmjpegsrc)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_deinit()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
+
+  /* unmap the buffer */
+  munmap(GST_V4LELEMENT(v4lmjpegsrc)->buffer, v4lmjpegsrc->breq.size * v4lmjpegsrc->breq.count);
+  GST_V4LELEMENT(v4lmjpegsrc)->buffer = NULL;
+
+  return TRUE;
+}
diff --git a/sys/v4l/v4lmjpegsrc_calls.h b/sys/v4l/v4lmjpegsrc_calls.h
new file mode 100644 (file)
index 0000000..f8572e5
--- /dev/null
@@ -0,0 +1,63 @@
+/* G-Streamer hardware MJPEG video source plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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 __V4L_MJPEG_SRC_CALLS_H__
+#define __V4L_MJPEG_SRC_CALLS_H__
+
+#include "gstv4lmjpegsrc.h"
+#include "v4l_calls.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+typedef enum {
+  V4L_MJPEG_INPUT_COMPOSITE = 0,
+  V4L_MJPEG_INPUT_SVIDEO    = 1,
+  V4L_MJPEG_INPUT_TVTUNER   = 2,
+  V4L_MJPEG_INPUT_AUTO      = 3,
+} GstV4lMjpegInputType;
+
+extern char *input_name[];
+
+
+/* set input/norm (includes autodetection, norm = VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) */
+gboolean gst_v4lmjpegsrc_set_input_norm (GstV4lMjpegSrc *v4lmjpegsrc, GstV4lMjpegInputType input, gint norm);
+
+/* frame grabbing/capture */
+gboolean gst_v4lmjpegsrc_set_buffer     (GstV4lMjpegSrc *v4lmjpegsrc,  gint numbufs,    gint bufsize);
+gboolean gst_v4lmjpegsrc_set_capture    (GstV4lMjpegSrc *v4lmjpegsrc,  gint decimation, gint quality);
+gboolean gst_v4lmjpegsrc_set_capture_m  (GstV4lMjpegSrc *v4lmjpegsrc,
+                                         gint x_offset, gint y_offset, gint width,      gint height,
+                                         gint h_decimation,     gint v_decimation,      gint quality);
+gboolean gst_v4lmjpegsrc_capture_init   (GstV4lMjpegSrc *v4lmjpegsrc);
+gboolean gst_v4lmjpegsrc_capture_start  (GstV4lMjpegSrc *v4lmjpegsrc);
+gboolean gst_v4lmjpegsrc_grab_frame     (GstV4lMjpegSrc *v4lmjpegsrc,  gint *num,       gint *size);
+guint8 * gst_v4lmjpegsrc_get_buffer     (GstV4lMjpegSrc *v4lmjpegsrc,  gint  num);
+gboolean gst_v4lmjpegsrc_requeue_frame  (GstV4lMjpegSrc *v4lmjpegsrc,  gint  num);
+gboolean gst_v4lmjpegsrc_capture_stop   (GstV4lMjpegSrc *v4lmjpegsrc);
+gboolean gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc *v4lmjpegsrc);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __V4L_MJPEG_SRC_CALLS_H__ */
diff --git a/sys/v4l/v4lsrc_calls.c b/sys/v4l/v4lsrc_calls.c
new file mode 100644 (file)
index 0000000..e0e5321
--- /dev/null
@@ -0,0 +1,338 @@
+/* G-Streamer BT8x8/V4L frame grabber plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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.
+ */
+
+//#define DEBUG
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include "v4lsrc_calls.h"
+
+/* On some systems MAP_FAILED seems to be missing */
+#ifndef MAP_FAILED
+#define MAP_FAILED ( (caddr_t) -1 )
+#endif
+
+
+/******************************************************
+ * gst_v4lsrc_queue_frame():
+ *   queue a frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4lsrc_queue_frame (GstV4lSrc *v4lsrc,
+                        gint      num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_queue_frame(), num = %d\n",
+    num);
+#endif
+
+  v4lsrc->mmap.frame = num;
+
+  if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCMCAPTURE, &(v4lsrc->mmap)) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error queueing a buffer (%d): %s",
+      num, sys_errlist[errno]);
+    return FALSE;
+  }
+
+  v4lsrc->frame_queued[num] = TRUE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_sync_frame():
+ *   sync on a frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4lsrc_sync_next_frame (GstV4lSrc *v4lsrc,
+                            gint      *num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_sync_frame(), num = %d\n",
+    num);
+#endif
+
+  *num = (v4lsrc->sync_frame + 1)%v4lsrc->mbuf.frames;
+
+  if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCSYNC, num) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error syncing on a buffer (%d): %s",
+      *num, sys_errlist[errno]);
+    return FALSE;
+  }
+
+  v4lsrc->frame_queued[*num] = FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_set_capture():
+ *   set capture parameters, palette = VIDEO_PALETTE_*
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_set_capture (GstV4lSrc *v4lsrc,
+                        gint      width,
+                        gint      height,
+                        gint      palette)
+{
+#ifdef DBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_set_capture(), width = %d, height = %d, palette = %d\n",
+    width, height, palette);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  v4lsrc->mmap.width = width;
+  v4lsrc->mmap.height = height;
+  v4lsrc->mmap.format = palette;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_capture_init():
+ *   initialize the capture system
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_capture_init (GstV4lSrc *v4lsrc)
+{
+  int n;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_init()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* request buffer info */
+  if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCGMBUF, &(v4lsrc->mbuf)) < 0)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error getting buffer information: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+
+  gst_element_info(GST_ELEMENT(v4lsrc),
+    "Got %d buffers of size %d KB",
+    v4lsrc->mbuf.frames, v4lsrc->mbuf.size/(v4lsrc->mbuf.frames*1024));
+
+  /* keep trakc of queued buffers */
+  v4lsrc->frame_queued = (gint *) malloc(sizeof(gint) * v4lsrc->mbuf.frames);
+  if (!v4lsrc->frame_queued)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error creating buffer tracker: %s",
+      sys_errlist[errno]);
+    return FALSE;
+  }
+  for (n=0;n<v4lsrc->mbuf.frames;n++)
+    v4lsrc->frame_queued[n] = FALSE;
+
+  /* Map the buffers */
+  GST_V4LELEMENT(v4lsrc)->buffer = mmap(0, v4lsrc->mbuf.size, 
+    PROT_READ, MAP_SHARED, GST_V4LELEMENT(v4lsrc)->video_fd, 0);
+  if (GST_V4LELEMENT(v4lsrc)->buffer == MAP_FAILED)
+  {
+    gst_element_error(GST_ELEMENT(v4lsrc),
+      "Error mapping video buffers: %s",
+      sys_errlist[errno]);
+    GST_V4LELEMENT(v4lsrc)->buffer = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_capture_start():
+ *   start streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc)
+{
+  int n;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_start()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* queue all buffers, this starts streaming capture */
+  for (n=0;n<v4lsrc->mbuf.frames;n++)
+    if (!gst_v4lsrc_queue_frame(v4lsrc, n))
+      return FALSE;
+
+  v4lsrc->sync_frame = -1;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_grab_frame():
+ *   capture one frame during streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_grab_frame (GstV4lSrc *v4lsrc, gint *num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_grab_frame()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* syncing on the buffer grabs it */
+  if (!gst_v4lsrc_sync_next_frame(v4lsrc, num))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_get_buffer():
+ *   get the address of the just-capture buffer
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+guint8 *
+gst_v4lsrc_get_buffer (GstV4lSrc *v4lsrc, gint  num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_get_buffer(), num = %d\n",
+    num);
+#endif
+
+  if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc)))
+    return NULL;
+
+  return GST_V4LELEMENT(v4lsrc)->buffer+v4lsrc->mbuf.offsets[num];
+}
+
+
+/******************************************************
+ * gst_v4lsrc_requeue_frame():
+ *   re-queue a frame after we're done with the buffer
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_requeue_frame (GstV4lSrc *v4lsrc, gint  num)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_requeue_buffer(), num = %d\n",
+    num);
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* and let's queue the buffer */
+  if (!gst_v4lsrc_queue_frame(v4lsrc, num))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_capture_stop():
+ *   stop streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc)
+{
+  int n, num;
+
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_stop()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* we actually need to sync on all queued buffers but not on the non-queued ones */
+  for (n=0;n<v4lsrc->mbuf.frames;n++)
+    while (v4lsrc->frame_queued[n])
+      if (!gst_v4lsrc_sync_next_frame(v4lsrc, &num))
+        return FALSE;
+
+  return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_capture_deinit():
+ *   deinitialize the capture system
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc)
+{
+#ifdef DEBUG
+  fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_deinit()\n");
+#endif
+
+  GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
+  GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
+
+  /* free buffer tracker */
+  free(v4lsrc->frame_queued);
+
+  /* unmap the buffer */
+  munmap(GST_V4LELEMENT(v4lsrc)->buffer, v4lsrc->mbuf.size);
+  GST_V4LELEMENT(v4lsrc)->buffer = NULL;
+
+  return TRUE;
+}
diff --git a/sys/v4l/v4lsrc_calls.h b/sys/v4l/v4lsrc_calls.h
new file mode 100644 (file)
index 0000000..1a2a11c
--- /dev/null
@@ -0,0 +1,46 @@
+/* G-Streamer BT8x8/V4L frame grabber plugin
+ * Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * 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 __V4L_SRC_CALLS_H__
+#define __V4L_SRC_CALLS_H__
+
+#include "gstv4lsrc.h"
+#include "v4l_calls.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* frame grabbing/capture (palette = VIDEO_PALETTE_* - see videodev.h) */
+gboolean gst_v4lsrc_set_capture    (GstV4lSrc *v4lsrc, gint width, gint height, gint palette);
+gboolean gst_v4lsrc_capture_init   (GstV4lSrc *v4lsrc);
+gboolean gst_v4lsrc_capture_start  (GstV4lSrc *v4lsrc);
+gboolean gst_v4lsrc_grab_frame     (GstV4lSrc *v4lsrc, gint *num);
+guint8 * gst_v4lsrc_get_buffer     (GstV4lSrc *v4lsrc, gint  num);
+gboolean gst_v4lsrc_requeue_frame  (GstV4lSrc *v4lsrc, gint  num);
+gboolean gst_v4lsrc_capture_stop   (GstV4lSrc *v4lsrc);
+gboolean gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __V4L_SRC_CALLS_H__ */
diff --git a/sys/v4l/videodev_mjpeg.h b/sys/v4l/videodev_mjpeg.h
new file mode 100644 (file)
index 0000000..68fd79c
--- /dev/null
@@ -0,0 +1,118 @@
+/* These are the MJPEG API extensions for the Video4Linux API,
+   first introduced by the Iomega Buz driver by Rainer Johanni 
+   <rainer@johanni.de>
+*/
+
+/* This is identical with the mgavideo internal params struct, 
+   please tell me if you change this struct here ! <gz@lysator.liu.se) */
+struct mjpeg_params
+{
+
+   /* The following parameters can only be queried */
+
+   int major_version;            /* Major version number of driver */
+   int minor_version;            /* Minor version number of driver */
+
+   /* Main control parameters */
+
+   int input;                    /* Input channel: 0 = Composite, 1 = S-VHS */
+   int norm;                     /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+   int decimation;               /* decimation of captured video,
+                                    enlargement of video played back.
+                                    Valid values are 1, 2, 4 or 0.
+                                    0 is a special value where the user
+                                    has full control over video scaling */
+
+   /* The following parameters only have to be set if decimation==0,
+      for other values of decimation they provide the data how the image is captured */
+
+   int HorDcm;                    /* Horizontal decimation: 1, 2 or 4 */
+   int VerDcm;                    /* Vertical decimation: 1 or 2 */
+   int TmpDcm;                    /* Temporal decimation: 1 or 2,
+                                     if TmpDcm==2 in capture every second frame is dropped,
+                                     in playback every frame is played twice */
+   int field_per_buff;            /* Number of fields per buffer: 1 or 2 */
+   int img_x;                     /* start of image in x direction */
+   int img_y;                     /* start of image in y direction */
+   int img_width;                 /* image width BEFORE decimation,
+                                     must be a multiple of HorDcm*16 */
+   int img_height;                /* image height BEFORE decimation,
+                                     must be a multiple of VerDcm*8 */
+
+   /* --- End of parameters for decimation==0 only --- */
+
+   /* JPEG control parameters */
+
+   int  quality;                  /* Measure for quality of compressed images.
+                                     Scales linearly with the size of the compressed images.
+                                     Must be beetween 0 and 100, 100 is a compression
+                                     ratio of 1:4 */
+
+   int  odd_even;                 /* Which field should come first ???
+                                     This is more aptly named "top_first",
+                                     i.e. (odd_even==1) --> top-field-first */
+
+   int  APPn;                     /* Number of APP segment to be written, must be 0..15 */
+   int  APP_len;                  /* Length of data in JPEG APPn segment */
+   char APP_data[60];             /* Data in the JPEG APPn segment. */
+
+   int  COM_len;                  /* Length of data in JPEG COM segment */
+   char COM_data[60];             /* Data in JPEG COM segment */
+
+   unsigned long jpeg_markers;    /* Which markers should go into the JPEG output.
+                                     Unless you exactly know what you do, leave them untouched.
+                                     Inluding less markers will make the resulting code
+                                     smaller, but there will be fewer aplications
+                                     which can read it.
+                                     The presence of the APP and COM marker is
+                                     influenced by APP0_len and COM_len ONLY! */
+#define JPEG_MARKER_DHT (1<<3)    /* Define Huffman Tables */
+#define JPEG_MARKER_DQT (1<<4)    /* Define Quantization Tables */
+#define JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
+#define JPEG_MARKER_COM (1<<6)    /* Comment segment */
+#define JPEG_MARKER_APP (1<<7)    /* App segment, driver will allways use APP0 */
+
+   int  VFIFO_FB;                 /* Flag for enabling Video Fifo Feedback.
+                                     If this flag is turned on and JPEG decompressing
+                                     is going to the screen, the decompress process
+                                     is stopped every time the Video Fifo is full.
+                                     This enables a smooth decompress to the screen
+                                     but the video output signal will get scrambled */
+
+   /* Misc */
+
+       char reserved[312];  /* Makes 512 bytes for this structure */
+};
+
+struct mjpeg_requestbuffers
+{
+   unsigned long count;      /* Number of buffers for MJPEG grabbing */
+   unsigned long size;       /* Size PER BUFFER in bytes */
+};
+
+struct mjpeg_sync
+{
+   unsigned long frame;      /* Frame (0 - n) for double buffer */
+   unsigned long length;     /* number of code bytes in buffer (capture only) */
+   unsigned long seq;        /* frame sequence number */
+   struct timeval timestamp; /* timestamp */
+};
+
+struct mjpeg_status
+{
+   int input;                /* Input channel, has to be set prior to BUZIOC_G_STATUS */
+   int signal;               /* Returned: 1 if valid video signal detected */
+   int norm;                 /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
+   int color;                /* Returned: 1 if color signal detected */
+};
+
+/*
+Private IOCTL to set up for displaying MJPEG
+*/
+#define MJPIOC_G_PARAMS       _IOR ('v', BASE_VIDIOCPRIVATE+0,  struct mjpeg_params)
+#define MJPIOC_S_PARAMS       _IOWR('v', BASE_VIDIOCPRIVATE+1,  struct mjpeg_params)
+#define MJPIOC_REQBUFS        _IOWR('v', BASE_VIDIOCPRIVATE+2,  struct mjpeg_requestbuffers)
+#define MJPIOC_QBUF_CAPT      _IOW ('v', BASE_VIDIOCPRIVATE+3,  int)
+#define MJPIOC_QBUF_PLAY      _IOW ('v', BASE_VIDIOCPRIVATE+4,  int)
+#define MJPIOC_SYNC           _IOR ('v', BASE_VIDIOCPRIVATE+5,  struct mjpeg_sync)
+#define MJPIOC_G_STATUS       _IOWR('v', BASE_VIDIOCPRIVATE+6,  struct mjpeg_status)