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