mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
Changes proposed by Wingo in bug #338818.
Original commit message from CVS: Changes proposed by Wingo in bug #338818.
This commit is contained in:
parent
a3c4acecbd
commit
9edc0c0365
18 changed files with 1548 additions and 1385 deletions
|
@ -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
|
||||||
|
|
|
@ -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" */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
519
sys/v4l2/gstv4l2object.c
Normal 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
211
sys/v4l2/gstv4l2object.h
Normal 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__ */
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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 */
|
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue