Changes proposed by Wingo in bug #338818.

Original commit message from CVS:
Changes proposed by Wingo in bug #338818.
This commit is contained in:
Edgard Lima 2006-05-11 17:59:59 +00:00
parent a3c4acecbd
commit 9edc0c0365
18 changed files with 1548 additions and 1385 deletions

View file

@ -10,7 +10,7 @@ endif
libgstvideo4linux2_la_SOURCES = gstv4l2.c \ libgstvideo4linux2_la_SOURCES = gstv4l2.c \
gstv4l2colorbalance.c \ gstv4l2colorbalance.c \
gstv4l2element.c \ gstv4l2object.c \
gstv4l2src.c \ gstv4l2src.c \
gstv4l2tuner.c \ gstv4l2tuner.c \
v4l2_calls.c \ v4l2_calls.c \
@ -30,7 +30,7 @@ libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
$(xv_libs) \ $(xv_libs) \
-lgstinterfaces-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR)
noinst_HEADERS = gstv4l2element.h v4l2_calls.h \ noinst_HEADERS = gstv4l2object.h v4l2_calls.h \
gstv4l2src.h v4l2src_calls.h \ gstv4l2src.h v4l2src_calls.h \
gstv4l2tuner.h gstv4l2xoverlay.h \ gstv4l2tuner.h gstv4l2xoverlay.h \
gstv4l2colorbalance.h gstv4l2colorbalance.h

View file

@ -3,6 +3,7 @@
* gstv4l2.c: plugin for v4l2 elements * gstv4l2.c: plugin for v4l2 elements
* *
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -28,7 +29,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gstv4l2element.h" #include "gstv4l2object.h"
#include "gstv4l2src.h" #include "gstv4l2src.h"
/* #include "gstv4l2jpegsrc.h" */ /* #include "gstv4l2jpegsrc.h" */
/* #include "gstv4l2mjpegsrc.h" */ /* #include "gstv4l2mjpegsrc.h" */

View file

@ -1,5 +1,6 @@
/* GStreamer Color Balance interface implementation /* GStreamer Color Balance interface implementation
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * 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 * gstv4l2colorbalance.c: color balance interface implementation for V4L2
* *
@ -25,15 +26,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gstv4l2colorbalance.h" #include "gstv4l2colorbalance.h"
#include "gstv4l2element.h" #include "gstv4l2object.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);
GST_BOILERPLATE (GstV4l2ColorBalanceChannel, GST_BOILERPLATE (GstV4l2ColorBalanceChannel,
gst_v4l2_color_balance_channel, gst_v4l2_color_balance_channel,
@ -59,67 +52,55 @@ gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel,
channel->id = (guint32) - 1; 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 static G_GNUC_UNUSED gboolean
gst_v4l2_color_balance_contains_channel (GstV4l2Element * v4l2element, gst_v4l2_color_balance_contains_channel (GstV4l2Object * v4l2object,
GstV4l2ColorBalanceChannel * v4l2channel) GstV4l2ColorBalanceChannel * v4l2channel)
{ {
const GList *item; 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) if (item->data == v4l2channel)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
static const GList * const GList *
gst_v4l2_color_balance_list_channels (GstColorBalance * balance) gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object)
{ {
return GST_V4L2ELEMENT (balance)->colors; return v4l2object->colors;
} }
static void void
gst_v4l2_color_balance_set_value (GstColorBalance * balance, gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object,
GstColorBalanceChannel * channel, gint value) GstColorBalanceChannel * channel, gint value)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (balance);
GstV4l2ColorBalanceChannel *v4l2channel = GstV4l2ColorBalanceChannel *v4l2channel =
GST_V4L2_COLOR_BALANCE_CHANNEL (channel); GST_V4L2_COLOR_BALANCE_CHANNEL (channel);
/* assert that we're opened and that we're using a known item */ /* 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_IS_OPEN (v4l2object));
g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2element, g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object,
v4l2channel)); v4l2channel));
gst_v4l2_set_attribute (v4l2element, v4l2channel->id, value); gst_v4l2_set_attribute (v4l2object, v4l2channel->id, value);
} }
static gint gint
gst_v4l2_color_balance_get_value (GstColorBalance * balance, gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object,
GstColorBalanceChannel * channel) GstColorBalanceChannel * channel)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (balance);
GstV4l2ColorBalanceChannel *v4l2channel = GstV4l2ColorBalanceChannel *v4l2channel =
GST_V4L2_COLOR_BALANCE_CHANNEL (channel); GST_V4L2_COLOR_BALANCE_CHANNEL (channel);
gint value; gint value;
/* assert that we're opened and that we're using a known item */ /* 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_v4l2_color_balance_contains_channel (v4l2element, g_return_val_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object,
v4l2channel), 0); v4l2channel), 0);
if (!gst_v4l2_get_attribute (v4l2element, v4l2channel->id, &value)) if (!gst_v4l2_get_attribute (v4l2object, v4l2channel->id, &value))
return 0; return 0;
return value; return value;

View file

@ -1,5 +1,6 @@
/* G-Streamer generic V4L2 element - Color Balance interface implementation /* G-Streamer generic V4L2 element - Color Balance interface implementation
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * 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 * gstv4l2colorbalance.h: color balance interface implementation for V4L2
* *
@ -53,6 +54,52 @@ typedef struct _GstV4l2ColorBalanceChannelClass {
GType gst_v4l2_color_balance_channel_get_type (void); 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__ */ #endif /* __GST_V4L2_COLOR_BALANCE_H__ */

View file

@ -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;
}

View file

@ -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__ */

519
sys/v4l2/gstv4l2object.c Normal file
View file

@ -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;
}

211
sys/v4l2/gstv4l2object.h Normal file
View file

@ -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__ */

View file

@ -49,9 +49,11 @@
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
#include "v4l2src_calls.h" #include "v4l2src_calls.h"
#include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
#include "gstv4l2colorbalance.h"
#include "gstv4l2tuner.h"
#include "gstv4l2xoverlay.h"
static const GstElementDetails gst_v4l2src_details = static const GstElementDetails gst_v4l2src_details =
GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source", GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source",
@ -65,14 +67,8 @@ GST_DEBUG_CATEGORY (v4l2src_debug);
#define GST_CAT_DEFAULT v4l2src_debug #define GST_CAT_DEFAULT v4l2src_debug
enum OPEN_V4L2OBJECT_PROPS, PROP_USE_FIXED_FPS
{ CLOSE_V4L2OBJECT_PROPS static guint32 gst_v4l2_formats[] = {
PROP_0,
PROP_USE_FIXED_FPS
};
static guint32 gst_v4l2_formats[] = {
/* from Linux 2.6.15 videodev2.h */ /* from Linux 2.6.15 videodev2.h */
V4L2_PIX_FMT_RGB332, V4L2_PIX_FMT_RGB332,
V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_RGB555,
@ -130,8 +126,93 @@ static guint32 gst_v4l2_formats[] = {
#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats)) #define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src)
GST_BOILERPLATE (GstV4l2Src, gst_v4l2src, GstV4l2Element, GST_TYPE_V4L2ELEMENT); 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;
}
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); static void gst_v4l2src_dispose (GObject * object);
@ -156,6 +237,9 @@ static void
gst_v4l2src_base_init (gpointer g_class) gst_v4l2src_base_init (gpointer g_class)
{ {
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (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"); 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->set_property = gst_v4l2src_set_property;
gobject_class->get_property = gst_v4l2src_get_property; gobject_class->get_property = gst_v4l2src_get_property;
gst_v4l2object_install_properties_helper (gobject_class);
g_object_class_install_property g_object_class_install_property
(gobject_class, PROP_USE_FIXED_FPS, (gobject_class, PROP_USE_FIXED_FPS,
g_param_spec_boolean ("use_fixed_fps", "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) 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->breq.count = 0;
v4l2src->formats = NULL; v4l2src->formats = NULL;
@ -244,17 +333,24 @@ gst_v4l2src_set_property (GObject * object,
g_return_if_fail (GST_IS_V4L2SRC (object)); g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_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: if (!gst_v4l2object_set_property_helper (v4l2src->v4l2object,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); prop_id, value, pspec)) {
break;
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)); g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object); v4l2src = GST_V4L2SRC (object);
switch (prop_id) { if (!gst_v4l2object_get_property_helper (v4l2src->v4l2object,
case PROP_USE_FIXED_FPS: prop_id, value, pspec)) {
g_value_set_boolean (value, v4l2src->use_fixed_fps);
break;
default: switch (prop_id) {
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); case PROP_USE_FIXED_FPS:
break; g_value_set_boolean (value, v4l2src->use_fixed_fps);
} 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;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
} }
return (ret == 0);
} }
/* this function is a bit of a last resort */ /* this function is a bit of a last resort */
static void static void
gst_v4l2src_fixate (GstPad * pad, GstCaps * caps) gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
@ -636,7 +713,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
GstStructure *structure; GstStructure *structure;
guint fps_n, fps_d; guint fps_n, fps_d;
if (!GST_V4L2_IS_OPEN (GST_V4L2ELEMENT (v4l2src))) { if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
return return
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
(v4l2src))); (v4l2src)));
@ -702,11 +779,11 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
v4l2src = GST_V4L2SRC (src); v4l2src = GST_V4L2SRC (src);
/* if we're not open, punt -- we'll get setcaps'd later via negotiate */ /* 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; return FALSE;
/* make sure we stop capturing and dealloc buffers */ /* 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)) if (!gst_v4l2src_capture_stop (v4l2src))
return FALSE; return FALSE;
if (!gst_v4l2src_capture_deinit (v4l2src)) if (!gst_v4l2src_capture_deinit (v4l2src))
@ -751,7 +828,7 @@ gst_v4l2src_start (GstBaseSrc * src)
{ {
GstV4l2Src *v4l2src = GST_V4L2SRC (src); GstV4l2Src *v4l2src = GST_V4L2SRC (src);
if (!GST_BASE_SRC_CLASS (parent_class)->start (src)) if (!gst_v4l2object_start (v4l2src->v4l2object))
return FALSE; return FALSE;
v4l2src->offset = 0; v4l2src->offset = 0;
@ -764,15 +841,16 @@ gst_v4l2src_stop (GstBaseSrc * src)
{ {
GstV4l2Src *v4l2src = GST_V4L2SRC (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; return FALSE;
if (GST_V4L2ELEMENT (v4l2src)->buffer != NULL) { if (v4l2src->v4l2object->buffer != NULL) {
if (!gst_v4l2src_capture_deinit (v4l2src)) if (!gst_v4l2src_capture_deinit (v4l2src))
return FALSE; return FALSE;
} }
if (!GST_BASE_SRC_CLASS (parent_class)->stop (src)) if (!gst_v4l2object_stop (v4l2src->v4l2object))
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -791,7 +869,7 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
GST_BUFFER_OFFSET (*buf) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET (*buf) = GST_BUFFER_OFFSET_NONE;
amount = amount =
read (GST_V4L2ELEMENT (v4l2src)->video_fd, GST_BUFFER_DATA (*buf), read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
buffersize); buffersize);
if (amount == buffersize) { if (amount == buffersize) {
break; break;
@ -801,14 +879,14 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
} else { } else {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("error read()ing a buffer on device %s: %s", ("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); gst_buffer_unref (*buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
} else { } else {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("error read()ing a buffer on device %s: got only %d bytes instead of expected %d", ("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); gst_buffer_unref (*buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }

View file

@ -25,7 +25,7 @@
#define __GST_V4L2SRC_H__ #define __GST_V4L2SRC_H__
#include <gstv4l2element.h> #include <gstv4l2object.h>
GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug); GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug);
@ -78,7 +78,9 @@ enum
struct _GstV4l2Src struct _GstV4l2Src
{ {
GstV4l2Element v4l2element; GstPushSrc pushsrc;
GstV4l2Object * v4l2object;
/* pads */ /* pads */
GstPad *srcpad; GstPad *srcpad;
@ -104,12 +106,14 @@ struct _GstV4l2Src
struct _GstV4l2SrcClass struct _GstV4l2SrcClass
{ {
GstV4l2ElementClass parent_class; GstPushSrcClass parent_class;
GList *v4l2_class_devices;
}; };
GType gst_v4l2src_get_type (void); GType gst_v4l2src_get_type (void);
G_END_DECLS G_END_DECLS
#endif /* __GST_V4L2SRC_H__ */ #endif /* __GST_V4L2SRC_H__ */

View file

@ -27,12 +27,10 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gstv4l2tuner.h" #include "gstv4l2tuner.h"
#include "gstv4l2element.h" #include "gstv4l2object.h"
#include "v4l2_calls.h" #include "v4l2_calls.h"
#include "v4l2src_calls.h" #include "v4l2src_calls.h"
#include <sys/ioctl.h>
static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *
klass); klass);
static void gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel); 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_class_init (GstV4l2TunerNormClass * klass);
static void gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm); 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 GstTunerNormClass *norm_parent_class = NULL;
static GstTunerChannelClass *channel_parent_class = NULL; static GstTunerChannelClass *channel_parent_class = NULL;
@ -153,26 +121,9 @@ gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm)
norm->index = 0; 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 */ #if 0 /* output not handled by now */
static gboolean static gboolean
gst_v4l2_tuner_is_sink (GstV4l2Element * v4l2element) gst_v4l2_tuner_is_sink (GstV4l2Object * v4l2object)
{ {
GstPadDirection dir = GST_PAD_UNKNOWN; GstPadDirection dir = GST_PAD_UNKNOWN;
@ -181,56 +132,47 @@ gst_v4l2_tuner_is_sink (GstV4l2Element * v4l2element)
#endif /* #if 0 - output not handled by now */ #endif /* #if 0 - output not handled by now */
static G_GNUC_UNUSED gboolean static G_GNUC_UNUSED gboolean
gst_v4l2_tuner_contains_channel (GstV4l2Element * v4l2element, gst_v4l2_tuner_contains_channel (GstV4l2Object * v4l2object,
GstV4l2TunerChannel * v4l2channel) GstV4l2TunerChannel * v4l2channel)
{ {
const GList *item; 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) if (item->data == v4l2channel)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
static const GList * const GList *
gst_v4l2_tuner_list_channels (GstTuner * mixer) gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object)
{ {
return GST_V4L2ELEMENT (mixer)->inputs; return v4l2object->inputs;
} }
static void void
gst_v4l2_tuner_set_channel_and_notify (GstTuner * mixer, gst_v4l2_tuner_set_channel_and_notify (GstV4l2Object * v4l2object,
GstTunerChannel * channel) GstTunerChannel * channel)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); if (gst_v4l2_tuner_set_channel (v4l2object, channel)) {
g_object_notify (G_OBJECT (v4l2object->element), "input");
if (gst_v4l2_tuner_set_channel (mixer, channel)) {
g_object_notify (G_OBJECT (v4l2element), "input");
} }
} }
gboolean 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); GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
/* assert that we're opened and that we're using a known item */ /* 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_v4l2_tuner_contains_channel (v4l2element, g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
v4l2channel), FALSE); v4l2channel), FALSE);
if ( if (v4l2object->set_in_out_func (v4l2object, v4l2channel->index)) {
#if 0 /* output not handled by now */ gst_tuner_channel_changed (GST_TUNER (v4l2object->element), channel);
gst_v4l2_tuner_is_sink (v4l2element) ? v4l2object->update_fps_func (v4l2object);
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);
return TRUE; return TRUE;
} }
@ -238,62 +180,18 @@ gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel)
} }
static gboolean GstTunerChannel *
gst_v4l2_get_input (GstV4l2Element * v4l2element, gint * input) 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; GList *item;
gint channel; gint channel;
/* assert that we're opened and that we're using a known item */ /* 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 */ v4l2object->get_in_out_func (v4l2object, &channel);
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);
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) if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index)
return (GstTunerChannel *) item->data; return (GstTunerChannel *) item->data;
} }
@ -302,49 +200,46 @@ gst_v4l2_tuner_get_channel (GstTuner * mixer)
} }
static G_GNUC_UNUSED gboolean static G_GNUC_UNUSED gboolean
gst_v4l2_tuner_contains_norm (GstV4l2Element * v4l2element, gst_v4l2_tuner_contains_norm (GstV4l2Object * v4l2object,
GstV4l2TunerNorm * v4l2norm) GstV4l2TunerNorm * v4l2norm)
{ {
const GList *item; 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) if (item->data == v4l2norm)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
static const GList * const GList *
gst_v4l2_tuner_list_norms (GstTuner * mixer) gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object)
{ {
return GST_V4L2ELEMENT (mixer)->stds; return v4l2object->stds;
} }
static void void
gst_v4l2_tuner_set_norm_and_notify (GstTuner * mixer, GstTunerNorm * norm) gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object,
GstTunerNorm * norm)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); if (gst_v4l2_tuner_set_norm (v4l2object, norm)) {
g_object_notify (G_OBJECT (v4l2object->element), "std");
if (gst_v4l2_tuner_set_norm (mixer, norm)) {
g_object_notify (G_OBJECT (v4l2element), "std");
} }
} }
gboolean 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); GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm);
/* assert that we're opened and that we're using a known item */ /* 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_v4l2_tuner_contains_norm (v4l2element, v4l2norm), g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2object, v4l2norm),
FALSE); FALSE);
if (gst_v4l2_set_norm (v4l2element, v4l2norm->index)) { if (gst_v4l2_set_norm (v4l2object, v4l2norm->index)) {
gst_tuner_norm_changed (mixer, norm); gst_tuner_norm_changed (GST_TUNER (v4l2object->element), norm);
gst_v4l2src_get_fps (v4l2src, &v4l2src->fps_n, &v4l2src->fps_d); v4l2object->update_fps_func (v4l2object);
return TRUE; return TRUE;
} }
@ -352,19 +247,18 @@ gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm)
} }
static GstTunerNorm * GstTunerNorm *
gst_v4l2_tuner_get_norm (GstTuner * mixer) gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
GList *item; GList *item;
v4l2_std_id norm; v4l2_std_id norm;
/* assert that we're opened and that we're using a known item */ /* 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) if (norm == GST_V4L2_TUNER_NORM (item->data)->index)
return (GstTunerNorm *) item->data; return (GstTunerNorm *) item->data;
} }
@ -372,131 +266,85 @@ gst_v4l2_tuner_get_norm (GstTuner * mixer)
return NULL; return NULL;
} }
static void void
gst_v4l2_tuner_set_frequency_and_notify (GstTuner * mixer, gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object,
GstTunerChannel * channel, gulong frequency) GstTunerChannel * channel, gulong frequency)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer); if (gst_v4l2_tuner_set_frequency (v4l2object, channel, frequency)) {
g_object_notify (G_OBJECT (v4l2object->element), "frequency");
if (gst_v4l2_tuner_set_frequency (mixer, channel, frequency)) {
g_object_notify (G_OBJECT (v4l2element), "frequency");
} }
} }
gboolean gboolean
gst_v4l2_tuner_set_frequency (GstTuner * mixer, gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object,
GstTunerChannel * channel, gulong frequency) GstTunerChannel * channel, gulong frequency)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
gint chan; gint chan;
/* assert that we're opened and that we're using a known item */ /* 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, g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
GST_TUNER_CHANNEL_FREQUENCY), FALSE); 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); v4l2channel), FALSE);
gst_v4l2_get_input (v4l2element, &chan); v4l2object->get_in_out_func (v4l2object, &chan);
if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
if (gst_v4l2_set_frequency (v4l2element, v4l2channel->tuner, frequency)) { if (gst_v4l2_set_frequency (v4l2object, v4l2channel->tuner, frequency)) {
gst_tuner_frequency_changed (mixer, channel, frequency); gst_tuner_frequency_changed (GST_TUNER (v4l2object->element), channel,
frequency);
return TRUE; return TRUE;
} }
} }
return FALSE; return FALSE;
} }
static gulong gulong
gst_v4l2_tuner_get_frequency (GstTuner * mixer, GstTunerChannel * channel) gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object,
GstTunerChannel * channel)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
gint chan; gint chan;
gulong frequency = 0; gulong frequency = 0;
/* assert that we're opened and that we're using a known item */ /* 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, g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
GST_TUNER_CHANNEL_FREQUENCY), 0); GST_TUNER_CHANNEL_FREQUENCY), 0);
g_return_val_if_fail (gst_v4l2_tuner_contains_channel g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
(v4l2element, v4l2channel), 0); v4l2channel), 0);
gst_v4l2_get_input (v4l2element, &chan); v4l2object->get_in_out_func (v4l2object, &chan);
if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { 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; return frequency;
} }
static gint gint
gst_v4l2_tuner_signal_strength (GstTuner * mixer, GstTunerChannel * channel) gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object,
GstTunerChannel * channel)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (mixer);
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel); GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
gint chan; gint chan;
gulong signal = 0; gulong signal = 0;
/* assert that we're opened and that we're using a known item */ /* 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, g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
GST_TUNER_CHANNEL_FREQUENCY), 0); GST_TUNER_CHANNEL_FREQUENCY), 0);
g_return_val_if_fail (gst_v4l2_tuner_contains_channel g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
(v4l2element, v4l2channel), 0); v4l2channel), 0);
gst_v4l2_get_input (v4l2element, &chan); v4l2object->get_in_out_func (v4l2object, &chan);
if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index && if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { 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; 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 */

View file

@ -26,7 +26,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/interfaces/tuner.h> #include <gst/interfaces/tuner.h>
#include "gstv4l2element.h" #include "gstv4l2object.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -34,10 +34,10 @@ G_BEGIN_DECLS
(gst_v4l2_tuner_channel_get_type ()) (gst_v4l2_tuner_channel_get_type ())
#define GST_V4L2_TUNER_CHANNEL(obj) \ #define GST_V4L2_TUNER_CHANNEL(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \
GstV4l2TunerChannel)) GstV4l2TunerChannel))
#define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \ #define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \
GstV4l2TunerChannelClass)) GstV4l2TunerChannelClass))
#define GST_IS_V4L2_TUNER_CHANNEL(obj) \ #define GST_IS_V4L2_TUNER_CHANNEL(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_CHANNEL)) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_CHANNEL))
#define GST_IS_V4L2_TUNER_CHANNEL_CLASS(klass) \ #define GST_IS_V4L2_TUNER_CHANNEL_CLASS(klass) \
@ -59,10 +59,10 @@ typedef struct _GstV4l2TunerChannelClass {
(gst_v4l2_tuner_norm_get_type ()) (gst_v4l2_tuner_norm_get_type ())
#define GST_V4L2_TUNER_NORM(obj) \ #define GST_V4L2_TUNER_NORM(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \
GstV4l2TunerNorm)) GstV4l2TunerNorm))
#define GST_V4L2_TUNER_NORM_CLASS(klass) \ #define GST_V4L2_TUNER_NORM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \
GstV4l2TunerNormClass)) GstV4l2TunerNormClass))
#define GST_IS_V4L2_TUNER_NORM(obj) \ #define GST_IS_V4L2_TUNER_NORM(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_NORM)) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_NORM))
#define GST_IS_V4L2_TUNER_NORM_CLASS(klass) \ #define GST_IS_V4L2_TUNER_NORM_CLASS(klass) \
@ -78,19 +78,121 @@ typedef struct _GstV4l2TunerNormClass {
GstTunerNormClass parent; GstTunerNormClass parent;
} GstV4l2TunerNormClass; } 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 extern gboolean
gst_v4l2_tuner_set_channel (GstTuner * mixer, GstTunerChannel * channel); gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object, GstTunerChannel * channel);
gboolean
gst_v4l2_tuner_set_norm (GstTuner * mixer, GstTunerNorm * norm);
extern gboolean extern gboolean
gst_v4l2_tuner_set_frequency (GstTuner * mixer, gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm);
GstTunerChannel * channel, gulong frequency); extern gboolean
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__ */ #endif /* __GST_V4L2_TUNER_H__ */

View file

@ -1,5 +1,6 @@
/* GStreamer X-based overlay interface implementation /* GStreamer X-based overlay interface implementation
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * 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 * gstv4l2xoverlay.c: X-based overlay interface implementation for V4L2
* *
@ -32,12 +33,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "gstv4l2xoverlay.h" #include "gstv4l2xoverlay.h"
#include "gstv4l2element.h" #include "gstv4l2object.h"
#include "v4l2_calls.h" #include "v4l2_calls.h"
GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug);
#define GST_CAT_DEFAULT v4l2xv_debug
struct _GstV4l2Xv struct _GstV4l2Xv
{ {
Display *dpy; Display *dpy;
@ -45,21 +43,18 @@ struct _GstV4l2Xv
GMutex *mutex; GMutex *mutex;
}; };
static void gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug);
XID xwindow_id); #define GST_CAT_DEFAULT v4l2xv_debug
void void
gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass) 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, GST_DEBUG_CATEGORY_INIT (v4l2xv_debug, "v4l2xv", 0,
"V4L2 XOverlay interface debugging"); "V4L2 XOverlay interface debugging");
} }
static void static void
gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) gst_v4l2_xoverlay_open (GstV4l2Object * v4l2object)
{ {
struct stat s; struct stat s;
GstV4l2Xv *v4l2xv; GstV4l2Xv *v4l2xv;
@ -71,33 +66,35 @@ gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element)
/* we need a display, obviously */ /* we need a display, obviously */
if (!name || !(dpy = XOpenDisplay (name))) { if (!name || !(dpy = XOpenDisplay (name))) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"No $DISPLAY set or failed to open - no overlay"); "No $DISPLAY set or failed to open - no overlay");
return; return;
} }
/* First let's check that XVideo extension is available */ /* First let's check that XVideo extension is available */
if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) { 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); XCloseDisplay (dpy);
return; return;
} }
/* find port that belongs to this device */ /* find port that belongs to this device */
if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) { 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); XCloseDisplay (dpy);
return; return;
} }
if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) { 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); XCloseDisplay (dpy);
return; return;
} }
if (fstat (v4l2element->video_fd, &s) < 0) { if (fstat (v4l2object->video_fd, &s) < 0) {
GST_ELEMENT_ERROR (v4l2element, RESOURCE, GST_RESOURCE_ERROR_NOT_FOUND, GST_ELEMENT_ERROR (v4l2object, RESOURCE, GST_RESOURCE_ERROR_NOT_FOUND,
(_("Cannot identify '%s': %d, %s\n"), (_("Cannot identify '%s': %d, %s\n"),
v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); v4l2object->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM);
XCloseDisplay (dpy); XCloseDisplay (dpy);
return; return;
} }
@ -115,7 +112,7 @@ gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element)
XvFreeAdaptorInfo (ai); XvFreeAdaptorInfo (ai);
if (id == 0) { 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); XCloseDisplay (dpy);
return; return;
} }
@ -125,24 +122,23 @@ gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element)
v4l2xv->port = id; v4l2xv->port = id;
v4l2xv->mutex = g_mutex_new (); v4l2xv->mutex = g_mutex_new ();
v4l2xv->idle_id = 0; v4l2xv->idle_id = 0;
v4l2element->xv = v4l2xv; v4l2object->xv = v4l2xv;
if (v4l2element->xwindow_id) { if (v4l2object->xwindow_id) {
gst_v4l2_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4l2element), gst_v4l2_xoverlay_set_xwindow_id (v4l2object, v4l2object->xwindow_id);
v4l2element->xwindow_id);
} }
} }
static void 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; return;
if (v4l2element->xwindow_id) { if (v4l2object->xwindow_id) {
gst_v4l2_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4l2element), 0); gst_v4l2_xoverlay_set_xwindow_id (v4l2object, 0);
} }
XCloseDisplay (v4l2xv->dpy); XCloseDisplay (v4l2xv->dpy);
@ -150,35 +146,35 @@ gst_v4l2_xoverlay_close (GstV4l2Element * v4l2element)
if (v4l2xv->idle_id) if (v4l2xv->idle_id)
g_source_remove (v4l2xv->idle_id); g_source_remove (v4l2xv->idle_id);
g_free (v4l2xv); g_free (v4l2xv);
v4l2element->xv = NULL; v4l2object->xv = NULL;
} }
void void
gst_v4l2_xoverlay_start (GstV4l2Element * v4l2element) gst_v4l2_xoverlay_start (GstV4l2Object * v4l2object)
{ {
if (v4l2element->xwindow_id) { if (v4l2object->xwindow_id) {
gst_v4l2_xoverlay_open (v4l2element); gst_v4l2_xoverlay_open (v4l2object);
} }
} }
void 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 static gboolean
idle_refresh (gpointer data) idle_refresh (gpointer data)
{ {
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (data); GstV4l2Object *v4l2object = GST_V4L2OBJECT (data);
GstV4l2Xv *v4l2xv = v4l2element->xv; GstV4l2Xv *v4l2xv = v4l2object->xv;
XWindowAttributes attr; XWindowAttributes attr;
if (v4l2xv) { if (v4l2xv) {
g_mutex_lock (v4l2xv->mutex); g_mutex_lock (v4l2xv->mutex);
XGetWindowAttributes (v4l2xv->dpy, v4l2element->xwindow_id, &attr); XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr);
XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id, XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id,
DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)),
0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
@ -191,34 +187,34 @@ idle_refresh (gpointer data)
} }
static void 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; GstV4l2Xv *v4l2xv;
XWindowAttributes attr; 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)) if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object))
gst_v4l2_xoverlay_open (v4l2element); gst_v4l2_xoverlay_open (v4l2object);
v4l2xv = v4l2element->xv; v4l2xv = v4l2object->xv;
if (v4l2xv) if (v4l2xv)
g_mutex_lock (v4l2xv->mutex); g_mutex_lock (v4l2xv->mutex);
if (change) { if (change) {
if (v4l2element->xwindow_id && v4l2xv) { if (v4l2object->xwindow_id && v4l2xv) {
GST_DEBUG_OBJECT (v4l2element, GST_DEBUG_OBJECT (v4l2object->element,
"Deactivating old port %lx", v4l2element->xwindow_id); "Deactivating old port %lx", v4l2object->xwindow_id);
XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 0); XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 0);
XvSelectVideoNotify (v4l2xv->dpy, v4l2element->xwindow_id, 0); XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 0);
XvStopVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id); XvStopVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id);
} }
v4l2element->xwindow_id = xwindow_id; v4l2object->xwindow_id = xwindow_id;
} }
if (!v4l2xv || xwindow_id == 0) { if (!v4l2xv || xwindow_id == 0) {
@ -228,20 +224,21 @@ gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
} }
if (change) { if (change) {
GST_DEBUG_OBJECT (v4l2element, "Activating new port %lx", xwindow_id); GST_DEBUG_OBJECT (v4l2object->element, "Activating new port %lx",
xwindow_id);
/* draw */ /* draw */
XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 1); 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); XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr);
XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id, XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id,
DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)),
0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
if (v4l2xv->idle_id) if (v4l2xv->idle_id)
g_source_remove (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); g_mutex_unlock (v4l2xv->mutex);
} }

View file

@ -1,5 +1,6 @@
/* G-Streamer generic V4L2 element - X overlay interface implementation /* G-Streamer generic V4L2 element - X overlay interface implementation
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * 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 * gstv4l2xoverlay.h: tv mixer interface implementation for V4L2
* *
@ -22,16 +23,43 @@
#ifndef __GST_V4L2_X_OVERLAY_H__ #ifndef __GST_V4L2_X_OVERLAY_H__
#define __GST_V4L2_X_OVERLAY_H__ #define __GST_V4L2_X_OVERLAY_H__
#include <X11/X.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/interfaces/xoverlay.h> #include <gst/interfaces/xoverlay.h>
#include "gstv4l2element.h" #include "gstv4l2object.h"
G_BEGIN_DECLS 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__ */ #endif /* __GST_V4L2_X_OVERLAY_H__ */

View file

@ -47,16 +47,15 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_capabilities (GstV4l2Element * v4l2element) gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
{ {
GST_DEBUG_OBJECT (v4l2element, "getting capabilities"); GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities");
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &(v4l2object->vcap)) < 0) {
GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Error getting capabilities '%s': %d, %s\n"), (_("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);
v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM);
return FALSE; return FALSE;
} }
@ -71,7 +70,7 @@ gst_v4l2_get_capabilities (GstV4l2Element * v4l2element)
******************************************************/ ******************************************************/
static gboolean static gboolean
gst_v4l2_fill_lists (GstV4l2Element * v4l2element) gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
{ {
gint n; gint n;
@ -79,8 +78,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
GstPadDirection dir = GST_PAD_UNKNOWN; GstPadDirection dir = GST_PAD_UNKNOWN;
#endif /* #if 0 - output not handled by now */ #endif /* #if 0 - output not handled by now */
GST_DEBUG_OBJECT (v4l2element, "getting enumerations"); GST_DEBUG_OBJECT (v4l2object->element, "getting enumerations");
GST_V4L2_CHECK_OPEN (v4l2element); GST_V4L2_CHECK_OPEN (v4l2object);
#if 0 /* output not handled by now */ #if 0 /* output not handled by now */
if (dir != GST_PAD_SINK) { if (dir != GST_PAD_SINK) {
@ -93,13 +92,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
GstTunerChannel *channel; GstTunerChannel *channel;
input.index = n; input.index = n;
if (ioctl (v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
if (errno == EINVAL) if (errno == EINVAL)
break; /* end of enumeration */ break; /* end of enumeration */
else { 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", ("Failed to get %d in input enumeration for %s: %s",
n, v4l2element->videodev, g_strerror (errno))); n, v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -116,10 +115,10 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
vtun.index = input.tuner; vtun.index = input.tuner;
if (ioctl (v4l2element->video_fd, VIDIOC_G_TUNER, &vtun) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
GST_ELEMENT_ERROR (v4l2element, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, (NULL),
("Failed to get tuner %d settings on %s: %s", ("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)); g_object_unref (G_OBJECT (channel));
return FALSE; return FALSE;
} }
@ -138,8 +137,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
channel->flags |= GST_TUNER_CHANNEL_AUDIO; channel->flags |= GST_TUNER_CHANNEL_AUDIO;
} }
v4l2element->inputs = v4l2object->inputs =
g_list_append (v4l2element->inputs, (gpointer) channel); g_list_append (v4l2object->inputs, (gpointer) channel);
} }
#if 0 /* output not handled by now */ #if 0 /* output not handled by now */
@ -151,13 +150,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
GstTunerChannel *channel; GstTunerChannel *channel;
output.index = n; output.index = n;
if (ioctl (v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
if (errno == EINVAL) if (errno == EINVAL)
break; /* end of enumeration */ break; /* end of enumeration */
else { 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", ("Failed to get %d in output enumeration for %s: %s",
n, v4l2element->videodev, g_strerror (errno))); n, v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -175,8 +174,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
channel->flags |= GST_TUNER_CHANNEL_AUDIO; channel->flags |= GST_TUNER_CHANNEL_AUDIO;
} }
v4l2element->inputs = v4l2object->inputs =
g_list_append (v4l2element->inputs, (gpointer) channel); g_list_append (v4l2object->inputs, (gpointer) channel);
} }
} }
#endif /* #if 0 - output not handled by now */ #endif /* #if 0 - output not handled by now */
@ -188,13 +187,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
GstTunerNorm *norm; GstTunerNorm *norm;
standard.index = n; standard.index = n;
if (ioctl (v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
if (errno == EINVAL) if (errno == EINVAL)
break; /* end of enumeration */ break; /* end of enumeration */
else { 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", ("Failed to get %d in norm enumeration for %s: %s",
n, v4l2element->videodev, g_strerror (errno))); n, v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -206,7 +205,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
standard.frameperiod.denominator, standard.frameperiod.numerator); standard.frameperiod.denominator, standard.frameperiod.numerator);
v4l2norm->index = standard.id; 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) */ /* and lastly, controls+menus (if appropriate) */
@ -220,16 +219,16 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
n = V4L2_CID_PRIVATE_BASE; n = V4L2_CID_PRIVATE_BASE;
control.id = n; 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 (errno == EINVAL) {
if (n < V4L2_CID_PRIVATE_BASE) if (n < V4L2_CID_PRIVATE_BASE)
continue; continue;
else else
break; break;
} else { } 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", ("Failed to get %d in control enumeration for %s: %s",
n, v4l2element->videodev, g_strerror (errno))); n, v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -253,8 +252,8 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
/* we only handle these for now */ /* we only handle these for now */
break; break;
default: default:
GST_DEBUG_OBJECT (v4l2element, "ControlID %s (%d) unhandled, FIXME", GST_DEBUG_OBJECT (v4l2object->element,
control.name, n); "ControlID %s (%d) unhandled, FIXME", control.name, n);
control.id++; control.id++;
break; break;
} }
@ -274,13 +273,13 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
menu.id = n; menu.id = n;
for (i = 0;; i++) { for (i = 0;; i++) {
menu.index = 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) if (errno == EINVAL)
break; /* end of enumeration */ break; /* end of enumeration */
else { 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", ("Failed to get %d in menu enumeration for %s: %s",
n, v4l2element->videodev, g_strerror (errno))); n, v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -289,7 +288,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
menus = g_list_append (menus, mptr); menus = g_list_append (menus, mptr);
} }
} }
v4l2element->menus = g_list_append (v4l2element->menus, menus); v4l2object->menus = g_list_append (v4l2object->menus, menus);
#endif #endif
switch (control.type) { switch (control.type) {
@ -306,8 +305,7 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
break; break;
} }
v4l2element->colors = g_list_append (v4l2element->colors, v4l2object->colors = g_list_append (v4l2object->colors, (gpointer) channel);
(gpointer) channel);
} }
return TRUE; return TRUE;
@ -315,153 +313,101 @@ gst_v4l2_fill_lists (GstV4l2Element * v4l2element)
static void 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_foreach (v4l2object->inputs, (GFunc) g_object_unref, NULL);
g_list_free (v4l2element->inputs); g_list_free (v4l2object->inputs);
v4l2element->inputs = NULL; v4l2object->inputs = NULL;
g_list_foreach (v4l2element->stds, (GFunc) g_object_unref, NULL); g_list_foreach (v4l2object->stds, (GFunc) g_object_unref, NULL);
g_list_free (v4l2element->stds); g_list_free (v4l2object->stds);
v4l2element->stds = NULL; v4l2object->stds = NULL;
g_list_foreach (v4l2element->colors, (GFunc) g_object_unref, NULL); g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
g_list_free (v4l2element->colors); g_list_free (v4l2object->colors);
v4l2element->colors = NULL; 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(): * gst_v4l2_open():
* open the video device (v4l2element->videodev) * open the video device (v4l2object->videodev)
* return value: TRUE on success, FALSE on error * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_open (GstV4l2Element * v4l2element) gst_v4l2_open (GstV4l2Object * v4l2object)
{ {
struct stat st; struct stat st;
GST_DEBUG_OBJECT (v4l2element, "Trying to open device %s", GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
v4l2element->videodev); v4l2object->videodev);
GST_V4L2_CHECK_NOT_OPEN (v4l2element); GST_V4L2_CHECK_NOT_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2element); GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
/* be sure we have a device */ /* be sure we have a device */
if (!v4l2element->videodev) if (!v4l2object->videodev)
v4l2element->videodev = g_strdup ("/dev/video"); v4l2object->videodev = g_strdup ("/dev/video");
/* check if it is a device */ /* check if it is a device */
if (-1 == stat (v4l2element->videodev, &st)) { if (-1 == stat (v4l2object->videodev, &st)) {
GST_ELEMENT_ERROR (v4l2element, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Cannot identify '%s': %d, %s\n"), (_("Cannot identify '%s': %d, %s\n"),
v4l2element->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM); v4l2object->videodev, errno, strerror (errno)), GST_ERROR_SYSTEM);
goto error; goto error;
} }
if (!S_ISCHR (st.st_mode)) { 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"), (_("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; goto error;
} }
/* open the device */ /* open the device */
v4l2element->video_fd = open (v4l2element->videodev, v4l2object->video_fd =
O_RDWR /* | O_NONBLOCK */ ); open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
if (!GST_V4L2_IS_OPEN (v4l2element)) { if (!GST_V4L2_IS_OPEN (v4l2object)) {
GST_ELEMENT_ERROR (v4l2element, RESOURCE, OPEN_READ_WRITE, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
(_("Could not open device \"%s\" for reading and writing."), (_("Could not open device \"%s\" for reading and writing."),
v4l2element->videodev), GST_ERROR_SYSTEM); v4l2object->videodev), GST_ERROR_SYSTEM);
goto error; goto error;
} }
/* get capabilities */ /* get capabilities */
if (!gst_v4l2_get_capabilities (v4l2element)) { if (!gst_v4l2_get_capabilities (v4l2object)) {
goto error; goto error;
} }
/* do we need to be a capture device? */ /* do we need to be a capture device? */
if (GST_IS_V4L2SRC (v4l2element) && if (GST_IS_V4L2SRC (v4l2object) &&
!(v4l2element->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
GST_ELEMENT_ERROR (v4l2element, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Device \"%s\" is not a capture device."), (_("Device \"%s\" is not a capture device."),
v4l2element->videodev), ("Capabilities: 0x%x", v4l2object->videodev), ("Capabilities: 0x%x",
v4l2element->vcap.capabilities)); v4l2object->vcap.capabilities));
goto error; goto error;
} }
/* create enumerations */ /* create enumerations */
if (!gst_v4l2_fill_lists (v4l2element)) if (!gst_v4l2_fill_lists (v4l2object))
goto error; goto error;
/* set defaults */ GST_INFO_OBJECT (v4l2object->element,
gst_v4l2_set_defaults (v4l2element); "Opened device '%s' (%s) successfully\n", v4l2object->vcap.card,
v4l2object->videodev);
GST_INFO_OBJECT (v4l2element, "Opened device '%s' (%s) successfully\n",
v4l2element->vcap.card, v4l2element->videodev);
return TRUE; return TRUE;
error: error:
if (GST_V4L2_IS_OPEN (v4l2element)) { if (GST_V4L2_IS_OPEN (v4l2object)) {
/* close device */ /* close device */
close (v4l2element->video_fd); close (v4l2object->video_fd);
v4l2element->video_fd = -1; v4l2object->video_fd = -1;
} }
/* empty lists */ /* empty lists */
gst_v4l2_empty_lists (v4l2element); gst_v4l2_empty_lists (v4l2object);
return FALSE; return FALSE;
} }
@ -469,23 +415,24 @@ error:
/****************************************************** /******************************************************
* gst_v4l2_close(): * 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 * return value: TRUE on success, FALSE on error
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_close (GstV4l2Element * v4l2element) gst_v4l2_close (GstV4l2Object * v4l2object)
{ {
GST_DEBUG_OBJECT (v4l2element, "Trying to close %s", v4l2element->videodev); GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
GST_V4L2_CHECK_OPEN (v4l2element); v4l2object->videodev);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2element); GST_V4L2_CHECK_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
/* close device */ /* close device */
close (v4l2element->video_fd); close (v4l2object->video_fd);
v4l2element->video_fd = -1; v4l2object->video_fd = -1;
/* empty lists */ /* empty lists */
gst_v4l2_empty_lists (v4l2element); gst_v4l2_empty_lists (v4l2object);
return TRUE; return TRUE;
} }
@ -498,16 +445,16 @@ gst_v4l2_close (GstV4l2Element * v4l2element)
******************************************************/ ******************************************************/
gboolean 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"); GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2element->video_fd, VIDIOC_G_STD, norm) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to get the current norm for device %s: %s", "Failed to get the current norm for device %s: %s",
v4l2element->videodev, g_strerror (errno)); v4l2object->videodev, g_strerror (errno));
return FALSE; return FALSE;
} }
@ -524,16 +471,16 @@ gst_v4l2_get_norm (GstV4l2Element * v4l2element, v4l2_std_id * norm)
******************************************************/ ******************************************************/
gboolean 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); GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm);
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
if (ioctl (v4l2element->video_fd, VIDIOC_S_STD, &norm) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to set norm 0x%llx for device %s: %s", norm, "Failed to set norm 0x%llx for device %s: %s", norm,
v4l2element->videodev, g_strerror (errno)); v4l2object->videodev, g_strerror (errno));
return FALSE; return FALSE;
} }
@ -547,23 +494,23 @@ gst_v4l2_set_norm (GstV4l2Element * v4l2element, v4l2_std_id norm)
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_frequency (GstV4l2Element * v4l2element, gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
gint tunernum, gulong * frequency) gint tunernum, gulong * frequency)
{ {
struct v4l2_frequency freq; struct v4l2_frequency freq;
GstTunerChannel *channel; GstTunerChannel *channel;
GST_DEBUG_OBJECT (v4l2element, "getting current tuner frequency"); GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
channel = gst_tuner_get_channel (GST_TUNER (v4l2element)); channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
freq.tuner = tunernum; freq.tuner = tunernum;
if (ioctl (v4l2element->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to get current tuner frequency for device %s: %s", "Failed to get current tuner frequency for device %s: %s",
v4l2element->videodev, g_strerror (errno)); v4l2object->videodev, g_strerror (errno));
return FALSE; return FALSE;
} }
@ -580,28 +527,28 @@ gst_v4l2_get_frequency (GstV4l2Element * v4l2element,
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_set_frequency (GstV4l2Element * v4l2element, gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
gint tunernum, gulong frequency) gint tunernum, gulong frequency)
{ {
struct v4l2_frequency freq; struct v4l2_frequency freq;
GstTunerChannel *channel; GstTunerChannel *channel;
GST_DEBUG_OBJECT (v4l2element, "setting current tuner frequency to %lu", GST_DEBUG_OBJECT (v4l2object->element,
frequency); "setting current tuner frequency to %lu", frequency);
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
channel = gst_tuner_get_channel (GST_TUNER (v4l2element)); channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
freq.tuner = tunernum; freq.tuner = tunernum;
/* fill in type - ignore error */ /* 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; freq.frequency = frequency / channel->freq_multiplicator;
if (ioctl (v4l2element->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to set current tuner frequency for device %s to %lu: %s", "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; return FALSE;
} }
@ -616,20 +563,20 @@ gst_v4l2_set_frequency (GstV4l2Element * v4l2element,
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_signal_strength (GstV4l2Element * v4l2element, gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
gint tunernum, gulong * signal_strength) gint tunernum, gulong * signal_strength)
{ {
struct v4l2_tuner tuner; struct v4l2_tuner tuner;
GST_DEBUG_OBJECT (v4l2element, "trying to get signal strength"); GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
tuner.index = tunernum; tuner.index = tunernum;
if (ioctl (v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to get signal strength for device %s: %s", "Failed to get signal strength for device %s: %s",
v4l2element->videodev, g_strerror (errno)); v4l2object->videodev, g_strerror (errno));
return FALSE; return FALSE;
} }
@ -646,23 +593,23 @@ gst_v4l2_signal_strength (GstV4l2Element * v4l2element,
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_get_attribute (GstV4l2Element * v4l2element, gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
int attribute_num, int *value) int attribute_num, int *value)
{ {
struct v4l2_control control; struct v4l2_control control;
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
GST_DEBUG_OBJECT (v4l2element, "getting value of attribute %d", GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
attribute_num); attribute_num);
control.id = attribute_num; control.id = attribute_num;
if (ioctl (v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to get value for control %d on device %s: %s", "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; return FALSE;
} }
@ -679,26 +626,109 @@ gst_v4l2_get_attribute (GstV4l2Element * v4l2element,
******************************************************/ ******************************************************/
gboolean gboolean
gst_v4l2_set_attribute (GstV4l2Element * v4l2element, gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
int attribute_num, const int value) int attribute_num, const int value)
{ {
struct v4l2_control control; struct v4l2_control control;
if (!GST_V4L2_IS_OPEN (v4l2element)) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; 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); attribute_num, value);
control.id = attribute_num; control.id = attribute_num;
control.value = value; control.value = value;
if (ioctl (v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) { if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
GST_WARNING_OBJECT (v4l2element, GST_WARNING_OBJECT (v4l2object->element,
"Failed to set value %d for control %d on device %s: %s", "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 FALSE;
} }
return TRUE; 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 */

View file

@ -21,100 +21,106 @@
#ifndef __V4L2_CALLS_H__ #ifndef __V4L2_CALLS_H__
#define __V4L2_CALLS_H__ #define __V4L2_CALLS_H__
#include "gstv4l2element.h" #include "gstv4l2object.h"
#include "gst/gst-i18n-plugin.h" #include "gst/gst-i18n-plugin.h"
/* simple check whether the device is open */ /* simple check whether the device is open */
#define GST_V4L2_IS_OPEN(element) \ #define GST_V4L2_IS_OPEN(v4l2object) \
(GST_V4L2ELEMENT(element)->video_fd > 0) (v4l2object->video_fd > 0)
/* check whether the device is 'active' */ /* check whether the device is 'active' */
#define GST_V4L2_IS_ACTIVE(element) \ #define GST_V4L2_IS_ACTIVE(v4l2object) \
(GST_V4L2ELEMENT(element)->buffer != NULL) (v4l2object->buffer != NULL)
#define GST_V4L2_IS_OVERLAY(element) \ #define GST_V4L2_IS_OVERLAY(v4l2object) \
(GST_V4L2ELEMENT(element)->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY) (v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
/* checks whether the current v4lelement has already been open()'ed or not */ /* checks whether the current v4lv4l2object has already been open()'ed or not */
#define GST_V4L2_CHECK_OPEN(element) \ #define GST_V4L2_CHECK_OPEN(v4l2object) \
if (!GST_V4L2_IS_OPEN(element)) \ 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)); \ (_("Device is not open.")), (NULL)); \
return FALSE; \ return FALSE; \
} }
/* checks whether the current v4lelement is close()'ed or whether it is still open */ /* checks whether the current v4lv4l2object is close()'ed or whether it is still open */
#define GST_V4L2_CHECK_NOT_OPEN(element) \ #define GST_V4L2_CHECK_NOT_OPEN(v4l2object) \
if (GST_V4L2_IS_OPEN(element)) \ 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)); \ (_("Device is open.")), (NULL)); \
return FALSE; \ return FALSE; \
} }
/* checks whether the current v4lelement does video overlay */ /* checks whether the current v4lv4l2object does video overlay */
#define GST_V4L2_CHECK_OVERLAY(element) \ #define GST_V4L2_CHECK_OVERLAY(v4l2object) \
if (!GST_V4L2_IS_OVERLAY(element)) \ 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")); \ (NULL), ("Device cannot handle overlay")); \
return FALSE; \ return FALSE; \
} }
/* checks whether we're in capture mode or not */ /* checks whether we're in capture mode or not */
#define GST_V4L2_CHECK_ACTIVE(element) \ #define GST_V4L2_CHECK_ACTIVE(v4l2object) \
if (!GST_V4L2_IS_ACTIVE(element)) \ 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")); \ (NULL), ("Device is not in streaming mode")); \
return FALSE; \ return FALSE; \
} }
/* checks whether we're out of capture mode or not */ /* checks whether we're out of capture mode or not */
#define GST_V4L2_CHECK_NOT_ACTIVE(element) \ #define GST_V4L2_CHECK_NOT_ACTIVE(v4l2object) \
if (GST_V4L2_IS_ACTIVE(element)) \ 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")); \ (NULL), ("Device is in streaming mode")); \
return FALSE; \ return FALSE; \
} }
/* open/close the device */ /* open/close the device */
gboolean gst_v4l2_open (GstV4l2Element *v4l2element); gboolean gst_v4l2_open (GstV4l2Object *v4l2object);
gboolean gst_v4l2_close (GstV4l2Element *v4l2element); gboolean gst_v4l2_close (GstV4l2Object *v4l2object);
/* norm/input/output */ /* norm/input/output */
gboolean gst_v4l2_get_norm (GstV4l2Element *v4l2element, gboolean gst_v4l2_get_norm (GstV4l2Object *v4l2object,
v4l2_std_id *norm); v4l2_std_id *norm);
gboolean gst_v4l2_set_norm (GstV4l2Element *v4l2element, gboolean gst_v4l2_set_norm (GstV4l2Object *v4l2object,
v4l2_std_id norm); 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); gint *output);
gboolean gst_v4l2_set_output (GstV4l2Element *v4l2element, gboolean gst_v4l2_set_output (GstV4l2Object *v4l2object,
gint output); gint output);
#endif /* #if 0 - output not handled by now */
/* frequency control */ /* frequency control */
gboolean gst_v4l2_get_frequency (GstV4l2Element *v4l2element, gboolean gst_v4l2_get_frequency (GstV4l2Object *v4l2object,
gint tunernum, gint tunernum,
gulong *frequency); gulong *frequency);
gboolean gst_v4l2_set_frequency (GstV4l2Element *v4l2element, gboolean gst_v4l2_set_frequency (GstV4l2Object *v4l2object,
gint tunernum, gint tunernum,
gulong frequency); gulong frequency);
gboolean gst_v4l2_signal_strength (GstV4l2Element *v4l2element, gboolean gst_v4l2_signal_strength (GstV4l2Object *v4l2object,
gint tunernum, gint tunernum,
gulong *signal); gulong *signal);
/* attribute control */ /* attribute control */
gboolean gst_v4l2_get_attribute (GstV4l2Element *v4l2element, gboolean gst_v4l2_get_attribute (GstV4l2Object *v4l2object,
int attribute, int attribute,
int *value); int *value);
gboolean gst_v4l2_set_attribute (GstV4l2Element *v4l2element, gboolean gst_v4l2_set_attribute (GstV4l2Object *v4l2object,
int attribute, int attribute,
const int value); const int value);
gboolean gst_v4l2_get_capabilities (GstV4l2Element * v4l2element); gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object);
#endif /* __V4L2_CALLS_H__ */ #endif /* __V4L2_CALLS_H__ */

View file

@ -73,14 +73,13 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
format->index = n; format->index = n;
format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_ENUM_FMT, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
format) < 0) {
if (errno == EINVAL) { if (errno == EINVAL) {
break; /* end of enumeration */ break; /* end of enumeration */
} else { } else {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
("failed to get number %d in pixelformat enumeration for %s: %s", ("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); g_free (format);
return FALSE; return FALSE;
} }
@ -122,11 +121,11 @@ gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
{ {
GST_LOG_OBJECT (v4l2src, "queueing frame %u", 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) { &v4l2src->pool->buffers[i].buffer) < 0) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE, GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
(_("Could not write to device \"%s\"."), (_("Could not write to device \"%s\"."),
GST_V4L2ELEMENT (v4l2src)->videodev), v4l2src->v4l2object->videodev),
("Error queueing buffer %u on device %s", i, g_strerror (errno))); ("Error queueing buffer %u on device %s", i, g_strerror (errno)));
return FALSE; return FALSE;
} }
@ -150,26 +149,26 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
memset (&buffer, 0x00, sizeof (buffer)); memset (&buffer, 0x00, sizeof (buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = v4l2src->breq.memory; 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 */ /* if the sync() got interrupted, we can retry */
switch (errno) { switch (errno) {
case EAGAIN: case EAGAIN:
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("Non-blocking I/O has been selected using O_NONBLOCK and" ("Non-blocking I/O has been selected using O_NONBLOCK and"
" no buffer was in the outgoing queue. device %s: %s", " no buffer was in the outgoing queue. device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
break; break;
case EINVAL: case EINVAL:
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("The buffer type is not supported, or the index is out of bounds," ("The buffer type is not supported, or the index is out of bounds,"
" or no buffers have been allocated yet, or the userptr" " or no buffers have been allocated yet, or the userptr"
" or length are invalid. device %s: %s", " or length are invalid. device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
break; break;
case ENOMEM: case ENOMEM:
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("isufficient memory to enqueue a user pointer buffer. device %s: %s", ("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; break;
case EIO: case EIO:
GST_WARNING_OBJECT (v4l2src, GST_WARNING_OBJECT (v4l2src,
@ -178,12 +177,12 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
" Note the driver might dequeue an (empty) buffer despite" " Note the driver might dequeue an (empty) buffer despite"
" returning an error, or even stop capturing." " returning an error, or even stop capturing."
" device %s: %s", " device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno)); v4l2src->v4l2object->videodev, g_strerror (errno));
break; break;
case EINTR: case EINTR:
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("could not sync on a buffer on device %s: %s", ("could not sync on a buffer on device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
break; break;
default: default:
GST_DEBUG_OBJECT (v4l2src, "grab got interrupted"); GST_DEBUG_OBJECT (v4l2src, "grab got interrupted");
@ -193,7 +192,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
if (--trials == -1) { if (--trials == -1) {
return -1; return -1;
} else { } else {
ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_QBUF, &buffer); ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer);
memset (&buffer, 0x00, sizeof (buffer)); memset (&buffer, 0x00, sizeof (buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = v4l2src->breq.memory; buffer.memory = v4l2src->breq.memory;
@ -218,14 +217,13 @@ gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
{ {
DEBUG ("Getting capture format"); 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; v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_FMT, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) {
&v4l2src->format) < 0) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
("failed to get pixelformat for device %s: %s", ("failed to get pixelformat for device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
@ -246,8 +244,8 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
DEBUG ("Setting capture format to %dx%d, format %s", DEBUG ("Setting capture format to %dx%d, format %s",
width, height, fmt->description); width, height, fmt->description);
GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
memset (&v4l2src->format, 0, sizeof (struct v4l2_format)); memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
v4l2src->format.fmt.pix.width = width; 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.fmt.pix.field = V4L2_FIELD_INTERLACED;
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_S_FMT, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) {
&v4l2src->format) < 0) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS, (NULL),
("failed to set pixelformat to %s @ %dx%d for device %s: %s", ("failed to set pixelformat to %s @ %dx%d for device %s: %s",
fmt->description, width, height, fmt->description, width, height,
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
@ -284,8 +281,8 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
GST_DEBUG_OBJECT (v4l2src, "initting the capture system"); GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
/* request buffer info */ /* request buffer info */
buffers = v4l2src->breq.count; buffers = v4l2src->breq.count;
@ -296,32 +293,32 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
v4l2src->breq.count = GST_V4L2_MIN_BUFFERS; v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
} }
v4l2src->breq.type = v4l2src->format.type; 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; 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) { &v4l2src->breq) < 0) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get buffers from device \"%s\"."), (_("Could not get buffers from device \"%s\"."),
GST_V4L2ELEMENT (v4l2src)->videodev), v4l2src->v4l2object->videodev),
("error requesting %d buffers: %s", ("error requesting %d buffers: %s",
v4l2src->breq.count, g_strerror (errno))); v4l2src->breq.count, g_strerror (errno)));
return FALSE; return FALSE;
} }
GST_LOG_OBJECT (v4l2src, "using default mmap method"); 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; v4l2src->breq.memory = 0;
GST_INFO_OBJECT (v4l2src, "using fallback read method"); GST_INFO_OBJECT (v4l2src, "using fallback read method");
} else { } else {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("the driver of device \"%s\" is broken."), (_("the driver of device \"%s\" is broken."),
GST_V4L2ELEMENT (v4l2src)->videodev), v4l2src->v4l2object->videodev),
("no supported read capability from %s", ("no supported read capability from %s",
GST_V4L2ELEMENT (v4l2src)->videodev)); v4l2src->v4l2object->videodev));
return FALSE; return FALSE;
} }
/* Determine the device's framerate */ /* 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."); GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown.");
v4l2src->fps_d = 1; v4l2src->fps_d = 1;
v4l2src->fps_n = 0; v4l2src->fps_n = 0;
@ -331,7 +328,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) { if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get enough buffers from device \"%s\"."), (_("Could not get enough buffers from device \"%s\"."),
GST_V4L2ELEMENT (v4l2src)->videodev), v4l2src->v4l2object->videodev),
("we received %d, we want at least %d", ("we received %d, we want at least %d",
v4l2src->breq.count, GST_V4L2_MIN_BUFFERS)); v4l2src->breq.count, GST_V4L2_MIN_BUFFERS));
v4l2src->breq.count = buffers; v4l2src->breq.count = buffers;
@ -351,7 +348,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
v4l2src->pool = g_new (GstV4l2BufferPool, 1); v4l2src->pool = g_new (GstV4l2BufferPool, 1);
gst_atomic_int_set (&v4l2src->pool->refcount, 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->buffer_count = v4l2src->breq.count;
v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, 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.type = v4l2src->breq.type;
buffer->buffer.memory = v4l2src->breq.memory; 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) { &buffer->buffer) < 0) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
("Could not get buffer properties of buffer %d: %s", ("Could not get buffer properties of buffer %d: %s",
@ -375,7 +372,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
} }
buffer->start = buffer->start =
mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, 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) { if (buffer->start == MAP_FAILED) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
("Could not mmap video buffer %d: %s", n, g_strerror (errno))); ("Could not mmap video buffer %d: %s", n, g_strerror (errno)));
@ -394,7 +391,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
v4l2src->pool = NULL; v4l2src->pool = NULL;
} }
GST_V4L2_SET_ACTIVE (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
return TRUE; return TRUE;
} }
@ -413,19 +410,19 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
GST_DEBUG_OBJECT (v4l2src, "starting the capturing"); GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
if (!GST_V4L2_IS_ACTIVE (GST_V4L2ELEMENT (v4l2src))) { if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
/* gst_pad_renegotiate (v4l2src->srcpad); FIX: is it still required in 0.10 */ /* 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; v4l2src->quit = FALSE;
if (v4l2src->breq.memory != 0) { 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), GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ, (NULL),
("Error starting streaming capture from device %s: %s", ("Error starting streaming capture from device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -448,17 +445,16 @@ gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE; gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
GST_DEBUG_OBJECT (v4l2src, "stopping capturing"); GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
if (v4l2src->breq.memory != 0) { if (v4l2src->breq.memory != 0) {
/* we actually need to sync on all queued buffers but not /* we actually need to sync on all queued buffers but not
* on the non-queued ones */ * on the non-queued ones */
if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_STREAMOFF, if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0) {
&type) < 0) {
GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, (NULL), GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE, (NULL),
("Error stopping streaming capture from device %s: %s", ("Error stopping streaming capture from device %s: %s",
GST_V4L2ELEMENT (v4l2src)->videodev, g_strerror (errno))); v4l2src->v4l2object->videodev, g_strerror (errno)));
return FALSE; return FALSE;
} }
} }
@ -524,14 +520,14 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
GST_DEBUG_OBJECT (v4l2src, "deinitting capture system"); GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
GST_V4L2_CHECK_OPEN (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_ACTIVE (GST_V4L2ELEMENT (v4l2src)); GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
if (v4l2src->pool) { if (v4l2src->pool) {
/* free the buffers */ /* free the buffers */
for (i = 0; i < v4l2src->breq.count; i++) { for (i = 0; i < v4l2src->breq.count; i++) {
if (g_atomic_int_dec_and_test (&v4l2src->pool->buffers[i].refcount)) { 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) &v4l2src->pool->buffers[i].buffer) < 0)
GST_WARNING_OBJECT (v4l2src, GST_WARNING_OBJECT (v4l2src,
"Could not dequeue buffer on uninitialization: %s - will try reinit instead", "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; return TRUE;
} }
@ -585,7 +581,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
fmt.fmt.pix.height = 0; fmt.fmt.pix.height = 0;
fmt.fmt.pix.pixelformat = format->pixelformat; fmt.fmt.pix.pixelformat = format->pixelformat;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 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; return FALSE;
} }
@ -598,7 +594,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
fmt.fmt.pix.width = G_MAXINT; fmt.fmt.pix.width = G_MAXINT;
fmt.fmt.pix.height = 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; return FALSE;
} }
@ -612,20 +608,29 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
return TRUE; return TRUE;
} }
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 gboolean
gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
{ {
GstV4l2Object *v4l2object = v4l2src->v4l2object;
v4l2_std_id std; v4l2_std_id std;
struct v4l2_streamparm stream; struct v4l2_streamparm stream;
const GList *item; const GList *item;
if (!GST_V4L2_IS_OPEN (GST_V4L2ELEMENT (v4l2src))) if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE; return FALSE;
/* Try to get the frame rate directly from the device using VIDIOC_G_PARM */ /* Try to get the frame rate directly from the device using VIDIOC_G_PARM */
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (GST_V4L2ELEMENT (v4l2src)->video_fd, VIDIOC_G_PARM, &stream) == 0 if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) == 0 &&
&& stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
/* Note: V4L2 gives us the frame interval, we need the frame rate */ /* Note: V4L2 gives us the frame interval, we need the frame rate */
*fps_n = stream.parm.capture.timeperframe.denominator; *fps_n = stream.parm.capture.timeperframe.denominator;
*fps_d = stream.parm.capture.timeperframe.numerator; *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 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; 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; GstV4l2TunerNorm *v4l2norm = item->data;
if (v4l2norm->index == std) { if (v4l2norm->index == std) {
@ -667,8 +672,8 @@ GValue *
gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src) gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src)
{ {
gint fps_index; gint fps_index;
struct video_window *vwin = &GST_V4L2ELEMENT (v4l2src)->vwin; struct video_window *vwin = &v4l2src->v4l2object->vwin;
GstV4l2Element *v4l2element = GST_V4L2ELEMENT (v4l2src); GstV4l2Object *v4l2object = v4l2src->v4l2object;
/* check if we have vwin window properties giving a framerate, /* check if we have vwin window properties giving a framerate,
* as is done for webcams * as is done for webcams
@ -701,7 +706,7 @@ gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src)
vwin->flags &= (0x3F00 - 1); vwin->flags &= (0x3F00 - 1);
/* set bits 16 to 21 to the index */ /* set bits 16 to 21 to the index */
vwin->flags |= i << 16; 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. */ /* setting it succeeded. FIXME: get it and check. */
g_value_init (&value, GST_TYPE_FRACTION); g_value_init (&value, GST_TYPE_FRACTION);
gst_value_set_fraction (&value, i * 15, 16); 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 */ /* FIXME: set back the original fps_index */
vwin->flags &= (0x3F00 - 1); vwin->flags &= (0x3F00 - 1);
vwin->flags |= fps_index << 16; vwin->flags |= fps_index << 16;
gst_v4l2_set_window_properties (v4l2element); gst_v4l2_set_window_properties (v4l2object);
return list; return list;
} }
return NULL; return NULL;

View file

@ -48,8 +48,11 @@ gboolean gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
void gst_v4l2src_free_buffer (GstBuffer * buffer); 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); GValue *gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src);