this adds video4linux2 source and element plugins. The division in v4l2* plugins...
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>
Mon, 9 Sep 2002 07:14:35 +0000 (07:14 +0000)
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>
Mon, 9 Sep 2002 07:14:35 +0000 (07:14 +0000)
Original commit message from CVS:
this adds video4linux2 source and element plugins. The division in v4l2* plugins is the same as for v4l1 - i.e. an element, a src and a sink, but there won't be separate encoding plugins (like v4lmjpegsrc) - all functionality is (thanks to video4linux2) integrated in one plugin: v4l2src. v4l2sink is still to be done, that'll come later.

12 files changed:
common
sys/v4l2/Makefile.am [new file with mode: 0644]
sys/v4l2/README [new file with mode: 0644]
sys/v4l2/gstv4l2element.c [new file with mode: 0644]
sys/v4l2/gstv4l2element.h [new file with mode: 0644]
sys/v4l2/gstv4l2src.c [new file with mode: 0644]
sys/v4l2/gstv4l2src.h [new file with mode: 0644]
sys/v4l2/v4l2-overlay_calls.c [new file with mode: 0644]
sys/v4l2/v4l2_calls.c [new file with mode: 0644]
sys/v4l2/v4l2_calls.h [new file with mode: 0644]
sys/v4l2/v4l2src_calls.c [new file with mode: 0644]
sys/v4l2/v4l2src_calls.h [new file with mode: 0644]

diff --git a/common b/common
index 355c616..2f6d9cf 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 355c616d5f6779ea194f8b61704229c6fb04ae7b
+Subproject commit 2f6d9cfdaaa83ab454d263d6eba88046debadc2d
diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am
new file mode 100644 (file)
index 0000000..18fe742
--- /dev/null
@@ -0,0 +1,18 @@
+plugindir = $(libdir)/gst
+
+plugin_LTLIBRARIES = \
+       libgstv4l2element.la \
+       libgstv4l2src.la
+
+libgstv4l2element_la_SOURCES = gstv4l2element.c v4l2_calls.c v4l2-overlay_calls.c
+libgstv4l2element_la_CFLAGS = $(GST_CFLAGS)
+libgstv4l2element_la_LIBADD =
+libgstv4l2element_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+libgstv4l2src_la_SOURCES = gstv4l2src.c v4l2src_calls.c
+libgstv4l2src_la_CFLAGS = $(GST_CFLAGS)
+libgstv4l2src_la_LIBADD = libgstv4l2element.la
+libgstv4l2src_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstv4l2element.h v4l2_calls.h \
+               gstv4l2src.h v4l2src_calls.h
diff --git a/sys/v4l2/README b/sys/v4l2/README
new file mode 100644 (file)
index 0000000..f10c27c
--- /dev/null
@@ -0,0 +1,24 @@
+v4l2 plugins
+============
+
+The idea is a bit the same as the idea for the v4l1 plugins. We want
+one generic v4l2element, and a few child objects (probably only two:
+v4l2src and v4l2sink):
+
+                /-------- v4l2src
+v4l2element ---=
+                \-------- v4l2sink
+
+Both v4l2src and v4l2sink have a uncompressed and a compressed
+recording-/playback-mode. Since this is all part of v4l2, the 'client'
+of these elements, i.e. an applicaiton using v4l2src/v4l2sink, will
+hardly notice this. All capsnego stuff is done inside, and the plugin
+knows which formats are compressed and which are not.
+
+Please note that the v4l1 and the v4l2 plugins are *not* compatible
+concerning properties. Naming has been kept the same where possible,
+but in some cases, properties had to be removed or added to make
+full use of v4l2.
+
+V4L2 API: http://thedirks.org/v4l2/. Kernel patches available from
+          http://bytesex.org/patches/.
diff --git a/sys/v4l2/gstv4l2element.c b/sys/v4l2/gstv4l2element.c
new file mode 100644 (file)
index 0000000..2ab68a3
--- /dev/null
@@ -0,0 +1,493 @@
+/* G-Streamer generic V4L2 element
+ * Copyright (C) 2002 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "v4l2_calls.h"
+
+
+static GstElementDetails gst_v4l2element_details = {
+       "Generic video4linux2 Element",
+       "None/Video",
+       "Generic plugin for handling common video4linux2 calls",
+       VERSION,
+       "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+       "(C) 2002",
+};
+
+/* V4l2Element signals and args */
+enum {
+       /* FILL ME */
+       LAST_SIGNAL
+};
+
+enum {
+       ARG_0,
+       ARG_CHANNEL,
+       ARG_CHANNEL_NAMES,
+       ARG_OUTPUT,
+       ARG_OUTPUT_NAMES,
+       ARG_NORM,
+       ARG_NORM_NAMES,
+       ARG_HAS_TUNER,
+       ARG_FREQUENCY,
+       ARG_SIGNAL_STRENGTH,
+       ARG_HAS_AUDIO,
+       ARG_ATTRIBUTE,
+       ARG_ATTRIBUTE_SETS,
+       ARG_DEVICE,
+       ARG_DEVICE_NAME,
+       ARG_DEVICE_HAS_CAPTURE,
+       ARG_DEVICE_HAS_OVERLAY,
+       ARG_DEVICE_HAS_CODEC,
+       ARG_DISPLAY,
+       ARG_VIDEOWINDOW,
+       ARG_CLIPPING,
+       ARG_DO_OVERLAY,
+};
+
+
+static void                    gst_v4l2element_class_init      (GstV4l2ElementClass *klass);
+static void                    gst_v4l2element_init            (GstV4l2Element      *v4lelement);
+static void                    gst_v4l2element_set_property    (GObject             *object,
+                                                                guint               prop_id,
+                                                                const GValue        *value,
+                                                                GParamSpec          *pspec);
+static void                    gst_v4l2element_get_property    (GObject             *object,
+                                                                guint               prop_id,
+                                                                GValue              *value,
+                                                                GParamSpec          *pspec);
+static GstElementStateReturn   gst_v4l2element_change_state    (GstElement          *element);
+
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_v4l2element_signals[LAST_SIGNAL] = { 0 }; */
+
+
+GType
+gst_v4l2element_get_type (void)
+{
+       static GType v4l2element_type = 0;
+
+       if (!v4l2element_type) {
+               static const GTypeInfo v4l2element_info = {
+                       sizeof(GstV4l2ElementClass),
+                       NULL,
+                       NULL,
+                       (GClassInitFunc) gst_v4l2element_class_init,
+                       NULL,
+                       NULL,
+                       sizeof(GstV4l2Element),
+                       0,
+                       (GInstanceInitFunc) gst_v4l2element_init,
+                       NULL
+               };
+               v4l2element_type = g_type_register_static(GST_TYPE_ELEMENT,
+                                       "GstV4l2Element", &v4l2element_info, 0);
+       }
+       return v4l2element_type;
+}
+
+
+
+static void
+gst_v4l2element_class_init (GstV4l2ElementClass *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_CHANNEL_NAMES,
+               g_param_spec_pointer("channel_names","channel_names","channel_names",
+               G_PARAM_READABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT,
+               g_param_spec_int("output","output","output",
+               G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT_NAMES,
+               g_param_spec_pointer("output_names","output_names","output_names",
+               G_PARAM_READABLE));
+       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_NORM_NAMES,
+               g_param_spec_pointer("norm_names","norm_names","norm_names",
+               G_PARAM_READABLE));
+
+       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_SIGNAL_STRENGTH,
+               g_param_spec_ulong("signal_strength","signal_strength","signal_strength",
+               0,G_MAXULONG,0,G_PARAM_READABLE));
+
+       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_ATTRIBUTE,
+               g_param_spec_pointer("attribute","attribute","attribute",
+               G_PARAM_READWRITE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ATTRIBUTE_SETS,
+               g_param_spec_pointer("attribute_sets","attribute_sets","attribute_sets",
+               G_PARAM_READABLE));
+
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
+               g_param_spec_string("device","device","device",
+               NULL, G_PARAM_READWRITE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_NAME,
+               g_param_spec_string("device_name","device_name","device_name",
+               NULL, G_PARAM_READABLE));
+
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CAPTURE,
+               g_param_spec_boolean("can_capture","can_capture","can_capture",
+               0,G_PARAM_READABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_OVERLAY,
+               g_param_spec_boolean("has_overlay","has_overlay","has_overlay",
+               0,G_PARAM_READABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CODEC,
+               g_param_spec_boolean("has_compression","has_compression","has_compression",
+               0,G_PARAM_READABLE));
+
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DISPLAY,
+               g_param_spec_string("display","display","display",
+               NULL, G_PARAM_WRITABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DO_OVERLAY,
+               g_param_spec_boolean("do_overlay","do_overlay","do_overlay",
+               0,G_PARAM_WRITABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VIDEOWINDOW,
+               g_param_spec_pointer("videowindow","videowindow","videowindow",
+               G_PARAM_WRITABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CLIPPING,
+               g_param_spec_pointer("videowindowclip","videowindowclip","videowindowclip",
+               G_PARAM_WRITABLE));
+
+       gobject_class->set_property = gst_v4l2element_set_property;
+       gobject_class->get_property = gst_v4l2element_get_property;
+
+       gstelement_class->change_state = gst_v4l2element_change_state;
+}
+
+
+static void
+gst_v4l2element_init (GstV4l2Element *v4l2element)
+{
+       /* some default values */
+       v4l2element->video_fd = -1;
+       v4l2element->buffer = NULL;
+       v4l2element->device = NULL;
+
+       v4l2element->norm = -1;
+       v4l2element->channel = -1;
+       v4l2element->output = -1;
+       v4l2element->frequency = 0;
+
+       v4l2element->controls = NULL;
+       v4l2element->formats = NULL;
+       v4l2element->outputs = NULL;
+       v4l2element->inputs = NULL;
+       v4l2element->norms = NULL;
+}
+
+
+static void
+gst_v4l2element_set_property (GObject      *object,
+                              guint        prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+       GstV4l2Element *v4l2element;
+
+       /* it's not null if we got it, but it might not be ours */
+       g_return_if_fail(GST_IS_V4L2ELEMENT(object));
+       v4l2element = GST_V4L2ELEMENT(object);
+
+       switch (prop_id) {
+               case ARG_CHANNEL:
+                       v4l2element->channel = g_value_get_int(value);
+                       if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
+                               if (!gst_v4l2_set_input(v4l2element, g_value_get_int(value)))
+                                       return;
+                       }
+                       break;
+               case ARG_OUTPUT:
+                       v4l2element->output = g_value_get_int(value);
+                       if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
+                               if (!gst_v4l2_set_output(v4l2element, g_value_get_int(value)))
+                                       return;
+                       }
+                       break;
+               case ARG_NORM:
+                       v4l2element->norm = g_value_get_int(value);
+                       if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
+                               if (!gst_v4l2_set_norm(v4l2element, g_value_get_int(value)))
+                                       return;
+                       }
+                       break;
+               case ARG_FREQUENCY:
+                       v4l2element->frequency = g_value_get_ulong(value);
+                       if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
+                               if (!gst_v4l2_set_frequency(v4l2element, g_value_get_ulong(value)))
+                                       return;
+                       }
+                       break;
+               case ARG_ATTRIBUTE:
+                       if (GST_V4L2_IS_OPEN(v4l2element)) {
+                               gst_v4l2_set_attribute(v4l2element,
+                                       ((GstV4l2Attribute*)g_value_get_pointer(value))->index,
+                                       ((GstV4l2Attribute*)g_value_get_pointer(value))->value);
+                       }
+                       break;
+               case ARG_DEVICE:
+                       if (!GST_V4L2_IS_OPEN(v4l2element)) {
+                               if (v4l2element->device)
+                                       g_free(v4l2element->device);
+                               v4l2element->device = g_strdup(g_value_get_string(value));
+                       }
+                       break;
+               case ARG_DISPLAY:
+                       if (!gst_v4l2_set_display(v4l2element, g_value_get_string(value)))
+                               return;
+                       break;
+               case ARG_VIDEOWINDOW:
+                       if (GST_V4L2_IS_OPEN(v4l2element)) {
+                               gst_v4l2_set_window(v4l2element,
+                                       ((GstV4l2Rect*)g_value_get_pointer(value))->x,
+                                       ((GstV4l2Rect*)g_value_get_pointer(value))->y,
+                                       ((GstV4l2Rect*)g_value_get_pointer(value))->w,
+                                       ((GstV4l2Rect*)g_value_get_pointer(value))->h);
+                       }
+                       break;
+               case ARG_CLIPPING:
+                       if (GST_V4L2_IS_OPEN(v4l2element)) {
+                               gint i;
+                               struct v4l2_clip *clips;
+                               GList *list = (GList*)g_value_get_pointer(value);
+                               clips = g_malloc(sizeof(struct v4l2_clip) * g_list_length(list));
+                               for (i=0;i<g_list_length(list);i++)
+                               {
+                                       clips[i].x = ((GstV4l2Rect*)g_list_nth_data(list, i))->x;
+                                       clips[i].y = ((GstV4l2Rect*)g_list_nth_data(list, i))->y;
+                                       clips[i].width = ((GstV4l2Rect*)g_list_nth_data(list, i))->w;
+                                       clips[i].height = ((GstV4l2Rect*)g_list_nth_data(list, i))->h;
+                               }
+                               gst_v4l2_set_clips(v4l2element, clips, g_list_length(list));
+                               g_free(clips);
+                       }
+                       break;
+               case ARG_DO_OVERLAY:
+                       if (GST_V4L2_IS_OPEN(v4l2element)) {
+                               if (!gst_v4l2_enable_overlay(v4l2element, g_value_get_boolean(value)))
+                                       return;
+                       }
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+
+static void
+gst_v4l2element_get_property (GObject    *object,
+                              guint      prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+       GstV4l2Element *v4l2element;
+       gint temp_i = 0;
+       gulong temp_ul = 0;
+       GList *list = NULL;
+
+       /* it's not null if we got it, but it might not be ours */
+       g_return_if_fail(GST_IS_V4L2ELEMENT(object));
+       v4l2element = GST_V4L2ELEMENT(object);
+
+       switch (prop_id) {
+               case ARG_CHANNEL:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               gst_v4l2_get_input(v4l2element, &temp_i);
+                       g_value_set_int(value, temp_i);
+                       break;
+               case ARG_CHANNEL_NAMES:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               list = gst_v4l2_get_input_names(v4l2element);
+                       g_value_set_pointer(value, list);
+                       break;
+               case ARG_OUTPUT:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               gst_v4l2_get_output(v4l2element, &temp_i);
+                       g_value_set_int(value, temp_i);
+                       break;
+               case ARG_OUTPUT_NAMES:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               list = gst_v4l2_get_output_names(v4l2element);
+                       g_value_set_pointer(value, list);
+                       break;
+               case ARG_NORM:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               gst_v4l2_get_norm(v4l2element, &temp_i);
+                       g_value_set_int(value, temp_i);
+                       break;
+               case ARG_NORM_NAMES:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               list = gst_v4l2_get_norm_names(v4l2element);
+                       g_value_set_pointer(value, list);
+                       break;
+               case ARG_HAS_TUNER:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               temp_i = gst_v4l2_has_tuner(v4l2element);
+                       g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
+                       break;
+               case ARG_FREQUENCY:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               gst_v4l2_get_frequency(v4l2element, &temp_ul);
+                       g_value_set_ulong(value, temp_ul);
+                       break;
+               case ARG_SIGNAL_STRENGTH:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               gst_v4l2_signal_strength(v4l2element, &temp_ul);
+                       g_value_set_ulong(value, temp_ul);
+                       break;
+               case ARG_HAS_AUDIO:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               temp_i = gst_v4l2_has_audio(v4l2element);
+                       g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
+                       break;
+               case ARG_ATTRIBUTE:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               gst_v4l2_get_attribute(v4l2element,
+                                       ((GstV4l2Attribute*)g_value_get_pointer(value))->index, &temp_i);
+                       ((GstV4l2Attribute*)g_value_get_pointer(value))->value = temp_i;
+                       break;
+               case ARG_ATTRIBUTE_SETS:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               list = gst_v4l2_get_attributes(v4l2element);
+                       g_value_set_pointer(value, list);
+                       break;
+               case ARG_DEVICE:
+                       g_value_set_string(value, g_strdup(v4l2element->device));
+                       break;
+               case ARG_DEVICE_NAME:
+                       if (GST_V4L2_IS_OPEN(v4l2element))
+                               g_value_set_string(value, g_strdup(v4l2element->vcap.name));
+                       break;
+               case ARG_DEVICE_HAS_CAPTURE:
+                       if (GST_V4L2_IS_OPEN(v4l2element) &&
+                           (v4l2element->vcap.type == V4L2_TYPE_CODEC ||
+                            v4l2element->vcap.type == V4L2_TYPE_CAPTURE) &&
+                           v4l2element->vcap.flags & V4L2_FLAG_STREAMING)
+                               temp_i = 1;
+                       g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
+                       break;
+               case ARG_DEVICE_HAS_OVERLAY:
+                       if (GST_V4L2_IS_OPEN(v4l2element) &&
+                           v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)
+                               temp_i = 1;
+                       g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
+                       break;
+               case ARG_DEVICE_HAS_CODEC:
+                       if (GST_V4L2_IS_OPEN(v4l2element) &&
+                           v4l2element->vcap.type == V4L2_TYPE_CODEC)
+                               temp_i = 1;
+                       g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+                       break;
+       }
+}
+
+
+static GstElementStateReturn
+gst_v4l2element_change_state (GstElement *element)
+{
+       GstV4l2Element *v4l2element;
+
+       g_return_val_if_fail(GST_IS_V4L2ELEMENT(element), GST_STATE_FAILURE);
+  
+       v4l2element = GST_V4L2ELEMENT(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_TRANSITION(element)) {
+               case GST_STATE_NULL_TO_READY:
+                       if (!gst_v4l2_open(v4l2element))
+                               return GST_STATE_FAILURE;
+
+                       /* now, sync options */
+                       if (v4l2element->norm >= 0)
+                               if (!gst_v4l2_set_norm(v4l2element, v4l2element->norm))
+                                       return GST_STATE_FAILURE;
+                       if (v4l2element->channel >= 0)
+                               if (!gst_v4l2_set_input(v4l2element, v4l2element->channel))
+                                       return GST_STATE_FAILURE;
+                       if (v4l2element->output >= 0)
+                               if (!gst_v4l2_set_output(v4l2element, v4l2element->output))
+                                       return GST_STATE_FAILURE;
+                       if (v4l2element->frequency > 0)
+                               if (!gst_v4l2_set_frequency(v4l2element, v4l2element->frequency))
+                                       return GST_STATE_FAILURE;
+                       break;
+               case GST_STATE_READY_TO_NULL:
+                       if (!gst_v4l2_close(v4l2element))
+                               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 gboolean
+plugin_init (GModule   *module,
+             GstPlugin *plugin)
+{
+       GstElementFactory *factory;
+
+       /* create an elementfactory for the v4l2element */
+       factory = gst_element_factory_new("v4l2element", GST_TYPE_V4L2ELEMENT,
+                               &gst_v4l2element_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,
+       "v4l2element",
+       plugin_init
+};
diff --git a/sys/v4l2/gstv4l2element.h b/sys/v4l2/gstv4l2element.h
new file mode 100644 (file)
index 0000000..617aad6
--- /dev/null
@@ -0,0 +1,110 @@
+/* G-Streamer generic V4L2 element
+ * Copyright (C) 2002 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_V4L2ELEMENT_H__
+#define __GST_V4L2ELEMENT_H__
+
+#include <gst/gst.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+
+#define GST_TYPE_V4L2ELEMENT \
+               (gst_v4l2element_get_type())
+#define GST_V4L2ELEMENT(obj) \
+               (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_V4L2ELEMENT, GstV4l2Element))
+#define GST_V4L2ELEMENT_CLASS(klass) \
+               (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_V4L2ELEMENT, GstV4l2ElementClass))
+#define GST_IS_V4L2ELEMENT(obj) \
+               (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_V4L2ELEMENT))
+#define GST_IS_V4L2ELEMENT_CLASS(obj) \
+               (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_V4L2ELEMENT))
+
+
+typedef        struct _GstV4l2Element          GstV4l2Element;
+typedef        struct _GstV4l2ElementClass     GstV4l2ElementClass;
+
+typedef struct _GstV4l2Rect {
+       gint x, y, w, h;
+} GstV4l2Rect;
+
+typedef enum {
+       GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT,
+       GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN,
+       GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON,
+       GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST,
+} GstV4l2AttributeValueType;
+
+typedef enum {
+       GST_V4L2_ATTRIBUTE_TYPE_VIDEO,
+       GST_V4L2_ATTRIBUTE_TYPE_AUDIO,
+       GST_V4L2_ATTRIBUTE_TYPE_EFFECT,
+} GstV4l2AttributeType;
+
+typedef struct _GstV4l2Attribute {
+       gint index;
+       gchar *name;
+       GstV4l2AttributeType type;
+       GstV4l2AttributeValueType val_type;
+       gint min, max, value;
+       GList *list_items; /* in case of 'list' */
+} GstV4l2Attribute;
+
+struct _GstV4l2Element {
+       GstElement element;
+
+       /* the video device */
+       char *device;
+
+       /* the video-device's file descriptor */
+       gint video_fd;
+
+       /* the video buffer (mmap()'ed) */
+       guint8 **buffer;
+
+       /* the video-device's capabilities */
+       struct v4l2_capability vcap;
+
+       /* the toys available to us */
+       GList /*v4l2_fmtdesc*/ *formats; /* list of available capture formats */
+       GList /*v4l2_input*/ *inputs;
+       GList /*v4l2_output*/ *outputs;
+       GList /*v4l2_enumstd*/ *norms;
+       GList /*v4l2_queryctrl*/ *controls;
+       GList /*GList:v4l2_querymenu*/ *menus;
+
+       /* and last but not least, the current video window */
+       struct v4l2_window vwin;
+
+       /* caching values */
+       gint channel;
+       gint output;
+       gint norm;
+       gulong frequency;
+};
+
+struct _GstV4l2ElementClass {
+       GstElementClass parent_class;
+};
+
+
+GType gst_v4l2element_get_type (void);
+
+#endif /* __GST_V4L2ELEMENT_H__ */
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c
new file mode 100644 (file)
index 0000000..7dce792
--- /dev/null
@@ -0,0 +1,837 @@
+/* G-Streamer Video4linux2 video-capture plugin
+ * Copyright (C) 2002 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 <sys/time.h>
+#include "v4l2src_calls.h"
+
+
+static GstElementDetails gst_v4l2src_details = {
+       "Video (video4linux2) Source",
+       "Source/Video",
+       "Reads frames (compressed or uncompressed) from a video4linux2 device",
+       VERSION,
+       "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+       "(C) 2002",
+};
+
+/* V4l2Src signals and args */
+enum {
+       /* FILL ME */
+       LAST_SIGNAL
+};
+
+/* arguments */
+enum {
+       ARG_0,
+       ARG_WIDTH,
+       ARG_HEIGHT,
+       ARG_PALETTE,
+       ARG_PALETTE_NAMES,
+       ARG_FOURCC,
+       ARG_FOURCC_LIST,
+       ARG_NUMBUFS,
+       ARG_BUFSIZE
+};
+
+
+/* init functions */
+static void                    gst_v4l2src_class_init          (GstV4l2SrcClass *klass);
+static void                    gst_v4l2src_init                (GstV4l2Src      *v4l2src);
+
+/* pad/buffer functions */
+static GstPadConnectReturn     gst_v4l2src_srcconnect          (GstPad          *pad,
+                                                                GstCaps         *caps);
+static GstBuffer *             gst_v4l2src_get                 (GstPad         *pad);
+
+/* get/set params */
+static void                    gst_v4l2src_set_property        (GObject         *object,
+                                                                guint           prop_id,
+                                                                const GValue    *value,
+                                                                GParamSpec      *pspec);
+static void                    gst_v4l2src_get_property        (GObject         *object,
+                                                                guint           prop_id,
+                                                                GValue          *value,
+                                                                GParamSpec      *pspec);
+
+/* state handling */
+static GstElementStateReturn   gst_v4l2src_change_state        (GstElement      *element);
+
+/* bufferpool functions */
+static GstBuffer *             gst_v4l2src_buffer_new          (GstBufferPool   *pool,
+                                                                guint64         offset,
+                                                                guint           size,
+                                                                gpointer        user_data);
+static GstBuffer *             gst_v4l2src_buffer_copy         (GstBufferPool   *pool,
+                                                                const GstBuffer *srcbuf,
+                                                                gpointer        user_data);
+static void                    gst_v4l2src_buffer_free         (GstBufferPool   *pool,
+                                                                GstBuffer       *buf,
+                                                                gpointer        user_data);
+
+
+static GstPadTemplate *src_template;
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_v4l2src_signals[LAST_SIGNAL] = { 0 }; */
+
+
+GType
+gst_v4l2src_get_type (void)
+{
+       static GType v4l2src_type = 0;
+
+       if (!v4l2src_type) {
+               static const GTypeInfo v4l2src_info = {
+                       sizeof(GstV4l2SrcClass),
+                       NULL,
+                       NULL,
+                       (GClassInitFunc) gst_v4l2src_class_init,
+                       NULL,
+                       NULL,
+                       sizeof(GstV4l2Src),
+                       0,
+                       (GInstanceInitFunc) gst_v4l2src_init,
+                       NULL
+               };
+               v4l2src_type = g_type_register_static(GST_TYPE_V4L2ELEMENT,
+                       "GstV4l2Src", &v4l2src_info, 0);
+       }
+       return v4l2src_type;
+}
+
+
+static void
+gst_v4l2src_class_init (GstV4l2SrcClass *klass)
+{
+       GObjectClass *gobject_class;
+       GstElementClass *gstelement_class;
+
+       gobject_class = (GObjectClass*)klass;
+       gstelement_class = (GstElementClass*)klass;
+
+       parent_class = g_type_class_ref(GST_TYPE_V4L2ELEMENT);
+
+       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));
+       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));
+
+       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));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE_NAMES,
+               g_param_spec_pointer("palette_name","palette_name","palette_name",
+               G_PARAM_READABLE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FOURCC,
+               g_param_spec_string("fourcc","fourcc","fourcc",
+               NULL,G_PARAM_READWRITE));
+       g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FOURCC_LIST,
+               g_param_spec_pointer("fourcc_list","fourcc_list","fourcc_list",
+               G_PARAM_READABLE));
+
+       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_READABLE));
+
+       gobject_class->set_property = gst_v4l2src_set_property;
+       gobject_class->get_property = gst_v4l2src_get_property;
+
+       gstelement_class->change_state = gst_v4l2src_change_state;
+}
+
+
+static void
+gst_v4l2src_init (GstV4l2Src *v4l2src)
+{
+       v4l2src->srcpad = gst_pad_new_from_template(src_template, "src");
+       gst_element_add_pad(GST_ELEMENT(v4l2src), v4l2src->srcpad);
+
+       gst_pad_set_get_function(v4l2src->srcpad, gst_v4l2src_get);
+       gst_pad_set_connect_function(v4l2src->srcpad, gst_v4l2src_srcconnect);
+
+       v4l2src->bufferpool = gst_buffer_pool_new(NULL, NULL,
+                                       gst_v4l2src_buffer_new,
+                                       gst_v4l2src_buffer_copy,
+                                       gst_v4l2src_buffer_free,
+                                       v4l2src);
+
+       v4l2src->palette = 0; /* means 'any' - user can specify a specific palette */
+       v4l2src->width = 160;
+       v4l2src->height = 120;
+       v4l2src->breq.count = 0;
+}
+
+
+static GstCaps *
+gst_v4l2src_v4l2fourcc_to_caps (guint32  fourcc,
+                                gint     width,
+                                gint     height,
+                                gboolean compressed)
+{
+       GstCaps *capslist = NULL, *caps;
+
+       switch (fourcc) {
+               case V4L2_PIX_FMT_MJPEG: /* v4l2_fourcc('M','J','P','G') */
+                       caps = gst_caps_new("v4l2src_caps",
+                                       "video/jpeg",
+                                       gst_props_new(
+                                               "width",        GST_PROPS_INT(width),
+                                               "height",       GST_PROPS_INT(height),
+                                               NULL));
+                       capslist = gst_caps_append(capslist, caps);
+                       break;
+               case V4L2_PIX_FMT_RGB332:
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+               case V4L2_PIX_FMT_RGB24:
+               case V4L2_PIX_FMT_BGR24:
+               case V4L2_PIX_FMT_RGB32:
+               case V4L2_PIX_FMT_BGR32: {
+                       guint depth=0, bpp=0;
+                       gint endianness=0;
+                       gulong r_mask=0, b_mask=0, g_mask=0;
+                       switch (fourcc) {
+                               case V4L2_PIX_FMT_RGB332:
+                                       bpp = depth = 8;
+                                       endianness = G_BYTE_ORDER; /* 'like, whatever' */
+                                       r_mask = 0xe0; g_mask = 0x1c; b_mask = 0x03;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555:
+                                       bpp = 16; depth = 15;
+                                       endianness = G_LITTLE_ENDIAN;
+                                       r_mask = 0x7c00; g_mask = 0x03e0; b_mask = 0x001f;
+                                       break;
+                               case V4L2_PIX_FMT_RGB555X:
+                                       bpp = 16; depth = 15;
+                                       endianness = G_BIG_ENDIAN;
+                                       r_mask = 0x7c00; g_mask = 0x03e0; b_mask = 0x001f;
+                                       break;
+                               case V4L2_PIX_FMT_RGB565:
+                                       bpp = depth = 16;
+                                       endianness = G_LITTLE_ENDIAN;
+                                       r_mask = 0xf800; g_mask = 0x07e0; b_mask = 0x001f;
+                                       break;
+                               case V4L2_PIX_FMT_RGB565X:
+                                       bpp = depth = 16;
+                                       endianness = G_BIG_ENDIAN;
+                                       r_mask = 0xf800; g_mask = 0x07e0; b_mask = 0x001f;
+                                       break;
+                               case V4L2_PIX_FMT_RGB24:
+                                       bpp = depth = 24;
+                                       endianness = G_BIG_ENDIAN;
+                                       r_mask = 0xff0000; g_mask = 0x00ff00; b_mask = 0x0000ff;
+                                       break;
+                               case V4L2_PIX_FMT_BGR24:
+                                       bpp = depth = 24;
+                                       endianness = G_LITTLE_ENDIAN;
+                                       r_mask = 0xff0000; g_mask = 0x00ff00; b_mask = 0x0000ff;
+                                       break;
+                               case V4L2_PIX_FMT_RGB32:
+                                       bpp = depth = 32;
+                                       endianness = G_BIG_ENDIAN;
+                                       r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff;
+                                       break;
+                               case V4L2_PIX_FMT_BGR32:
+                                       endianness = G_LITTLE_ENDIAN;
+                                       bpp = depth = 32;
+                                       r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff;
+                                       break;
+                       }
+                       caps = gst_caps_new("v4l2src_caps",
+                                       "video/raw",
+                                       gst_props_new(
+                                               "format",       GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')),
+                                               "width",        GST_PROPS_INT(width),
+                                               "height",       GST_PROPS_INT(height),
+                                               "bpp",          GST_PROPS_INT(bpp),
+                                               "depth",        GST_PROPS_INT(depth),
+                                               "red_mask",     GST_PROPS_INT(r_mask),
+                                               "green_mask",   GST_PROPS_INT(g_mask),
+                                               "blue_mask",    GST_PROPS_INT(b_mask),
+                                               "endianness",   GST_PROPS_INT(endianness),
+                                               NULL));
+                       capslist = gst_caps_append(capslist, caps);
+                       break; }
+               case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
+                       caps = gst_caps_new("v4l2src_caps",
+                               "video/raw",
+                               gst_props_new(
+                                       "format",       GST_PROPS_FOURCC(GST_MAKE_FOURCC('I','4','2','0')),
+                                       "width",        GST_PROPS_INT(width),
+                                       "height",       GST_PROPS_INT(height),
+                                       NULL));
+                       capslist = gst_caps_append(capslist, caps);
+                       caps = gst_caps_new("v4l2src_caps",
+                               "video/raw",
+                               gst_props_new(
+                                       "format",       GST_PROPS_FOURCC(GST_MAKE_FOURCC('I','Y','U','V')),
+                                       "width",        GST_PROPS_INT(width),
+                                       "height",       GST_PROPS_INT(height),
+                                       NULL));
+                       capslist = gst_caps_append(capslist, caps);
+                       break;
+               case V4L2_PIX_FMT_YUYV:
+                       caps = gst_caps_new("v4l2src_caps",
+                               "video/raw",
+                               gst_props_new(
+                                       "format",       GST_PROPS_FOURCC(GST_MAKE_FOURCC('Y','U','Y','2')),
+                                       "width",        GST_PROPS_INT(width),
+                                       "height",       GST_PROPS_INT(height),
+                                       NULL));
+                       capslist = gst_caps_append(capslist, caps);
+                       break;
+               default:
+                       break;
+       }
+
+       /* add the standard one */
+       if (compressed) {
+               guint32 print_format = GUINT32_FROM_LE(fourcc);
+               gchar *print_format_str = (gchar *) &print_format, *string_format;
+               gint i;
+               for (i=0;i<4;i++)
+                       print_format_str[i] = g_ascii_tolower(print_format_str[i]);
+               string_format = g_strdup_printf("video/%4.4s", print_format_str);
+               caps = gst_caps_new("v4l2src_caps",
+                               string_format,
+                               gst_props_new(
+                                       "width",        GST_PROPS_INT(width),
+                                       "height",       GST_PROPS_INT(height),
+                                       NULL));
+               capslist = gst_caps_append(capslist, caps);
+               g_free(string_format);
+       } else {
+               caps = gst_caps_new("v4l2src_caps",
+                               "video/raw",
+                               gst_props_new(
+                                       "format",       GST_PROPS_FOURCC(fourcc),
+                                       "width",        GST_PROPS_INT(width),
+                                       "height",       GST_PROPS_INT(height),
+                                       NULL));
+               capslist = gst_caps_append(capslist, caps);
+       }
+
+       return capslist;
+}
+
+
+static GList *
+gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src,
+                             GstCaps    *capslist)
+{
+       GList *fourcclist = NULL;
+       GstCaps *caps;
+       guint32 fourcc;
+       gint i;
+
+       for (caps = capslist;caps != NULL; caps = caps->next) {
+               const gchar *format = gst_caps_get_mime(caps);
+
+               if (!strcmp(format, "video/raw")) {
+                       /* non-compressed */
+                       gst_caps_get_fourcc_int(caps, "format", &fourcc);
+                       switch (fourcc) {
+                               case GST_MAKE_FOURCC('I','4','2','0'):
+                               case GST_MAKE_FOURCC('I','Y','U','V'):
+                                       fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_YUV420);
+                                       break;
+                               case GST_MAKE_FOURCC('Y','U','Y','2'):
+                                       fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_YUYV);
+                                       break;
+                               case GST_MAKE_FOURCC('R','G','B',' '): {
+                                       gint depth, endianness;
+                                       gst_caps_get_int(caps, "depth", &depth);
+                                       gst_caps_get_int(caps, "endianness", &endianness);
+                                       if (depth == 8) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB332);
+                                       } else if (depth == 15 && endianness == G_LITTLE_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB555);
+                                       } else if (depth == 15 && endianness == G_BIG_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB555X);
+                                       } else if (depth == 16 && endianness == G_LITTLE_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB565);
+                                       } else if (depth == 16 && endianness == G_BIG_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB565X);
+                                       } else if (depth == 24 && endianness == G_LITTLE_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_BGR24);
+                                       } else if (depth == 24 && endianness == G_BIG_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB24);
+                                       } else if (depth == 32 && endianness == G_LITTLE_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_BGR32);
+                                       } else if (depth == 32 && endianness == G_BIG_ENDIAN) {
+                                               fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB32);
+                                       }
+                                       break; }
+                       }
+
+                       for (i=0;i<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);i++) {
+                               struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, i);
+                               if (fmt->pixelformat == fourcc)
+                                       fourcclist = g_list_append(fourcclist, (gpointer)fourcc);
+                       }
+               } else {
+                       /* compressed */
+                       gchar *format_us;
+                       gint i;
+                       if (strncmp(format, "video/", 6))
+                               continue;
+                       format = &format[6];
+                       if (strlen(format) != 4)
+                               continue;
+                       format_us = g_strdup(format);
+                       for (i=0;i<4;i++)
+                               format_us[i] = g_ascii_toupper(format_us[i]);
+                       fourcc = GST_MAKE_FOURCC(format_us[0],format_us[1],format_us[2],format_us[3]);
+                       switch (fourcc) {
+                               case GST_MAKE_FOURCC('J','P','E','G'):
+                                       fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_MJPEG);
+                                       break;
+                       }
+                       fourcclist = g_list_append(fourcclist, (gpointer)fourcc);
+               }
+       }
+
+       return fourcclist;
+}
+
+
+static GstCaps *
+gst_v4l2src_caps_intersect (GstCaps *caps1,
+                            GstCaps *_caps2)
+{
+       GstCaps *_list = NULL;
+
+       if (!_caps2)
+               return caps1;
+
+       for (;caps1!=NULL;caps1=caps1->next) {
+               GstCaps *caps2 = _caps2;
+
+               for (;caps2!=NULL;caps2=caps2->next) {
+                       if (!strcmp(gst_caps_get_mime(caps1), gst_caps_get_mime(caps2))) {
+                               if (!strcmp(gst_caps_get_mime(caps1), "video/raw")) {
+                                       guint32 fmt1, fmt2;
+                                       gst_caps_get_fourcc_int(caps1, "format", &fmt1);
+                                       gst_caps_get_fourcc_int(caps2, "format", &fmt2);
+                                       if (fmt1 == fmt2)
+                                               goto try_it_out;
+                               } else if (!strncmp(gst_caps_get_mime(caps1), "video/", 6)) {
+                                       goto try_it_out;
+                               }
+                               continue;
+                       }
+                       continue;
+
+               try_it_out:
+                       if (!strcmp(gst_caps_get_mime(caps1), "video/raw")) {
+                               GstCaps *list = _list;
+                               for (;list!=NULL;list=list->next) {
+                                       if (!strcmp(gst_caps_get_mime(list), gst_caps_get_mime(caps1))) {
+                                               guint32 fmt1, fmt2;
+                                               gst_caps_get_fourcc_int(caps1, "format", &fmt1);
+                                               gst_caps_get_fourcc_int(list, "format", &fmt2);
+                                               if (fmt1 == fmt2)
+                                                       break;
+                                       }
+                               }
+                               if (list == NULL)
+                                       goto add_it;
+                       } else {
+                               GstCaps *list = _list;
+                               for (;list!=NULL;list=list->next) {
+                                       if (!strcmp(gst_caps_get_mime(list), gst_caps_get_mime(caps1))) {
+                                                       break;
+                                       }
+                               }
+                               if (list == NULL)
+                                       goto add_it;
+                       }
+                       continue;
+
+               add_it:
+                       _list = gst_caps_append(_list, gst_caps_copy_1(caps1));
+                       break;
+               }
+       }
+
+       return _list;
+}
+
+
+static GstPadConnectReturn
+gst_v4l2src_srcconnect (GstPad  *pad,
+                        GstCaps *vscapslist)
+{
+       GstV4l2Src *v4l2src;
+       GstV4l2Element *v4l2element;
+       GstCaps *owncapslist;
+       GstCaps *caps;
+       GList *fourccs;
+       gint i;
+
+       v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
+       v4l2element = GST_V4L2ELEMENT(v4l2src);
+
+       /* clean up if we still haven't cleaned up our previous
+        * capture session */
+       if (GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src)))
+               if (!gst_v4l2src_capture_deinit(v4l2src))
+                       return GST_PAD_CONNECT_REFUSED;
+
+       /* build our own capslist */
+       if (v4l2src->palette) {
+               struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, v4l2src->palette);
+               owncapslist = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
+                                               v4l2src->width, v4l2src->height,
+                                               format->flags & V4L2_FMT_FLAG_COMPRESSED);
+       } else {
+               gint i;
+               owncapslist = NULL;
+               for (i=0;i<g_list_length(v4l2element->formats);i++) {
+                       struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, i);
+                       caps = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
+                                                       v4l2src->width, v4l2src->height,
+                                                       format->flags & V4L2_FMT_FLAG_COMPRESSED);
+                       owncapslist = gst_caps_append(owncapslist, caps);
+               }
+       }
+
+       /* and now, get the caps that we have in common */
+       if (!(caps = gst_v4l2src_caps_intersect(owncapslist, vscapslist)))
+               return GST_PAD_CONNECT_REFUSED;
+
+       /* and get them back to V4L2-compatible fourcc codes */
+       if (!(fourccs = gst_v4l2_caps_to_v4l2fourcc(v4l2src, caps)))
+               return GST_PAD_CONNECT_REFUSED;
+
+       /* we now have the fourcc codes. try out each of them */
+       for (i=0;i<g_list_length(fourccs);i++) {
+               guint32 fourcc = (guint32)g_list_nth_data(fourccs, i);
+               gint n;
+               for (n=0;n<g_list_length(v4l2element->formats);n++) {
+                       struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, n);
+                       if (format->pixelformat == fourcc) {
+                               /* we found the pixelformat! - try it out */
+                               if (gst_v4l2src_set_capture(v4l2src, format,
+                                           v4l2src->width, v4l2src->height)) {
+                                       /* it fits! Now, get the proper counterpart and retry
+                                        * it on the other side (again...) - if it works, we're
+                                        * done -> GST_PAD_CONNECT_OK */
+                                       GstCaps *lastcaps = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
+                                                               v4l2src->format.fmt.pix.width, v4l2src->format.fmt.pix.height,
+                                                               format->flags & V4L2_FMT_FLAG_COMPRESSED);
+                                       GstCaps *onecaps;
+                                       for (;lastcaps != NULL; lastcaps = lastcaps->next) {
+                                               onecaps = gst_caps_copy_1(lastcaps);
+                                               if (gst_pad_try_set_caps(v4l2src->srcpad, onecaps))
+                                                       if (gst_v4l2src_capture_init(v4l2src))
+                                                               return GST_PAD_CONNECT_OK;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return GST_PAD_CONNECT_REFUSED;
+}
+
+
+static GstBuffer*
+gst_v4l2src_get (GstPad *pad)
+{
+       GstV4l2Src *v4l2src;
+       GstBuffer *buf;
+       gint num;
+
+       g_return_val_if_fail (pad != NULL, NULL);
+
+       v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
+
+       buf = gst_buffer_new_from_pool(v4l2src->bufferpool, 0, 0);
+       if (!buf) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Failed to create a new GstBuffer");
+               return NULL;
+       }
+
+       /* grab a frame from the device */
+       if (!gst_v4l2src_grab_frame(v4l2src, &num))
+               return NULL;
+       GST_BUFFER_DATA(buf) = GST_V4L2ELEMENT(v4l2src)->buffer[num];
+       GST_BUFFER_SIZE(buf) = v4l2src->bufsettings.bytesused;
+       GST_BUFFER_MAXSIZE(buf) = v4l2src->bufsettings.length;
+       if (!v4l2src->first_timestamp)
+               v4l2src->first_timestamp = v4l2src->bufsettings.timestamp;
+       GST_BUFFER_TIMESTAMP(buf) = v4l2src->bufsettings.length - v4l2src->first_timestamp;
+
+       return buf;
+}
+
+
+static void
+gst_v4l2src_set_property (GObject      *object,
+                          guint        prop_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+       GstV4l2Src *v4l2src;
+
+       g_return_if_fail(GST_IS_V4L2SRC(object));
+       v4l2src = GST_V4L2SRC(object);
+
+       switch (prop_id) {
+               case ARG_WIDTH:
+                       if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
+                               v4l2src->width = g_value_get_int(value);
+                       }
+                       break;
+
+               case ARG_HEIGHT:
+                       if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
+                               v4l2src->height = g_value_get_int(value);
+                       }
+                       break;
+
+               case ARG_PALETTE:
+                       if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
+                               v4l2src->palette = g_value_get_int(value);
+                       }
+                       break;
+
+               case ARG_FOURCC:
+                       if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
+                               gint i;
+                               const gchar *formatstr = g_value_get_string(value);
+                               guint32 fourcc = GST_MAKE_FOURCC(formatstr[0],formatstr[1],formatstr[2],formatstr[3]);
+                               for (i=0;i<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);i++) {
+                                       struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, i);
+                                       if (fmt->pixelformat == fourcc)
+                                               v4l2src->palette = i;
+                               }
+                       }
+                       break;
+
+               case ARG_NUMBUFS:
+                       if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
+                               v4l2src->breq.count = g_value_get_int(value);
+                       }
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+
+static void
+gst_v4l2src_get_property (GObject    *object,
+                          guint      prop_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+       GstV4l2Src *v4l2src;
+
+       g_return_if_fail(GST_IS_V4L2SRC(object));
+       v4l2src = GST_V4L2SRC(object);
+
+       switch (prop_id) {
+               case ARG_WIDTH:
+                       g_value_set_int(value, v4l2src->width);
+                       break;
+
+               case ARG_HEIGHT:
+                       g_value_set_int(value, v4l2src->height);
+                       break;
+
+               case ARG_PALETTE:
+                       g_value_set_int(value, v4l2src->palette);
+                       break;
+
+               case ARG_PALETTE_NAMES:
+                       g_value_set_pointer(value, gst_v4l2src_get_format_list(v4l2src));
+                       break;
+
+               case ARG_FOURCC: {
+                       struct v4l2_fmtdesc *fmt = g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, v4l2src->palette);
+                       guint32 print_format = GUINT32_FROM_LE(fmt->pixelformat);
+                       gchar *print_format_str = (gchar *) &print_format;
+                       g_value_set_string(value, g_strndup(print_format_str, 4));
+                       break; }
+
+               case ARG_FOURCC_LIST:
+                       g_value_set_pointer(value, gst_v4l2src_get_fourcc_list(v4l2src));
+                       break;
+
+               case ARG_NUMBUFS:
+                       g_value_set_int(value, v4l2src->breq.count);
+                       break;
+
+               case ARG_BUFSIZE:
+                       g_value_set_int(value, v4l2src->format.fmt.pix.sizeimage);
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+
+static GstElementStateReturn
+gst_v4l2src_change_state (GstElement *element)
+{
+       GstV4l2Src *v4l2src;
+       gint transition = GST_STATE_TRANSITION (element);
+       GstElementStateReturn parent_return;
+
+       g_return_val_if_fail(GST_IS_V4L2SRC(element), GST_STATE_FAILURE);
+       v4l2src = GST_V4L2SRC(element);
+
+       if (GST_ELEMENT_CLASS (parent_class)->change_state) {
+               parent_return = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+               if (parent_return != GST_STATE_SUCCESS)
+                       return parent_return;
+       }
+
+       switch (transition) {
+               case GST_STATE_NULL_TO_READY:
+                       if (!gst_v4l2src_get_capture(v4l2src))
+                               return GST_STATE_FAILURE;
+                       break;
+               case GST_STATE_READY_TO_PAUSED:
+                       v4l2src->first_timestamp = 0;
+                       /* buffer setup moved to capsnego */
+                       break;
+               case GST_STATE_PAUSED_TO_PLAYING:
+                       /* queue all buffer, start streaming capture */
+                       if (!gst_v4l2src_capture_start(v4l2src))
+                               return GST_STATE_FAILURE;
+                       break;
+               case GST_STATE_PLAYING_TO_PAUSED:
+                       /* de-queue all queued buffers */
+                       if (!gst_v4l2src_capture_stop(v4l2src))
+                               return GST_STATE_FAILURE;
+                       break;
+               case GST_STATE_PAUSED_TO_READY:
+                       /* stop capturing, unmap all buffers */
+                       if (!gst_v4l2src_capture_deinit(v4l2src))
+                               return GST_STATE_FAILURE;
+                       break;
+               case GST_STATE_READY_TO_NULL:
+                       break;
+       }
+
+       return GST_STATE_SUCCESS;
+}
+
+
+static GstBuffer*
+gst_v4l2src_buffer_new (GstBufferPool *pool,
+                        guint64        offset,
+                        guint          size,
+                        gpointer       user_data)
+{
+       GstBuffer *buffer;
+
+       buffer = gst_buffer_new();
+       if (!buffer) return NULL;
+       /* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
+
+       return buffer;
+}
+
+
+static GstBuffer*
+gst_v4l2src_buffer_copy (GstBufferPool   *pool,
+                         const GstBuffer *srcbuf,
+                         gpointer         user_data)
+{
+       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_MAXSIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
+       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_v4l2src_buffer_free (GstBufferPool *pool,
+                         GstBuffer     *buf,
+                         gpointer      user_data)
+{
+       GstV4l2Src *v4l2src = GST_V4L2SRC(user_data);
+       int n;
+
+       for (n=0;n<v4l2src->breq.count;n++)
+               if (GST_BUFFER_DATA(buf) == GST_V4L2ELEMENT(v4l2src)->buffer[n]) {
+                       gst_v4l2src_requeue_frame(v4l2src, n);
+                       return;
+               }
+
+       gst_element_error(GST_ELEMENT(v4l2src),
+               "Couldn\'t find the buffer");
+}
+
+
+static gboolean
+plugin_init (GModule   *module,
+             GstPlugin *plugin)
+{
+       GstElementFactory *factory;
+
+       /* create an elementfactory for the v4l2src */
+       factory = gst_element_factory_new("v4l2src", GST_TYPE_V4L2SRC,
+                               &gst_v4l2src_details);
+       g_return_val_if_fail(factory != NULL, FALSE);
+
+       src_template = gst_pad_template_new("src",
+                               GST_PAD_SRC,
+                               GST_PAD_ALWAYS,
+                               NULL);
+
+       gst_element_factory_add_pad_template(factory, src_template);
+
+       gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE(factory));
+
+       return TRUE;
+}
+
+
+GstPluginDesc plugin_desc = {
+       GST_VERSION_MAJOR,
+       GST_VERSION_MINOR,
+       "v4l2src",
+       plugin_init
+};
diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h
new file mode 100644 (file)
index 0000000..004347a
--- /dev/null
@@ -0,0 +1,69 @@
+/* G-Streamer Video4linux2 video-capture plugin
+ * Copyright (C) 2002 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_V4L2SRC_H__
+#define __GST_V4L2SRC_H__
+
+#include <gstv4l2element.h>
+
+
+#define GST_TYPE_V4L2SRC \
+               (gst_v4l2src_get_type())
+#define GST_V4L2SRC(obj) \
+               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2SRC,GstV4l2Src))
+#define GST_V4L2SRC_CLASS(klass) \
+               (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2SRC,GstV4l2SrcClass))
+#define GST_IS_V4L2SRC(obj) \
+               (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2SRC))
+#define GST_IS_V4L2SRC_CLASS(obj) \
+               (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2SRC))
+
+
+typedef        struct _GstV4l2Src      GstV4l2Src;
+typedef        struct _GstV4l2SrcClass GstV4l2SrcClass;
+
+struct _GstV4l2Src {
+       GstV4l2Element v4l2element;
+
+       /* pads */
+       GstPad *srcpad;
+
+       /* buffer properties */
+       struct v4l2_buffer bufsettings;
+       struct v4l2_requestbuffers breq;
+       struct v4l2_format format;
+       stamp_t first_timestamp;
+
+       /* bufferpool for the buffers we're gonna use */
+       GstBufferPool *bufferpool;
+
+       /* caching values */
+       gint width;
+       gint height;
+       gint palette;
+};
+
+struct _GstV4l2SrcClass {
+       GstV4l2ElementClass parent_class;
+};
+
+
+GType gst_v4l2src_get_type(void);
+
+#endif /* __GST_V4L2SRC_H__ */
diff --git a/sys/v4l2/v4l2-overlay_calls.c b/sys/v4l2/v4l2-overlay_calls.c
new file mode 100644 (file)
index 0000000..89cae62
--- /dev/null
@@ -0,0 +1,168 @@
+/* G-Streamer generic V4L2 element - generic V4L2 overlay handling
+ * Copyright (C) 2002 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#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 "v4l2_calls.h"
+
+#define DEBUG(format, args...) \
+       GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
+               GST_ELEMENT(v4l2element), \
+               "V4L2-overlay: " format "\n", ##args)
+
+
+/******************************************************
+ * gst_v4l2_set_display():
+ *   calls v4l-conf
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_display (GstV4l2Element *v4l2element,
+                      const gchar    *display)
+{
+       gchar *buff;
+
+       DEBUG("trying to set overlay to '%s'", display);
+
+       /* start v4l-conf */
+       buff = g_strdup_printf("v4l-conf -q -c %s -d %s",
+               v4l2element->device?v4l2element->device:"/dev/video", display);
+
+       switch (system(buff)) {
+               case -1:
+                       gst_element_error(GST_ELEMENT(v4l2element),
+                               "Could not start v4l-conf: %s", sys_errlist[errno]);
+                       g_free(buff);
+                       return FALSE;
+               case 0:
+                       break;
+               default:
+                       gst_element_error(GST_ELEMENT(v4l2element),
+                               "v4l-conf failed to run correctly: %s", sys_errlist[errno]);
+                       g_free(buff);
+                       return FALSE;
+       }
+
+       g_free(buff);
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_set_vwin():
+ *   does the VIDIOC_S_WIN ioctl()
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4l2_set_vwin (GstV4l2Element *v4l2element)
+{
+       if (ioctl(v4l2element->video_fd, VIDIOC_S_WIN, &(v4l2element->vwin)) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set the video window on device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_set_window():
+ *   sets the window where to display the video overlay
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_window (GstV4l2Element *v4l2element,
+                     gint x,         gint y,
+                     gint w,         gint h)
+{
+       DEBUG("trying to set video window to %dx%d,%d,%d", x,y,w,h);
+       GST_V4L2_CHECK_OVERLAY(v4l2element);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       v4l2element->vwin.clipcount = 0;
+       v4l2element->vwin.x = x;
+       v4l2element->vwin.y = y;
+       v4l2element->vwin.width = w;
+       v4l2element->vwin.height = h;
+
+       return gst_v4l2_set_vwin(v4l2element);
+}
+
+
+/******************************************************
+ * gst_v4l_set_clips():
+ *   sets video overlay clips
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_clips (GstV4l2Element     *v4l2element,
+                    struct v4l2_clip   *clips,
+                    gint                num_clips)
+{
+       DEBUG("trying to set video clipping information");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_OVERLAY(v4l2element);
+
+       v4l2element->vwin.clips = clips;
+       v4l2element->vwin.clipcount = num_clips;
+
+       return gst_v4l2_set_vwin(v4l2element);
+}
+
+
+/******************************************************
+ * gst_v4l_set_overlay():
+ *   enables/disables actual video overlay display
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_enable_overlay (GstV4l2Element *v4l2element,
+                         gboolean        enable)
+{
+       gint doit = enable?1:0;
+
+       DEBUG("trying to %s overlay display", enable?"enable":"disable");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_OVERLAY(v4l2element);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_PREVIEW, &doit) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to %s overlay display for device %s: %s",
+                       enable?"enable":"disable", v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c
new file mode 100644 (file)
index 0000000..c24d0e4
--- /dev/null
@@ -0,0 +1,863 @@
+/* G-Streamer generic V4L2 element - generic V4L2 calls handling
+ * Copyright (C) 2002 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#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 "v4l2_calls.h"
+
+#define DEBUG(format, args...) \
+       GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
+               GST_ELEMENT(v4l2element), \
+               "V4L2: " format "\n", ##args)
+
+
+/******************************************************
+ * gst_v4l2_get_capabilities():
+ *   get the device's capturing capabilities
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
+{
+       DEBUG("getting capabilities");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Error getting %s capabilities: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
+ *   fill/empty the lists of enumerations
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4l2_fill_lists (GstV4l2Element *v4l2element)
+{
+       gint n;
+
+       DEBUG("getting enumerations");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       /* create enumeration lists - let's start with format enumeration */
+       for (n=0;;n++) {
+               struct v4l2_fmtdesc format, *fmtptr;
+               format.index = n;
+               if (ioctl(v4l2element->video_fd, VIDIOC_ENUM_PIXFMT, &format) < 0) {
+                       if (errno == EINVAL)
+                               break; /* end of enumeration */
+                       else {
+                               gst_element_error(GST_ELEMENT(v4l2element),
+                                       "Failed to get no. %d in pixelformat enumeration for %s: %s",
+                                       n, v4l2element->device, sys_errlist[errno]);
+                               return FALSE;
+                       }
+               }
+               fmtptr = g_malloc(sizeof(format));
+               memcpy(fmtptr, &format, sizeof(format));
+               v4l2element->formats = g_list_append(v4l2element->formats, fmtptr);
+       }
+
+       /* and now, the inputs */
+       for (n=0;;n++) {
+               struct v4l2_input input, *inpptr;
+               input.index = n;
+               if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
+                       if (errno == EINVAL)
+                               break; /* end of enumeration */
+                       else {
+                               gst_element_error(GST_ELEMENT(v4l2element),
+                                       "Failed to get no. %d in input enumeration for %s: %s",
+                                       n, v4l2element->device, sys_errlist[errno]);
+                               return FALSE;
+                       }
+               }
+               inpptr = g_malloc(sizeof(input));
+               memcpy(inpptr, &input, sizeof(input));
+               v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr);
+       }
+
+       /* outputs */
+       for (n=0;;n++) {
+               struct v4l2_output output, *outptr;
+               output.index = n;
+               if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
+                       if (errno == EINVAL)
+                               break; /* end of enumeration */
+                       else {
+                               gst_element_error(GST_ELEMENT(v4l2element),
+                                       "Failed to get no. %d in output enumeration for %s: %s",
+                                       n, v4l2element->device, sys_errlist[errno]);
+                               return FALSE;
+                       }
+               }
+               outptr = g_malloc(sizeof(output));
+               memcpy(outptr, &output, sizeof(output));
+               v4l2element->outputs = g_list_append(v4l2element->outputs, outptr);
+       }
+
+       /* norms... */
+       for (n=0;;n++) {
+               struct v4l2_enumstd standard, *stdptr;
+               standard.index = n;
+               if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
+                       if (errno == EINVAL)
+                               break; /* end of enumeration */
+                       else {
+                               gst_element_error(GST_ELEMENT(v4l2element),
+                                       "Failed to get no. %d in norm enumeration for %s: %s",
+                                       n, v4l2element->device, sys_errlist[errno]);
+                               return FALSE;
+                       }
+               }
+               stdptr = g_malloc(sizeof(standard));
+               memcpy(stdptr, &standard, sizeof(standard));
+               v4l2element->norms = g_list_append(v4l2element->norms, stdptr);
+       }
+
+       /* and lastly, controls+menus (if appropriate) */
+       for (n=0;;n++) {
+               struct v4l2_queryctrl control, *ctrlptr;
+               GList *menus = NULL;
+               control.id = n;
+               if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
+                       if (errno == EINVAL)
+                               break; /* end of enumeration */
+                       else {
+                               gst_element_error(GST_ELEMENT(v4l2element),
+                                       "Failed to get no. %d in control enumeration for %s: %s",
+                                       n, v4l2element->device, sys_errlist[errno]);
+                               return FALSE;
+                       }
+               }
+               ctrlptr = g_malloc(sizeof(control));
+               memcpy(ctrlptr, &control, sizeof(control));
+               v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr);
+               if (control.type == V4L2_CTRL_TYPE_MENU) {
+                       struct v4l2_querymenu menu, *mptr;
+                       int i;
+                       menu.id = n;
+                       for (i=0;;i++) {
+                               menu.index = i;
+                               if (ioctl(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
+                                       if (errno == EINVAL)
+                                               break; /* end of enumeration */
+                                       else {
+                                               gst_element_error(GST_ELEMENT(v4l2element),
+                                                       "Failed to get no. %d in menu %d enumeration for %s: %s",
+                                                       i, n, v4l2element->device, sys_errlist[errno]);
+                                               return FALSE;
+                                       }
+                               }
+                               mptr = g_malloc(sizeof(menu));
+                               memcpy(mptr, &menu, sizeof(menu));
+                               menus = g_list_append(menus, mptr);
+                       }
+               }
+               v4l2element->menus = g_list_append(v4l2element->menus, menus);
+       }
+
+       return TRUE;
+}
+
+
+static void
+gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
+{
+       DEBUG("deleting enumerations");
+
+       /* empty lists */
+       while (g_list_length(v4l2element->inputs) > 0) {
+               gpointer data = g_list_nth_data(v4l2element->inputs, 0);
+               v4l2element->inputs = g_list_remove(v4l2element->inputs, data);
+               g_free(data);
+       }
+       while (g_list_length(v4l2element->outputs) > 0) {
+               gpointer data = g_list_nth_data(v4l2element->outputs, 0);
+               v4l2element->outputs = g_list_remove(v4l2element->outputs, data);
+               g_free(data);
+       }
+       while (g_list_length(v4l2element->norms) > 0) {
+               gpointer data = g_list_nth_data(v4l2element->norms, 0);
+               v4l2element->norms = g_list_remove(v4l2element->norms, data);
+               g_free(data);
+       }
+       while (g_list_length(v4l2element->formats) > 0) {
+               gpointer data = g_list_nth_data(v4l2element->formats, 0);
+               v4l2element->formats = g_list_remove(v4l2element->formats, data);
+               g_free(data);
+       }
+       while (g_list_length(v4l2element->controls) > 0) {
+               gpointer data = g_list_nth_data(v4l2element->controls, 0);
+               v4l2element->controls = g_list_remove(v4l2element->controls, data);
+               g_free(data);
+       }
+       v4l2element->menus = g_list_remove_all(v4l2element->menus, NULL);
+       while (g_list_length(v4l2element->menus) > 0) {
+               GList *items = (GList *) g_list_nth_data(v4l2element->menus, 0);
+               v4l2element->inputs = g_list_remove(v4l2element->inputs, items);
+               while (g_list_length(items) > 0) {
+                       gpointer data = g_list_nth_data(v4l2element->menus, 0);
+                       items = g_list_remove(items, data);
+                       g_free(data);
+               }
+       }
+}
+
+
+/******************************************************
+ * gst_v4l2_open():
+ *   open the video device (v4l2element->device)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_open (GstV4l2Element *v4l2element)
+{
+       DEBUG("Trying to open device %s", v4l2element->device);
+       GST_V4L2_CHECK_NOT_OPEN(v4l2element);
+       GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+
+       /* be sure we have a device */
+       if (!v4l2element->device)
+               v4l2element->device = g_strdup("/dev/video");
+
+       /* open the device */
+       v4l2element->video_fd = open(v4l2element->device, O_RDWR);
+       if (!GST_V4L2_IS_OPEN(v4l2element)) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to open device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               goto error;
+       }
+
+       /* get capabilities */
+       if (!gst_v4l2_get_capabilities(v4l2element)) {
+               goto error;
+       }
+
+       /* and get the video window */
+       if (GST_V4L2_IS_OVERLAY(v4l2element)) {
+               if (ioctl(v4l2element->video_fd, VIDIOC_G_WIN, &(v4l2element->vwin)) < 0) {
+                       gst_element_error(GST_ELEMENT(v4l2element),
+                               "Failed to get video window properties of %s: %s",
+                               v4l2element->device, sys_errlist[errno]);
+                       goto error;
+               }
+       }
+
+       /* create enumerations */
+       if (!gst_v4l2_fill_lists(v4l2element))
+               goto error;
+
+       gst_info("Opened device '%s' (%s) successfully\n",
+               v4l2element->vcap.name, v4l2element->device);
+
+       return TRUE;
+
+error:
+       if (GST_V4L2_IS_OPEN(v4l2element)) {
+               /* close device */
+               close(v4l2element->video_fd);
+               v4l2element->video_fd = -1;
+       }
+       /* empty lists */
+       gst_v4l2_empty_lists(v4l2element);
+
+       return FALSE;
+}
+
+
+/******************************************************
+ * gst_v4l2_close():
+ *   close the video device (v4l2element->video_fd)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_close (GstV4l2Element *v4l2element)
+{
+       DEBUG("Trying to close %s", v4l2element->device);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+
+       /* close device */
+       close(v4l2element->video_fd);
+       v4l2element->video_fd = -1;
+
+       /* empty lists */
+       gst_v4l2_empty_lists(v4l2element);
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_norm()
+ *   Get the norm of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_get_norm (GstV4l2Element *v4l2element,
+                   gint           *norm)
+{
+       struct v4l2_standard standard;
+       gint n;
+
+       DEBUG("getting norm");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &standard) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to get the current norm for device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       /* try to find out what norm number this actually is */
+       for (n=0;n<g_list_length(v4l2element->norms);n++) {
+               struct v4l2_enumstd *stdptr = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
+               if (!strcmp(stdptr->std.name, standard.name)) {
+                       *norm = n;
+                       return TRUE;
+               }
+       }
+
+       gst_element_error(GST_ELEMENT(v4l2element),
+               "Failed to find norm '%s' in our list of available norms for device %s",
+               standard.name, v4l2element->device);
+       return FALSE;
+}
+
+
+/******************************************************
+ * gst_v4l2_set_norm()
+ *   Set the norm of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_norm (GstV4l2Element *v4l2element,
+                   gint            norm)
+{
+       struct v4l2_enumstd *standard;
+
+       DEBUG("trying to set norm to %d", norm);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+
+       if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Invalid norm number %d (%d-%d)",
+                       norm, 0, g_list_length(v4l2element->norms));
+               return FALSE;
+       }
+
+       standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->std) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set norm '%s' (%d) for device %s: %s",
+                       standard->std.name, norm, v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_norm_names()
+ *   Get the list of available norms
+ * return value: the list
+ ******************************************************/
+
+GList *
+gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
+{
+       GList *names = NULL;
+       gint n;
+
+       DEBUG("getting a list of norm names");
+
+       for (n=0;n<g_list_length(v4l2element->norms);n++) {
+               struct v4l2_enumstd *standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
+               names = g_list_append(names, g_strdup(standard->std.name));
+       }
+
+       return names;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_input()
+ *   Get the input of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_get_input (GstV4l2Element *v4l2element,
+                    gint           *input)
+{
+       gint n;
+
+       DEBUG("trying to get input");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to get current input on device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       *input = n;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_set_input()
+ *   Set the input of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_input (GstV4l2Element *v4l2element,
+                    gint            input)
+{
+       DEBUG("trying to set input to %d", input);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+
+       if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Invalid input number %d (%d-%d)",
+                       input, 0, g_list_length(v4l2element->inputs));
+               return FALSE;
+       }
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set input %d on device %s: %s",
+                       input, v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_input_names()
+ *   Get the list of available input channels
+ * return value: the list
+ ******************************************************/
+
+GList *
+gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
+{
+       GList *names = NULL;
+       gint n;
+
+       DEBUG("getting a list of input names");
+
+       for (n=0;n<g_list_length(v4l2element->inputs);n++) {
+               struct v4l2_input *input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, n);
+               names = g_list_append(names, g_strdup(input->name));
+       }
+
+       return names;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_output()
+ *   Get the output of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_get_output (GstV4l2Element *v4l2element,
+                     gint           *output)
+{
+       gint n;
+
+       DEBUG("trying to get output");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to get current output on device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       *output = n;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_set_output()
+ *   Set the output of the current device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_output (GstV4l2Element *v4l2element,
+                     gint            output)
+{
+       DEBUG("trying to set output to %d", output);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+
+       if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Invalid output number %d (%d-%d)",
+                       output, 0, g_list_length(v4l2element->outputs));
+               return FALSE;
+       }
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set output %d on device %s: %s",
+                       output, v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2_get_output_names()
+ *   Get the list of available output channels
+ * return value: the list, or NULL on error
+ ******************************************************/
+
+GList *
+gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
+{
+       GList *names = NULL;
+       gint n;
+
+       DEBUG("getting a list of output names");
+
+       for (n=0;n<g_list_length(v4l2element->outputs);n++) {
+               struct v4l2_output *output = (struct v4l2_output *) g_list_nth_data(v4l2element->outputs, n);
+               names = g_list_append(names, g_strdup(output->name));
+       }
+
+       return names;
+}
+
+
+/******************************************************
+ * gst_v4l_has_tuner():
+ *   Check whether the device has a tuner
+ * return value: TRUE if it has a tuner, else FALSE
+ ******************************************************/
+
+gboolean
+gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
+{
+       gint input_num;
+       struct v4l2_input *input;
+
+       DEBUG("detecting whether device has a tuner");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (!gst_v4l2_get_input(v4l2element, &input_num))
+               return FALSE;
+
+       input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
+
+       return (input->type == V4L2_INPUT_TYPE_TUNER &&
+               v4l2element->vcap.flags & V4L2_FLAG_TUNER);
+}
+
+
+/******************************************************
+ * gst_v4l_get_frequency():
+ *   get the current frequency
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
+                        gulong         *frequency)
+{
+       gint n;
+
+       DEBUG("getting current tuner frequency");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (!gst_v4l2_has_tuner(v4l2element))
+               return FALSE;
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to get current tuner frequency for device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       *frequency = n;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_set_frequency():
+ *   set frequency
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
+                        gulong          frequency)
+{
+       gint n = frequency;
+
+       DEBUG("setting current tuner frequency to %lu", frequency);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+       GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
+
+       if (!gst_v4l2_has_tuner(v4l2element))
+               return FALSE;
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set tuner frequency to %lu for device %s: %s",
+                       frequency, v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_signal_strength():
+ *   get the strength of the signal on the current input
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
+                          gulong         *signal_strength)
+{
+       struct v4l2_tuner tuner;
+
+       DEBUG("trying to get signal strength");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set signal strength for device %s: %s",
+                       v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       *signal_strength = tuner.signal;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_has_audio():
+ *   Check whether the device has audio capabilities
+ * return value: TRUE if it has a tuner, else FALSE
+ ******************************************************/
+
+gboolean
+gst_v4l2_has_audio (GstV4l2Element *v4l2element)
+{
+       gint input_num;
+       struct v4l2_input *input;
+
+       DEBUG("detecting whether device has audio");
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (!gst_v4l2_get_input(v4l2element, &input_num))
+               return FALSE;
+
+       input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
+
+       return (input->capability & V4L2_INPUT_CAP_AUDIO);
+}
+
+
+/******************************************************
+ * gst_v4l_get_attributes():
+ *   get a list of attributes available on this device
+ * return value: the list
+ ******************************************************/
+
+GList *
+gst_v4l2_get_attributes        (GstV4l2Element *v4l2element)
+{
+       gint i;
+       GList *list = NULL;
+
+       DEBUG("getting a list of available attributes");
+
+       for (i=0;i<g_list_length(v4l2element->controls);i++) {
+               struct v4l2_queryctrl *control = (struct v4l2_queryctrl *) g_list_nth_data(v4l2element->controls, i);
+               GstV4l2Attribute* attribute = g_malloc(sizeof(GstV4l2Attribute));
+               attribute->name = g_strdup(control->name);
+               attribute->index = i;
+               attribute->list_items = NULL;
+               switch (control->type) {
+                       case V4L2_CTRL_TYPE_INTEGER:
+                               attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT;
+                               break;
+                       case V4L2_CTRL_TYPE_BOOLEAN:
+                               attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
+                               break;
+                       case V4L2_CTRL_TYPE_MENU: {
+                               /* list items */
+                               gint n;
+                               GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
+                               for (n=0;n<g_list_length(menus);n++) {
+                                       struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
+                                       attribute->list_items = g_list_append(attribute->list_items, g_strdup(menu->name));
+                               }
+                               attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
+                               break; }
+                       case V4L2_CTRL_TYPE_BUTTON:
+                               attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
+                               break;
+               }
+               switch (control->category) {
+                       case V4L2_CTRL_CAT_VIDEO:
+                               attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
+                               break;
+                       case V4L2_CTRL_CAT_AUDIO:
+                               attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
+                               break;
+                       case V4L2_CTRL_CAT_EFFECT:
+                               attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
+                               break;
+               }
+               gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
+               attribute->min = control->minimum;
+               attribute->max = control->maximum;
+       }
+
+       return list;
+}
+
+
+/******************************************************
+ * gst_v4l_get_attribute():
+ *   try to get the value of one specific attribute
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
+                         gint            attribute_num,
+                         gint           *value)
+{
+       struct v4l2_control control;
+
+       DEBUG("getting value of attribute %d", attribute_num);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Invalid control ID %d", attribute_num);
+               return FALSE;
+       }
+
+       control.id = attribute_num;
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to get value for control %d on device %s: %s",
+                       attribute_num, v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       *value = control.value;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l_set_attribute():
+ *   try to set the value of one specific attribute
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
+                         gint            attribute_num,
+                         gint            value)
+{
+       struct v4l2_control control;
+
+       DEBUG("setting value of attribute %d to %d", attribute_num, value);
+       GST_V4L2_CHECK_OPEN(v4l2element);
+
+       if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Invalid control ID %d", attribute_num);
+               return FALSE;
+       }
+
+       control.id = attribute_num;
+       control.value = value;
+
+       if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2element),
+                       "Failed to set value %d for control %d on device %s: %s",
+                       value, attribute_num, v4l2element->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+    
diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h
new file mode 100644 (file)
index 0000000..ce562d4
--- /dev/null
@@ -0,0 +1,135 @@
+/* G-Streamer generic V4L2 element - generic V4L2 calls handling
+ * Copyright (C) 2002 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 __V4L2_CALLS_H__
+#define __V4L2_CALLS_H__
+
+#include "gstv4l2element.h"
+
+
+/* simple check whether the device is open */
+#define GST_V4L2_IS_OPEN(v4l2element) \
+  (v4l2element->video_fd > 0)
+
+/* check whether the device is 'active' */
+#define GST_V4L2_IS_ACTIVE(v4l2element) \
+  (v4l2element->buffer != NULL)
+
+#define GST_V4L2_IS_OVERLAY(v4l2element) \
+  (v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)
+
+/* checks whether the current v4lelement has already been open()'ed or not */
+#define GST_V4L2_CHECK_OPEN(v4l2element) \
+  if (v4l2element->video_fd <= 0)               \
+  {                                             \
+    gst_element_error(GST_ELEMENT(v4l2element), \
+      "Device is not open");                    \
+    return FALSE;                               \
+  }
+
+/* checks whether the current v4lelement is close()'ed or whether it is still open */
+#define GST_V4L2_CHECK_NOT_OPEN(v4l2element) \
+  if (v4l2element->video_fd != -1)              \
+  {                                             \
+    gst_element_error(GST_ELEMENT(v4l2element), \
+      "Device is open");                        \
+    return FALSE;                               \
+  }
+
+/* checks whether the current v4lelement does video overlay */
+#define GST_V4L2_CHECK_OVERLAY(v4l2element) \
+  if (!(v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)) \
+  {                                                   \
+    gst_element_error(GST_ELEMENT(v4l2element),       \
+      "Device doesn't do overlay");                   \
+    return FALSE;                                     \
+  }
+
+/* checks whether we're in capture mode or not */
+#define GST_V4L2_CHECK_ACTIVE(v4l2element) \
+  if (v4l2element->buffer == NULL)              \
+  {                                             \
+    gst_element_error(GST_ELEMENT(v4l2element), \
+      "Device is not in streaming mode");       \
+    return FALSE;                               \
+  }
+
+/* checks whether we're out of capture mode or not */
+#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2element) \
+  if (v4l2element->buffer != NULL)              \
+  {                                             \
+    gst_element_error(GST_ELEMENT(v4l2element), \
+      "Device is in streaming mode");           \
+    return FALSE;                               \
+  }
+
+
+/* open/close the device */
+gboolean       gst_v4l2_open                   (GstV4l2Element *v4l2element);
+gboolean       gst_v4l2_close                  (GstV4l2Element *v4l2element);
+
+/* norm/input/output */
+gboolean       gst_v4l2_get_norm               (GstV4l2Element *v4l2element,
+                                                gint           *norm);
+gboolean       gst_v4l2_set_norm               (GstV4l2Element *v4l2element,
+                                                gint            norm);
+GList *                gst_v4l2_get_norm_names         (GstV4l2Element *v4l2element);
+gboolean       gst_v4l2_get_input              (GstV4l2Element *v4l2element,
+                                                gint           *input);
+gboolean       gst_v4l2_set_input              (GstV4l2Element *v4l2element,
+                                                gint            input);
+GList *                gst_v4l2_get_input_names        (GstV4l2Element *v4l2element);
+gboolean       gst_v4l2_get_output             (GstV4l2Element *v4l2element,
+                                                gint           *output);
+gboolean       gst_v4l2_set_output             (GstV4l2Element *v4l2element,
+                                                gint            output);
+GList *                gst_v4l2_get_output_names       (GstV4l2Element *v4l2element);
+
+/* frequency control */
+gboolean       gst_v4l2_has_tuner              (GstV4l2Element *v4l2element);
+gboolean       gst_v4l2_get_frequency          (GstV4l2Element *v4l2element,
+                                                gulong         *frequency);
+gboolean       gst_v4l2_set_frequency          (GstV4l2Element *v4l2element,
+                                               gulong          frequency);
+gboolean       gst_v4l2_signal_strength        (GstV4l2Element *v4l2element,
+                                                gulong         *signal_strength);
+
+/* attribute control */
+gboolean       gst_v4l2_has_audio              (GstV4l2Element *v4l2element);
+GList *                gst_v4l2_get_attributes         (GstV4l2Element *v4l2element);
+gboolean       gst_v4l2_get_attribute          (GstV4l2Element *v4l2element,
+                                                gint            attribute_num,
+                                                gint           *value);
+gboolean       gst_v4l2_set_attribute          (GstV4l2Element *v4l2element,
+                                                gint            attribute_num,
+                                                gint            value);
+
+/* overlay */
+gboolean       gst_v4l2_set_display            (GstV4l2Element *v4l2element,
+                                                const gchar    *display);
+gboolean       gst_v4l2_set_window             (GstV4l2Element *v4l2element,
+                                                gint x,         gint y,
+                                                gint w,         gint h);
+gboolean       gst_v4l2_set_clips              (GstV4l2Element *v4l2element,
+                                                struct v4l2_clip *clips,
+                                                gint            num_clips);
+gboolean       gst_v4l2_enable_overlay         (GstV4l2Element *v4l2element,
+                                                gboolean        enable);
+
+#endif /* __V4L2_CALLS_H__ */
diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c
new file mode 100644 (file)
index 0000000..5dcff33
--- /dev/null
@@ -0,0 +1,397 @@
+/* G-Streamer Video4linux2 video-capture plugin - system calls
+ * Copyright (C) 2002 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 <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 "v4l2src_calls.h"
+#include <sys/time.h>
+
+#define DEBUG(format, args...) \
+       GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
+               GST_ELEMENT(v4l2src), \
+               "V4L2SRC: " format "\n", ##args)
+
+#define MIN_BUFFERS_QUEUED 2
+
+/* On some systems MAP_FAILED seems to be missing */
+#ifndef MAP_FAILED
+#define MAP_FAILED ( (caddr_t) -1 )
+#endif
+
+
+/******************************************************
+ * gst_v4l2src_queue_frame():
+ *   queue a frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4l2src_queue_frame (GstV4l2Src *v4l2src,
+                         gint        num)
+{
+       DEBUG("queueing frame %d", num);
+
+       v4l2src->bufsettings.index = num;
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_QBUF, &v4l2src->bufsettings) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Error queueing buffer %d on device %s: %s",
+                       num, GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4lsrc_sync_frame():
+ *   sync on a frame for capturing
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+static gboolean
+gst_v4l2src_sync_next_frame (GstV4l2Src *v4l2src,
+                             gint       *num)
+{
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_DQBUF, &v4l2src->bufsettings) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Error syncing on a buffer on device %s: %s",
+                       GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+       DEBUG("synced on frame %d", v4l2src->bufsettings.index);
+       *num = v4l2src->bufsettings.index;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_get_capture():
+ *   get capture parameters
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_get_capture (GstV4l2Src *v4l2src)
+{
+       DEBUG("Getting capture format");
+
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Failed to get pixel format for device %s: %s",
+                       GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_set_capture():
+ *   set capture parameters
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_set_capture (GstV4l2Src          *v4l2src,
+                         struct v4l2_fmtdesc *fmt,
+                         gint                 width,
+                         gint                 height)
+{
+       DEBUG("Setting capture format to %dx%d, format %s",
+               width, height, fmt->description);
+
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_NOT_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       memset(&v4l2src->format, 0, sizeof(struct v4l2_format));
+       v4l2src->format.fmt.pix.width = width;
+       v4l2src->format.fmt.pix.height = height;
+       v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
+       if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
+               v4l2src->format.fmt.pix.flags = V4L2_FMT_FLAG_COMPRESSED;
+               v4l2src->format.type = V4L2_BUF_TYPE_CODECIN;
+       } else {
+               v4l2src->format.type = V4L2_BUF_TYPE_CAPTURE;
+       }
+
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Failed to set pixel format to %s @ %dx%d for device %s: %s",
+                       fmt->description, width, height,
+                       GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_capture_init():
+ *   initialize the capture system
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_capture_init (GstV4l2Src *v4l2src)
+{
+       gint n;
+       gchar *desc = NULL;
+
+       DEBUG("initting the capture system");
+
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_NOT_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       /* request buffer info */
+       if (v4l2src->breq.count < MIN_BUFFERS_QUEUED)
+               v4l2src->breq.count = MIN_BUFFERS_QUEUED;
+       v4l2src->breq.type = v4l2src->format.type;
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_REQBUFS, &v4l2src->breq) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Error requesting buffers (%d) for %s: %s",
+                       v4l2src->breq.count, GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       if (v4l2src->breq.count < MIN_BUFFERS_QUEUED) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Too little buffers. We got %d, we want at least %d",
+                       v4l2src->breq.count, MIN_BUFFERS_QUEUED);
+               return FALSE;
+       }
+       v4l2src->bufsettings.type = v4l2src->format.type;
+
+       for (n=0;n<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);n++) {
+               struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, n);
+               if (v4l2src->format.fmt.pix.pixelformat == fmt->pixelformat) {
+                       desc = fmt->description;
+                       break;
+               }
+       }
+       gst_info("Got %d buffers (%s) of size %d KB\n",
+               v4l2src->breq.count, desc, v4l2src->format.fmt.pix.sizeimage/1024);
+
+       /* Map the buffers */
+       GST_V4L2ELEMENT(v4l2src)->buffer = (guint8 **) g_malloc(sizeof(guint8*) * v4l2src->breq.count);
+       for (n=0;n<v4l2src->breq.count;n++) {
+               GST_V4L2ELEMENT(v4l2src)->buffer[n] = mmap(0, v4l2src->format.fmt.pix.sizeimage, 
+                       PROT_READ|PROT_WRITE, MAP_SHARED, GST_V4L2ELEMENT(v4l2src)->video_fd, v4l2src->format.fmt.pix.sizeimage*n);
+               if (GST_V4L2ELEMENT(v4l2src)->buffer[n] == MAP_FAILED) {
+                       gst_element_error(GST_ELEMENT(v4l2src),
+                               "Error mapping video buffer %d on device %s: %s",
+                               n, GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+                       GST_V4L2ELEMENT(v4l2src)->buffer[n] = NULL;
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_capture_start():
+ *   start streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_capture_start (GstV4l2Src *v4l2src)
+{
+       gint n;
+
+       DEBUG("starting the capturing");
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       /* queue all buffers, this starts streaming capture */
+       for (n=0;n<v4l2src->breq.count;n++)
+               if (!gst_v4l2src_queue_frame(v4l2src, n))
+                       return FALSE;
+       n = 1;
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_STREAMON, &n) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Error starting streaming capture for %s: %s",
+                       GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_grab_frame():
+ *   capture one frame during streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_grab_frame (GstV4l2Src *v4l2src,
+                        gint       *num)
+{
+       DEBUG("syncing on the next frame");
+
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       /* syncing on the buffer grabs it */
+       if (!gst_v4l2src_sync_next_frame(v4l2src, num))
+               return FALSE;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_requeue_frame():
+ *   re-queue a frame after we're done with the buffer
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_requeue_frame (GstV4l2Src *v4l2src,
+                           gint        num)
+{
+       DEBUG("requeueing frame %d", num);
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       /* and let's queue the buffer */
+       if (!gst_v4l2src_queue_frame(v4l2src, num))
+               return FALSE;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_capture_stop():
+ *   stop streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_capture_stop (GstV4l2Src *v4l2src)
+{
+       gint n = 0;
+
+       DEBUG("stopping capturing");
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       /* we actually need to sync on all queued buffers but not on the non-queued ones */
+       if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_STREAMOFF, &n) < 0) {
+               gst_element_error(GST_ELEMENT(v4l2src),
+                       "Error stopping streaming capture for %s: %s",
+                       GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_capture_deinit():
+ *   deinitialize the capture system
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+
+gboolean
+gst_v4l2src_capture_deinit (GstV4l2Src *v4l2src)
+{
+       gint n;
+
+       DEBUG("deinitting capture system");
+       GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
+       GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
+
+       /* unmap the buffer */
+       for (n=0;n<v4l2src->breq.count;n++) {
+               if (!GST_V4L2ELEMENT(v4l2src)->buffer[n])
+                       break;
+               munmap(GST_V4L2ELEMENT(v4l2src)->buffer[n], v4l2src->format.fmt.pix.sizeimage);
+               GST_V4L2ELEMENT(v4l2src)->buffer[n] = NULL;
+       }
+       g_free(GST_V4L2ELEMENT(v4l2src)->buffer);
+       GST_V4L2ELEMENT(v4l2src)->buffer = NULL;
+
+       return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2src_get_fourcc_list():
+ *   create a list of all available fourccs
+ * return value: the list
+ ******************************************************/
+
+GList *
+gst_v4l2src_get_fourcc_list (GstV4l2Src *v4l2src)
+{
+       GList *list = NULL;
+       GstV4l2Element *v4l2element = GST_V4L2ELEMENT(v4l2src);
+       gint n;
+
+       for (n=0;n<g_list_length(v4l2element->formats);n++) {
+               struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2element->formats, n);
+               guint32 print_format = GUINT32_FROM_LE(fmt->pixelformat);
+               gchar *print_format_str = (gchar *) &print_format;
+
+               list = g_list_append(list, g_strndup(print_format_str, 4));
+       }
+
+       return list;
+}
+
+
+/******************************************************
+ * gst_v4l2src_get_format_list():
+ *   create a list of all available capture formats
+ * return value: the list
+ ******************************************************/
+
+GList *
+gst_v4l2src_get_format_list (GstV4l2Src *v4l2src)
+{
+       GList *list = NULL;
+       GstV4l2Element *v4l2element = GST_V4L2ELEMENT(v4l2src);
+       gint n;
+
+       for (n=0;n<g_list_length(v4l2element->formats);n++) {
+               struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2element->formats, n);
+
+               list = g_list_append(list, g_strdup(fmt->description));
+       }
+
+       return list;
+}
diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h
new file mode 100644 (file)
index 0000000..c9a108a
--- /dev/null
@@ -0,0 +1,45 @@
+/* G-Streamer Video4linux2 video-capture plugin - system calls
+ * Copyright (C) 2002 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 __V4L2_SRC_CALLS_H__
+#define __V4L2_SRC_CALLS_H__
+
+#include "gstv4l2src.h"
+#include "v4l2_calls.h"
+
+
+gboolean       gst_v4l2src_get_capture         (GstV4l2Src *v4l2src);
+gboolean       gst_v4l2src_set_capture         (GstV4l2Src *v4l2src,
+                                                struct v4l2_fmtdesc *fmt,
+                                                gint        width,
+                                                gint        height);
+gboolean       gst_v4l2src_capture_init        (GstV4l2Src *v4l2src);
+gboolean       gst_v4l2src_capture_start       (GstV4l2Src *v4l2src);
+gboolean       gst_v4l2src_grab_frame          (GstV4l2Src *v4l2src,
+                                                gint       *num);
+gboolean       gst_v4l2src_requeue_frame       (GstV4l2Src *v4l2src,
+                                                gint        num);
+gboolean       gst_v4l2src_capture_stop        (GstV4l2Src *v4l2src);
+gboolean       gst_v4l2src_capture_deinit      (GstV4l2Src *v4l2src);
+
+GList *                gst_v4l2src_get_fourcc_list     (GstV4l2Src *v4l2src);
+GList *                gst_v4l2src_get_format_list     (GstV4l2Src *v4l2src);
+
+
+#endif /* __V4L2_SRC_CALLS_H__ */