diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | sys/v4l2/Makefile.am | 4 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2.c | 3 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2colorbalance.c | 55 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2colorbalance.h | 49 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2element.c | 572 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2element.h | 125 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.c | 519 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.h | 211 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.c | 196 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.h | 12 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2tuner.c | 294 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2tuner.h | 136 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2xoverlay.c | 107 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2xoverlay.h | 36 | ||||
-rw-r--r-- | sys/v4l2/v4l2_calls.c | 404 | ||||
-rw-r--r-- | sys/v4l2/v4l2_calls.h | 80 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.c | 125 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.h | 5 |
19 files changed, 1570 insertions, 1385 deletions
@@ -1,3 +1,25 @@ +2006-05-11 Edgard Lima <edgard.lima@indt.org.br> + + * sys/v4l2/Makefile.am: + * sys/v4l2/gstv4l2.c: + * sys/v4l2/gstv4l2colorbalance.c: + * sys/v4l2/gstv4l2colorbalance.h: + * sys/v4l2/gstv4l2element.c: + * sys/v4l2/gstv4l2element.h: + * sys/v4l2/gstv4l2object.c: + * sys/v4l2/gstv4l2object.h: + * sys/v4l2/gstv4l2src.c: + * sys/v4l2/gstv4l2src.h: + * sys/v4l2/gstv4l2tuner.c: + * sys/v4l2/gstv4l2tuner.h: + * sys/v4l2/gstv4l2xoverlay.c: + * sys/v4l2/gstv4l2xoverlay.h: + * sys/v4l2/v4l2_calls.c: + * sys/v4l2/v4l2_calls.h: + * sys/v4l2/v4l2src_calls.c: + * sys/v4l2/v4l2src_calls.h: + Changes proposed by Wingo in bug #338818. + 2006-05-11 Wim Taymans <wim@fluendo.com> * gst/qtdemux/qtdemux.c: (qtdemux_parse), (qtdemux_parse_trak), diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am index 547e0687..b3f58816 100644 --- a/sys/v4l2/Makefile.am +++ b/sys/v4l2/Makefile.am @@ -10,7 +10,7 @@ endif libgstvideo4linux2_la_SOURCES = gstv4l2.c \ gstv4l2colorbalance.c \ - gstv4l2element.c \ + gstv4l2object.c \ gstv4l2src.c \ gstv4l2tuner.c \ v4l2_calls.c \ @@ -30,7 +30,7 @@ libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ $(xv_libs) \ -lgstinterfaces-$(GST_MAJORMINOR) -noinst_HEADERS = gstv4l2element.h v4l2_calls.h \ +noinst_HEADERS = gstv4l2object.h v4l2_calls.h \ gstv4l2src.h v4l2src_calls.h \ gstv4l2tuner.h gstv4l2xoverlay.h \ gstv4l2colorbalance.h diff --git a/sys/v4l2/gstv4l2.c b/sys/v4l2/gstv4l2.c index 513899ed..11b33549 100644 --- a/sys/v4l2/gstv4l2.c +++ b/sys/v4l2/gstv4l2.c @@ -3,6 +3,7 @@ * gstv4l2.c: plugin for v4l2 elements * * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2001-2002 Edgard Lima <edgard.lima@indt.org.br> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,7 +29,7 @@ #include <gst/gst.h> -#include "gstv4l2element.h" +#include "gstv4l2object.h" #include "gstv4l2src.h" /* #include "gstv4l2jpegsrc.h" */ /* #include "gstv4l2mjpegsrc.h" */ diff --git a/sys/v4l2/gstv4l2colorbalance.c b/sys/v4l2/gstv4l2colorbalance.c index 7a0378f7..d8bfd35e 100644 --- a/sys/v4l2/gstv4l2colorbalance.c +++ b/sys/v4l2/gstv4l2colorbalance.c @@ -1,5 +1,6 @@ /* GStreamer Color Balance interface implementation * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> * * gstv4l2colorbalance.c: color balance interface implementation for V4L2 * @@ -25,15 +26,7 @@ #include <gst/gst.h> #include "gstv4l2colorbalance.h" -#include "gstv4l2element.h" - -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); - +#include "gstv4l2object.h" GST_BOILERPLATE (GstV4l2ColorBalanceChannel, gst_v4l2_color_balance_channel, @@ -59,67 +52,55 @@ gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel, channel->id = (guint32) - 1; } -void -gst_v4l2_color_balance_interface_init (GstColorBalanceClass * klass) -{ - GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; - - /* 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 G_GNUC_UNUSED gboolean -gst_v4l2_color_balance_contains_channel (GstV4l2Element * v4l2element, +gst_v4l2_color_balance_contains_channel (GstV4l2Object * v4l2object, GstV4l2ColorBalanceChannel * v4l2channel) { const GList *item; - for (item = v4l2element->colors; item != NULL; item = item->next) + for (item = v4l2object->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) +const GList * +gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object) { - return GST_V4L2ELEMENT (balance)->colors; + return v4l2object->colors; } -static void -gst_v4l2_color_balance_set_value (GstColorBalance * balance, +void +gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object, 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, + g_return_if_fail (GST_V4L2_IS_OPEN (v4l2object)); + g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object, v4l2channel)); - gst_v4l2_set_attribute (v4l2element, v4l2channel->id, value); + gst_v4l2_set_attribute (v4l2object, v4l2channel->id, value); } -static gint -gst_v4l2_color_balance_get_value (GstColorBalance * balance, +gint +gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object, 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, + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0); + g_return_val_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object, v4l2channel), 0); - if (!gst_v4l2_get_attribute (v4l2element, v4l2channel->id, &value)) + if (!gst_v4l2_get_attribute (v4l2object, v4l2channel->id, &value)) return 0; return value; diff --git a/sys/v4l2/gstv4l2colorbalance.h b/sys/v4l2/gstv4l2colorbalance.h index 358270fc..761360fa 100644 --- a/sys/v4l2/gstv4l2colorbalance.h +++ b/sys/v4l2/gstv4l2colorbalance.h @@ -1,5 +1,6 @@ /* G-Streamer generic V4L2 element - Color Balance interface implementation * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> * * gstv4l2colorbalance.h: color balance interface implementation for V4L2 * @@ -53,6 +54,52 @@ typedef struct _GstV4l2ColorBalanceChannelClass { GType gst_v4l2_color_balance_channel_get_type (void); -void gst_v4l2_color_balance_interface_init (GstColorBalanceClass *klass); +extern const GList * +gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object); + +extern void +gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object, + GstColorBalanceChannel * channel, gint value); + +extern gint +gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object, + GstColorBalanceChannel * channel); + +#define GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS(Type, interface_as_function) \ + \ +static const GList * \ +interface_as_function ## _color_balance_list_channels (GstColorBalance * balance) \ +{ \ + Type *this = (Type*) balance; \ + return gst_v4l2_color_balance_list_channels(this->v4l2object); \ +} \ + \ +static void \ +interface_as_function ## _color_balance_set_value (GstColorBalance * balance, \ + GstColorBalanceChannel * channel, \ + gint value) \ +{ \ + Type *this = (Type*) balance; \ + return gst_v4l2_color_balance_set_value(this->v4l2object, channel, value); \ +} \ + \ +static gint \ +interface_as_function ## _color_balance_get_value (GstColorBalance * balance, \ + GstColorBalanceChannel * channel) \ +{ \ + Type *this = (Type*) balance; \ + return gst_v4l2_color_balance_get_value(this->v4l2object, channel); \ +} \ + \ +void \ +interface_as_function ## _color_balance_interface_init (GstColorBalanceClass * klass) \ +{ \ + GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; \ + \ + /* default virtual functions */ \ + klass->list_channels = interface_as_function ## _color_balance_list_channels; \ + klass->set_value = interface_as_function ## _color_balance_set_value; \ + klass->get_value = interface_as_function ## _color_balance_get_value; \ +} \ #endif /* __GST_V4L2_COLOR_BALANCE_H__ */ diff --git a/sys/v4l2/gstv4l2element.c b/sys/v4l2/gstv4l2element.c deleted file mode 100644 index 5bbc260e..00000000 --- a/sys/v4l2/gstv4l2element.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * GStreamer gstv4l2element.c: base class for V4L2 elements - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. This library is distributed in the hope - * that it will be useful, but WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU Library General Public License for more details. - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> - -#include <gst/interfaces/propertyprobe.h> - -#include "v4l2_calls.h" -#include "gstv4l2tuner.h" -#ifdef HAVE_XVIDEO -#include "gstv4l2xoverlay.h" -#endif -#include "gstv4l2colorbalance.h" - - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME, - PROP_FLAGS, - PROP_STD, - PROP_INPUT, - PROP_FREQUENCY -}; - - -static void gst_v4l2element_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstV4l2Element, gst_v4l2element, GstPushSrc, - GST_TYPE_PUSH_SRC, gst_v4l2element_init_interfaces); - -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 gboolean gst_v4l2element_start (GstBaseSrc * src); -static gboolean gst_v4l2element_stop (GstBaseSrc * src); - - -static gboolean -gst_v4l2_iface_supported (GstImplementsInterface * iface, GType iface_type) -{ - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (iface); - -#ifdef HAVE_XVIDEO - g_assert (iface_type == GST_TYPE_TUNER || - iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_COLOR_BALANCE); -#else - g_assert (iface_type == GST_TYPE_TUNER || - iface_type == GST_TYPE_COLOR_BALANCE); -#endif - - if (v4l2element->video_fd == -1) - return FALSE; - -#ifdef HAVE_XVIDEO - if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L2_IS_OVERLAY (v4l2element)) - return FALSE; -#endif - - return TRUE; -} - -static void -gst_v4l2_interface_init (GstImplementsInterfaceClass * klass) -{ - /* - * default virtual functions - */ - klass->supported = gst_v4l2_iface_supported; -} - -static const GList * -gst_v4l2_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - /* well, not perfect, but better than no locking at all. - * In the worst case we leak a list node, so who cares? */ - GST_CLASS_LOCK (GST_OBJECT_CLASS (klass)); - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - } - - GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass)); - - return list; -} - -static gboolean -gst_v4l2_class_probe_devices (GstV4l2ElementClass * klass, gboolean check) -{ - static gboolean init = FALSE; - static GList *devices = NULL; - - if (!init && !check) { - gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL }; - gint base, n, fd; - - while (devices) { - GList *item = devices; - gchar *device = item->data; - - devices = g_list_remove (devices, item); - g_free (device); - } - - /* - * detect /dev entries - */ - for (n = 0; n < 64; n++) { - for (base = 0; dev_base[base] != NULL; base++) { - struct stat s; - gchar *device = g_strdup_printf ("%s%d", - dev_base[base], - n); - - /* - * does the /dev/ entry exist at all? - */ - if (stat (device, &s) == 0) { - /* - * yes: is a device attached? - */ - if (S_ISCHR (s.st_mode)) { - - if ((fd = open (device, O_RDWR | O_NONBLOCK)) > 0 || errno == EBUSY) { - if (fd > 0) - close (fd); - - devices = g_list_append (devices, device); - break; - } - } - } - g_free (device); - } - } - - init = TRUE; - } - - klass->devices = devices; - - return init; -} - -static void -gst_v4l2_probe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4l2ElementClass *klass = GST_V4L2ELEMENT_GET_CLASS (probe); - - switch (prop_id) { - case PROP_DEVICE: - gst_v4l2_class_probe_devices (klass, FALSE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4l2ElementClass *klass = GST_V4L2ELEMENT_GET_CLASS (probe); - gboolean ret = FALSE; - - switch (prop_id) { - case PROP_DEVICE: - ret = !gst_v4l2_class_probe_devices (klass, TRUE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_v4l2_class_list_devices (GstV4l2ElementClass * klass) -{ - GValueArray *array; - GValue value = { 0 }; - GList *item; - - if (!klass->devices) - return NULL; - - array = g_value_array_new (g_list_length (klass->devices)); - item = klass->devices; - g_value_init (&value, G_TYPE_STRING); - while (item) { - gchar *device = item->data; - - g_value_set_string (&value, device); - g_value_array_append (array, &value); - - item = item->next; - } - g_value_unset (&value); - - return array; -} - -static GValueArray * -gst_v4l2_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4l2ElementClass *klass = GST_V4L2ELEMENT_GET_CLASS (probe); - GValueArray *array = NULL; - - switch (prop_id) { - case PROP_DEVICE: - array = gst_v4l2_class_list_devices (klass); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return array; -} - -static void -gst_v4l2_property_probe_interface_init (GstPropertyProbeInterface * iface) -{ - iface->get_properties = gst_v4l2_probe_get_properties; - iface->probe_property = gst_v4l2_probe_probe_property; - iface->needs_probe = gst_v4l2_probe_needs_probe; - iface->get_values = gst_v4l2_probe_get_values; -} - -#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 supports video capture"}, - {V4L2_CAP_VIDEO_OUTPUT, "PLAYBACK", - "Device supports video playback"}, - {V4L2_CAP_VIDEO_OVERLAY, "OVERLAY", - "Device supports video overlay"}, - - {V4L2_CAP_VBI_CAPTURE, "VBI_CAPTURE", - "Device supports the VBI capture"}, - {V4L2_CAP_VBI_OUTPUT, "VBI_OUTPUT", - "Device supports the VBI output"}, - - {V4L2_CAP_TUNER, "TUNER", - "Device has a tuner or modulator"}, - {V4L2_CAP_AUDIO, "AUDIO", - "Device has audio inputs or outputs"}, - - {0, NULL, NULL} - }; - - v4l2_device_type = - g_flags_register_static ("GstV4l2DeviceTypeFlags", values); - } - - return v4l2_device_type; -} - -static void -gst_v4l2element_init_interfaces (GType type) -{ - 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, - }; -#ifdef HAVE_XVIDEO - static const GInterfaceInfo v4l2_xoverlay_info = { - (GInterfaceInitFunc) gst_v4l2_xoverlay_interface_init, - NULL, - NULL, - }; -#endif - static const GInterfaceInfo v4l2_colorbalance_info = { - (GInterfaceInitFunc) gst_v4l2_color_balance_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo v4l2_propertyprobe_info = { - (GInterfaceInitFunc) gst_v4l2_property_probe_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, - GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info); - g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info); -#ifdef HAVE_XVIDEO - g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info); -#endif - g_type_add_interface_static (type, - GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info); - g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, - &v4l2_propertyprobe_info); -} - - -static void -gst_v4l2element_base_init (gpointer g_class) -{ - GstV4l2ElementClass *klass = GST_V4L2ELEMENT_CLASS (g_class); - - klass->devices = NULL; -} - -static void -gst_v4l2element_class_init (GstV4l2ElementClass * klass) -{ - GObjectClass *gobject_class; - GstBaseSrcClass *basesrc_class; - - gobject_class = (GObjectClass *) klass; - basesrc_class = (GstBaseSrcClass *) klass; - - gobject_class->set_property = gst_v4l2element_set_property; - gobject_class->get_property = gst_v4l2element_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE, - g_param_spec_string ("device", - "Device", "Device location", NULL, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_DEVICE_NAME, - 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), PROP_FLAGS, - g_param_spec_flags ("flags", "Flags", - "Device type flags", - GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE)); - g_object_class_install_property (gobject_class, PROP_STD, - g_param_spec_string ("std", "std", - "standard (norm) to use", NULL, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_INPUT, - g_param_spec_string ("input", - "input", - "input/output (channel) to switch to", NULL, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_FREQUENCY, - g_param_spec_ulong ("frequency", - "frequency", - "frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE)); - - basesrc_class->start = gst_v4l2element_start; - basesrc_class->stop = gst_v4l2element_stop; - - gobject_class->dispose = gst_v4l2element_dispose; -} - - -static void -gst_v4l2element_init (GstV4l2Element * v4l2element, GstV4l2ElementClass * klass) -{ - /* - * some default values - */ - v4l2element->video_fd = -1; - v4l2element->buffer = NULL; - v4l2element->videodev = g_strdup ("/dev/video0"); - - v4l2element->stds = NULL; - v4l2element->inputs = NULL; - v4l2element->colors = NULL; - - v4l2element->xwindow_id = 0; -} - - -static void -gst_v4l2element_dispose (GObject * object) -{ - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (object); - - if (v4l2element->videodev) { - g_free (v4l2element->videodev); - v4l2element->videodev = NULL; - } - - if (((GObjectClass *) parent_class)->dispose) - ((GObjectClass *) parent_class)->dispose (object); -} - - -static void -gst_v4l2element_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE: - if (v4l2element->videodev) - g_free (v4l2element->videodev); - v4l2element->videodev = g_strdup (g_value_get_string (value)); - break; - case PROP_STD: - if (GST_V4L2_IS_OPEN (v4l2element)) { - GstTuner *tuner = GST_TUNER (v4l2element); - GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner, - (gchar *) - g_value_get_string (value)); - - if (norm) { - /* more generic would be gst_tuner_set_norm (tuner, norm) - without g_object_notify */ - gst_v4l2_tuner_set_norm (tuner, norm); - } - } else { - g_free (v4l2element->std); - v4l2element->std = g_value_dup_string (value); - } - break; - case PROP_INPUT: - if (GST_V4L2_IS_OPEN (v4l2element)) { - GstTuner *tuner = GST_TUNER (v4l2element); - GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner, - (gchar *) - g_value_get_string (value)); - - if (channel) { - /* more generic would be gst_tuner_set_channel (tuner, channel) - without g_object_notify */ - gst_v4l2_tuner_set_channel (tuner, channel); - } - } else { - g_free (v4l2element->input); - v4l2element->input = g_value_dup_string (value); - } - break; - case PROP_FREQUENCY: - if (GST_V4L2_IS_OPEN (v4l2element)) { - GstTuner *tuner = GST_TUNER (v4l2element); - GstTunerChannel *channel = gst_tuner_get_channel (tuner); - - if (channel && - GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { - /* more generic would be - gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value)) - without g_object_notify */ - gst_v4l2_tuner_set_frequency (tuner, channel, - g_value_get_ulong (value)); - } - } else { - v4l2element->frequency = g_value_get_ulong (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4l2element_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE: - g_value_set_string (value, v4l2element->videodev); - break; - case PROP_DEVICE_NAME: - { - gchar *new = NULL; - - if (GST_V4L2_IS_OPEN (v4l2element)) - new = (gchar *) v4l2element->vcap.card; - g_value_set_string (value, new); - break; - } - case PROP_FLAGS: - { - guint flags = 0; - - if (GST_V4L2_IS_OPEN (v4l2element)) { - flags |= v4l2element->vcap.capabilities & - (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_TUNER | V4L2_CAP_AUDIO); - if (v4l2element->vcap.capabilities & V4L2_CAP_AUDIO) - flags |= V4L2_FBUF_CAP_CHROMAKEY; - } - g_value_set_flags (value, flags); - break; - } - case PROP_STD: - g_value_set_string (value, v4l2element->std); - break; - case PROP_INPUT: - g_value_set_string (value, v4l2element->input); - break; - case PROP_FREQUENCY: - g_value_set_ulong (value, v4l2element->frequency); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_v4l2element_start (GstBaseSrc * src) -{ - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (src); - - if (!gst_v4l2_open (v4l2element)) - return FALSE; - -#ifdef HAVE_XVIDEO - gst_v4l2_xoverlay_start (v4l2element); -#endif - - return TRUE; -} - -static gboolean -gst_v4l2element_stop (GstBaseSrc * src) -{ - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (src); - -#ifdef HAVE_XVIDEO - gst_v4l2_xoverlay_stop (v4l2element); -#endif - - if (!gst_v4l2_close (v4l2element)) - return FALSE; - - return TRUE; -} diff --git a/sys/v4l2/gstv4l2element.h b/sys/v4l2/gstv4l2element.h deleted file mode 100644 index b8667695..00000000 --- a/sys/v4l2/gstv4l2element.h +++ /dev/null @@ -1,125 +0,0 @@ -/* GStreamer - * - * gstv4l2element.h: base class for V4L2 elements - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GST_V4L2ELEMENT_H__ -#define __GST_V4L2ELEMENT_H__ - -/* 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 - * ourselves. In all their intelligence, these people decided to fix - * this in the next version (video4linux2) in such a cool way that it - * breaks all compilations of old stuff... - * The real problem is actually that linux/time.h doesn't use proper - * macro checks before defining types like struct timeval. The proper - * fix here is to either fuck the kernel header (which is what we do - * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it - * upstream, which I'll consider doing later on. If you get compiler - * errors here, check your linux/time.h && sys/time.h header setup. - */ -#include <sys/types.h> -#include <linux/types.h> -#define _LINUX_TIME_H -#define __user -#include <linux/videodev2.h> - -#include <gst/gst.h> -#include <gst/base/gstpushsrc.h> - - -G_BEGIN_DECLS - -#define GST_TYPE_V4L2ELEMENT \ - (gst_v4l2element_get_type()) -#define GST_V4L2ELEMENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2ELEMENT,GstV4l2Element)) -#define GST_V4L2ELEMENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2ELEMENT,GstV4l2ElementClass)) -#define GST_IS_V4L2ELEMENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2ELEMENT)) -#define GST_IS_V4L2ELEMENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2ELEMENT)) -#define GST_V4L2ELEMENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_V4L2ELEMENT, GstV4l2ElementClass)) - -typedef struct _GstV4l2Element GstV4l2Element; -typedef struct _GstV4l2ElementClass GstV4l2ElementClass; -typedef struct _GstV4l2Xv GstV4l2Xv; - -struct _GstV4l2Element { - GstPushSrc 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 v4l2_capability vcap; - - /* the video device's window properties */ - struct v4l2_window vwin; - - /* some more info about the current input's capabilities */ - struct v4l2_input vinput; - - /* lists... */ - GList *colors; - GList *stds; - GList *inputs; - - /* properties */ - gchar *std; - gchar *input; - gulong frequency; - - - /* X-overlay */ - GstV4l2Xv *xv; - gulong xwindow_id; -}; - -struct _GstV4l2ElementClass { - GstPushSrcClass parent_class; - - /* probed devices */ - GList *devices; - - /* actions */ - gboolean (*get_attribute) (GstElement *element, - const gchar *attr_name, - int *value); - gboolean (*set_attribute) (GstElement *element, - const gchar *attr_name, - const int value); -}; - -GType gst_v4l2element_get_type(void); - - -G_END_DECLS - -#endif /* __GST_V4L2ELEMENT_H__ */ diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c new file mode 100644 index 00000000..941f9a6a --- /dev/null +++ b/sys/v4l2/gstv4l2object.c @@ -0,0 +1,519 @@ +/* + * GStreamer gstv4l2object.c: base class for V4L2 elements + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. This library is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU Library General Public License for more details. + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#include "v4l2_calls.h" +#include "gstv4l2tuner.h" +#ifdef HAVE_XVIDEO +#include "gstv4l2xoverlay.h" +#endif +#include "gstv4l2colorbalance.h" + +OPEN_V4L2OBJECT_PROPS CLOSE_V4L2OBJECT_PROPS const GList * +gst_v4l2_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *list = NULL; + + /* well, not perfect, but better than no locking at all. + * In the worst case we leak a list node, so who cares? */ + GST_CLASS_LOCK (GST_OBJECT_CLASS (klass)); + + if (!list) { + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); + } + + GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass)); + + return list; +} + +static gboolean +gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check, + GList ** klass_devices) +{ + static gboolean init = FALSE; + static GList *devices = NULL; + + if (!init && !check) { + gchar *dev_base[] = { "/dev/video", "/dev/v4l2/video", NULL }; + gint base, n, fd; + + while (devices) { + GList *item = devices; + gchar *device = item->data; + + devices = g_list_remove (devices, item); + g_free (device); + } + + /* + * detect /dev entries + */ + for (n = 0; n < 64; n++) { + for (base = 0; dev_base[base] != NULL; base++) { + struct stat s; + gchar *device = g_strdup_printf ("%s%d", + dev_base[base], + n); + + /* + * does the /dev/ entry exist at all? + */ + if (stat (device, &s) == 0) { + /* + * yes: is a device attached? + */ + if (S_ISCHR (s.st_mode)) { + + if ((fd = open (device, O_RDWR | O_NONBLOCK)) > 0 || errno == EBUSY) { + if (fd > 0) + close (fd); + + devices = g_list_append (devices, device); + break; + } + } + } + g_free (device); + } + } + + init = TRUE; + } + + *klass_devices = devices; + + return init; +} + +void +gst_v4l2_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec, GList ** klass_devices) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + + switch (prop_id) { + case PROP_DEVICE: + gst_v4l2_class_probe_devices (klass, FALSE, klass_devices); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +gboolean +gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec, GList ** klass_devices) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + gboolean ret = FALSE; + + switch (prop_id) { + case PROP_DEVICE: + ret = !gst_v4l2_class_probe_devices (klass, TRUE, klass_devices); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return ret; + +} + +static GValueArray * +gst_v4l2_class_list_devices (GstElementClass * klass, GList ** klass_devices) +{ + GValueArray *array; + GValue value = { 0 }; + GList *item; + + if (!*klass_devices) + return NULL; + + array = g_value_array_new (g_list_length (*klass_devices)); + item = *klass_devices; + g_value_init (&value, G_TYPE_STRING); + while (item) { + gchar *device = item->data; + + g_value_set_string (&value, device); + g_value_array_append (array, &value); + + item = item->next; + } + g_value_unset (&value); + + return array; +} + +GValueArray * +gst_v4l2_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec, GList ** klass_devices) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case PROP_DEVICE: + array = gst_v4l2_class_list_devices (klass, klass_devices); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +#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 supports video capture"}, + {V4L2_CAP_VIDEO_OUTPUT, "PLAYBACK", + "Device supports video playback"}, + {V4L2_CAP_VIDEO_OVERLAY, "OVERLAY", + "Device supports video overlay"}, + + {V4L2_CAP_VBI_CAPTURE, "VBI_CAPTURE", + "Device supports the VBI capture"}, + {V4L2_CAP_VBI_OUTPUT, "VBI_OUTPUT", + "Device supports the VBI output"}, + + {V4L2_CAP_TUNER, "TUNER", + "Device has a tuner or modulator"}, + {V4L2_CAP_AUDIO, "AUDIO", + "Device has audio inputs or outputs"}, + + {0, NULL, NULL} + }; + + v4l2_device_type = + g_flags_register_static ("GstV4l2DeviceTypeFlags", values); + } + + return v4l2_device_type; +} + +void +gst_v4l2object_install_properties_helper (GObjectClass * gobject_class) +{ + + g_object_class_install_property + (G_OBJECT_CLASS (gobject_class), PROP_DEVICE, + g_param_spec_string ("device", + "Device", "Device location", NULL, G_PARAM_READWRITE)); + g_object_class_install_property + (G_OBJECT_CLASS (gobject_class), + PROP_DEVICE_NAME, + g_param_spec_string ("device_name", + "Device name", "Name of the device", NULL, G_PARAM_READABLE)); + g_object_class_install_property + (G_OBJECT_CLASS (gobject_class), PROP_FLAGS, + g_param_spec_flags ("flags", "Flags", + "Device type flags", + GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE)); + g_object_class_install_property + (gobject_class, PROP_STD, + g_param_spec_string ("std", "std", + "standard (norm) to use", NULL, G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, PROP_INPUT, + g_param_spec_string ("input", + "input", + "input/output (channel) to switch to", NULL, G_PARAM_READWRITE)); + g_object_class_install_property + (gobject_class, PROP_FREQUENCY, + g_param_spec_ulong ("frequency", + "frequency", + "frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE)); + +} + +GstV4l2Object * +gst_v4l2object_new (GstElement * element, + GstV4l2GetInOutFunction get_in_out_func, + GstV4l2SetInOutFunction set_in_out_func, + GstV4l2UpdateFpsFunction update_fps_func) +{ + + GstV4l2Object *v4l2object; + + /* + * some default values + */ + + v4l2object = g_new0 (GstV4l2Object, 1); + + v4l2object->element = element; + v4l2object->get_in_out_func = get_in_out_func; + v4l2object->set_in_out_func = set_in_out_func; + v4l2object->update_fps_func = update_fps_func; + + v4l2object->video_fd = -1; + v4l2object->buffer = NULL; + v4l2object->videodev = g_strdup ("/dev/video0"); + + v4l2object->stds = NULL; + v4l2object->inputs = NULL; + v4l2object->colors = NULL; + + v4l2object->xwindow_id = 0; + + return v4l2object; + +} + + +void +gst_v4l2object_destroy (GstV4l2Object ** v4l2object) +{ + + if (*v4l2object) { + + if ((*v4l2object)->videodev) { + g_free ((*v4l2object)->videodev); + (*v4l2object)->videodev = NULL; + } + + g_free (*v4l2object); + *v4l2object = NULL; + + } + +} + + +gboolean +gst_v4l2object_set_property_helper (GstV4l2Object * v4l2object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + + switch (prop_id) { + case PROP_DEVICE: + if (v4l2object->videodev) + g_free (v4l2object->videodev); + v4l2object->videodev = g_strdup (g_value_get_string (value)); + break; + case PROP_STD: + if (GST_V4L2_IS_OPEN (v4l2object)) { + GstTuner *tuner = GST_TUNER (v4l2object->element); + GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner, + (gchar *) + g_value_get_string (value)); + + if (norm) { + /* like gst_tuner_set_norm (tuner, norm) + without g_object_notify */ + gst_v4l2_tuner_set_norm (v4l2object, norm); + } + } else { + g_free (v4l2object->std); + v4l2object->std = g_value_dup_string (value); + } + break; + case PROP_INPUT: + if (GST_V4L2_IS_OPEN (v4l2object)) { + GstTuner *tuner = GST_TUNER (v4l2object->element); + GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner, + (gchar *) + g_value_get_string (value)); + + if (channel) { + /* like gst_tuner_set_channel (tuner, channel) + without g_object_notify */ + gst_v4l2_tuner_set_channel (v4l2object, channel); + } + } else { + g_free (v4l2object->input); + v4l2object->input = g_value_dup_string (value); + } + break; + case PROP_FREQUENCY: + if (GST_V4L2_IS_OPEN (v4l2object)) { + GstTuner *tuner = GST_TUNER (v4l2object->element); + GstTunerChannel *channel = gst_tuner_get_channel (tuner); + + if (channel && + GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + /* like + gst_tuner_set_frequency (tuner, channel, g_value_get_ulong (value)) + without g_object_notify */ + gst_v4l2_tuner_set_frequency (v4l2object, channel, + g_value_get_ulong (value)); + } + } else { + v4l2object->frequency = g_value_get_ulong (value); + } + break; + default: + return FALSE; + break; + } + + return TRUE; + +} + + +gboolean +gst_v4l2object_get_property_helper (GstV4l2Object * v4l2object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + switch (prop_id) { + case PROP_DEVICE: + g_value_set_string (value, v4l2object->videodev); + break; + case PROP_DEVICE_NAME: + { + gchar *new = NULL; + + if (GST_V4L2_IS_OPEN (v4l2object)) + new = (gchar *) v4l2object->vcap.card; + g_value_set_string (value, new); + break; + } + case PROP_FLAGS: + { + guint flags = 0; + + if (GST_V4L2_IS_OPEN (v4l2object)) { + flags |= v4l2object->vcap.capabilities & + (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_TUNER | V4L2_CAP_AUDIO); + if (v4l2object->vcap.capabilities & V4L2_CAP_AUDIO) + flags |= V4L2_FBUF_CAP_CHROMAKEY; + } + g_value_set_flags (value, flags); + break; + } + case PROP_STD: + g_value_set_string (value, v4l2object->std); + break; + case PROP_INPUT: + g_value_set_string (value, v4l2object->input); + break; + case PROP_FREQUENCY: + g_value_set_ulong (value, v4l2object->frequency); + break; + default: + return FALSE; + break; + } + + return TRUE; + +} + +static void +gst_v4l2_set_defaults (GstV4l2Object * v4l2object) +{ + GstTunerNorm *norm = NULL; + GstTunerChannel *channel = NULL; + GstTuner *tuner = GST_TUNER (v4l2object->element); + + if (v4l2object->std) + norm = gst_tuner_find_norm_by_name (tuner, v4l2object->std); + if (norm) { + gst_tuner_set_norm (tuner, norm); + } else { + norm = + GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element))); + if (norm) { + v4l2object->std = g_strdup (norm->label); + gst_tuner_norm_changed (tuner, norm); + g_object_notify (G_OBJECT (v4l2object->element), "std"); + } + } + + if (v4l2object->input) + channel = gst_tuner_find_channel_by_name (tuner, v4l2object->input); + if (channel) { + gst_tuner_set_channel (tuner, channel); + } else { + channel = + GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2object-> + element))); + v4l2object->input = g_strdup (channel->label); + gst_tuner_channel_changed (tuner, channel); + g_object_notify (G_OBJECT (v4l2object->element), "input"); + } + + if (GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { + if (v4l2object->frequency != 0) { + gst_tuner_set_frequency (tuner, channel, v4l2object->frequency); + } else { + v4l2object->frequency = gst_tuner_get_frequency (tuner, channel); + if (v4l2object->frequency == 0) { + /* guess */ + gst_tuner_set_frequency (tuner, channel, 1000); + } else { + g_object_notify (G_OBJECT (v4l2object->element), "frequency"); + } + } + } +} + + +gboolean +gst_v4l2object_start (GstV4l2Object * v4l2object) +{ + if (gst_v4l2_open (v4l2object)) + gst_v4l2_set_defaults (v4l2object); + else + return FALSE; + + +#ifdef HAVE_XVIDEO + gst_v4l2_xoverlay_start (v4l2object); +#endif + + return TRUE; +} + +gboolean +gst_v4l2object_stop (GstV4l2Object * v4l2object) +{ + +#ifdef HAVE_XVIDEO + gst_v4l2_xoverlay_stop (v4l2object); +#endif + + if (!gst_v4l2_close (v4l2object)) + return FALSE; + + return TRUE; +} diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h new file mode 100644 index 00000000..37552185 --- /dev/null +++ b/sys/v4l2/gstv4l2object.h @@ -0,0 +1,211 @@ +/* GStreamer + * + * gstv4l2object.h: base class for V4L2 elements + * + * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> + * + * 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_V4L2OBJECT_H__ +#define __GST_V4L2OBJECT_H__ + +/* 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 + * ourselves. In all their intelligence, these people decided to fix + * this in the next version (video4linux2) in such a cool way that it + * breaks all compilations of old stuff... + * The real problem is actually that linux/time.h doesn't use proper + * macro checks before defining types like struct timeval. The proper + * fix here is to either fuck the kernel header (which is what we do + * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it + * upstream, which I'll consider doing later on. If you get compiler + * errors here, check your linux/time.h && sys/time.h header setup. + */ +#include <sys/types.h> +#include <linux/types.h> +#define _LINUX_TIME_H +#define __user +#include <linux/videodev2.h> + +#include <gst/gst.h> +#include <gst/base/gstpushsrc.h> + +#include <gst/interfaces/propertyprobe.h> + +G_BEGIN_DECLS + +typedef struct _GstV4l2Object GstV4l2Object; +typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper; +typedef struct _GstV4l2Xv GstV4l2Xv; + +typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input); +typedef gboolean (*GstV4l2SetInOutFunction) (GstV4l2Object * v4l2object, gint input); +typedef gboolean (*GstV4l2UpdateFpsFunction) (GstV4l2Object * v4l2object); + +struct _GstV4l2Object { + 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 v4l2_capability vcap; + + /* the video device's window properties */ + struct v4l2_window vwin; + + /* some more info about the current input's capabilities */ + struct v4l2_input vinput; + + /* lists... */ + GList *colors; + GList *stds; + GList *inputs; + + /* properties */ + gchar *std; + gchar *input; + gulong frequency; + + + /* X-overlay */ + GstV4l2Xv *xv; + gulong xwindow_id; + + /* funcs */ + GstV4l2GetInOutFunction get_in_out_func; + GstV4l2SetInOutFunction set_in_out_func; + GstV4l2UpdateFpsFunction update_fps_func; + +}; + +struct _GstV4l2ObjectClassHelper { + /* probed devices */ + GList *devices; + +}; + + +GType gst_v4l2object_get_type(void); + + +#define OPEN_V4L2OBJECT_PROPS \ + enum { \ + PROP_0, \ + PROP_DEVICE, \ + PROP_DEVICE_NAME, \ + PROP_FLAGS, \ + PROP_STD, \ + PROP_INPUT, \ + PROP_FREQUENCY + +#define CLOSE_V4L2OBJECT_PROPS }; + +extern GstV4l2Object * +gst_v4l2object_new (GstElement * element, + GstV4l2GetInOutFunction get_in_out_func, + GstV4l2SetInOutFunction set_in_out_func, + GstV4l2UpdateFpsFunction update_fps_func); + +extern void +gst_v4l2object_destroy (GstV4l2Object ** v4l2object); + +extern void +gst_v4l2object_install_properties_helper (GObjectClass *gobject_class); + +extern gboolean +gst_v4l2object_set_property_helper (GstV4l2Object *v4l2object, + guint prop_id, const GValue * value, GParamSpec * pspec); +extern gboolean +gst_v4l2object_get_property_helper (GstV4l2Object *v4l2object, + guint prop_id, GValue * value, GParamSpec * pspec); + +extern gboolean gst_v4l2object_start (GstV4l2Object *v4l2object); +extern gboolean gst_v4l2object_stop (GstV4l2Object *v4l2object); + +extern const GList * +gst_v4l2_probe_get_properties (GstPropertyProbe * probe); + +extern void +gst_v4l2_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, + const GParamSpec * pspec, + GList ** klass_devices); + +extern gboolean +gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, + const GParamSpec * pspec, + GList ** klass_devices); + +extern GValueArray * +gst_v4l2_probe_get_values (GstPropertyProbe * probe, + guint prop_id, + const GParamSpec * pspec, + GList ** klass_devices); + +#define GST_IMPLEMENT_V4L2_PROBE_METHODS(Type_Class, interface_as_function) \ + \ +static void \ +interface_as_function ## _probe_probe_property (GstPropertyProbe * probe, \ + guint prop_id, \ + const GParamSpec * pspec) \ +{ \ + Type_Class *this_class = (Type_Class*) probe; \ + gst_v4l2_probe_probe_property (probe, prop_id, pspec, \ + &this_class->v4l2_class_devices); \ +} \ + \ +static gboolean \ +interface_as_function ## _probe_needs_probe (GstPropertyProbe * probe, \ + guint prop_id, \ + const GParamSpec * pspec) \ +{ \ + Type_Class *this_class = (Type_Class*) probe; \ + return gst_v4l2_probe_needs_probe (probe, prop_id, pspec, \ + &this_class->v4l2_class_devices); \ +} \ + \ +static GValueArray * \ +interface_as_function ## _probe_get_values (GstPropertyProbe * probe, \ + guint prop_id, \ + const GParamSpec * pspec) \ +{ \ + Type_Class *this_class = (Type_Class*) probe; \ + return gst_v4l2_probe_get_values (probe, prop_id, pspec, \ + &this_class->v4l2_class_devices); \ +} \ + \ +static void \ +interface_as_function ## _property_probe_interface_init (GstPropertyProbeInterface * iface) \ +{ \ + iface->get_properties = gst_v4l2_probe_get_properties; \ + iface->probe_property = interface_as_function ## _probe_probe_property; \ + iface->needs_probe = interface_as_function ## _probe_needs_probe; \ + iface->get_values = interface_as_function ## _probe_get_values; \ +} + +G_END_DECLS + +#endif /* __GST_V4L2OBJECT_H__ */ diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index dc8b7cbe..b38d34ea 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -49,9 +49,11 @@ #include <string.h> #include <sys/time.h> #include "v4l2src_calls.h" -#include <sys/ioctl.h> #include <unistd.h> +#include "gstv4l2colorbalance.h" +#include "gstv4l2tuner.h" +#include "gstv4l2xoverlay.h" static const GstElementDetails gst_v4l2src_details = GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source", @@ -65,14 +67,8 @@ GST_DEBUG_CATEGORY (v4l2src_debug); #define GST_CAT_DEFAULT v4l2src_debug -enum -{ - PROP_0, - PROP_USE_FIXED_FPS -}; - - -static guint32 gst_v4l2_formats[] = { +OPEN_V4L2OBJECT_PROPS, PROP_USE_FIXED_FPS + CLOSE_V4L2OBJECT_PROPS static guint32 gst_v4l2_formats[] = { /* from Linux 2.6.15 videodev2.h */ V4L2_PIX_FMT_RGB332, V4L2_PIX_FMT_RGB555, @@ -130,8 +126,93 @@ static guint32 gst_v4l2_formats[] = { #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats)) +GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src) + + GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src) + + GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src) +#ifdef HAVE_XVIDEO + GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Src, gst_v4l2src) +#endif + static gboolean + gst_v4l2src_iface_supported (GstImplementsInterface * iface, + GType iface_type) +{ + GstV4l2Object *v4l2object = GST_V4L2SRC (iface)->v4l2object; + +#ifdef HAVE_XVIDEO + g_assert (iface_type == GST_TYPE_TUNER || + iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_COLOR_BALANCE); +#else + g_assert (iface_type == GST_TYPE_TUNER || + iface_type == GST_TYPE_COLOR_BALANCE); +#endif + + if (v4l2object->video_fd == -1) + return FALSE; + +#ifdef HAVE_XVIDEO + if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L2_IS_OVERLAY (v4l2object)) + return FALSE; +#endif + + return TRUE; +} -GST_BOILERPLATE (GstV4l2Src, gst_v4l2src, GstV4l2Element, GST_TYPE_V4L2ELEMENT); +static void +gst_v4l2src_interface_init (GstImplementsInterfaceClass * klass) +{ + /* + * default virtual functions + */ + klass->supported = gst_v4l2src_iface_supported; +} + +void +gst_v4l2src_init_interfaces (GType type) +{ + static const GInterfaceInfo v4l2iface_info = { + (GInterfaceInitFunc) gst_v4l2src_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_tuner_info = { + (GInterfaceInitFunc) gst_v4l2src_tuner_interface_init, + NULL, + NULL, + }; +#ifdef HAVE_XVIDEO + static const GInterfaceInfo v4l2_xoverlay_info = { + (GInterfaceInitFunc) gst_v4l2src_xoverlay_interface_init, + NULL, + NULL, + }; +#endif + static const GInterfaceInfo v4l2_colorbalance_info = { + (GInterfaceInitFunc) gst_v4l2src_color_balance_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo v4l2_propertyprobe_info = { + (GInterfaceInitFunc) gst_v4l2src_property_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info); + g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info); +#ifdef HAVE_XVIDEO + g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info); +#endif + g_type_add_interface_static (type, + GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info); + g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, + &v4l2_propertyprobe_info); +} + +GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC, + gst_v4l2src_init_interfaces); static void gst_v4l2src_dispose (GObject * object); @@ -156,6 +237,9 @@ static void gst_v4l2src_base_init (gpointer g_class) { GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class); + + gstv4l2src_class->v4l2_class_devices = NULL; GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element"); @@ -181,6 +265,8 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass) gobject_class->set_property = gst_v4l2src_set_property; gobject_class->get_property = gst_v4l2src_get_property; + gst_v4l2object_install_properties_helper (gobject_class); + g_object_class_install_property (gobject_class, PROP_USE_FIXED_FPS, g_param_spec_boolean ("use_fixed_fps", "Use Fixed FPS", @@ -203,6 +289,9 @@ static void gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass) { + v4l2src->v4l2object = gst_v4l2object_new (GST_ELEMENT (v4l2src), + gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps); + v4l2src->breq.count = 0; v4l2src->formats = NULL; @@ -244,17 +333,24 @@ gst_v4l2src_set_property (GObject * object, g_return_if_fail (GST_IS_V4L2SRC (object)); v4l2src = GST_V4L2SRC (object); - switch (prop_id) { - case PROP_USE_FIXED_FPS: - if (!GST_V4L2_IS_ACTIVE (GST_V4L2ELEMENT (v4l2src))) { - v4l2src->use_fixed_fps = g_value_get_boolean (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + if (!gst_v4l2object_set_property_helper (v4l2src->v4l2object, + prop_id, value, pspec)) { + + switch (prop_id) { + case PROP_USE_FIXED_FPS: + if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { + v4l2src->use_fixed_fps = g_value_get_boolean (value); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + } @@ -267,42 +363,23 @@ gst_v4l2src_get_property (GObject * object, g_return_if_fail (GST_IS_V4L2SRC (object)); v4l2src = GST_V4L2SRC (object); - switch (prop_id) { - case PROP_USE_FIXED_FPS: - g_value_set_boolean (value, v4l2src->use_fixed_fps); - break; + if (!gst_v4l2object_get_property_helper (v4l2src->v4l2object, + prop_id, value, pspec)) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -gboolean -get_fmt_width_height (GstV4l2Src * v4l2src, int *width, int *height) -{ - int ret; - - struct v4l2_format format; - - memset (&format, 0x00, sizeof (format)); - - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_FMT, &format); - - if (ret == 0) { - - *width = format.fmt.pix.width; - *height = format.fmt.pix.height; + switch (prop_id) { + case PROP_USE_FIXED_FPS: + g_value_set_boolean (value, v4l2src->use_fixed_fps); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } - return (ret == 0); - } + /* this function is a bit of a last resort */ static void gst_v4l2src_fixate (GstPad * pad, GstCaps * caps) @@ -636,7 +713,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src) GstStructure *structure; guint fps_n, fps_d; - if (!GST_V4L2_IS_OPEN (GST_V4L2ELEMENT (v4l2src))) { + if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) { return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (v4l2src))); @@ -702,11 +779,11 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) v4l2src = GST_V4L2SRC (src); /* if we're not open, punt -- we'll get setcaps'd later via negotiate */ - if (!GST_V4L2_IS_OPEN (v4l2src)) + if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) return FALSE; /* make sure we stop capturing and dealloc buffers */ - if (GST_V4L2_IS_ACTIVE (v4l2src)) { + if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { if (!gst_v4l2src_capture_stop (v4l2src)) return FALSE; if (!gst_v4l2src_capture_deinit (v4l2src)) @@ -751,7 +828,7 @@ gst_v4l2src_start (GstBaseSrc * src) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); - if (!GST_BASE_SRC_CLASS (parent_class)->start (src)) + if (!gst_v4l2object_start (v4l2src->v4l2object)) return FALSE; v4l2src->offset = 0; @@ -764,15 +841,16 @@ gst_v4l2src_stop (GstBaseSrc * src) { GstV4l2Src *v4l2src = GST_V4L2SRC (src); - if (GST_V4L2_IS_ACTIVE (v4l2src) && !gst_v4l2src_capture_stop (v4l2src)) + if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object) + && !gst_v4l2src_capture_stop (v4l2src)) return FALSE; - if (GST_V4L2ELEMENT (v4l2src)->buffer != NULL) { + if (v4l2src->v4l2object->buffer != NULL) { if (!gst_v4l2src_capture_deinit (v4l2src)) return FALSE; } - if (!GST_BASE_SRC_CLASS (parent_class)->stop (src)) + if (!gst_v4l2object_stop (v4l2src->v4l2object)) return FALSE; return TRUE; @@ -791,7 +869,7 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf) GST_BUFFER_OFFSET (*buf) = GST_BUFFER_OFFSET_NONE; amount = - read (GST_V4L2ELEMENT (v4l2src)->video_fd, GST_BUFFER_DATA (*buf), + read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf), buffersize); if (amount == buffersize) { break; @@ -801,14 +879,14 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf) } else { GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), ("error read()ing a buffer on device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); gst_buffer_unref (*buf); return GST_FLOW_ERROR; } } else { GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), ("error read()ing a buffer on device %s: got only %d bytes instead of expected %d", - GST_V4L2ELEMENT (v4l2src)->videodev, amount, buffersize)); + v4l2src->v4l2object->videodev, amount, buffersize)); gst_buffer_unref (*buf); return GST_FLOW_ERROR; } diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h index 58815ddd..54500ac0 100644 --- a/sys/v4l2/gstv4l2src.h +++ b/sys/v4l2/gstv4l2src.h @@ -25,7 +25,7 @@ #define __GST_V4L2SRC_H__ -#include <gstv4l2element.h> +#include <gstv4l2object.h> GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug); @@ -78,7 +78,9 @@ enum struct _GstV4l2Src { - GstV4l2Element v4l2element; + GstPushSrc pushsrc; + + GstV4l2Object * v4l2object; /* pads */ GstPad *srcpad; @@ -104,12 +106,14 @@ struct _GstV4l2Src struct _GstV4l2SrcClass { - GstV4l2ElementClass parent_class; + GstPushSrcClass parent_class; + + GList *v4l2_class_devices; + }; GType gst_v4l2src_get_type (void); - G_END_DECLS #endif /* __GST_V4L2SRC_H__ */ diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c index ff813b5e..d0a9a1f4 100644 --- a/sys/v4l2/gstv4l2tuner.c +++ b/sys/v4l2/gstv4l2tuner.c @@ -27,12 +27,10 @@ #include <gst/gst.h> #include "gstv4l2tuner.h" -#include "gstv4l2element.h" +#include "gstv4l2object.h" #include "v4l2_calls.h" #include "v4l2src_calls.h" -#include <sys/ioctl.h> - static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * klass); static void gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel); @@ -40,36 +38,6 @@ 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_and_notify (GstTuner * mixer, - GstTunerChannel * channel); -static 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_and_notify (GstTuner * mixer, GstTunerNorm * norm); -static GstTunerNorm *gst_v4l2_tuner_get_norm (GstTuner * mixer); - -static void -gst_v4l2_tuner_set_frequency_and_notify (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 gboolean gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input); -static gboolean gst_v4l2_set_input (GstV4l2Element * v4l2element, gint input); - -#if 0 /* output not handled by now */ -static gboolean -gst_v4l2_get_output (GstV4l2Element * v4l2element, gint * output); -static gboolean gst_v4l2_set_output (GstV4l2Element * v4l2element, gint output); -#endif /* #if 0 - output not handled by now */ - static GstTunerNormClass *norm_parent_class = NULL; static GstTunerChannelClass *channel_parent_class = NULL; @@ -153,26 +121,9 @@ 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_and_notify; - klass->get_channel = gst_v4l2_tuner_get_channel; - - klass->list_norms = gst_v4l2_tuner_list_norms; - klass->set_norm = gst_v4l2_tuner_set_norm_and_notify; - klass->get_norm = gst_v4l2_tuner_get_norm; - - klass->set_frequency = gst_v4l2_tuner_set_frequency_and_notify; - klass->get_frequency = gst_v4l2_tuner_get_frequency; - klass->signal_strength = gst_v4l2_tuner_signal_strength; -} - #if 0 /* output not handled by now */ static gboolean -gst_v4l2_tuner_is_sink (GstV4l2Element * v4l2element) +gst_v4l2_tuner_is_sink (GstV4l2Object * v4l2object) { GstPadDirection dir = GST_PAD_UNKNOWN; @@ -181,56 +132,47 @@ gst_v4l2_tuner_is_sink (GstV4l2Element * v4l2element) #endif /* #if 0 - output not handled by now */ static G_GNUC_UNUSED gboolean -gst_v4l2_tuner_contains_channel (GstV4l2Element * v4l2element, +gst_v4l2_tuner_contains_channel (GstV4l2Object * v4l2object, GstV4l2TunerChannel * v4l2channel) { const GList *item; - for (item = v4l2element->inputs; item != NULL; item = item->next) + for (item = v4l2object->inputs; item != NULL; item = item->next) if (item->data == v4l2channel) return TRUE; return FALSE; } -static const GList * -gst_v4l2_tuner_list_channels (GstTuner * mixer) +const GList * +gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object) { - return GST_V4L2ELEMENT (mixer)->inputs; + return v4l2object->inputs; } -static void -gst_v4l2_tuner_set_channel_and_notify (GstTuner * mixer, +void +gst_v4l2_tuner_set_channel_and_notify (GstV4l2Object * v4l2object, GstTunerChannel * channel) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); - - if (gst_v4l2_tuner_set_channel (mixer, channel)) { - g_object_notify (G_OBJECT (v4l2element), "input"); + if (gst_v4l2_tuner_set_channel (v4l2object, channel)) { + g_object_notify (G_OBJECT (v4l2object->element), "input"); } } gboolean -gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel) +gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object, + GstTunerChannel * channel) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); - GstV4l2Src *v4l2src = GST_V4L2SRC (v4l2element); GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), FALSE); - g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, v4l2channel), FALSE); - if ( -#if 0 /* output not handled by now */ - gst_v4l2_tuner_is_sink (v4l2element) ? - gst_v4l2_set_output (v4l2element, v4l2channel->index) : -#endif /* #if 0 - output not handled by now */ - gst_v4l2_set_input (v4l2element, v4l2channel->index) - ) { - gst_tuner_channel_changed (mixer, channel); - gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d); + if (v4l2object->set_in_out_func (v4l2object, v4l2channel->index)) { + gst_tuner_channel_changed (GST_TUNER (v4l2object->element), channel); + v4l2object->update_fps_func (v4l2object); return TRUE; } @@ -238,62 +180,18 @@ gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel) } -static gboolean -gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input) +GstTunerChannel * +gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object) { - gint n; - - GST_DEBUG_OBJECT (v4l2element, "trying to get input"); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) { - GST_WARNING_OBJECT (v4l2element, - "Failed to get current input on device %s: %s", - v4l2element->videodev, g_strerror (errno)); - return FALSE; - } - - *input = n; - - return TRUE; -} - -static gboolean -gst_v4l2_set_input (GstV4l2Element * v4l2element, gint input) -{ - GST_DEBUG_OBJECT (v4l2element, "trying to set input to %d", input); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) { - GST_WARNING_OBJECT (v4l2element, "Failed to set input %d on device %s: %s", - input, v4l2element->videodev, g_strerror (errno)); - return FALSE; - } - - return TRUE; -} - - -static 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); + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL); -#if 0 /* output not handled by now */ - if (gst_v4l2_tuner_is_sink (v4l2element)) - gst_v4l2_get_output (v4l2element, &channel); - else -#endif /* #if 0 - output not handled by now */ - gst_v4l2_get_input (v4l2element, &channel); + v4l2object->get_in_out_func (v4l2object, &channel); - for (item = v4l2element->inputs; item != NULL; item = item->next) { + for (item = v4l2object->inputs; item != NULL; item = item->next) { if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index) return (GstTunerChannel *) item->data; } @@ -302,49 +200,46 @@ gst_v4l2_tuner_get_channel (GstTuner * mixer) } static G_GNUC_UNUSED gboolean -gst_v4l2_tuner_contains_norm (GstV4l2Element * v4l2element, +gst_v4l2_tuner_contains_norm (GstV4l2Object * v4l2object, GstV4l2TunerNorm * v4l2norm) { const GList *item; - for (item = v4l2element->stds; item != NULL; item = item->next) + for (item = v4l2object->stds; item != NULL; item = item->next) if (item->data == v4l2norm) return TRUE; return FALSE; } -static const GList * -gst_v4l2_tuner_list_norms (GstTuner * mixer) +const GList * +gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object) { - return GST_V4L2ELEMENT (mixer)->stds; + return v4l2object->stds; } -static void -gst_v4l2_tuner_set_norm_and_notify (GstTuner * mixer, GstTunerNorm * norm) +void +gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object, + GstTunerNorm * norm) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); - - if (gst_v4l2_tuner_set_norm (mixer, norm)) { - g_object_notify (G_OBJECT (v4l2element), "std"); + if (gst_v4l2_tuner_set_norm (v4l2object, norm)) { + g_object_notify (G_OBJECT (v4l2object->element), "std"); } } gboolean -gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm) +gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); - GstV4l2Src *v4l2src = GST_V4L2SRC (v4l2element); GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm); /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), FALSE); - g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2element, v4l2norm), + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE); + g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2object, v4l2norm), FALSE); - if (gst_v4l2_set_norm (v4l2element, v4l2norm->index)) { - gst_tuner_norm_changed (mixer, norm); - gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d); + if (gst_v4l2_set_norm (v4l2object, v4l2norm->index)) { + gst_tuner_norm_changed (GST_TUNER (v4l2object->element), norm); + v4l2object->update_fps_func (v4l2object); return TRUE; } @@ -352,19 +247,18 @@ gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm) } -static GstTunerNorm * -gst_v4l2_tuner_get_norm (GstTuner * mixer) +GstTunerNorm * +gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object) { - 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); + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL); - gst_v4l2_get_norm (v4l2element, &norm); + gst_v4l2_get_norm (v4l2object, &norm); - for (item = v4l2element->stds; item != NULL; item = item->next) { + for (item = v4l2object->stds; item != NULL; item = item->next) { if (norm == GST_V4L2_TUNER_NORM (item->data)->index) return (GstTunerNorm *) item->data; } @@ -372,131 +266,85 @@ gst_v4l2_tuner_get_norm (GstTuner * mixer) return NULL; } -static void -gst_v4l2_tuner_set_frequency_and_notify (GstTuner * mixer, +void +gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object, GstTunerChannel * channel, gulong frequency) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); - - if (gst_v4l2_tuner_set_frequency (mixer, channel, frequency)) { - g_object_notify (G_OBJECT (v4l2element), "frequency"); + if (gst_v4l2_tuner_set_frequency (v4l2object, channel, frequency)) { + g_object_notify (G_OBJECT (v4l2object->element), "frequency"); } } gboolean -gst_v4l2_tuner_set_frequency (GstTuner * mixer, +gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object, 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_val_if_fail (GST_V4L2_IS_OPEN (v4l2element), FALSE); + g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE); g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY), FALSE); - g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2element, + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, v4l2channel), FALSE); - gst_v4l2_get_input (v4l2element, &chan); + v4l2object->get_in_out_func (v4l2object, &chan); if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { - if (gst_v4l2_set_frequency (v4l2element, v4l2channel->tuner, frequency)) { - gst_tuner_frequency_changed (mixer, channel, frequency); + if (gst_v4l2_set_frequency (v4l2object, v4l2channel->tuner, frequency)) { + gst_tuner_frequency_changed (GST_TUNER (v4l2object->element), channel, + frequency); return TRUE; } } return FALSE; } -static gulong -gst_v4l2_tuner_get_frequency (GstTuner * mixer, GstTunerChannel * channel) +gulong +gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object, + 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_V4L2_IS_OPEN (v4l2object), 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); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, + v4l2channel), 0); - gst_v4l2_get_input (v4l2element, &chan); + v4l2object->get_in_out_func (v4l2object, &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); + gst_v4l2_get_frequency (v4l2object, v4l2channel->tuner, &frequency); } return frequency; } -static gint -gst_v4l2_tuner_signal_strength (GstTuner * mixer, GstTunerChannel * channel) +gint +gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object, + 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_V4L2_IS_OPEN (v4l2object), 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); + g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object, + v4l2channel), 0); - gst_v4l2_get_input (v4l2element, &chan); + v4l2object->get_in_out_func (v4l2object, &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); + gst_v4l2_signal_strength (v4l2object, v4l2channel->tuner, &signal); } return signal; } - -#if 0 /* output not handled by now */ - -static gboolean -gst_v4l2_get_output (GstV4l2Element * v4l2element, gint * output) -{ - gint n; - - GST_DEBUG_OBJECT (v4l2element, "trying to get output"); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) { - GST_WARNING_OBJECT (v4l2element, - "Failed to get current output on device %s: %s", - v4l2element->videodev, g_strerror (errno)); - return FALSE; - } - - *output = n; - - return TRUE; -} - -static gboolean -gst_v4l2_set_output (GstV4l2Element * v4l2element, gint output) -{ - GST_DEBUG_OBJECT (v4l2element, "trying to set output to %d", output); - if (!GST_V4L2_IS_OPEN (v4l2element)) - return FALSE; - if (!GST_V4L2_IS_ACTIVE (v4l2element)) - return FALSE; - - if (ioctl (v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) { - GST_WARNING_OBJECT (v4l2element, - "Failed to set current output on device %s to %d: %s", - v4l2element->videodev, output, g_strerror (errno)); - return FALSE; - } - - return TRUE; -} - -#endif /* #if 0 - output not handled by now */ diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h index ede9ab2d..523eea35 100644 --- a/sys/v4l2/gstv4l2tuner.h +++ b/sys/v4l2/gstv4l2tuner.h @@ -26,7 +26,7 @@ #include <gst/gst.h> #include <gst/interfaces/tuner.h> -#include "gstv4l2element.h" +#include "gstv4l2object.h" G_BEGIN_DECLS @@ -34,10 +34,10 @@ G_BEGIN_DECLS (gst_v4l2_tuner_channel_get_type ()) #define GST_V4L2_TUNER_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \ - GstV4l2TunerChannel)) + GstV4l2TunerChannel)) #define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \ - GstV4l2TunerChannelClass)) + 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) \ @@ -59,10 +59,10 @@ typedef struct _GstV4l2TunerChannelClass { (gst_v4l2_tuner_norm_get_type ()) #define GST_V4L2_TUNER_NORM(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \ - GstV4l2TunerNorm)) + GstV4l2TunerNorm)) #define GST_V4L2_TUNER_NORM_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \ - GstV4l2TunerNormClass)) + 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) \ @@ -78,19 +78,121 @@ 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); - extern gboolean -gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel); - -gboolean -gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm); - +gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object, GstTunerChannel * channel); +extern gboolean +gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm); extern gboolean -gst_v4l2_tuner_set_frequency (GstTuner * mixer, - GstTunerChannel * channel, gulong frequency); +gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object, + GstTunerChannel * channel, gulong frequency); + +GType gst_v4l2_tuner_channel_get_type (void); +GType gst_v4l2_tuner_norm_get_type (void); + +extern const GList * +gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object); +extern void +gst_v4l2_tuner_set_channel_and_notify (GstV4l2Object * v4l2object, GstTunerChannel * channel); +extern GstTunerChannel * +gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object); + +extern const GList * +gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object); +extern void +gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object, GstTunerNorm * norm); +extern GstTunerNorm * +gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object); + +extern void +gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object, + GstTunerChannel * channel, gulong frequency); +extern gulong +gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object, GstTunerChannel * channel); +extern gint +gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object, GstTunerChannel * channel); + +#define GST_IMPLEMENT_V4L2_TUNER_METHODS(Type, interface_as_function) \ + \ +static const GList * \ +interface_as_function ## _tuner_list_channels (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_list_channels (this->v4l2object); \ +} \ + \ +static void \ +interface_as_function ## _tuner_set_channel_and_notify (GstTuner * mixer, \ + GstTunerChannel * channel) \ +{ \ + Type *this = (Type*) mixer; \ + gst_v4l2_tuner_set_channel_and_notify (this->v4l2object, channel); \ +} \ +static GstTunerChannel * \ +interface_as_function ## _tuner_get_channel (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_get_channel (this->v4l2object); \ +} \ +static const GList * \ +interface_as_function ## _tuner_list_norms (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_list_norms (this->v4l2object); \ +} \ +static void \ +interface_as_function ## _tuner_set_norm_and_notify (GstTuner * mixer, \ + GstTunerNorm * norm) \ +{ \ + Type *this = (Type*) mixer; \ + gst_v4l2_tuner_set_norm_and_notify (this->v4l2object, norm); \ +} \ +static GstTunerNorm * \ +interface_as_function ## _tuner_get_norm (GstTuner * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_get_norm (this->v4l2object); \ +} \ + \ +static void \ +interface_as_function ## _tuner_set_frequency_and_notify (GstTuner * mixer, \ + GstTunerChannel * channel, \ + gulong frequency) \ +{ \ + Type *this = (Type*) mixer; \ + gst_v4l2_tuner_set_frequency_and_notify (this->v4l2object, channel, frequency); \ +} \ + \ +static gulong \ +interface_as_function ## _tuner_get_frequency (GstTuner * mixer, \ + GstTunerChannel * channel) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_get_frequency (this->v4l2object, channel); \ +} \ + \ +static gint \ +interface_as_function ## _tuner_signal_strength (GstTuner * mixer, \ + GstTunerChannel * channel) \ +{ \ + Type *this = (Type*) mixer; \ + return gst_v4l2_tuner_signal_strength (this->v4l2object, channel); \ +} \ + \ +void \ +interface_as_function ## _tuner_interface_init (GstTunerClass * klass) \ +{ \ + /* default virtual functions */ \ + klass->list_channels = interface_as_function ## _tuner_list_channels; \ + klass->set_channel = interface_as_function ## _tuner_set_channel_and_notify; \ + klass->get_channel = interface_as_function ## _tuner_get_channel; \ + \ + klass->list_norms = interface_as_function ## _tuner_list_norms; \ + klass->set_norm = interface_as_function ## _tuner_set_norm_and_notify; \ + klass->get_norm = interface_as_function ## _tuner_get_norm; \ + \ + klass->set_frequency = interface_as_function ## _tuner_set_frequency_and_notify; \ + klass->get_frequency = interface_as_function ## _tuner_get_frequency; \ + klass->signal_strength = interface_as_function ## _tuner_signal_strength; \ +} \ #endif /* __GST_V4L2_TUNER_H__ */ diff --git a/sys/v4l2/gstv4l2xoverlay.c b/sys/v4l2/gstv4l2xoverlay.c index 8d597a45..bcf095e7 100644 --- a/sys/v4l2/gstv4l2xoverlay.c +++ b/sys/v4l2/gstv4l2xoverlay.c @@ -1,5 +1,6 @@ /* GStreamer X-based overlay interface implementation * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> * * gstv4l2xoverlay.c: X-based overlay interface implementation for V4L2 * @@ -32,12 +33,9 @@ #include <sys/stat.h> #include "gstv4l2xoverlay.h" -#include "gstv4l2element.h" +#include "gstv4l2object.h" #include "v4l2_calls.h" -GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug); -#define GST_CAT_DEFAULT v4l2xv_debug - struct _GstV4l2Xv { Display *dpy; @@ -45,21 +43,18 @@ struct _GstV4l2Xv GMutex *mutex; }; -static void gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, - XID xwindow_id); +GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug); +#define GST_CAT_DEFAULT v4l2xv_debug void gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass) { - /* default virtual functions */ - klass->set_xwindow_id = gst_v4l2_xoverlay_set_xwindow_id; - GST_DEBUG_CATEGORY_INIT (v4l2xv_debug, "v4l2xv", 0, "V4L2 XOverlay interface debugging"); } static void -gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) +gst_v4l2_xoverlay_open (GstV4l2Object * v4l2object) { struct stat s; GstV4l2Xv *v4l2xv; @@ -71,33 +66,35 @@ gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) /* we need a display, obviously */ if (!name || !(dpy = XOpenDisplay (name))) { - GST_WARNING_OBJECT (v4l2element, + GST_WARNING_OBJECT (v4l2object->element, "No $DISPLAY set or failed to open - no overlay"); return; } /* First let's check that XVideo extension is available */ if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) { - GST_WARNING_OBJECT (v4l2element, "Xv extension not available - no overlay"); + GST_WARNING_OBJECT (v4l2object->element, + "Xv extension not available - no overlay"); XCloseDisplay (dpy); return; } /* find port that belongs to this device */ if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) { - GST_WARNING_OBJECT (v4l2element, "Xv extension not supported - no overlay"); + GST_WARNING_OBJECT (v4l2object->element, + "Xv extension not supported - no overlay"); XCloseDisplay (dpy); return; } if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) { - GST_WARNING_OBJECT (v4l2element, "Failed to query Xv adaptors"); + GST_WARNING_OBJECT (v4l2object->element, "Failed to query Xv adaptors"); XCloseDisplay (dpy); return; } - if (fstat (v4l2element->video_fd, &s) < 0) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, GST_RESOURCE_ERROR_NOT_FOUND, + if (fstat (v4l2object->video_fd, &s) < 0) { + GST_ELEMENT_ERROR (v4l2object, RESOURCE, GST_RESOURCE_ERROR_NOT_FOUND, (_("Cannot identify '%s': %d, %s\n"), - v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); + v4l2object->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); XCloseDisplay (dpy); return; } @@ -115,7 +112,7 @@ gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) XvFreeAdaptorInfo (ai); if (id == 0) { - GST_WARNING (v4l2element, "Did not find XvPortID for device - no overlay"); + GST_WARNING (v4l2object, "Did not find XvPortID for device - no overlay"); XCloseDisplay (dpy); return; } @@ -125,24 +122,23 @@ gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) v4l2xv->port = id; v4l2xv->mutex = g_mutex_new (); v4l2xv->idle_id = 0; - v4l2element->xv = v4l2xv; + v4l2object->xv = v4l2xv; - if (v4l2element->xwindow_id) { - gst_v4l2_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4l2element), - v4l2element->xwindow_id); + if (v4l2object->xwindow_id) { + gst_v4l2_xoverlay_set_xwindow_id (v4l2object, v4l2object->xwindow_id); } } static void -gst_v4l2_xoverlay_close (GstV4l2Element * v4l2element) +gst_v4l2_xoverlay_close (GstV4l2Object * v4l2object) { - GstV4l2Xv *v4l2xv = v4l2element->xv; + GstV4l2Xv *v4l2xv = v4l2object->xv; - if (!v4l2element->xv) + if (!v4l2object->xv) return; - if (v4l2element->xwindow_id) { - gst_v4l2_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4l2element), 0); + if (v4l2object->xwindow_id) { + gst_v4l2_xoverlay_set_xwindow_id (v4l2object, 0); } XCloseDisplay (v4l2xv->dpy); @@ -150,35 +146,35 @@ gst_v4l2_xoverlay_close (GstV4l2Element * v4l2element) if (v4l2xv->idle_id) g_source_remove (v4l2xv->idle_id); g_free (v4l2xv); - v4l2element->xv = NULL; + v4l2object->xv = NULL; } void -gst_v4l2_xoverlay_start (GstV4l2Element * v4l2element) +gst_v4l2_xoverlay_start (GstV4l2Object * v4l2object) { - if (v4l2element->xwindow_id) { - gst_v4l2_xoverlay_open (v4l2element); + if (v4l2object->xwindow_id) { + gst_v4l2_xoverlay_open (v4l2object); } } void -gst_v4l2_xoverlay_stop (GstV4l2Element * v4l2element) +gst_v4l2_xoverlay_stop (GstV4l2Object * v4l2object) { - gst_v4l2_xoverlay_close (v4l2element); + gst_v4l2_xoverlay_close (v4l2object); } static gboolean idle_refresh (gpointer data) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (data); - GstV4l2Xv *v4l2xv = v4l2element->xv; + GstV4l2Object *v4l2object = GST_V4L2OBJECT (data); + GstV4l2Xv *v4l2xv = v4l2object->xv; XWindowAttributes attr; if (v4l2xv) { g_mutex_lock (v4l2xv->mutex); - XGetWindowAttributes (v4l2xv->dpy, v4l2element->xwindow_id, &attr); - XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id, + XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr); + XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id, DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); @@ -191,34 +187,34 @@ idle_refresh (gpointer data) } static void -gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) +gst_v4l2_xoverlay_set_xwindow_id (GstV4l2Object * v4l2object, XID xwindow_id) { - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (overlay); GstV4l2Xv *v4l2xv; XWindowAttributes attr; - gboolean change = (v4l2element->xwindow_id != xwindow_id); + gboolean change = (v4l2object->xwindow_id != xwindow_id); - GST_LOG_OBJECT (v4l2element, "Setting XID to %lx", (gulong) xwindow_id); + GST_LOG_OBJECT (v4l2object->element, "Setting XID to %lx", + (gulong) xwindow_id); - if (!v4l2element->xv && GST_V4L2_IS_OPEN (v4l2element)) - gst_v4l2_xoverlay_open (v4l2element); + if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object)) + gst_v4l2_xoverlay_open (v4l2object); - v4l2xv = v4l2element->xv; + v4l2xv = v4l2object->xv; if (v4l2xv) g_mutex_lock (v4l2xv->mutex); if (change) { - if (v4l2element->xwindow_id && v4l2xv) { - GST_DEBUG_OBJECT (v4l2element, - "Deactivating old port %lx", v4l2element->xwindow_id); + if (v4l2object->xwindow_id && v4l2xv) { + GST_DEBUG_OBJECT (v4l2object->element, + "Deactivating old port %lx", v4l2object->xwindow_id); XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 0); - XvSelectVideoNotify (v4l2xv->dpy, v4l2element->xwindow_id, 0); - XvStopVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id); + XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 0); + XvStopVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id); } - v4l2element->xwindow_id = xwindow_id; + v4l2object->xwindow_id = xwindow_id; } if (!v4l2xv || xwindow_id == 0) { @@ -228,20 +224,21 @@ gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) } if (change) { - GST_DEBUG_OBJECT (v4l2element, "Activating new port %lx", xwindow_id); + GST_DEBUG_OBJECT (v4l2object->element, "Activating new port %lx", + xwindow_id); /* draw */ XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 1); - XvSelectVideoNotify (v4l2xv->dpy, v4l2element->xwindow_id, 1); + XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 1); } - XGetWindowAttributes (v4l2xv->dpy, v4l2element->xwindow_id, &attr); - XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id, + XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr); + XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id, DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); if (v4l2xv->idle_id) g_source_remove (v4l2xv->idle_id); - v4l2xv->idle_id = g_idle_add (idle_refresh, v4l2element); + v4l2xv->idle_id = g_idle_add (idle_refresh, v4l2object); g_mutex_unlock (v4l2xv->mutex); } diff --git a/sys/v4l2/gstv4l2xoverlay.h b/sys/v4l2/gstv4l2xoverlay.h index a0c25abc..1f39cc75 100644 --- a/sys/v4l2/gstv4l2xoverlay.h +++ b/sys/v4l2/gstv4l2xoverlay.h @@ -1,5 +1,6 @@ /* G-Streamer generic V4L2 element - X overlay interface implementation * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br> * * gstv4l2xoverlay.h: tv mixer interface implementation for V4L2 * @@ -22,16 +23,43 @@ #ifndef __GST_V4L2_X_OVERLAY_H__ #define __GST_V4L2_X_OVERLAY_H__ +#include <X11/X.h> + #include <gst/gst.h> #include <gst/interfaces/xoverlay.h> -#include "gstv4l2element.h" +#include "gstv4l2object.h" G_BEGIN_DECLS -void gst_v4l2_xoverlay_interface_init (GstXOverlayClass *klass); +void gst_v4l2_xoverlay_start (GstV4l2Object *v4l2object); +void gst_v4l2_xoverlay_stop (GstV4l2Object *v4l2object); + +extern void gst_v4l2_xoverlay_set_xwindow_id (GstV4l2Object *v4l2object, + XID xwindow_id); + +extern void +gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass); + +#define GST_IMPLEMENT_V4L2_XOVERLAY_METHODS(Type, interface_as_function) \ + \ +static void \ +interface_as_function ## _xoverlay_set_xwindow_id (GstXOverlay * xoverlay, \ + XID xwindow_id) \ +{ \ + Type *this = (Type*) xoverlay; \ + gst_v4l2_xoverlay_set_xwindow_id (this->v4l2object, xwindow_id); \ +} \ + \ +static void \ +interface_as_function ## _xoverlay_interface_init (GstXOverlayClass * klass) \ +{ \ + /* default virtual functions */ \ + klass->set_xwindow_id = interface_as_function ## _xoverlay_set_xwindow_id; \ + \ + gst_v4l2_xoverlay_interface_init(GstXOverlayClass * klass); \ +} \ + \ -void gst_v4l2_xoverlay_start (GstV4l2Element *v4l2element); -void gst_v4l2_xoverlay_stop (GstV4l2Element *v4l2element); #endif /* __GST_V4L2_X_OVERLAY_H__ */ diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index 2ca2d868..b77389c6 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -47,16 +47,15 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); ******************************************************/ gboolean -gst_v4l2_get_capabilities (GstV4l2Element * v4l2element) +gst_v4l2_get_capabilities (GstV4l2Object * v4l2object) { - GST_DEBUG_OBJECT (v4l2element, "getting capabilities"); - if (!GST_V4L2_IS_OPEN (v4l2element)) + GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities"); + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - if (ioctl (v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, - (_("Error getting capabilities '%s': %d, %s\n"), - v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); + if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &(v4l2object->vcap)) < 0) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, + (_("Error getting capabilities '%s': %d, %s. It isn't a v4l2 driver. Check if it is a v4l1 driver\n"), v4l2object->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); return FALSE; } @@ -71,7 +70,7 @@ gst_v4l2_get_capabilities (GstV4l2Element * v4l2element) ******************************************************/ static gboolean -gst_v4l2_fill_lists (GstV4l2Element * v4l2element) +gst_v4l2_fill_lists (GstV4l2Object * v4l2object) { gint n; @@ -79,8 +78,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) GstPadDirection dir = GST_PAD_UNKNOWN; #endif /* #if 0 - output not handled by now */ - GST_DEBUG_OBJECT (v4l2element, "getting enumerations"); - GST_V4L2_CHECK_OPEN (v4l2element); + GST_DEBUG_OBJECT (v4l2object->element, "getting enumerations"); + GST_V4L2_CHECK_OPEN (v4l2object); #if 0 /* output not handled by now */ if (dir != GST_PAD_SINK) { @@ -93,13 +92,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) GstTunerChannel *channel; input.index = n; - if (ioctl (v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { + if (ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL), ("Failed to get %d in input enumeration for %s: %s", - n, v4l2element->videodev, g_strerror (errno))); + n, v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -116,10 +115,10 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; vtun.index = input.tuner; - if (ioctl (v4l2element->video_fd, VIDIOC_G_TUNER, &vtun) < 0) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), + if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL), ("Failed to get tuner %d settings on %s: %s", - input.tuner, v4l2element->videodev, g_strerror (errno))); + input.tuner, v4l2object->videodev, g_strerror (errno))); g_object_unref (G_OBJECT (channel)); return FALSE; } @@ -138,8 +137,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) channel->flags |= GST_TUNER_CHANNEL_AUDIO; } - v4l2element->inputs = - g_list_append (v4l2element->inputs, (gpointer) channel); + v4l2object->inputs = + g_list_append (v4l2object->inputs, (gpointer) channel); } #if 0 /* output not handled by now */ @@ -151,13 +150,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) GstTunerChannel *channel; output.index = n; - if (ioctl (v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) { + if (ioctl (v4l2object->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) { if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL), ("Failed to get %d in output enumeration for %s: %s", - n, v4l2element->videodev, g_strerror (errno))); + n, v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -175,8 +174,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) channel->flags |= GST_TUNER_CHANNEL_AUDIO; } - v4l2element->inputs = - g_list_append (v4l2element->inputs, (gpointer) channel); + v4l2object->inputs = + g_list_append (v4l2object->inputs, (gpointer) channel); } } #endif /* #if 0 - output not handled by now */ @@ -188,13 +187,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) GstTunerNorm *norm; standard.index = n; - if (ioctl (v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { + if (ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL), ("Failed to get %d in norm enumeration for %s: %s", - n, v4l2element->videodev, g_strerror (errno))); + n, v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -206,7 +205,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) standard.frameperiod.denominator, standard.frameperiod.numerator); v4l2norm->index = standard.id; - v4l2element->stds = g_list_append (v4l2element->stds, (gpointer) norm); + v4l2object->stds = g_list_append (v4l2object->stds, (gpointer) norm); } /* and lastly, controls+menus (if appropriate) */ @@ -220,16 +219,16 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) n = V4L2_CID_PRIVATE_BASE; control.id = n; - if (ioctl (v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) { + if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) { if (errno == EINVAL) { if (n < V4L2_CID_PRIVATE_BASE) continue; else break; } else { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL), ("Failed to get %d in control enumeration for %s: %s", - n, v4l2element->videodev, g_strerror (errno))); + n, v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -253,8 +252,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) /* we only handle these for now */ break; default: - GST_DEBUG_OBJECT (v4l2element, "ControlID %s (%d) unhandled, FIXME", - control.name, n); + GST_DEBUG_OBJECT (v4l2object->element, + "ControlID %s (%d) unhandled, FIXME", control.name, n); control.id++; break; } @@ -274,13 +273,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) menu.id = n; for (i = 0;; i++) { menu.index = i; - if (ioctl (v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) { + if (ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) { if (errno == EINVAL) break; /* end of enumeration */ else { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL), ("Failed to get %d in menu enumeration for %s: %s", - n, v4l2element->videodev, g_strerror (errno))); + n, v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -289,7 +288,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) menus = g_list_append (menus, mptr); } } - v4l2element->menus = g_list_append (v4l2element->menus, menus); + v4l2object->menus = g_list_append (v4l2object->menus, menus); #endif switch (control.type) { @@ -306,8 +305,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) break; } - v4l2element->colors = g_list_append (v4l2element->colors, - (gpointer) channel); + v4l2object->colors = g_list_append (v4l2object->colors, (gpointer) channel); } return TRUE; @@ -315,153 +313,101 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element) static void -gst_v4l2_empty_lists (GstV4l2Element * v4l2element) +gst_v4l2_empty_lists (GstV4l2Object * v4l2object) { - GST_DEBUG_OBJECT (v4l2element, "deleting enumerations"); + GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations"); - g_list_foreach (v4l2element->inputs, (GFunc) g_object_unref, NULL); - g_list_free (v4l2element->inputs); - v4l2element->inputs = NULL; + g_list_foreach (v4l2object->inputs, (GFunc) g_object_unref, NULL); + g_list_free (v4l2object->inputs); + v4l2object->inputs = NULL; - g_list_foreach (v4l2element->stds, (GFunc) g_object_unref, NULL); - g_list_free (v4l2element->stds); - v4l2element->stds = NULL; + g_list_foreach (v4l2object->stds, (GFunc) g_object_unref, NULL); + g_list_free (v4l2object->stds); + v4l2object->stds = NULL; - g_list_foreach (v4l2element->colors, (GFunc) g_object_unref, NULL); - g_list_free (v4l2element->colors); - v4l2element->colors = NULL; + g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL); + g_list_free (v4l2object->colors); + v4l2object->colors = NULL; } -/* FIXME: move this stuff to gstv4l2tuner.c? */ - -static void -gst_v4l2_set_defaults (GstV4l2Element * v4l2element) -{ - GstTunerNorm *norm = NULL; - GstTunerChannel *channel = NULL; - GstTuner *tuner = GST_TUNER (v4l2element); - - if (v4l2element->std) - norm = gst_tuner_find_norm_by_name (tuner, v4l2element->std); - if (norm) { - gst_tuner_set_norm (tuner, norm); - } else { - norm = GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2element))); - if (norm) { - v4l2element->std = g_strdup (norm->label); - gst_tuner_norm_changed (tuner, norm); - g_object_notify (G_OBJECT (v4l2element), "std"); - } - } - - if (v4l2element->input) - channel = gst_tuner_find_channel_by_name (tuner, v4l2element->input); - if (channel) { - gst_tuner_set_channel (tuner, channel); - } else { - channel = - GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2element))); - v4l2element->input = g_strdup (channel->label); - gst_tuner_channel_changed (tuner, channel); - g_object_notify (G_OBJECT (v4l2element), "input"); - } - - if (GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { - if (v4l2element->frequency != 0) { - gst_tuner_set_frequency (tuner, channel, v4l2element->frequency); - } else { - v4l2element->frequency = gst_tuner_get_frequency (tuner, channel); - if (v4l2element->frequency == 0) { - /* guess */ - gst_tuner_set_frequency (tuner, channel, 1000); - } else { - g_object_notify (G_OBJECT (v4l2element), "frequency"); - } - } - } -} - - /****************************************************** * gst_v4l2_open(): - * open the video device (v4l2element->videodev) + * open the video device (v4l2object->videodev) * return value: TRUE on success, FALSE on error ******************************************************/ gboolean -gst_v4l2_open (GstV4l2Element * v4l2element) +gst_v4l2_open (GstV4l2Object * v4l2object) { struct stat st; - GST_DEBUG_OBJECT (v4l2element, "Trying to open device %s", - v4l2element->videodev); - GST_V4L2_CHECK_NOT_OPEN (v4l2element); - GST_V4L2_CHECK_NOT_ACTIVE (v4l2element); + GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s", + v4l2object->videodev); + GST_V4L2_CHECK_NOT_OPEN (v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); /* be sure we have a device */ - if (!v4l2element->videodev) - v4l2element->videodev = g_strdup ("/dev/video"); + if (!v4l2object->videodev) + v4l2object->videodev = g_strdup ("/dev/video"); /* check if it is a device */ - if (-1 == stat (v4l2element->videodev, &st)) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, NOT_FOUND, + if (-1 == stat (v4l2object->videodev, &st)) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, (_("Cannot identify '%s': %d, %s\n"), - v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); + v4l2object->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); goto error; } if (!S_ISCHR (st.st_mode)) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, NOT_FOUND, + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, (_("It isn't a device '%s': %d, %s\n"), - v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); + v4l2object->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); goto error; } /* open the device */ - v4l2element->video_fd = open (v4l2element->videodev, - O_RDWR /* | O_NONBLOCK */ ); + v4l2object->video_fd = + open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ ); - if (!GST_V4L2_IS_OPEN (v4l2element)) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, OPEN_READ_WRITE, + if (!GST_V4L2_IS_OPEN (v4l2object)) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE, (_("Could not open device \"%s\" for reading and writing."), - v4l2element->videodev), GST_ERROR_SYSTEM); + v4l2object->videodev), GST_ERROR_SYSTEM); goto error; } /* get capabilities */ - if (!gst_v4l2_get_capabilities (v4l2element)) { + if (!gst_v4l2_get_capabilities (v4l2object)) { goto error; } /* do we need to be a capture device? */ - if (GST_IS_V4L2SRC (v4l2element) && - !(v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { - GST_ELEMENT_ERROR (v4l2element, RESOURCE, NOT_FOUND, + if (GST_IS_V4L2SRC (v4l2object) && + !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, (_("Device \"%s\" is not a capture device."), - v4l2element->videodev), ("Capabilities: 0x%x", - v4l2element->vcap.capabilities)); + v4l2object->videodev), ("Capabilities: 0x%x", + v4l2object->vcap.capabilities)); goto error; } /* create enumerations */ - if (!gst_v4l2_fill_lists (v4l2element)) + if (!gst_v4l2_fill_lists (v4l2object)) goto error; - /* set defaults */ - gst_v4l2_set_defaults (v4l2element); - - GST_INFO_OBJECT (v4l2element, "Opened device '%s' (%s) successfully\n", - v4l2element->vcap.card, v4l2element->videodev); + GST_INFO_OBJECT (v4l2object->element, + "Opened device '%s' (%s) successfully\n", v4l2object->vcap.card, + v4l2object->videodev); return TRUE; error: - if (GST_V4L2_IS_OPEN (v4l2element)) { + if (GST_V4L2_IS_OPEN (v4l2object)) { /* close device */ - close (v4l2element->video_fd); - v4l2element->video_fd = -1; + close (v4l2object->video_fd); + v4l2object->video_fd = -1; } /* empty lists */ - gst_v4l2_empty_lists (v4l2element); + gst_v4l2_empty_lists (v4l2object); return FALSE; } @@ -469,23 +415,24 @@ error: /****************************************************** * gst_v4l2_close(): - * close the video device (v4l2element->video_fd) + * close the video device (v4l2object->video_fd) * return value: TRUE on success, FALSE on error ******************************************************/ gboolean -gst_v4l2_close (GstV4l2Element * v4l2element) +gst_v4l2_close (GstV4l2Object * v4l2object) { - GST_DEBUG_OBJECT (v4l2element, "Trying to close %s", v4l2element->videodev); - GST_V4L2_CHECK_OPEN (v4l2element); - GST_V4L2_CHECK_NOT_ACTIVE (v4l2element); + GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s", + v4l2object->videodev); + GST_V4L2_CHECK_OPEN (v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2object); /* close device */ - close (v4l2element->video_fd); - v4l2element->video_fd = -1; + close (v4l2object->video_fd); + v4l2object->video_fd = -1; /* empty lists */ - gst_v4l2_empty_lists (v4l2element); + gst_v4l2_empty_lists (v4l2object); return TRUE; } @@ -498,16 +445,16 @@ gst_v4l2_close (GstV4l2Element * v4l2element) ******************************************************/ gboolean -gst_v4l2_get_norm (GstV4l2Element * v4l2element, v4l2_std_id * norm) +gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm) { - GST_DEBUG_OBJECT (v4l2element, "getting norm"); - if (!GST_V4L2_IS_OPEN (v4l2element)) + GST_DEBUG_OBJECT (v4l2object->element, "getting norm"); + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - if (ioctl (v4l2element->video_fd, VIDIOC_G_STD, norm) < 0) { - GST_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to get the current norm for device %s: %s", - v4l2element->videodev, g_strerror (errno)); + v4l2object->videodev, g_strerror (errno)); return FALSE; } @@ -524,16 +471,16 @@ gst_v4l2_get_norm (GstV4l2Element * v4l2element, v4l2_std_id * norm) ******************************************************/ gboolean -gst_v4l2_set_norm (GstV4l2Element * v4l2element, v4l2_std_id norm) +gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm) { - GST_DEBUG_OBJECT (v4l2element, "trying to set norm to %llx", norm); - if (!GST_V4L2_IS_OPEN (v4l2element)) + GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm); + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - if (ioctl (v4l2element->video_fd, VIDIOC_S_STD, &norm) < 0) { - GST_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to set norm 0x%llx for device %s: %s", norm, - v4l2element->videodev, g_strerror (errno)); + v4l2object->videodev, g_strerror (errno)); return FALSE; } @@ -547,23 +494,23 @@ gst_v4l2_set_norm (GstV4l2Element * v4l2element, v4l2_std_id norm) ******************************************************/ gboolean -gst_v4l2_get_frequency (GstV4l2Element * v4l2element, +gst_v4l2_get_frequency (GstV4l2Object * v4l2object, gint tunernum, gulong * frequency) { struct v4l2_frequency freq; GstTunerChannel *channel; - GST_DEBUG_OBJECT (v4l2element, "getting current tuner frequency"); - if (!GST_V4L2_IS_OPEN (v4l2element)) + GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency"); + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - channel = gst_tuner_get_channel (GST_TUNER (v4l2element)); + channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element)); freq.tuner = tunernum; - if (ioctl (v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) { - GST_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to get current tuner frequency for device %s: %s", - v4l2element->videodev, g_strerror (errno)); + v4l2object->videodev, g_strerror (errno)); return FALSE; } @@ -580,28 +527,28 @@ gst_v4l2_get_frequency (GstV4l2Element * v4l2element, ******************************************************/ gboolean -gst_v4l2_set_frequency (GstV4l2Element * v4l2element, +gst_v4l2_set_frequency (GstV4l2Object * v4l2object, gint tunernum, gulong frequency) { struct v4l2_frequency freq; GstTunerChannel *channel; - GST_DEBUG_OBJECT (v4l2element, "setting current tuner frequency to %lu", - frequency); - if (!GST_V4L2_IS_OPEN (v4l2element)) + GST_DEBUG_OBJECT (v4l2object->element, + "setting current tuner frequency to %lu", frequency); + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - channel = gst_tuner_get_channel (GST_TUNER (v4l2element)); + channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element)); freq.tuner = tunernum; /* fill in type - ignore error */ - ioctl (v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq); + ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq); freq.frequency = frequency / channel->freq_multiplicator; - if (ioctl (v4l2element->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) { - GST_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to set current tuner frequency for device %s to %lu: %s", - v4l2element->videodev, frequency, g_strerror (errno)); + v4l2object->videodev, frequency, g_strerror (errno)); return FALSE; } @@ -616,20 +563,20 @@ gst_v4l2_set_frequency (GstV4l2Element * v4l2element, ******************************************************/ gboolean -gst_v4l2_signal_strength (GstV4l2Element * v4l2element, +gst_v4l2_signal_strength (GstV4l2Object * v4l2object, gint tunernum, gulong * signal_strength) { struct v4l2_tuner tuner; - GST_DEBUG_OBJECT (v4l2element, "trying to get signal strength"); - if (!GST_V4L2_IS_OPEN (v4l2element)) + GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength"); + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; tuner.index = tunernum; - if (ioctl (v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) { - GST_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to get signal strength for device %s: %s", - v4l2element->videodev, g_strerror (errno)); + v4l2object->videodev, g_strerror (errno)); return FALSE; } @@ -646,23 +593,23 @@ gst_v4l2_signal_strength (GstV4l2Element * v4l2element, ******************************************************/ gboolean -gst_v4l2_get_attribute (GstV4l2Element * v4l2element, +gst_v4l2_get_attribute (GstV4l2Object * v4l2object, int attribute_num, int *value) { struct v4l2_control control; - if (!GST_V4L2_IS_OPEN (v4l2element)) + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - GST_DEBUG_OBJECT (v4l2element, "getting value of attribute %d", + GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d", attribute_num); control.id = attribute_num; - if (ioctl (v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) { - GST_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to get value for control %d on device %s: %s", - attribute_num, v4l2element->videodev, g_strerror (errno)); + attribute_num, v4l2object->videodev, g_strerror (errno)); return FALSE; } @@ -679,26 +626,109 @@ gst_v4l2_get_attribute (GstV4l2Element * v4l2element, ******************************************************/ gboolean -gst_v4l2_set_attribute (GstV4l2Element * v4l2element, +gst_v4l2_set_attribute (GstV4l2Object * v4l2object, int attribute_num, const int value) { struct v4l2_control control; - if (!GST_V4L2_IS_OPEN (v4l2element)) + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; - GST_DEBUG_OBJECT (v4l2element, "setting value of attribute %d to %d", + GST_DEBUG_OBJECT (v4l2object->element, "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_WARNING_OBJECT (v4l2element, + if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2object->element, "Failed to set value %d for control %d on device %s: %s", - value, attribute_num, v4l2element->videodev, g_strerror (errno)); + value, attribute_num, v4l2object->videodev, g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +gboolean +gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input) +{ + gint n; + + GST_DEBUG_OBJECT (v4l2object->element, "trying to get input"); + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0) { + GST_WARNING_OBJECT (v4l2object->element, + "Failed to get current input on device %s: %s", + v4l2object->videodev, g_strerror (errno)); + return FALSE; + } + + *input = n; + + return TRUE; +} + +gboolean +gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input); + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0) { + GST_WARNING_OBJECT (v4l2object->element, + "Failed to set input %d on device %s: %s", input, v4l2object->videodev, + g_strerror (errno)); return FALSE; } return TRUE; } + + +#if 0 /* output not handled by now */ + +gboolean +gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output) +{ + gint n; + + GST_DEBUG_OBJECT (v4l2object->element, "trying to get output"); + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + if (ioctl (v4l2object->video_fd, VIDIOC_G_OUTPUT, &n) < 0) { + GST_WARNING_OBJECT (v4l2object->element, + "Failed to get current output on device %s: %s", + v4l2object->videodev, g_strerror (errno)); + return FALSE; + } + + *output = n; + + return TRUE; +} + +gboolean +gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output) +{ + GST_DEBUG_OBJECT (v4l2object->element, "trying to set output to %d", output); + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + if (!GST_V4L2_IS_ACTIVE (v4l2object)) + return FALSE; + + if (ioctl (v4l2object->video_fd, VIDIOC_S_OUTPUT, &output) < 0) { + GST_WARNING_OBJECT (v4l2object->element, + "Failed to set current output on device %s to %d: %s", + v4l2object->videodev, output, g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +#endif /* #if 0 - output not handled by now */ diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h index 35d80d50..36075c6f 100644 --- a/sys/v4l2/v4l2_calls.h +++ b/sys/v4l2/v4l2_calls.h @@ -21,100 +21,106 @@ #ifndef __V4L2_CALLS_H__ #define __V4L2_CALLS_H__ -#include "gstv4l2element.h" +#include "gstv4l2object.h" #include "gst/gst-i18n-plugin.h" /* simple check whether the device is open */ -#define GST_V4L2_IS_OPEN(element) \ - (GST_V4L2ELEMENT(element)->video_fd > 0) +#define GST_V4L2_IS_OPEN(v4l2object) \ + (v4l2object->video_fd > 0) /* check whether the device is 'active' */ -#define GST_V4L2_IS_ACTIVE(element) \ - (GST_V4L2ELEMENT(element)->buffer != NULL) +#define GST_V4L2_IS_ACTIVE(v4l2object) \ + (v4l2object->buffer != NULL) -#define GST_V4L2_IS_OVERLAY(element) \ - (GST_V4L2ELEMENT(element)->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY) +#define GST_V4L2_IS_OVERLAY(v4l2object) \ + (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY) -/* checks whether the current v4lelement has already been open()'ed or not */ -#define GST_V4L2_CHECK_OPEN(element) \ - if (!GST_V4L2_IS_OPEN(element)) \ +/* checks whether the current v4lv4l2object has already been open()'ed or not */ +#define GST_V4L2_CHECK_OPEN(v4l2object) \ + if (!GST_V4L2_IS_OPEN(v4l2object)) \ { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, TOO_LAZY, \ (_("Device is not open.")), (NULL)); \ return FALSE; \ } -/* checks whether the current v4lelement is close()'ed or whether it is still open */ -#define GST_V4L2_CHECK_NOT_OPEN(element) \ - if (GST_V4L2_IS_OPEN(element)) \ +/* checks whether the current v4lv4l2object is close()'ed or whether it is still open */ +#define GST_V4L2_CHECK_NOT_OPEN(v4l2object) \ + if (GST_V4L2_IS_OPEN(v4l2object)) \ { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, TOO_LAZY, \ (_("Device is open.")), (NULL)); \ return FALSE; \ } -/* checks whether the current v4lelement does video overlay */ -#define GST_V4L2_CHECK_OVERLAY(element) \ - if (!GST_V4L2_IS_OVERLAY(element)) \ +/* checks whether the current v4lv4l2object does video overlay */ +#define GST_V4L2_CHECK_OVERLAY(v4l2object) \ + if (!GST_V4L2_IS_OVERLAY(v4l2object)) \ { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, TOO_LAZY, \ (NULL), ("Device cannot handle overlay")); \ return FALSE; \ } /* checks whether we're in capture mode or not */ -#define GST_V4L2_CHECK_ACTIVE(element) \ - if (!GST_V4L2_IS_ACTIVE(element)) \ +#define GST_V4L2_CHECK_ACTIVE(v4l2object) \ + if (!GST_V4L2_IS_ACTIVE(v4l2object)) \ { \ - GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ (NULL), ("Device is not in streaming mode")); \ return FALSE; \ } /* checks whether we're out of capture mode or not */ -#define GST_V4L2_CHECK_NOT_ACTIVE(element) \ - if (GST_V4L2_IS_ACTIVE(element)) \ +#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2object) \ + if (GST_V4L2_IS_ACTIVE(v4l2object)) \ { \ - GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, \ + GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \ (NULL), ("Device is in streaming mode")); \ return FALSE; \ } /* open/close the device */ -gboolean gst_v4l2_open (GstV4l2Element *v4l2element); -gboolean gst_v4l2_close (GstV4l2Element *v4l2element); +gboolean gst_v4l2_open (GstV4l2Object *v4l2object); +gboolean gst_v4l2_close (GstV4l2Object *v4l2object); /* norm/input/output */ -gboolean gst_v4l2_get_norm (GstV4l2Element *v4l2element, +gboolean gst_v4l2_get_norm (GstV4l2Object *v4l2object, v4l2_std_id *norm); -gboolean gst_v4l2_set_norm (GstV4l2Element *v4l2element, +gboolean gst_v4l2_set_norm (GstV4l2Object *v4l2object, v4l2_std_id norm); -gboolean gst_v4l2_get_output (GstV4l2Element *v4l2element, +gboolean gst_v4l2_get_input (GstV4l2Object * v4l2object, + gint * input); +gboolean gst_v4l2_set_input (GstV4l2Object * v4l2object, + gint input); +#if 0 /* output not handled by now */ +gboolean gst_v4l2_get_output (GstV4l2Object *v4l2object, gint *output); -gboolean gst_v4l2_set_output (GstV4l2Element *v4l2element, +gboolean gst_v4l2_set_output (GstV4l2Object *v4l2object, gint output); +#endif /* #if 0 - output not handled by now */ /* frequency control */ -gboolean gst_v4l2_get_frequency (GstV4l2Element *v4l2element, +gboolean gst_v4l2_get_frequency (GstV4l2Object *v4l2object, gint tunernum, gulong *frequency); -gboolean gst_v4l2_set_frequency (GstV4l2Element *v4l2element, +gboolean gst_v4l2_set_frequency (GstV4l2Object *v4l2object, gint tunernum, gulong frequency); -gboolean gst_v4l2_signal_strength (GstV4l2Element *v4l2element, +gboolean gst_v4l2_signal_strength (GstV4l2Object *v4l2object, gint tunernum, gulong *signal); /* attribute control */ -gboolean gst_v4l2_get_attribute (GstV4l2Element *v4l2element, +gboolean gst_v4l2_get_attribute (GstV4l2Object *v4l2object, int attribute, int *value); -gboolean gst_v4l2_set_attribute (GstV4l2Element *v4l2element, +gboolean gst_v4l2_set_attribute (GstV4l2Object *v4l2object, int attribute, const int value); -gboolean gst_v4l2_get_capabilities (GstV4l2Element * v4l2element); +gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object); #endif /* __V4L2_CALLS_H__ */ diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 4f55d8b6..f50c6478 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -73,14 +73,13 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src) format->index = n; format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_ENUM_FMT, - format) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) { if (errno == EINVAL) { break; /* end of enumeration */ } else { GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), ("failed to get number %d in pixelformat enumeration for %s: %s", - n, GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + n, v4l2src->v4l2object->videodev, g_strerror (errno))); g_free (format); return FALSE; } @@ -122,11 +121,11 @@ gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i) { GST_LOG_OBJECT (v4l2src, "queueing frame %u", i); - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QBUF, + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &v4l2src->pool->buffers[i].buffer) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE, (_("Could not write to device \"%s\"."), - GST_V4L2ELEMENT (v4l2src)->videodev), + v4l2src->v4l2object->videodev), ("Error queueing buffer %u on device %s", i, g_strerror (errno))); return FALSE; } @@ -150,26 +149,26 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) memset (&buffer, 0x00, sizeof (buffer)); buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = v4l2src->breq.memory; - while (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, &buffer) < 0) { + while (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_DQBUF, &buffer) < 0) { /* if the sync() got interrupted, we can retry */ switch (errno) { case EAGAIN: GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), ("Non-blocking I/O has been selected using O_NONBLOCK and" " no buffer was in the outgoing queue. device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); break; case EINVAL: GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), ("The buffer type is not supported, or the index is out of bounds," " or no buffers have been allocated yet, or the userptr" " or length are invalid. device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); break; case ENOMEM: GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), ("isufficient memory to enqueue a user pointer buffer. device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); break; case EIO: GST_WARNING_OBJECT (v4l2src, @@ -178,12 +177,12 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) " Note the driver might dequeue an (empty) buffer despite" " returning an error, or even stop capturing." " device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno)); + v4l2src->v4l2object->videodev, g_strerror (errno)); break; case EINTR: GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), ("could not sync on a buffer on device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); break; default: GST_DEBUG_OBJECT (v4l2src, "grab got interrupted"); @@ -193,7 +192,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src) if (--trials == -1) { return -1; } else { - ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QBUF, &buffer); + ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer); memset (&buffer, 0x00, sizeof (buffer)); buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.memory = v4l2src->breq.memory; @@ -218,14 +217,13 @@ gst_v4l2src_get_capture (GstV4l2Src * v4l2src) { DEBUG ("Getting capture format"); - GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_FMT, - &v4l2src->format) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), ("failed to get pixelformat for device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); return FALSE; } @@ -246,8 +244,8 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src, DEBUG ("Setting capture format to %dx%d, format %s", width, height, fmt->description); - GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); - GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object); memset (&v4l2src->format, 0, sizeof (struct v4l2_format)); v4l2src->format.fmt.pix.width = width; @@ -256,12 +254,11 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src, v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED; v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_S_FMT, - &v4l2src->format) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), ("failed to set pixelformat to %s @ %dx%d for device %s: %s", fmt->description, width, height, - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); return FALSE; } @@ -284,8 +281,8 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) GST_DEBUG_OBJECT (v4l2src, "initting the capture system"); - GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); - GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object); /* request buffer info */ buffers = v4l2src->breq.count; @@ -296,32 +293,32 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) v4l2src->breq.count = GST_V4L2_MIN_BUFFERS; } v4l2src->breq.type = v4l2src->format.type; - if (GST_V4L2ELEMENT (v4l2src)->vcap.capabilities & V4L2_CAP_STREAMING) { + if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) { v4l2src->breq.memory = V4L2_MEMORY_MMAP; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_REQBUFS, + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_REQBUFS, &v4l2src->breq) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (_("Could not get buffers from device \"%s\"."), - GST_V4L2ELEMENT (v4l2src)->videodev), + v4l2src->v4l2object->videodev), ("error requesting %d buffers: %s", v4l2src->breq.count, g_strerror (errno))); return FALSE; } GST_LOG_OBJECT (v4l2src, "using default mmap method"); - } else if (GST_V4L2ELEMENT (v4l2src)->vcap.capabilities & V4L2_CAP_READWRITE) { + } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) { v4l2src->breq.memory = 0; GST_INFO_OBJECT (v4l2src, "using fallback read method"); } else { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (_("the driver of device \"%s\" is broken."), - GST_V4L2ELEMENT (v4l2src)->videodev), + v4l2src->v4l2object->videodev), ("no supported read capability from %s", - GST_V4L2ELEMENT (v4l2src)->videodev)); + v4l2src->v4l2object->videodev)); return FALSE; } /* Determine the device's framerate */ - if (!gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d)) { + if (!gst_v4l2src_update_fps (v4l2src->v4l2object)) { GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown."); v4l2src->fps_d = 1; v4l2src->fps_n = 0; @@ -331,7 +328,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (_("Could not get enough buffers from device \"%s\"."), - GST_V4L2ELEMENT (v4l2src)->videodev), + v4l2src->v4l2object->videodev), ("we received %d, we want at least %d", v4l2src->breq.count, GST_V4L2_MIN_BUFFERS)); v4l2src->breq.count = buffers; @@ -351,7 +348,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) v4l2src->pool = g_new (GstV4l2BufferPool, 1); gst_atomic_int_set (&v4l2src->pool->refcount, 1); - v4l2src->pool->video_fd = GST_V4L2ELEMENT (v4l2src)->video_fd; + v4l2src->pool->video_fd = v4l2src->v4l2object->video_fd; v4l2src->pool->buffer_count = v4l2src->breq.count; v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count); @@ -365,7 +362,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) buffer->buffer.type = v4l2src->breq.type; buffer->buffer.memory = v4l2src->breq.memory; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QUERYBUF, + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QUERYBUF, &buffer->buffer) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL), ("Could not get buffer properties of buffer %d: %s", @@ -375,7 +372,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) } buffer->start = mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, - GST_V4L2ELEMENT (v4l2src)->video_fd, buffer->buffer.m.offset); + v4l2src->v4l2object->video_fd, buffer->buffer.m.offset); if (buffer->start == MAP_FAILED) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL), ("Could not mmap video buffer %d: %s", n, g_strerror (errno))); @@ -394,7 +391,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src) v4l2src->pool = NULL; } - GST_V4L2_SET_ACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_SET_ACTIVE (v4l2src->v4l2object); return TRUE; } @@ -413,19 +410,19 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src) GST_DEBUG_OBJECT (v4l2src, "starting the capturing"); - GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); - if (!GST_V4L2_IS_ACTIVE (GST_V4L2ELEMENT (v4l2src))) { + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) { /* gst_pad_renegotiate (v4l2src->srcpad); FIX: is it still required in 0.10 */ } - GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); v4l2src->quit = FALSE; if (v4l2src->breq.memory != 0) { - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMON, &type) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMON, &type) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ, (NULL), ("Error starting streaming capture from device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -448,17 +445,16 @@ gst_v4l2src_capture_stop (GstV4l2Src * v4l2src) gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE; GST_DEBUG_OBJECT (v4l2src, "stopping capturing"); - GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); - GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); if (v4l2src->breq.memory != 0) { /* we actually need to sync on all queued buffers but not * on the non-queued ones */ - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMOFF, - &type) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0) { GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, (NULL), ("Error stopping streaming capture from device %s: %s", - GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); + v4l2src->v4l2object->videodev, g_strerror (errno))); return FALSE; } } @@ -524,14 +520,14 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src) GST_DEBUG_OBJECT (v4l2src, "deinitting capture system"); - GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); - GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object); if (v4l2src->pool) { /* free the buffers */ for (i = 0; i < v4l2src->breq.count; i++) { if (g_atomic_int_dec_and_test (&v4l2src->pool->buffers[i].refcount)) { - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_DQBUF, + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_DQBUF, &v4l2src->pool->buffers[i].buffer) < 0) GST_WARNING_OBJECT (v4l2src, "Could not dequeue buffer on uninitialization: %s - will try reinit instead", @@ -558,7 +554,7 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src) } } - GST_V4L2_SET_INACTIVE (GST_V4L2ELEMENT (v4l2src)); + GST_V4L2_SET_INACTIVE (v4l2src->v4l2object); return TRUE; } @@ -585,7 +581,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, fmt.fmt.pix.height = 0; fmt.fmt.pix.pixelformat = format->pixelformat; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { return FALSE; } @@ -598,7 +594,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, fmt.fmt.pix.width = G_MAXINT; fmt.fmt.pix.height = G_MAXINT; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) { return FALSE; } @@ -613,19 +609,28 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, } gboolean +gst_v4l2src_update_fps (GstV4l2Object * v4l2object) +{ + GstV4l2Src *v4l2src = GST_V4L2SRC (v4l2object->element); + + return gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d); +} + +gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) { + GstV4l2Object *v4l2object = v4l2src->v4l2object; v4l2_std_id std; struct v4l2_streamparm stream; const GList *item; - if (!GST_V4L2_IS_OPEN (GST_V4L2ELEMENT (v4l2src))) + if (!GST_V4L2_IS_OPEN (v4l2object)) return FALSE; /* Try to get the frame rate directly from the device using VIDIOC_G_PARM */ stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_PARM, &stream) == 0 - && stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { + if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) == 0 && + stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { /* Note: V4L2 gives us the frame interval, we need the frame rate */ *fps_n = stream.parm.capture.timeperframe.denominator; *fps_d = stream.parm.capture.timeperframe.numerator; @@ -635,9 +640,9 @@ gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) } /* If G_PARM failed, try to get the same information from the video standard */ - if (!gst_v4l2_get_norm (GST_V4L2ELEMENT (v4l2src), &std)) + if (!gst_v4l2_get_norm (v4l2object, &std)) return FALSE; - for (item = GST_V4L2ELEMENT (v4l2src)->stds; item != NULL; item = item->next) { + for (item = v4l2object->stds; item != NULL; item = item->next) { GstV4l2TunerNorm *v4l2norm = item->data; if (v4l2norm->index == std) { @@ -667,8 +672,8 @@ GValue * gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src) { gint fps_index; - struct video_window *vwin = &GST_V4L2ELEMENT (v4l2src)->vwin; - GstV4l2Element *v4l2element = GST_V4L2ELEMENT (v4l2src); + struct video_window *vwin = &v4l2src->v4l2object->vwin; + GstV4l2Object *v4l2object = v4l2src->v4l2object; /* check if we have vwin window properties giving a framerate, * as is done for webcams @@ -701,7 +706,7 @@ gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src) vwin->flags &= (0x3F00 - 1); /* set bits 16 to 21 to the index */ vwin->flags |= i << 16; - if (gst_v4l2_set_window_properties (v4l2element)) { + if (gst_v4l2_set_window_properties (v4l2object)) { /* setting it succeeded. FIXME: get it and check. */ g_value_init (&value, GST_TYPE_FRACTION); gst_value_set_fraction (&value, i * 15, 16); @@ -712,7 +717,7 @@ gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src) /* FIXME: set back the original fps_index */ vwin->flags &= (0x3F00 - 1); vwin->flags |= fps_index << 16; - gst_v4l2_set_window_properties (v4l2element); + gst_v4l2_set_window_properties (v4l2object); return list; } return NULL; diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h index 3839ef2a..51d871ff 100644 --- a/sys/v4l2/v4l2src_calls.h +++ b/sys/v4l2/v4l2src_calls.h @@ -48,8 +48,11 @@ gboolean gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src, void gst_v4l2src_free_buffer (GstBuffer * buffer); +extern gboolean +gst_v4l2src_update_fps (GstV4l2Object * v4l2object); -gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d); +extern gboolean +gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d); GValue *gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src); |