From 862d28a1b7321cc660a4230a0b19b3bd93279ce9 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Fri, 10 Oct 2003 12:47:42 +0000 Subject: [PATCH] Some interface implementations for video4linux/video4linux2 plugins: a Tuner interface, with which one can select inp... Original commit message from CVS: Some interface implementations for video4linux/video4linux2 plugins: * a Tuner interface, with which one can select inputs and stations. Audio work is underway here, but unfinished. * A Xoverlay interface with which one can do simple overlay. Similar to the API of the v4l/Xv XFree86 extension. Widget implementation for GTK-2.0 coming up in the sandbox. * Colorbalance - for adapting colors (brightness, contrast, etc.) - pretty basic and maybe somewhat overdesigned. But it'll do for now. Apart from these interfaces, there's also a loadable library 'xwindowlistener' that listenes to X for the movement of a window and the overlap of other windows. This is partly copied from xawtv (and thus partly GPL :(), but it's needed for the xoverlay interface implementation in the v4l/v4l2 elements. Lastly, some small changes to remove redundant properties from the v4l/v4l2 elements since these can be done much simpler. Comments appreciated! --- configure.ac | 4 + sys/v4l2/gstv4l2colorbalance.c | 151 +++++++++ sys/v4l2/gstv4l2colorbalance.h | 58 ++++ sys/v4l2/gstv4l2element-marshal.list | 3 - sys/v4l2/gstv4l2element.c | 430 ++++++++++-------------- sys/v4l2/gstv4l2element.h | 33 +- sys/v4l2/gstv4l2src.c | 17 +- sys/v4l2/gstv4l2tuner.c | 361 ++++++++++++++++++++ sys/v4l2/gstv4l2tuner.h | 85 +++++ sys/v4l2/gstv4l2xoverlay.c | 128 +++++++ sys/v4l2/gstv4l2xoverlay.h | 42 +++ sys/v4l2/v4l2-overlay_calls.c | 17 +- sys/v4l2/v4l2_calls.c | 479 ++++++++++++--------------- sys/v4l2/v4l2_calls.h | 25 +- 14 files changed, 1249 insertions(+), 584 deletions(-) create mode 100644 sys/v4l2/gstv4l2colorbalance.c create mode 100644 sys/v4l2/gstv4l2colorbalance.h delete mode 100644 sys/v4l2/gstv4l2element-marshal.list create mode 100644 sys/v4l2/gstv4l2tuner.c create mode 100644 sys/v4l2/gstv4l2tuner.h create mode 100644 sys/v4l2/gstv4l2xoverlay.c create mode 100644 sys/v4l2/gstv4l2xoverlay.h diff --git a/configure.ac b/configure.ac index 5bcb93ac67..765bac4ccc 100644 --- a/configure.ac +++ b/configure.ac @@ -1287,6 +1287,7 @@ ext/xvid/Makefile gst-libs/Makefile gst-libs/gst/Makefile gst-libs/gst/audio/Makefile +gst-libs/gst/colorbalance/Makefile gst-libs/gst/floatcast/Makefile gst-libs/gst/gconf/Makefile gst-libs/gst/idct/Makefile @@ -1296,7 +1297,10 @@ gst-libs/gst/navigation/Makefile gst-libs/gst/play/Makefile gst-libs/gst/resample/Makefile gst-libs/gst/riff/Makefile +gst-libs/gst/tuner/Makefile gst-libs/gst/video/Makefile +gst-libs/gst/xoverlay/Makefile +gst-libs/gst/xwindowlistener/Makefile gst-libs/ext/Makefile gst-libs/ext/ffmpeg/Makefile gst-libs/ext/mplex/Makefile diff --git a/sys/v4l2/gstv4l2colorbalance.c b/sys/v4l2/gstv4l2colorbalance.c new file mode 100644 index 0000000000..d0c1dcf81a --- /dev/null +++ b/sys/v4l2/gstv4l2colorbalance.c @@ -0,0 +1,151 @@ +/* GStreamer Color Balance interface implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstv4l2colorbalance.c: color balance interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "gstv4l2colorbalance.h" +#include "gstv4l2element.h" + +static void +gst_v4l2_color_balance_channel_class_init(GstV4l2ColorBalanceChannelClass *klass); +static void +gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel *channel); + +static const GList * +gst_v4l2_color_balance_list_channels (GstColorBalance *balance); +static void +gst_v4l2_color_balance_set_value (GstColorBalance *balance, + GstColorBalanceChannel *channel, + gint value); +static gint +gst_v4l2_color_balance_get_value (GstColorBalance *balance, + GstColorBalanceChannel *channel); + +static GstColorBalanceChannelClass *parent_class = NULL; + +GType +gst_v4l2_color_balance_channel_get_type (void) +{ + static GType gst_v4l2_color_balance_channel_type = 0; + + if (!gst_v4l2_color_balance_channel_type) { + static const GTypeInfo v4l2_tuner_channel_info = { + sizeof (GstV4l2ColorBalanceChannelClass), + NULL, + NULL, + (GClassInitFunc) gst_v4l2_color_balance_channel_class_init, + NULL, + NULL, + sizeof (GstV4l2ColorBalanceChannel), + 0, + (GInstanceInitFunc) gst_v4l2_color_balance_channel_init, + NULL + }; + + gst_v4l2_color_balance_channel_type = + g_type_register_static (GST_TYPE_COLOR_BALANCE_CHANNEL, + "GstV4l2ColorBalanceChannel", + &v4l2_tuner_channel_info, 0); + } + + return gst_v4l2_color_balance_channel_type; +} + +static void +gst_v4l2_color_balance_channel_class_init (GstV4l2ColorBalanceChannelClass *klass) +{ + parent_class = g_type_class_ref (GST_TYPE_COLOR_BALANCE_CHANNEL); +} + +static void +gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel *channel) +{ + channel->index = 0; +} + +void +gst_v4l2_color_balance_interface_init (GstColorBalanceClass *klass) +{ + /* default virtual functions */ + klass->list_channels = gst_v4l2_color_balance_list_channels; + klass->set_value = gst_v4l2_color_balance_set_value; + klass->get_value = gst_v4l2_color_balance_get_value; +} + +static gboolean +gst_v4l2_color_balance_contains_channel (GstV4l2Element *v4l2element, + GstV4l2ColorBalanceChannel *v4l2channel) +{ + const GList *item; + + for (item = v4l2element->colors; item != NULL; item = item->next) + if (item->data == v4l2channel) + return TRUE; + + return FALSE; +} + +static const GList * +gst_v4l2_color_balance_list_channels (GstColorBalance *balance) +{ + return GST_V4L2ELEMENT (balance)->colors; +} + +static void +gst_v4l2_color_balance_set_value (GstColorBalance *balance, + GstColorBalanceChannel *channel, + gint value) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (balance); + GstV4l2ColorBalanceChannel *v4l2channel = + GST_V4L2_COLOR_BALANCE_CHANNEL (channel); + + /* assert that we're opened and that we're using a known item */ + g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); + g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2element, + v4l2channel)); + + gst_v4l2_set_attribute (v4l2element, v4l2channel->index, value); +} + +static gint +gst_v4l2_color_balance_get_value (GstColorBalance *balance, + GstColorBalanceChannel *channel) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (balance); + GstV4l2ColorBalanceChannel *v4l2channel = + GST_V4L2_COLOR_BALANCE_CHANNEL (channel); + gint value; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0); + g_return_val_if_fail (gst_v4l2_color_balance_contains_channel (v4l2element, + v4l2channel), + 0); + + if (!gst_v4l2_get_attribute (v4l2element, v4l2channel->index, &value)) + return 0; + + return value; +} diff --git a/sys/v4l2/gstv4l2colorbalance.h b/sys/v4l2/gstv4l2colorbalance.h new file mode 100644 index 0000000000..4003203b6e --- /dev/null +++ b/sys/v4l2/gstv4l2colorbalance.h @@ -0,0 +1,58 @@ +/* G-Streamer generic V4L2 element - Color Balance interface implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstv4l2colorbalance.h: color balance interface implementation for V4L2 + * + * 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_V4L2_COLOR_BALANCE_H__ +#define __GST_V4L2_COLOR_BALANCE_H__ + +#include +#include +#include "v4l2_calls.h" + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL \ + (gst_v4l2_color_balance_channel_get_type ()) +#define GST_V4L2_COLOR_BALANCE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \ + GstV4l2ColorBalanceChannel)) +#define GST_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \ + GstV4l2ColorBalanceChannelClass)) +#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL)) +#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL)) + +typedef struct _GstV4l2ColorBalanceChannel { + GstColorBalanceChannel parent; + + guint32 index; +} GstV4l2ColorBalanceChannel; + +typedef struct _GstV4l2ColorBalanceChannelClass { + GstColorBalanceChannelClass parent; +} GstV4l2ColorBalanceChannelClass; + +GType gst_v4l2_color_balance_channel_get_type (void); + +void gst_v4l2_color_balance_interface_init (GstColorBalanceClass *klass); + +#endif /* __GST_V4L2_COLOR_BALANCE_H__ */ diff --git a/sys/v4l2/gstv4l2element-marshal.list b/sys/v4l2/gstv4l2element-marshal.list deleted file mode 100644 index 432112121b..0000000000 --- a/sys/v4l2/gstv4l2element-marshal.list +++ /dev/null @@ -1,3 +0,0 @@ -BOOLEAN:INT,INT,INT,INT,POINTER,INT -BOOLEAN:STRING,INT -BOOLEAN:STRING,POINTER diff --git a/sys/v4l2/gstv4l2element.c b/sys/v4l2/gstv4l2element.c index 9ff553cead..35f0629017 100644 --- a/sys/v4l2/gstv4l2element.c +++ b/sys/v4l2/gstv4l2element.c @@ -22,12 +22,14 @@ #endif #include "v4l2_calls.h" -#include "gstv4l2element-marshal.h" +#include "gstv4l2tuner.h" +#include "gstv4l2xoverlay.h" +#include "gstv4l2colorbalance.h" /* elementfactory details */ static GstElementDetails gst_v4l2element_details = { "Generic video4linux2 Element", - "None/Video", + "Generic/Video", "LGPL", "Generic plugin for handling common video4linux2 calls", VERSION, @@ -40,52 +42,65 @@ enum { /* FILL ME */ SIGNAL_OPEN, SIGNAL_CLOSE, - SIGNAL_SET_VIDEOWINDOW, - SIGNAL_GET_ATTRIBUTE, - SIGNAL_SET_ATTRIBUTE, LAST_SIGNAL }; enum { ARG_0, - ARG_CHANNEL, - ARG_CHANNEL_NAMES, - ARG_OUTPUT, - ARG_OUTPUT_NAMES, - ARG_NORM, - ARG_NORM_NAMES, - ARG_HAS_TUNER, - ARG_FREQUENCY, - ARG_SIGNAL_STRENGTH, - ARG_HAS_AUDIO, - ARG_ATTRIBUTES, ARG_DEVICE, ARG_DEVICE_NAME, - ARG_DEVICE_HAS_CAPTURE, - ARG_DEVICE_HAS_OVERLAY, - ARG_DEVICE_HAS_PLAYBACK, - ARG_DISPLAY, - ARG_DO_OVERLAY, + ARG_FLAGS }; -static void gst_v4l2element_class_init (GstV4l2ElementClass *klass); -static void gst_v4l2element_init (GstV4l2Element *v4lelement); -static void gst_v4l2element_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gst_v4l2element_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static GstElementStateReturn gst_v4l2element_change_state (GstElement *element); +static void gst_v4l2element_class_init (GstV4l2ElementClass *klass); +static void gst_v4l2element_init (GstV4l2Element *v4lelement); +static void gst_v4l2element_dispose (GObject *object); +static void gst_v4l2element_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gst_v4l2element_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static GstElementStateReturn + gst_v4l2element_change_state (GstElement *element); static GstElementClass *parent_class = NULL; static guint gst_v4l2element_signals[LAST_SIGNAL] = { 0 }; +static gboolean +gst_v4l2_iface_supported (GstInterface *iface, + GType iface_type) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (iface); + + g_assert (iface_type == GST_TYPE_TUNER || + iface_type == GST_TYPE_X_OVERLAY || + iface_type == GST_TYPE_COLOR_BALANCE); + + if (v4l2element->video_fd == -1) + return FALSE; + + if (iface_type == GST_TYPE_X_OVERLAY && + !GST_V4L2_IS_OVERLAY(v4l2element)) + return FALSE; + + return TRUE; +} + + +static void +gst_v4l2_interface_init (GstInterfaceClass *klass) +{ + /* default virtual functions */ + klass->supported = gst_v4l2_iface_supported; +} + + GType gst_v4l2element_get_type (void) { @@ -104,13 +119,78 @@ gst_v4l2element_get_type (void) (GInstanceInitFunc) gst_v4l2element_init, NULL }; - v4l2element_type = g_type_register_static(GST_TYPE_ELEMENT, - "GstV4l2Element", &v4l2element_info, 0); + static const GInterfaceInfo v4l2iface_info = { + (GInterfaceInitFunc) gst_v4l2_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_tuner_info = { + (GInterfaceInitFunc) gst_v4l2_tuner_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_xoverlay_info = { + (GInterfaceInitFunc) gst_v4l2_xoverlay_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_colorbalance_info = { + (GInterfaceInitFunc) gst_v4l2_color_balance_interface_init, + NULL, + NULL, + }; + + v4l2element_type = + g_type_register_static(GST_TYPE_ELEMENT, + "GstV4l2Element", &v4l2element_info, 0); + + g_type_add_interface_static (v4l2element_type, + GST_TYPE_INTERFACE, + &v4l2iface_info); + g_type_add_interface_static (v4l2element_type, + GST_TYPE_TUNER, + &v4l2_tuner_info); + g_type_add_interface_static (v4l2element_type, + GST_TYPE_X_OVERLAY, + &v4l2_xoverlay_info); + g_type_add_interface_static (v4l2element_type, + GST_TYPE_COLOR_BALANCE, + &v4l2_colorbalance_info); } + return v4l2element_type; } +#define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ()) +GType +gst_v4l2_device_get_type (void) +{ + static GType v4l2_device_type = 0; + + if (v4l2_device_type == 0) { + static const GFlagsValue values[] = { + { V4L2_CAP_VIDEO_CAPTURE, "CAPTURE", + "Device can capture" }, + { V4L2_CAP_VIDEO_OUTPUT, "PLAYBACK", + "Device can playback" }, + { V4L2_CAP_VIDEO_OVERLAY, "OVERLAY", + "Device can do overlay" }, + { V4L2_CAP_TUNER, "TUNER", + "Device has a tuner" }, + { V4L2_CAP_AUDIO, "AUDIO", + "Device handles audio" }, + { 0, NULL, NULL } + }; + + v4l2_device_type = + g_flags_register_static ("GstV4l2DeviceTypeFlags", + values); + } + + return v4l2_device_type; +} + static void gst_v4l2element_class_init (GstV4l2ElementClass *klass) @@ -123,96 +203,15 @@ gst_v4l2element_class_init (GstV4l2ElementClass *klass) parent_class = g_type_class_ref(GST_TYPE_ELEMENT); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL, - g_param_spec_int("channel","channel","channel", - G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL_NAMES, - g_param_spec_pointer("channel_names","channel_names","channel_names", - G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT, - g_param_spec_int("output","output","output", - G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT_NAMES, - g_param_spec_pointer("output_names","output_names","output_names", - G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM, - g_param_spec_int("norm","norm","norm", - G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM_NAMES, - g_param_spec_pointer("norm_names","norm_names","norm_names", - G_PARAM_READABLE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_TUNER, - g_param_spec_boolean("has_tuner","has_tuner","has_tuner", - 0,G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY, - g_param_spec_ulong("frequency","frequency","frequency", - 0,G_MAXULONG,0,G_PARAM_READWRITE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SIGNAL_STRENGTH, - g_param_spec_ulong("signal_strength","signal_strength","signal_strength", - 0,G_MAXULONG,0,G_PARAM_READABLE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_AUDIO, - g_param_spec_boolean("has_audio","has_audio","has_audio", - 0,G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ATTRIBUTES, - g_param_spec_pointer("attributes","attributes","attributes", - G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE, - g_param_spec_string("device","device","device", - NULL, G_PARAM_READWRITE)); + g_param_spec_string("device", "Device", "Device location", + NULL, G_PARAM_READWRITE)); g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_NAME, - g_param_spec_string("device_name","device_name","device_name", - NULL, G_PARAM_READABLE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CAPTURE, - g_param_spec_boolean("can_capture","can_capture","can_capture", - 0,G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_PLAYBACK, - g_param_spec_boolean("can_playback","can_playback","can_playback", - 0,G_PARAM_READABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_OVERLAY, - g_param_spec_boolean("has_overlay","has_overlay","has_overlay", - 0,G_PARAM_READABLE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DISPLAY, - g_param_spec_string("display","display","display", - NULL, G_PARAM_WRITABLE)); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DO_OVERLAY, - g_param_spec_boolean("do_overlay","do_overlay","do_overlay", - 0,G_PARAM_WRITABLE)); - - /* actions */ - gst_v4l2element_signals[SIGNAL_SET_VIDEOWINDOW] = - g_signal_new ("set_videowindow", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GstV4l2ElementClass, set_videowindow), - NULL, NULL, - gstv4l2_cclosure_marshal_BOOLEAN__INT_INT_INT_INT_POINTER_INT, - G_TYPE_BOOLEAN, 6, - G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, - G_TYPE_POINTER, G_TYPE_INT); - klass->set_videowindow = gst_v4l2_set_window; - gst_v4l2element_signals[SIGNAL_GET_ATTRIBUTE] = - g_signal_new ("get_attribute", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GstV4l2ElementClass, get_attribute), - NULL, NULL, - gstv4l2_cclosure_marshal_BOOLEAN__STRING_POINTER, - G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_POINTER); - klass->get_attribute = gst_v4l2_get_attribute; - gst_v4l2element_signals[SIGNAL_SET_ATTRIBUTE] = - g_signal_new ("set_attribute", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GstV4l2ElementClass, set_attribute), - NULL, NULL, - gstv4l2_cclosure_marshal_BOOLEAN__STRING_INT, - G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_INT); - klass->set_attribute = gst_v4l2_set_attribute; + g_param_spec_string("device_name", "Device name", + "Name of the device", NULL, G_PARAM_READABLE)); + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FLAGS, + g_param_spec_flags("flags", "Flags", "Device type flags", + GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE)); /* signals */ gst_v4l2element_signals[SIGNAL_OPEN] = @@ -228,6 +227,7 @@ gst_v4l2element_class_init (GstV4l2ElementClass *klass) gobject_class->set_property = gst_v4l2element_set_property; gobject_class->get_property = gst_v4l2element_get_property; + gobject_class->dispose = gst_v4l2element_dispose; gstelement_class->change_state = gst_v4l2element_change_state; } @@ -239,25 +239,38 @@ gst_v4l2element_init (GstV4l2Element *v4l2element) /* some default values */ v4l2element->video_fd = -1; v4l2element->buffer = NULL; - v4l2element->device = NULL; + v4l2element->device = g_strdup("/dev/video"); + v4l2element->display = g_strdup(g_getenv("DISPLAY")); - v4l2element->norm = -1; - v4l2element->channel = -1; - v4l2element->output = -1; - v4l2element->frequency = 0; - - v4l2element->controls = NULL; - v4l2element->menus = NULL; - v4l2element->control_specs = NULL; - v4l2element->outputs = NULL; - v4l2element->output_names = NULL; - v4l2element->inputs = NULL; - v4l2element->input_names = NULL; + v4l2element->channels = NULL; v4l2element->norms = NULL; - v4l2element->norm_names = NULL; + v4l2element->colors = NULL; + + v4l2element->overlay = gst_v4l2_xoverlay_new(v4l2element); } +static void +gst_v4l2element_dispose (GObject *object) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT(object); + + if (v4l2element->overlay) { + gst_v4l2_xoverlay_free(v4l2element); + } + + if (v4l2element->display) { + g_free (v4l2element->display); + } + + if (v4l2element->device) { + g_free (v4l2element->device); + } + + if (((GObjectClass *) parent_class)->dispose) + ((GObjectClass *) parent_class)->dispose(object); +} + static void gst_v4l2element_set_property (GObject *object, guint prop_id, @@ -271,34 +284,6 @@ gst_v4l2element_set_property (GObject *object, v4l2element = GST_V4L2ELEMENT(object); switch (prop_id) { - case ARG_CHANNEL: - v4l2element->channel = g_value_get_int(value); - if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) { - if (!gst_v4l2_set_input(v4l2element, g_value_get_int(value))) - return; - } - break; - case ARG_OUTPUT: - v4l2element->output = g_value_get_int(value); - if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) { - if (!gst_v4l2_set_output(v4l2element, g_value_get_int(value))) - return; - } - break; - case ARG_NORM: - v4l2element->norm = g_value_get_int(value); - if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) { - if (!gst_v4l2_set_norm(v4l2element, g_value_get_int(value))) - return; - } - break; - case ARG_FREQUENCY: - v4l2element->frequency = g_value_get_ulong(value); - if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) { - if (!gst_v4l2_set_frequency(v4l2element, g_value_get_ulong(value))) - return; - } - break; case ARG_DEVICE: if (!GST_V4L2_IS_OPEN(v4l2element)) { if (v4l2element->device) @@ -306,16 +291,6 @@ gst_v4l2element_set_property (GObject *object, v4l2element->device = g_strdup(g_value_get_string(value)); } break; - case ARG_DISPLAY: - if (!gst_v4l2_set_display(v4l2element, g_value_get_string(value))) - return; - break; - case ARG_DO_OVERLAY: - if (GST_V4L2_IS_OPEN(v4l2element)) { - if (!gst_v4l2_enable_overlay(v4l2element, g_value_get_boolean(value))) - return; - } - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -330,88 +305,31 @@ gst_v4l2element_get_property (GObject *object, GParamSpec *pspec) { GstV4l2Element *v4l2element; - 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_V4L2ELEMENT(object)); v4l2element = GST_V4L2ELEMENT(object); switch (prop_id) { - case ARG_CHANNEL: - if (GST_V4L2_IS_OPEN(v4l2element)) - gst_v4l2_get_input(v4l2element, &temp_i); - g_value_set_int(value, temp_i); - break; - case ARG_CHANNEL_NAMES: - g_value_set_pointer(value, v4l2element->input_names); - break; - case ARG_OUTPUT: - if (GST_V4L2_IS_OPEN(v4l2element)) - gst_v4l2_get_output(v4l2element, &temp_i); - g_value_set_int(value, temp_i); - break; - case ARG_OUTPUT_NAMES: - g_value_set_pointer(value, v4l2element->output_names); - break; - case ARG_NORM: - if (GST_V4L2_IS_OPEN(v4l2element)) - gst_v4l2_get_norm(v4l2element, &temp_i); - g_value_set_int(value, temp_i); - break; - case ARG_NORM_NAMES: - g_value_set_pointer(value, v4l2element->norm_names); - break; - case ARG_HAS_TUNER: - if (GST_V4L2_IS_OPEN(v4l2element)) - g_value_set_boolean(value, - gst_v4l2_has_tuner(v4l2element, &temp_i)); - break; - case ARG_FREQUENCY: - if (GST_V4L2_IS_OPEN(v4l2element)) - gst_v4l2_get_frequency(v4l2element, &temp_ul); - g_value_set_ulong(value, temp_ul); - break; - case ARG_SIGNAL_STRENGTH: - if (GST_V4L2_IS_OPEN(v4l2element)) - gst_v4l2_signal_strength(v4l2element, &temp_ul); - g_value_set_ulong(value, temp_ul); - break; - case ARG_HAS_AUDIO: - if (GST_V4L2_IS_OPEN(v4l2element)) - temp_i = gst_v4l2_has_audio(v4l2element); - g_value_set_boolean(value, temp_i>0?TRUE:FALSE); - break; - case ARG_ATTRIBUTES: - g_value_set_pointer(value, v4l2element->control_specs); - break; case ARG_DEVICE: g_value_set_string(value, v4l2element->device); break; - case ARG_DEVICE_NAME: + case ARG_DEVICE_NAME: { + gchar *new = NULL; if (GST_V4L2_IS_OPEN(v4l2element)) - g_value_set_string(value, v4l2element->vcap.card); + new = v4l2element->vcap.card; + g_value_set_string(value, new); break; - case ARG_DEVICE_HAS_CAPTURE: - if (GST_V4L2_IS_OPEN(v4l2element) && - v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE && - v4l2element->vcap.capabilities & V4L2_CAP_STREAMING) - temp_i = 1; - g_value_set_boolean(value, temp_i>0?TRUE:FALSE); - break; - case ARG_DEVICE_HAS_OVERLAY: - if (GST_V4L2_IS_OPEN(v4l2element) && - v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY) - temp_i = 1; - g_value_set_boolean(value, temp_i>0?TRUE:FALSE); - break; - case ARG_DEVICE_HAS_PLAYBACK: - if (GST_V4L2_IS_OPEN(v4l2element) && - v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT && - v4l2element->vcap.capabilities & V4L2_CAP_STREAMING) - temp_i = 1; - g_value_set_boolean(value, temp_i>0?TRUE:FALSE); + } + case ARG_FLAGS: { + guint flags = 0; + if (GST_V4L2_IS_OPEN(v4l2element)) { + flags |= v4l2element->vcap.capabilities & + 30007; + } + g_value_set_flags(value, flags); break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -433,29 +351,21 @@ gst_v4l2element_change_state (GstElement *element) */ switch (GST_STATE_TRANSITION(element)) { case GST_STATE_NULL_TO_READY: + gst_v4l2_set_display(v4l2element); + if (!gst_v4l2_open(v4l2element)) return GST_STATE_FAILURE; + gst_v4l2_xoverlay_open(v4l2element); + /* emit a signal! whoopie! */ g_signal_emit(G_OBJECT(v4l2element), gst_v4l2element_signals[SIGNAL_OPEN], 0, v4l2element->device); - - /* now, sync options */ - if (v4l2element->norm >= 0) - if (!gst_v4l2_set_norm(v4l2element, v4l2element->norm)) - return GST_STATE_FAILURE; - if (v4l2element->channel >= 0) - if (!gst_v4l2_set_input(v4l2element, v4l2element->channel)) - return GST_STATE_FAILURE; - if (v4l2element->output >= 0) - if (!gst_v4l2_set_output(v4l2element, v4l2element->output)) - return GST_STATE_FAILURE; - if (v4l2element->frequency > 0) - if (!gst_v4l2_set_frequency(v4l2element, v4l2element->frequency)) - return GST_STATE_FAILURE; break; case GST_STATE_READY_TO_NULL: + gst_v4l2_xoverlay_close(v4l2element); + if (!gst_v4l2_close(v4l2element)) return GST_STATE_FAILURE; @@ -478,6 +388,10 @@ gst_v4l2element_factory_init (GstPlugin *plugin) { GstElementFactory *factory; + /* we can run without... But not yet. ;). */ + if (!gst_library_load ("xwindowlistener")) + return FALSE; + /* create an elementfactory for the v4l2element */ factory = gst_element_factory_new("v4l2element", GST_TYPE_V4L2ELEMENT, &gst_v4l2element_details); diff --git a/sys/v4l2/gstv4l2element.h b/sys/v4l2/gstv4l2element.h index 6d86d4a973..f6e19e7e2c 100644 --- a/sys/v4l2/gstv4l2element.h +++ b/sys/v4l2/gstv4l2element.h @@ -21,6 +21,7 @@ #define __GST_V4L2ELEMENT_H__ #include +#include /* Because of some really cool feature in video4linux1, also known as * 'not including sys/types.h and sys/time.h', we had to include it @@ -71,17 +72,16 @@ struct _GstV4l2Element { struct v4l2_capability vcap; /* the toys available to us */ - GList /*v4l2_input*/ *inputs, *input_names; - GList /*v4l2_output*/ *outputs, *output_names; - GList /*v4l2_enumstd*/ *norms, *norm_names; - GList /*v4l2_queryctrl*/ *controls, *control_specs; - GList /*GList:v4l2_querymenu*/ *menus; + GList *channels; + GList *norms; + GList *colors; + + /* X-overlay */ + GstXWindowListener *overlay; + XID xwindow_id; /* caching values */ - gint channel; - gint output; - gint norm; - gulong frequency; + gchar *display; }; struct _GstV4l2ElementClass { @@ -92,21 +92,6 @@ struct _GstV4l2ElementClass { const gchar *device); void (*close) (GstElement *element, const gchar *device); - - /* actions */ - gboolean (*set_videowindow) (GstElement *element, - gint x_offset, - gint y_offset, - gint height, - gint width, - struct v4l2_clip *clips, - gint num_clips); - gboolean (*get_attribute) (GstElement *element, - const gchar *attr_name, - int *value); - gboolean (*set_attribute) (GstElement *element, - const gchar *attr_name, - const int value); }; diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 7a0094bd16..67b683e782 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -24,6 +24,7 @@ #include #include #include "v4l2src_calls.h" +#include "gstv4l2tuner.h" /* elementfactory details */ static GstElementDetails gst_v4l2src_details = { @@ -247,9 +248,8 @@ gst_v4l2src_close (GstElement *element, static gfloat gst_v4l2src_get_fps (GstV4l2Src *v4l2src) { - gint norm; - struct v4l2_standard *std; - gfloat fps; + v4l2_std_id norm; + const GList *item; if (!v4l2src->use_fixed_fps && v4l2src->clock != NULL && @@ -267,11 +267,14 @@ gst_v4l2src_get_fps (GstV4l2Src *v4l2src) if (!gst_v4l2_get_norm(GST_V4L2ELEMENT(v4l2src), &norm)) return 0.; + for (item = GST_V4L2ELEMENT(v4l2src)->norms; + item != NULL; item = item->next) { + GstV4l2TunerNorm *v4l2norm = item->data; + if (v4l2norm->index == norm) + return GST_TUNER_NORM(v4l2norm)->fps; + } - std = ((struct v4l2_standard *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->norms, norm)); - fps = (1. * std->frameperiod.denominator) / std->frameperiod.numerator; - - return fps; + return 0.; } diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c new file mode 100644 index 0000000000..9cde6daab4 --- /dev/null +++ b/sys/v4l2/gstv4l2tuner.c @@ -0,0 +1,361 @@ +/* GStreamer Tuner interface implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstv4l2tuner.c: tuner interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "gstv4l2tuner.h" +#include "gstv4l2element.h" +#include "v4l2_calls.h" + +static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *klass); +static void gst_v4l2_tuner_channel_init (GstV4l2TunerChannel *channel); + +static void gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass *klass); +static void gst_v4l2_tuner_norm_init (GstV4l2TunerNorm *norm); + +static const GList * + gst_v4l2_tuner_list_channels (GstTuner *mixer); +static void gst_v4l2_tuner_set_channel (GstTuner *mixer, + GstTunerChannel *channel); +static const GstTunerChannel * + gst_v4l2_tuner_get_channel (GstTuner *mixer); + +static const GList * + gst_v4l2_tuner_list_norms (GstTuner *mixer); +static void gst_v4l2_tuner_set_norm (GstTuner *mixer, + GstTunerNorm *norm); +static const GstTunerNorm * + gst_v4l2_tuner_get_norm (GstTuner *mixer); + +static void gst_v4l2_tuner_set_frequency (GstTuner *mixer, + GstTunerChannel *channel, + gulong frequency); +static gulong gst_v4l2_tuner_get_frequency (GstTuner *mixer, + GstTunerChannel *channel); +static gint gst_v4l2_tuner_signal_strength (GstTuner *mixer, + GstTunerChannel *channel); + +static GstTunerNormClass *norm_parent_class = NULL; +static GstTunerChannelClass *channel_parent_class = NULL; + +GType +gst_v4l2_tuner_channel_get_type (void) +{ + static GType gst_v4l2_tuner_channel_type = 0; + + if (!gst_v4l2_tuner_channel_type) { + static const GTypeInfo v4l2_tuner_channel_info = { + sizeof (GstV4l2TunerChannelClass), + NULL, + NULL, + (GClassInitFunc) gst_v4l2_tuner_channel_class_init, + NULL, + NULL, + sizeof (GstV4l2TunerChannel), + 0, + (GInstanceInitFunc) gst_v4l2_tuner_channel_init, + NULL + }; + + gst_v4l2_tuner_channel_type = + g_type_register_static (GST_TYPE_TUNER_CHANNEL, + "GstV4l2TunerChannel", + &v4l2_tuner_channel_info, 0); + } + + return gst_v4l2_tuner_channel_type; +} + +static void +gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *klass) +{ + channel_parent_class = g_type_class_ref (GST_TYPE_TUNER_CHANNEL); +} + +static void +gst_v4l2_tuner_channel_init (GstV4l2TunerChannel *channel) +{ + channel->index = 0; + channel->tuner = 0; + channel->audio = 0; +} + +GType +gst_v4l2_tuner_norm_get_type (void) +{ + static GType gst_v4l2_tuner_norm_type = 0; + + if (!gst_v4l2_tuner_norm_type) { + static const GTypeInfo v4l2_tuner_norm_info = { + sizeof (GstV4l2TunerNormClass), + NULL, + NULL, + (GClassInitFunc) gst_v4l2_tuner_norm_class_init, + NULL, + NULL, + sizeof (GstV4l2TunerNorm), + 0, + (GInstanceInitFunc) gst_v4l2_tuner_norm_init, + NULL + }; + + gst_v4l2_tuner_norm_type = + g_type_register_static (GST_TYPE_TUNER_NORM, + "GstV4l2TunerNorm", + &v4l2_tuner_norm_info, 0); + } + + return gst_v4l2_tuner_norm_type; +} + +static void +gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass *klass) +{ + norm_parent_class = g_type_class_ref (GST_TYPE_TUNER_NORM); +} + +static void +gst_v4l2_tuner_norm_init (GstV4l2TunerNorm *norm) +{ + norm->index = 0; +} + +void +gst_v4l2_tuner_interface_init (GstTunerClass *klass) +{ + /* default virtual functions */ + klass->list_channels = gst_v4l2_tuner_list_channels; + klass->set_channel = gst_v4l2_tuner_set_channel; + klass->get_channel = gst_v4l2_tuner_get_channel; + + klass->list_norms = gst_v4l2_tuner_list_norms; + klass->set_norm = gst_v4l2_tuner_set_norm; + klass->get_norm = gst_v4l2_tuner_get_norm; + + klass->set_frequency = gst_v4l2_tuner_set_frequency; + klass->get_frequency = gst_v4l2_tuner_get_frequency; + klass->signal_strength = gst_v4l2_tuner_signal_strength; +} + +static gboolean +gst_v4l2_tuner_is_sink (GstV4l2Element *v4l2element) +{ + const GList *pads = gst_element_get_pad_list (GST_ELEMENT (v4l2element)); + GstPadDirection dir = GST_PAD_UNKNOWN; + + /* get direction */ + if (pads && g_list_length ((GList *) pads) == 1) + dir = GST_PAD_DIRECTION (GST_PAD (pads->data)); + + return (dir == GST_PAD_SINK); +} + +static gboolean +gst_v4l2_tuner_contains_channel (GstV4l2Element *v4l2element, + GstV4l2TunerChannel *v4l2channel) +{ + const GList *item; + + for (item = v4l2element->channels; item != NULL; item = item->next) + if (item->data == v4l2channel) + return TRUE; + + return FALSE; +} + +static const GList * +gst_v4l2_tuner_list_channels (GstTuner *mixer) +{ + /* ... or output, if we're a sink... */ + return GST_V4L2ELEMENT (mixer)->channels; +} + +static void +gst_v4l2_tuner_set_channel (GstTuner *mixer, + GstTunerChannel *channel) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + + /* assert that we're opened and that we're using a known item */ + g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); + g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel)); + + /* ... or output, if we're a sink... */ + if (gst_v4l2_tuner_is_sink (v4l2element)) + gst_v4l2_set_output (v4l2element, v4l2channel->index); + else + gst_v4l2_set_input (v4l2element, v4l2channel->index); +} + +static const GstTunerChannel * +gst_v4l2_tuner_get_channel (GstTuner *mixer) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GList *item; + gint channel; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL); + + /* ... or output, if we're a sink... */ + if (gst_v4l2_tuner_is_sink (v4l2element)) + gst_v4l2_get_output (v4l2element, &channel); + else + gst_v4l2_get_input (v4l2element, &channel); + + for (item = v4l2element->channels; item != NULL; item = item->next) { + if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index) + return (const GstTunerChannel *) item->data; + } + + return NULL; +} + +static gboolean +gst_v4l2_tuner_contains_norm (GstV4l2Element *v4l2element, + GstV4l2TunerNorm *v4l2norm) +{ + const GList *item; + + for (item = v4l2element->norms; item != NULL; item = item->next) + if (item->data == v4l2norm) + return TRUE; + + return FALSE; +} + +static const GList * +gst_v4l2_tuner_list_norms (GstTuner *mixer) +{ + return GST_V4L2ELEMENT (mixer)->norms; +} + +static void +gst_v4l2_tuner_set_norm (GstTuner *mixer, + GstTunerNorm *norm) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm); + + /* assert that we're opened and that we're using a known item */ + g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); + g_return_if_fail (gst_v4l2_tuner_contains_norm (v4l2element, v4l2norm)); + + gst_v4l2_set_norm (v4l2element, v4l2norm->index); +} + +static const GstTunerNorm * +gst_v4l2_tuner_get_norm (GstTuner *mixer) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GList *item; + v4l2_std_id norm; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), NULL); + + gst_v4l2_get_norm (v4l2element, &norm); + + for (item = v4l2element->norms; item != NULL; item = item->next) { + if (norm == GST_V4L2_TUNER_NORM (item->data)->index) + return (const GstTunerNorm *) item->data; + } + + return NULL; +} + +static void +gst_v4l2_tuner_set_frequency (GstTuner *mixer, + GstTunerChannel *channel, + gulong frequency) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + gint chan; + + /* assert that we're opened and that we're using a known item */ + g_return_if_fail (GST_V4L2_IS_OPEN (v4l2element)); + g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY)); + g_return_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, v4l2channel)); + + gst_v4l2_get_input (v4l2element, &chan); + if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + gst_v4l2_set_frequency (v4l2element, v4l2channel->tuner, frequency); + } +} + +static gulong +gst_v4l2_tuner_get_frequency (GstTuner *mixer, + GstTunerChannel *channel) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + gint chan; + gulong frequency = 0; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0); + g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY), 0); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, + v4l2channel), 0); + + gst_v4l2_get_input (v4l2element, &chan); + if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + gst_v4l2_get_frequency (v4l2element, v4l2channel->tuner, &frequency); + } + + return frequency; +} + +static gint +gst_v4l2_tuner_signal_strength (GstTuner *mixer, + GstTunerChannel *channel) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); + GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); + gint chan; + gulong signal = 0; + + /* assert that we're opened and that we're using a known item */ + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), 0); + g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, + GST_TUNER_CHANNEL_FREQUENCY), 0); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, + v4l2channel), 0); + + gst_v4l2_get_input (v4l2element, &chan); + if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + gst_v4l2_signal_strength (v4l2element, v4l2channel->tuner, &signal); + } + + return signal; +} diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h new file mode 100644 index 0000000000..a768ea2f76 --- /dev/null +++ b/sys/v4l2/gstv4l2tuner.h @@ -0,0 +1,85 @@ +/* G-Streamer generic V4L2 element - Tuner interface implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstv4l2tuner.h: tuner interface implementation for V4L2 + * + * 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_V4L2_TUNER_H__ +#define __GST_V4L2_TUNER_H__ + +#include +#include + +#include "gstv4l2element.h" + +G_BEGIN_DECLS + +#define GST_TYPE_V4L2_TUNER_CHANNEL \ + (gst_v4l2_tuner_channel_get_type ()) +#define GST_V4L2_TUNER_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \ + GstV4l2TunerChannel)) +#define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \ + GstV4l2TunerChannelClass)) +#define GST_IS_V4L2_TUNER_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_CHANNEL)) +#define GST_IS_V4L2_TUNER_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_CHANNEL)) + +typedef struct _GstV4l2TunerChannel { + GstTunerChannel parent; + + guint32 index; + guint32 tuner; + guint32 audio; +} GstV4l2TunerChannel; + +typedef struct _GstV4l2TunerChannelClass { + GstTunerChannelClass parent; +} GstV4l2TunerChannelClass; + +#define GST_TYPE_V4L2_TUNER_NORM \ + (gst_v4l2_tuner_norm_get_type ()) +#define GST_V4L2_TUNER_NORM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \ + GstV4l2TunerNorm)) +#define GST_V4L2_TUNER_NORM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \ + GstV4l2TunerNormClass)) +#define GST_IS_V4L2_TUNER_NORM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_NORM)) +#define GST_IS_V4L2_TUNER_NORM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_NORM)) + +typedef struct _GstV4l2TunerNorm { + GstTunerNorm parent; + + v4l2_std_id index; +} GstV4l2TunerNorm; + +typedef struct _GstV4l2TunerNormClass { + GstTunerNormClass parent; +} GstV4l2TunerNormClass; + +GType gst_v4l2_tuner_channel_get_type (void); +GType gst_v4l2_tuner_norm_get_type (void); + +void gst_v4l2_tuner_interface_init (GstTunerClass *klass); + +#endif /* __GST_V4L2_TUNER_H__ */ diff --git a/sys/v4l2/gstv4l2xoverlay.c b/sys/v4l2/gstv4l2xoverlay.c new file mode 100644 index 0000000000..10c5f77bc6 --- /dev/null +++ b/sys/v4l2/gstv4l2xoverlay.c @@ -0,0 +1,128 @@ +/* GStreamer X-based overlay interface implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstv4l2xoverlay.c: X-based overlay interface implementation for V4L2 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "gstv4l2xoverlay.h" +#include "gstv4l2element.h" +#include "v4l2_calls.h" + +static void gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay *overlay, + XID xwindow_id); + +void +gst_v4l2_xoverlay_interface_init (GstXOverlayClass *klass) +{ + /* default virtual functions */ + klass->set_xwindow_id = gst_v4l2_xoverlay_set_xwindow_id; +} + +GstXWindowListener * +gst_v4l2_xoverlay_new (GstV4l2Element *v4l2element) +{ + GstXWindowListener *xwin = + gst_x_window_listener_new (NULL, + (MapWindowFunc) gst_v4l2_enable_overlay, + (SetWindowFunc) gst_v4l2_set_window, + (gpointer) v4l2element); + + v4l2element->overlay = xwin; + v4l2element->xwindow_id = 0; + + return xwin; +} + +void +gst_v4l2_xoverlay_free (GstV4l2Element *v4l2element) +{ + gst_v4l2_xoverlay_close (v4l2element); + g_object_unref (G_OBJECT (v4l2element->overlay)); + v4l2element->overlay = NULL; +} + +void +gst_v4l2_xoverlay_open (GstV4l2Element *v4l2element) +{ + GstXWindowListener *xwin = v4l2element->overlay; + + if (xwin) { + xwin->display_name = g_strdup (v4l2element->display); + + if (v4l2element->xwindow_id != 0 && + xwin->display_name && + xwin->display_name[0] == ':') { + gst_x_window_listener_set_xid (xwin, v4l2element->xwindow_id); + } + } +} + +void +gst_v4l2_xoverlay_close (GstV4l2Element *v4l2element) +{ + GstXWindowListener *xwin = v4l2element->overlay; + + if (xwin != NULL) { + if (v4l2element->xwindow_id != 0 && + xwin->display_name && + xwin->display_name[0] == ':') { + gst_x_window_listener_set_xid (xwin, 0); + } + + g_free (xwin->display_name); + xwin->display_name = NULL; + } +} + +static void +gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay *overlay, + XID xwindow_id) +{ + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (overlay); + GstXWindowListener *xwin = v4l2element->overlay; + + if (v4l2element->xwindow_id == xwindow_id) { + return; + } + + if (gst_element_get_state (GST_ELEMENT (v4l2element)) != GST_STATE_NULL && + v4l2element->xwindow_id != 0 && + xwin != NULL && + xwin->display_name && + xwin->display_name[0] == ':') { + gst_x_window_listener_set_xid (xwin, 0); + } + + v4l2element->xwindow_id = xwindow_id; + + if (gst_element_get_state (GST_ELEMENT (v4l2element)) != GST_STATE_NULL && + v4l2element->xwindow_id != 0 && + xwin != NULL && + xwin->display_name && + xwin->display_name[0] == ':') { + gst_x_window_listener_set_xid (xwin, v4l2element->xwindow_id); + } +} diff --git a/sys/v4l2/gstv4l2xoverlay.h b/sys/v4l2/gstv4l2xoverlay.h new file mode 100644 index 0000000000..cfcdfd3531 --- /dev/null +++ b/sys/v4l2/gstv4l2xoverlay.h @@ -0,0 +1,42 @@ +/* G-Streamer generic V4L2 element - X overlay interface implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstv4l2xoverlay.h: tv mixer interface implementation for V4L2 + * + * 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_V4L2_X_OVERLAY_H__ +#define __GST_V4L2_X_OVERLAY_H__ + +#include +#include + +#include "gstv4l2element.h" + +G_BEGIN_DECLS + +void gst_v4l2_xoverlay_interface_init (GstXOverlayClass *klass); + +GstXWindowListener * + gst_v4l2_xoverlay_new (GstV4l2Element *v4l2element); +void gst_v4l2_xoverlay_free (GstV4l2Element *v4l2element); + +/* signal handlers */ +void gst_v4l2_xoverlay_open (GstV4l2Element *v4l2element); +void gst_v4l2_xoverlay_close (GstV4l2Element *v4l2element); + +#endif /* __GST_V4L2_X_OVERLAY_H__ */ diff --git a/sys/v4l2/v4l2-overlay_calls.c b/sys/v4l2/v4l2-overlay_calls.c index d6b35366d8..2de7426988 100644 --- a/sys/v4l2/v4l2-overlay_calls.c +++ b/sys/v4l2/v4l2-overlay_calls.c @@ -43,28 +43,33 @@ ******************************************************/ gboolean -gst_v4l2_set_display (GstV4l2Element *v4l2element, - const gchar *display) +gst_v4l2_set_display (GstV4l2Element *v4l2element) { gchar *buff; - DEBUG("trying to set overlay to '%s'", display); + if (v4l2element->display) + g_free(v4l2element->display); + v4l2element->display = g_strdup(g_getenv("DISPLAY")); + + DEBUG("trying to set overlay to '%s'", v4l2element->display); /* start v4l-conf */ buff = g_strdup_printf("v4l-conf -q -c %s -d %s", - v4l2element->device?v4l2element->device:"/dev/video", display); + v4l2element->device, v4l2element->display); switch (system(buff)) { case -1: gst_element_error(GST_ELEMENT(v4l2element), - "Could not start v4l-conf: %s", g_strerror(errno)); + "Could not start v4l-conf: %s", + g_strerror(errno)); g_free(buff); return FALSE; case 0: break; default: gst_element_error(GST_ELEMENT(v4l2element), - "v4l-conf failed to run correctly: %s", g_strerror(errno)); + "v4l-conf failed to run correctly: %s", + g_strerror(errno)); g_free(buff); return FALSE; } diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index 2ec66510c3..70c088cf00 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -30,6 +30,9 @@ #include #include #include "v4l2_calls.h" +#include "gstv4l2tuner.h" +#include "gstv4l2xoverlay.h" +#include "gstv4l2colorbalance.h" #define DEBUG(format, args...) \ GST_DEBUG_OBJECT (\ @@ -70,55 +73,126 @@ static gboolean gst_v4l2_fill_lists (GstV4l2Element *v4l2element) { gint n; + const GList *pads = + gst_element_get_pad_list (GST_ELEMENT (v4l2element)); + GstPadDirection dir = GST_PAD_UNKNOWN; DEBUG("getting enumerations"); GST_V4L2_CHECK_OPEN(v4l2element); + /* sinks have outputs, all others have inputs */ + if (pads && g_list_length ((GList *) pads) == 1) + dir = GST_PAD_DIRECTION (GST_PAD (pads->data)); + + if (dir == GST_PAD_SINK) { /* and now, the inputs */ - for (n=0;;n++) { - struct v4l2_input input, *inpptr; - input.index = n; - if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { - if (errno == EINVAL) - break; /* end of enumeration */ - else { - gst_element_error(GST_ELEMENT(v4l2element), - "Failed to get no. %d in input enumeration for %s: %s", - n, v4l2element->device, g_strerror(errno)); - return FALSE; + for (n=0;;n++) { + struct v4l2_input input; + GstV4l2TunerChannel *v4l2channel; + GstTunerChannel *channel; + + input.index = n; + if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, + &input) < 0) { + if (errno == EINVAL) + break; /* end of enumeration */ + else { + gst_element_error(GST_ELEMENT(v4l2element), + "Failed to get no. %d in input enumeration for %s: %s", + n, v4l2element->device, + g_strerror(errno)); + return FALSE; + } } - } - inpptr = g_malloc(sizeof(input)); - memcpy(inpptr, &input, sizeof(input)); - v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr); - v4l2element->input_names = g_list_append(v4l2element->input_names, inpptr->name); - } + v4l2channel = + g_object_new(GST_TYPE_V4L2_TUNER_CHANNEL, NULL); + channel = GST_TUNER_CHANNEL(v4l2channel); + channel->label = g_strdup(input.name); + channel->flags = GST_TUNER_CHANNEL_INPUT; + v4l2channel->index = n; + if (input.type == V4L2_INPUT_TYPE_TUNER) { + struct v4l2_tuner vtun; - /* outputs */ - for (n=0;;n++) { - struct v4l2_output output, *outptr; - output.index = n; - if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) { - if (errno == EINVAL) - break; /* end of enumeration */ - else { - gst_element_error(GST_ELEMENT(v4l2element), - "Failed to get no. %d in output enumeration for %s: %s", - n, v4l2element->device, g_strerror(errno)); - return FALSE; + v4l2channel->tuner = input.tuner; + channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; + + vtun.index = input.tuner; + if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, + &vtun) < 0) { + gst_element_error(GST_ELEMENT(v4l2element), + "Failed to get tuner %d settings on %s: %s", + input.tuner, + v4l2element->device, + g_strerror(errno)); + g_object_unref(G_OBJECT(channel)); + return FALSE; + } + channel->min_frequency = vtun.rangelow; + channel->max_frequency = vtun.rangehigh; + channel->min_signal = 0; + channel->max_signal = 0xffff; + } + if (input.audioset) { + /* we take the first. We don't care for + * the others for now */ + while (!(input.audioset & + (1<audio))) + v4l2channel->audio++; + channel->flags |= GST_TUNER_CHANNEL_AUDIO; } - } - outptr = g_malloc(sizeof(output)); - memcpy(outptr, &output, sizeof(output)); - v4l2element->outputs = g_list_append(v4l2element->outputs, outptr); - v4l2element->output_names = g_list_append(v4l2element->output_names, outptr->name); + v4l2element->channels = + g_list_append(v4l2element->channels, + (gpointer) channel); + } + } else { + /* outputs */ + for (n=0;;n++) { + struct v4l2_output output; + GstV4l2TunerChannel *v4l2channel; + GstTunerChannel *channel; + + output.index = n; + if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, + &output) < 0) { + if (errno == EINVAL) + break; /* end of enumeration */ + else { + gst_element_error(GST_ELEMENT(v4l2element), + "Failed to get no. %d in output enumeration for %s: %s", + n, v4l2element->device, + g_strerror(errno)); + return FALSE; + } + } + + v4l2channel = g_object_new(GST_TYPE_V4L2_TUNER_CHANNEL, NULL); + channel = GST_TUNER_CHANNEL(v4l2channel); + channel->label = g_strdup(output.name); + channel->flags = GST_TUNER_CHANNEL_OUTPUT; + v4l2channel->index = n; + if (output.audioset) { + /* we take the first. We don't care for + * the others for now */ + while (!(output.audioset & + (1<audio))) + v4l2channel->audio++; + channel->flags |= GST_TUNER_CHANNEL_AUDIO; + } + + v4l2element->channels = + g_list_append(v4l2element->channels, + (gpointer) channel); + } } /* norms... */ for (n=0;;n++) { - struct v4l2_standard standard, *stdptr; + struct v4l2_standard standard; + GstV4l2TunerNorm *v4l2norm; + GstTunerNorm *norm; + standard.index = n; if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { if (errno == EINVAL) @@ -130,21 +204,28 @@ gst_v4l2_fill_lists (GstV4l2Element *v4l2element) return FALSE; } } - stdptr = g_malloc(sizeof(standard)); - memcpy(stdptr, &standard, sizeof(standard)); - v4l2element->norms = g_list_append(v4l2element->norms, stdptr); - v4l2element->norm_names = g_list_append(v4l2element->norm_names, stdptr->name); + v4l2norm = g_object_new(GST_TYPE_V4L2_TUNER_NORM, NULL); + norm = GST_TUNER_NORM (v4l2norm); + norm->label = g_strdup(standard.name); + norm->fps = (gfloat) standard.frameperiod.denominator / + standard.frameperiod.numerator; + v4l2norm->index = standard.id; + + v4l2element->norms = g_list_append(v4l2element->norms, + (gpointer) norm); } /* and lastly, controls+menus (if appropriate) */ for (n=V4L2_CID_BASE;;n++) { - struct v4l2_queryctrl control, *ctrlptr; - GList *menus = NULL; - GParamSpec *spec = NULL; + struct v4l2_queryctrl control; + GstV4l2ColorBalanceChannel *v4l2channel; + GstColorBalanceChannel *channel; + /* hacky... */ if (n == V4L2_CID_LASTP1) n = V4L2_CID_PRIVATE_BASE; + control.id = n; if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) { if (errno == EINVAL) { @@ -161,9 +242,39 @@ gst_v4l2_fill_lists (GstV4l2Element *v4l2element) } if (control.flags & V4L2_CTRL_FLAG_DISABLED) continue; - ctrlptr = g_malloc(sizeof(control)); - memcpy(ctrlptr, &control, sizeof(control)); - v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr); + + switch (n) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + case V4L2_CID_BLACK_LEVEL: + case V4L2_CID_AUTO_WHITE_BALANCE: + case V4L2_CID_DO_WHITE_BALANCE: + case V4L2_CID_RED_BALANCE: + case V4L2_CID_BLUE_BALANCE: + case V4L2_CID_GAMMA: + case V4L2_CID_EXPOSURE: + case V4L2_CID_AUTOGAIN: + case V4L2_CID_GAIN: + /* we only handle these for now */ + break; + default: + DEBUG("ControlID %s (%d) unhandled, FIXME", + control.name, n); + control.id++; + break; + } + if (n != control.id) + continue; + + v4l2channel = g_object_new(GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, + NULL); + channel = GST_COLOR_BALANCE_CHANNEL(v4l2channel); + channel->label = g_strdup(control.name); + v4l2channel->index = n; + +#if 0 if (control.type == V4L2_CTRL_TYPE_MENU) { struct v4l2_querymenu menu, *mptr; int i; @@ -186,30 +297,25 @@ gst_v4l2_fill_lists (GstV4l2Element *v4l2element) } } v4l2element->menus = g_list_append(v4l2element->menus, menus); +#endif switch (control.type) { case V4L2_CTRL_TYPE_INTEGER: - spec = g_param_spec_int(ctrlptr->name, ctrlptr->name, - ctrlptr->name, ctrlptr->minimum, ctrlptr->maximum, - ctrlptr->default_value, G_PARAM_READWRITE); + channel->min_value = control.minimum; + channel->max_value = control.maximum; break; case V4L2_CTRL_TYPE_BOOLEAN: - spec = g_param_spec_boolean(ctrlptr->name, ctrlptr->name, - ctrlptr->name, ctrlptr->default_value, - G_PARAM_READWRITE); + channel->min_value = FALSE; + channel->max_value = TRUE; break; - case V4L2_CTRL_TYPE_MENU: - /* hacky... we abuse pointer for 'no value' */ - spec = g_param_spec_pointer(ctrlptr->name, ctrlptr->name, - ctrlptr->name, G_PARAM_WRITABLE); - break; - case V4L2_CTRL_TYPE_BUTTON: - /* help?!? */ - spec = NULL; + default: + channel->min_value = + channel->max_value = 0; break; } - v4l2element->control_specs = g_list_append(v4l2element->control_specs, spec); + v4l2element->colors = g_list_append(v4l2element->colors, + (gpointer) channel); } return TRUE; @@ -221,48 +327,17 @@ gst_v4l2_empty_lists (GstV4l2Element *v4l2element) { DEBUG("deleting enumerations"); - /* empty lists */ - while (g_list_length(v4l2element->inputs) > 0) { - gpointer data = g_list_nth_data(v4l2element->inputs, 0); - v4l2element->inputs = g_list_remove(v4l2element->inputs, data); - g_free(data); - } - g_list_free(v4l2element->input_names); - v4l2element->input_names = NULL; - while (g_list_length(v4l2element->outputs) > 0) { - gpointer data = g_list_nth_data(v4l2element->outputs, 0); - v4l2element->outputs = g_list_remove(v4l2element->outputs, data); - g_free(data); - } - g_list_free(v4l2element->output_names); - v4l2element->output_names = NULL; - while (g_list_length(v4l2element->norms) > 0) { - gpointer data = g_list_nth_data(v4l2element->norms, 0); - v4l2element->norms = g_list_remove(v4l2element->norms, data); - g_free(data); - } - g_list_free(v4l2element->norm_names); - v4l2element->norm_names = NULL; - while (g_list_length(v4l2element->controls) > 0) { - gpointer data = g_list_nth_data(v4l2element->controls, 0); - v4l2element->controls = g_list_remove(v4l2element->controls, data); - g_free(data); - } - v4l2element->menus = g_list_remove_all(v4l2element->menus, NULL); - while (g_list_length(v4l2element->menus) > 0) { - GList *items = (GList *) g_list_nth_data(v4l2element->menus, 0); - v4l2element->inputs = g_list_remove(v4l2element->inputs, items); - while (g_list_length(items) > 0) { - gpointer data = g_list_nth_data(v4l2element->menus, 0); - items = g_list_remove(items, data); - g_free(data); - } - } - while (g_list_length(v4l2element->control_specs) > 0) { - gpointer data = g_list_nth_data(v4l2element->control_specs, 0); - v4l2element->control_specs = g_list_remove(v4l2element->control_specs, data); - g_param_spec_unref(G_PARAM_SPEC(data)); - } + g_list_foreach (v4l2element->channels, (GFunc) g_object_unref, NULL); + g_list_free (v4l2element->channels); + v4l2element->channels = NULL; + + g_list_foreach (v4l2element->norms, (GFunc) g_object_unref, NULL); + g_list_free (v4l2element->norms); + v4l2element->norms = NULL; + + g_list_foreach (v4l2element->colors, (GFunc) g_object_unref, NULL); + g_list_free (v4l2element->colors); + v4l2element->colors = NULL; } @@ -351,34 +426,19 @@ gst_v4l2_close (GstV4l2Element *v4l2element) gboolean gst_v4l2_get_norm (GstV4l2Element *v4l2element, - gint *norm) + v4l2_std_id *norm) { - v4l2_std_id std_id; - gint n; - DEBUG("getting norm"); GST_V4L2_CHECK_OPEN(v4l2element); - if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &std_id) < 0) { + if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, norm) < 0) { gst_element_error(GST_ELEMENT(v4l2element), "Failed to get the current norm for device %s: %s", v4l2element->device, g_strerror(errno)); return FALSE; } - /* try to find out what norm number this actually is */ - for (n=0;nnorms);n++) { - struct v4l2_standard *stdptr = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, n); - if (stdptr->id == std_id) { - *norm = n; - return TRUE; - } - } - - gst_element_error(GST_ELEMENT(v4l2element), - "Failed to find norm '%llu' in our list of available norms for device %s", - std_id, v4l2element->device); - return FALSE; + return TRUE; } @@ -390,27 +450,16 @@ gst_v4l2_get_norm (GstV4l2Element *v4l2element, gboolean gst_v4l2_set_norm (GstV4l2Element *v4l2element, - gint norm) + v4l2_std_id norm) { - struct v4l2_standard *standard; - - DEBUG("trying to set norm to %d", norm); + DEBUG("trying to set norm to %llx", norm); GST_V4L2_CHECK_OPEN(v4l2element); GST_V4L2_CHECK_NOT_ACTIVE(v4l2element); - if (norm < 0 || norm >= g_list_length(v4l2element->norms)) { + if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &norm) < 0) { gst_element_error(GST_ELEMENT(v4l2element), - "Invalid norm number %d (%d-%d)", - norm, 0, g_list_length(v4l2element->norms)); - return FALSE; - } - - standard = (struct v4l2_standard *) g_list_nth_data(v4l2element->norms, norm); - - if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->id) < 0) { - gst_element_error(GST_ELEMENT(v4l2element), - "Failed to set norm '%s' (%llu) for device %s: %s", - standard->name, standard->id, v4l2element->device, g_strerror(errno)); + "Failed to set norm 0x%llx for device %s: %s", + norm, v4l2element->device, g_strerror(errno)); return FALSE; } @@ -460,13 +509,6 @@ gst_v4l2_set_input (GstV4l2Element *v4l2element, GST_V4L2_CHECK_OPEN(v4l2element); GST_V4L2_CHECK_NOT_ACTIVE(v4l2element); - if (input < 0 || input >= g_list_length(v4l2element->inputs)) { - gst_element_error(GST_ELEMENT(v4l2element), - "Invalid input number %d (%d-%d)", - input, 0, g_list_length(v4l2element->inputs)); - return FALSE; - } - if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) { gst_element_error(GST_ELEMENT(v4l2element), "Failed to set input %d on device %s: %s", @@ -520,13 +562,6 @@ gst_v4l2_set_output (GstV4l2Element *v4l2element, GST_V4L2_CHECK_OPEN(v4l2element); GST_V4L2_CHECK_NOT_ACTIVE(v4l2element); - if (output < 0 || output >= g_list_length(v4l2element->outputs)) { - gst_element_error(GST_ELEMENT(v4l2element), - "Invalid output number %d (%d-%d)", - output, 0, g_list_length(v4l2element->outputs)); - return FALSE; - } - if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) { gst_element_error(GST_ELEMENT(v4l2element), "Failed to set output %d on device %s: %s", @@ -538,36 +573,6 @@ gst_v4l2_set_output (GstV4l2Element *v4l2element, } -/****************************************************** - * gst_v4l2_has_tuner(): - * Check whether the device has a tuner - * return value: TRUE if it has a tuner, else FALSE - ******************************************************/ - -gint -gst_v4l2_has_tuner (GstV4l2Element *v4l2element, - gint *tuner_num) -{ - gint input_num; - struct v4l2_input *input; - - DEBUG("detecting whether device has a tuner"); - GST_V4L2_CHECK_OPEN(v4l2element); - - if (!gst_v4l2_get_input(v4l2element, &input_num)) - return FALSE; - - input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num); - - if (input->type == V4L2_INPUT_TYPE_TUNER && - v4l2element->vcap.capabilities & V4L2_CAP_TUNER) { - *tuner_num = input->tuner; - return TRUE; - } - return FALSE; -} - - /****************************************************** * gst_v4l2_get_frequency(): * get the current frequency @@ -576,6 +581,7 @@ gst_v4l2_has_tuner (GstV4l2Element *v4l2element, gboolean gst_v4l2_get_frequency (GstV4l2Element *v4l2element, + gint tunernum, gulong *frequency) { struct v4l2_frequency freq; @@ -583,11 +589,7 @@ gst_v4l2_get_frequency (GstV4l2Element *v4l2element, DEBUG("getting current tuner frequency"); GST_V4L2_CHECK_OPEN(v4l2element); - if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner)) - return FALSE; - - freq.type = 0; - + freq.tuner = tunernum; if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) { gst_element_error(GST_ELEMENT(v4l2element), "Failed to get current tuner frequency for device %s: %s", @@ -609,6 +611,7 @@ gst_v4l2_get_frequency (GstV4l2Element *v4l2element, gboolean gst_v4l2_set_frequency (GstV4l2Element *v4l2element, + gint tunernum, gulong frequency) { struct v4l2_frequency freq; @@ -617,13 +620,12 @@ gst_v4l2_set_frequency (GstV4l2Element *v4l2element, GST_V4L2_CHECK_OPEN(v4l2element); GST_V4L2_CHECK_NOT_ACTIVE(v4l2element); - if (!gst_v4l2_has_tuner(v4l2element, &freq.tuner)) - return FALSE; - + freq.tuner = tunernum; + /* fill in type - ignore error */ + ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq); freq.frequency = frequency; - freq.type = 0; - if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) { + if (ioctl(v4l2element->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) { gst_element_error(GST_ELEMENT(v4l2element), "Failed to set tuner frequency to %lu for device %s: %s", frequency, v4l2element->device, g_strerror(errno)); @@ -642,6 +644,7 @@ gst_v4l2_set_frequency (GstV4l2Element *v4l2element, gboolean gst_v4l2_signal_strength (GstV4l2Element *v4l2element, + gint tunernum, gulong *signal_strength) { struct v4l2_tuner tuner; @@ -649,6 +652,7 @@ gst_v4l2_signal_strength (GstV4l2Element *v4l2element, DEBUG("trying to get signal strength"); GST_V4L2_CHECK_OPEN(v4l2element); + tuner.index = tunernum; if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) { gst_element_error(GST_ELEMENT(v4l2element), "Failed to get signal strength for device %s: %s", @@ -662,51 +666,6 @@ gst_v4l2_signal_strength (GstV4l2Element *v4l2element, } -/****************************************************** - * gst_v4l2_has_audio(): - * Check whether the device has audio capabilities - * return value: TRUE if it has a tuner, else FALSE - ******************************************************/ - -gboolean -gst_v4l2_has_audio (GstV4l2Element *v4l2element) -{ - gint input_num; - struct v4l2_input *input; - - DEBUG("detecting whether device has audio"); - GST_V4L2_CHECK_OPEN(v4l2element); - - if (!gst_v4l2_get_input(v4l2element, &input_num)) - return FALSE; - - input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num); - - return (input->audioset != 0); -} - - -/****************************************************** - * gst_v4l2_control_name_to_num(): - * convert name to num (-1 if nothing) - ******************************************************/ - -static gint -gst_v4l2_control_name_to_num (GstV4l2Element *v4l2element, - const gchar *name) -{ - GList *item; - - for (item = v4l2element->controls; item != NULL; item = item->next) { - struct v4l2_queryctrl *ctrl = item->data; - if (!strcmp(ctrl->name, name)) - return ctrl->id; - } - - return -1; -} - - /****************************************************** * gst_v4l2_get_attribute(): * try to get the value of one specific attribute @@ -714,35 +673,22 @@ gst_v4l2_control_name_to_num (GstV4l2Element *v4l2element, ******************************************************/ gboolean -gst_v4l2_get_attribute (GstElement *element, - const gchar *name, - int *value) +gst_v4l2_get_attribute (GstV4l2Element *v4l2element, + int attribute_num, + int *value) { struct v4l2_control control; - GstV4l2Element *v4l2element; - gint attribute_num = -1; - g_return_val_if_fail(element != NULL && name != NULL && value != NULL, FALSE); - g_return_val_if_fail(GST_IS_V4L2ELEMENT(element), FALSE); - v4l2element = GST_V4L2ELEMENT(element); - - DEBUG("getting value of attribute %d", attribute_num); GST_V4L2_CHECK_OPEN(v4l2element); - attribute_num = gst_v4l2_control_name_to_num(v4l2element, name); - - if (attribute_num < 0) { - gst_element_error(GST_ELEMENT(v4l2element), - "Invalid control %s", name); - return FALSE; - } + DEBUG("getting value of attribute %d", attribute_num); control.id = attribute_num; if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) { gst_element_error(GST_ELEMENT(v4l2element), - "Failed to get value for control %s (%d) on device %s: %s", - name, attribute_num, v4l2element->device, g_strerror(errno)); + "Failed to get value for control %d on device %s: %s", + attribute_num, v4l2element->device, g_strerror(errno)); return FALSE; } @@ -759,36 +705,23 @@ gst_v4l2_get_attribute (GstElement *element, ******************************************************/ gboolean -gst_v4l2_set_attribute (GstElement *element, - const gchar *name, - const int value) +gst_v4l2_set_attribute (GstV4l2Element *v4l2element, + int attribute_num, + const int value) { struct v4l2_control control; - GstV4l2Element *v4l2element; - gint attribute_num = -1; - g_return_val_if_fail(element != NULL && name != NULL, FALSE); - g_return_val_if_fail(GST_IS_V4L2ELEMENT(element), FALSE); - v4l2element = GST_V4L2ELEMENT(element); - - DEBUG("setting value of attribute %d to %d", attribute_num, value); GST_V4L2_CHECK_OPEN(v4l2element); - attribute_num = gst_v4l2_control_name_to_num(v4l2element, name); - - if (attribute_num < 0) { - gst_element_error(GST_ELEMENT(v4l2element), - "Invalid control %s", name); - return FALSE; - } + DEBUG("setting value of attribute %d to %d", attribute_num, value); control.id = attribute_num; control.value = value; if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) { gst_element_error(GST_ELEMENT(v4l2element), - "Failed to set value %d for control %s (%d) on device %s: %s", - value, name, attribute_num, v4l2element->device, g_strerror(errno)); + "Failed to set value %d for control %d on device %s: %s", + value, attribute_num, v4l2element->device, g_strerror(errno)); return FALSE; } diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h index e03c7abe51..a999af8e8d 100644 --- a/sys/v4l2/v4l2_calls.h +++ b/sys/v4l2/v4l2_calls.h @@ -86,9 +86,9 @@ gboolean gst_v4l2_close (GstV4l2Element *v4l2element); /* norm/input/output */ gboolean gst_v4l2_get_norm (GstV4l2Element *v4l2element, - gint *norm); + v4l2_std_id *norm); gboolean gst_v4l2_set_norm (GstV4l2Element *v4l2element, - gint norm); + v4l2_std_id norm); gboolean gst_v4l2_get_input (GstV4l2Element *v4l2element, gint *input); gboolean gst_v4l2_set_input (GstV4l2Element *v4l2element, @@ -99,27 +99,26 @@ gboolean gst_v4l2_set_output (GstV4l2Element *v4l2element, gint output); /* frequency control */ -gboolean gst_v4l2_has_tuner (GstV4l2Element *v4l2element, - gint *tuner_num); gboolean gst_v4l2_get_frequency (GstV4l2Element *v4l2element, + gint tunernum, gulong *frequency); gboolean gst_v4l2_set_frequency (GstV4l2Element *v4l2element, - gulong frequency); + gint tunernum, + gulong frequency); gboolean gst_v4l2_signal_strength (GstV4l2Element *v4l2element, - gulong *signal_strength); + gint tunernum, + gulong *signal); /* attribute control */ -gboolean gst_v4l2_has_audio (GstV4l2Element *v4l2element); -gboolean gst_v4l2_get_attribute (GstElement *element, - const char *attribute, +gboolean gst_v4l2_get_attribute (GstV4l2Element *v4l2element, + int attribute, int *value); -gboolean gst_v4l2_set_attribute (GstElement *element, - const char *attribute, +gboolean gst_v4l2_set_attribute (GstV4l2Element *v4l2element, + int attribute, const int value); /* overlay */ -gboolean gst_v4l2_set_display (GstV4l2Element *v4l2element, - const gchar *display); +gboolean gst_v4l2_set_display (GstV4l2Element *v4l2element); gboolean gst_v4l2_set_window (GstElement *element, gint x, gint y, gint w, gint h,