moved to gst-plugins-good

Original commit message from CVS:
* configure.ac:
* sys/Makefile.am:
* sys/v4l2/Makefile.am:
* sys/v4l2/README:
* sys/v4l2/gstv4l2.c:
* sys/v4l2/gstv4l2colorbalance.c:
* sys/v4l2/gstv4l2colorbalance.h:
* sys/v4l2/gstv4l2object.c:
* sys/v4l2/gstv4l2object.h:
* sys/v4l2/gstv4l2src.c:
* sys/v4l2/gstv4l2src.h:
* sys/v4l2/gstv4l2tuner.c:
* sys/v4l2/gstv4l2tuner.h:
* sys/v4l2/gstv4l2vidorient.c:
* sys/v4l2/gstv4l2vidorient.h:
* sys/v4l2/gstv4l2xoverlay.c:
* sys/v4l2/gstv4l2xoverlay.h:
* sys/v4l2/v4l2_calls.c:
* sys/v4l2/v4l2_calls.h:
* sys/v4l2/v4l2src_calls.c:
* sys/v4l2/v4l2src_calls.h:
moved to gst-plugins-good
This commit is contained in:
Thomas Vander Stichele 2006-10-03 18:23:21 +00:00
parent 321d0c208c
commit ca7c4c657c
22 changed files with 28 additions and 5200 deletions

View file

@ -1,3 +1,28 @@
2006-10-03 Thomas Vander Stichele <thomas at apestaart dot org>
* configure.ac:
* sys/Makefile.am:
* sys/v4l2/Makefile.am:
* sys/v4l2/README:
* sys/v4l2/gstv4l2.c:
* sys/v4l2/gstv4l2colorbalance.c:
* sys/v4l2/gstv4l2colorbalance.h:
* sys/v4l2/gstv4l2object.c:
* sys/v4l2/gstv4l2object.h:
* sys/v4l2/gstv4l2src.c:
* sys/v4l2/gstv4l2src.h:
* sys/v4l2/gstv4l2tuner.c:
* sys/v4l2/gstv4l2tuner.h:
* sys/v4l2/gstv4l2vidorient.c:
* sys/v4l2/gstv4l2vidorient.h:
* sys/v4l2/gstv4l2xoverlay.c:
* sys/v4l2/gstv4l2xoverlay.h:
* sys/v4l2/v4l2_calls.c:
* sys/v4l2/v4l2_calls.h:
* sys/v4l2/v4l2src_calls.c:
* sys/v4l2/v4l2src_calls.h:
moved to gst-plugins-good
2006-10-03 Thomas Vander Stichele <thomas at apestaart dot org>
* sys/v4l2/gstv4l2object.c:

View file

@ -266,63 +266,6 @@ GST_CHECK_FEATURE(X, [X libraries and plugins],
CPPFLAGS="$ac_cppflags_save"
])
dnl *** Video 4 Linux 2 ***
dnl for information about the header/define, see sys/v4l2/gstv4l2element.h
dnl renamed to GST_V4L2 because of some conflict with kernel headers
translit(dnm, m, l) AM_CONDITIONAL(USE_GST_V4L2, true)
GST_CHECK_FEATURE(GST_V4L2, [Video 4 Linux 2], v4l2src, [
AC_MSG_CHECKING([Checking for uptodate v4l2 installation])
AC_TRY_COMPILE([
#include <sys/types.h>
#include <linux/types.h>
#define _LINUX_TIME_H
#define __user
#include <linux/videodev2.h>
#if defined(V4L2_MAJOR_VERSION) || defined(V4L2_MINOR_VERSION)
#error too early v4l2 version or no v4l2 at all
#endif
], [
return 0;
], [
HAVE_GST_V4L2="yes"
AC_MSG_RESULT(yes)
], [
HAVE_GST_V4L2="no"
AC_MSG_RESULT(no)
AC_CHECK_HEADER(linux/videodev2.h,
[
AC_MSG_WARN([video4linux2 headers were found, but they're old.])
AC_MSG_WARN([Please update v4l2 to compile the v4l2 plugins])
], [
AC_MSG_WARN([video4linux2 was not found])
])
])
if [ test x$HAVE_GST_V4L2 = xyes ]; then
dnl check for missing v4l2_buffer declaration (see #135919)
MISSING_DECL=0
AC_MSG_CHECKING(struct v4l2_buffer declaration)
AC_TRY_COMPILE([
#include <sys/types.h>
#include <linux/types.h>
#define _LINUX_TIME_H
#define __user
#include <linux/videodev2.h>
],[
struct v4l2_buffer buf;
buf.index = 0;
return 0;
], [ AC_MSG_RESULT(yes) ], [ MISSING_DECL=1 && AC_MSG_RESULT(no) ])
if [ test x$MISSING_DECL = x1 ]; then
AC_DEFINE(GST_V4L2_MISSING_BUFDECL, 1, [struct v4l2_buffer missing])
fi
dnl check for XOverlay libraries
GST_CHECK_XV
fi
])
AM_CONDITIONAL(USE_XVIDEO, test "x$HAVE_XVIDEO" = "xyes")
dnl *** ext plug-ins ***
dnl keep this list sorted alphabetically !
@ -855,7 +798,6 @@ gst-libs/Makefile
gst-libs/gst/Makefile
sys/Makefile
sys/glsink/Makefile
sys/v4l2/Makefile
examples/Makefile
examples/directfb/Makefile
ext/amrwb/amrwb-code/Makefile

View file

@ -10,12 +10,6 @@
# QCAM_DIR=
# endif
if USE_GST_V4L2
V4L2_DIR=v4l2
else
V4L2_DIR=
endif
# if USE_VCD
# VCD_DIR=vcd
# else
@ -34,6 +28,6 @@ else
GL_DIR=
endif
SUBDIRS = $(GL_DIR) $(V4L2_DIR)
SUBDIRS = $(GL_DIR)
DIST_SUBDIRS = glsink v4l2
DIST_SUBDIRS = glsink

View file

@ -1,37 +0,0 @@
plugin_LTLIBRARIES = libgstvideo4linux2.la
if USE_XVIDEO
xv_source = gstv4l2xoverlay.c
xv_libs = $(X_LIBS) $(XVIDEO_LIBS)
else
xv_source =
xv_libs =
endif
libgstvideo4linux2_la_SOURCES = gstv4l2.c \
gstv4l2colorbalance.c \
gstv4l2object.c \
gstv4l2src.c \
gstv4l2tuner.c \
gstv4l2vidorient.c \
v4l2_calls.c \
v4l2src_calls.c \
$(xv_source)
libgstvideo4linux2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS) \
$(X_CFLAGS)
libgstvideo4linux2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
$(GST_BASE_LIBS) \
-lgstinterfaces-$(GST_MAJORMINOR) \
$(GST_LIBS) \
$(xv_libs)
noinst_HEADERS = gstv4l2object.h v4l2_calls.h \
gstv4l2src.h v4l2src_calls.h \
gstv4l2tuner.h gstv4l2xoverlay.h \
gstv4l2colorbalance.h gstv4l2vidorient.h

View file

@ -1,28 +1 @@
v4l2 plugins
============
The idea is a bit the same as the idea for the v4l1 plugins. We want
one generic v4l2element, and a few child objects (probably only two:
v4l2src and v4l2sink):
/-------- v4l2src
v4l2element ---=
\-------- v4l2sink
Both v4l2src and v4l2sink have a uncompressed and a compressed
recording-/playback-mode. Since this is all part of v4l2, the 'client'
of these elements, i.e. an application using v4l2src/v4l2sink, will
hardly notice this. All capsnego stuff is done inside, and the plugin
knows which formats are compressed and which are not.
Please note that the v4l1 and the v4l2 plugins are *not* compatible
concerning properties. Naming has been kept the same where possible,
but in some cases, properties had to be removed or added to make
full use of v4l2.
V4L2 API: http://linux.bytesex.org/v4l2/.
http://v4l2spec.bytesex.org/
/usr/include/linux/videodev2.h or
Kernel patches available from
http://dl.bytesex.org/patches/.
moved to gst-plugins-good

View file

@ -1,68 +0,0 @@
/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2.c: plugin for v4l2 elements
*
* 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 "gst/gst-i18n-plugin.h"
#include <gst/gst.h>
#include "gstv4l2object.h"
#include "gstv4l2src.h"
/* #include "gstv4l2jpegsrc.h" */
/* #include "gstv4l2mjpegsrc.h" */
/* #include "gstv4l2mjpegsink.h" */
/* used in v4l2_calls.c and v4l2src_calls.c */
GST_DEBUG_CATEGORY (v4l2_debug);
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls");
if (!gst_element_register (plugin, "v4l2src", GST_RANK_NONE,
GST_TYPE_V4L2SRC))
/* !gst_element_register (plugin, "v4l2jpegsrc", */
/* GST_RANK_NONE, GST_TYPE_V4L2JPEGSRC) || */
/* !gst_element_register (plugin, "v4l2mjpegsrc", */
/* GST_RANK_NONE, GST_TYPE_V4L2MJPEGSRC) || */
/* !gst_element_register (plugin, "v4l2mjpegsink", */
/* GST_RANK_NONE, GST_TYPE_V4L2MJPEGSINK)) */
return FALSE;
#ifdef ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
#endif /* ENABLE_NLS */
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"video4linux2",
"elements for Video 4 Linux",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,106 +0,0 @@
/* GStreamer
*
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2colorbalance.c: color balance interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include "gstv4l2colorbalance.h"
#include "gstv4l2object.h"
GST_BOILERPLATE (GstV4l2ColorBalanceChannel,
gst_v4l2_color_balance_channel,
GstColorBalanceChannel, GST_TYPE_COLOR_BALANCE_CHANNEL);
static void
gst_v4l2_color_balance_channel_base_init (gpointer g_class)
{
}
static void
gst_v4l2_color_balance_channel_class_init (GstV4l2ColorBalanceChannelClass *
klass)
{
}
static void
gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel,
GstV4l2ColorBalanceChannelClass * klass)
{
channel->id = (guint32) - 1;
}
static G_GNUC_UNUSED gboolean
gst_v4l2_color_balance_contains_channel (GstV4l2Object * v4l2object,
GstV4l2ColorBalanceChannel * v4l2channel)
{
const GList *item;
for (item = v4l2object->colors; item != NULL; item = item->next)
if (item->data == v4l2channel)
return TRUE;
return FALSE;
}
const GList *
gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object)
{
return v4l2object->colors;
}
void
gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object,
GstColorBalanceChannel * channel, gint value)
{
GstV4l2ColorBalanceChannel *v4l2channel =
GST_V4L2_COLOR_BALANCE_CHANNEL (channel);
/* assert that we're opened and that we're using a known item */
g_return_if_fail (GST_V4L2_IS_OPEN (v4l2object));
g_return_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object,
v4l2channel));
gst_v4l2_set_attribute (v4l2object, v4l2channel->id, value);
}
gint
gst_v4l2_color_balance_get_value (GstV4l2Object * v4l2object,
GstColorBalanceChannel * channel)
{
GstV4l2ColorBalanceChannel *v4l2channel =
GST_V4L2_COLOR_BALANCE_CHANNEL (channel);
gint value;
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0);
g_return_val_if_fail (gst_v4l2_color_balance_contains_channel (v4l2object,
v4l2channel), 0);
if (!gst_v4l2_get_attribute (v4l2object, v4l2channel->id, &value))
return 0;
return value;
}

View file

@ -1,104 +0,0 @@
/* GStreamer
*
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2colorbalance.h: color balance interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_V4L2_COLOR_BALANCE_H__
#define __GST_V4L2_COLOR_BALANCE_H__
#include <gst/gst.h>
#include <gst/interfaces/colorbalance.h>
#include "v4l2_calls.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL \
(gst_v4l2_color_balance_channel_get_type ())
#define GST_V4L2_COLOR_BALANCE_CHANNEL(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \
GstV4l2ColorBalanceChannel))
#define GST_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, \
GstV4l2ColorBalanceChannelClass))
#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL))
#define GST_IS_V4L2_COLOR_BALANCE_CHANNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL))
typedef struct _GstV4l2ColorBalanceChannel {
GstColorBalanceChannel parent;
guint32 id;
} GstV4l2ColorBalanceChannel;
typedef struct _GstV4l2ColorBalanceChannelClass {
GstColorBalanceChannelClass parent;
} GstV4l2ColorBalanceChannelClass;
GType gst_v4l2_color_balance_channel_get_type (void);
const GList * gst_v4l2_color_balance_list_channels (GstV4l2Object * v4l2object);
void gst_v4l2_color_balance_set_value (GstV4l2Object * v4l2object,
GstColorBalanceChannel * channel,
gint value);
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__ */

View file

@ -1,509 +0,0 @@
/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2object.c: base class for V4L2 elements
*
* 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"
#define DEFAULT_PROP_DEVICE "/dev/video0"
#define DEFAULT_PROP_DEVICE_NAME NULL
#define DEFAULT_PROP_FLAGS 0
#define DEFAULT_PROP_NORM NULL
#define DEFAULT_PROP_CHANNEL NULL
#define DEFAULT_PROP_FREQUENCY 0
enum
{
PROP_0,
V4L2_STD_OBJECT_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) {
const 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, "Device supports video capture", "capture"},
{V4L2_CAP_VIDEO_OUTPUT, "Device supports video playback", "output"},
{V4L2_CAP_VIDEO_OVERLAY, "Device supports video overlay", "overlay"},
{V4L2_CAP_VBI_CAPTURE, "Device supports the VBI capture", "vbi-capture"},
{V4L2_CAP_VBI_OUTPUT, "Device supports the VBI output", "vbi-output"},
{V4L2_CAP_TUNER, "Device has a tuner or modulator", "tuner"},
{V4L2_CAP_AUDIO, "Device has audio inputs or outputs", "audio"},
{0, NULL, NULL}
};
v4l2_device_type =
g_flags_register_static ("GstV4l2DeviceTypeFlags", values);
}
return v4l2_device_type;
}
void
gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class)
{
g_object_class_install_property (gobject_class, PROP_DEVICE,
g_param_spec_string ("device", "Device", "Device location",
DEFAULT_PROP_DEVICE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
g_param_spec_string ("device-name", "Device name",
"Name of the device", DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE));
g_object_class_install_property (gobject_class, PROP_FLAGS,
g_param_spec_flags ("flags", "Flags", "Device type flags",
GST_TYPE_V4L2_DEVICE_FLAGS, DEFAULT_PROP_FLAGS, G_PARAM_READABLE));
/* FIXME norm, channel, frequency are part of the tuner interface, so they
should be removed from the properties
g_object_class_install_property (gobject_class, PROP_NORM,
g_param_spec_string ("norm", "Norm", "Standard norm to use",
DEFAULT_PROP_NORM, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_CHANNEL,
g_param_spec_string ("channel", "Channel",
"Input/output channel to switch to", DEFAULT_PROP_CHANNEL,
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, DEFAULT_PROP_FREQUENCY,
G_PARAM_READWRITE));
*/
}
GstV4l2Object *
gst_v4l2_object_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 (DEFAULT_PROP_DEVICE);
v4l2object->norms = NULL;
v4l2object->channels = NULL;
v4l2object->colors = NULL;
v4l2object->xwindow_id = 0;
return v4l2object;
}
void
gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
{
if (*v4l2object) {
if ((*v4l2object)->videodev) {
g_free ((*v4l2object)->videodev);
(*v4l2object)->videodev = NULL;
}
g_free (*v4l2object);
*v4l2object = NULL;
}
}
gboolean
gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
case PROP_DEVICE:
g_free (v4l2object->videodev);
v4l2object->videodev = g_value_dup_string (value);
break;
case PROP_NORM:
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->norm);
v4l2object->norm = g_value_dup_string (value);
}
break;
case PROP_CHANNEL:
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->channel);
v4l2object->channel = 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_v4l2_object_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:
{
const guchar *new = NULL;
if (GST_V4L2_IS_OPEN (v4l2object)) {
new = v4l2object->vcap.card;
} else if (gst_v4l2_open (v4l2object)) {
new = v4l2object->vcap.card;
gst_v4l2_close (v4l2object);
}
g_value_set_string (value, (gchar *) 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_VBI_CAPTURE |
V4L2_CAP_VBI_OUTPUT | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
}
g_value_set_flags (value, flags);
break;
}
case PROP_NORM:
g_value_set_string (value, v4l2object->norm);
break;
case PROP_CHANNEL:
g_value_set_string (value, v4l2object->channel);
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->norm)
norm = gst_tuner_find_norm_by_name (tuner, v4l2object->norm);
if (norm) {
gst_tuner_set_norm (tuner, norm);
} else {
norm =
GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
if (norm) {
g_free (v4l2object->norm);
v4l2object->norm = g_strdup (norm->label);
gst_tuner_norm_changed (tuner, norm);
/* FIXME: remove
g_object_notify (G_OBJECT (v4l2object->element), "norm");
*/
}
}
if (v4l2object->channel)
channel = gst_tuner_find_channel_by_name (tuner, v4l2object->channel);
if (channel) {
gst_tuner_set_channel (tuner, channel);
} else {
channel =
GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2object->
element)));
g_free (v4l2object->channel);
v4l2object->channel = g_strdup (channel->label);
gst_tuner_channel_changed (tuner, channel);
/* FIXME: remove
g_object_notify (G_OBJECT (v4l2object->element), "channel");
*/
}
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 {
/* FIXME: remove
g_object_notify (G_OBJECT (v4l2object->element), "frequency");
*/
}
}
}
}
gboolean
gst_v4l2_object_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_v4l2_object_stop (GstV4l2Object * v4l2object)
{
#ifdef HAVE_XVIDEO
gst_v4l2_xoverlay_stop (v4l2object);
#endif
if (!gst_v4l2_close (v4l2object))
return FALSE;
return TRUE;
}

View file

@ -1,195 +0,0 @@
/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2object.h: base class for V4L2 elements
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_V4L2_OBJECT_H__
#define __GST_V4L2_OBJECT_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
#define GST_V4L2_OBJECT(obj) (GstV4l2Object *)(obj)
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 *norms;
GList *channels;
/* properties */
gchar *norm;
gchar *channel;
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_v4l2_object_get_type(void);
#define V4L2_STD_OBJECT_PROPS \
PROP_DEVICE, \
PROP_DEVICE_NAME, \
PROP_FLAGS, \
PROP_NORM, \
PROP_CHANNEL, \
PROP_FREQUENCY
/* create/destroy */
GstV4l2Object * gst_v4l2_object_new (GstElement * element,
GstV4l2GetInOutFunction get_in_out_func,
GstV4l2SetInOutFunction set_in_out_func,
GstV4l2UpdateFpsFunction update_fps_func);
void gst_v4l2_object_destroy (GstV4l2Object ** v4l2object);
/* properties */
void gst_v4l2_object_install_properties_helper (GObjectClass *gobject_class);
gboolean gst_v4l2_object_set_property_helper (GstV4l2Object *v4l2object,
guint prop_id, const GValue * value,
GParamSpec * pspec);
gboolean gst_v4l2_object_get_property_helper (GstV4l2Object *v4l2object,
guint prop_id, GValue * value,
GParamSpec * pspec);
/* starting/stopping */
gboolean gst_v4l2_object_start (GstV4l2Object *v4l2object);
gboolean gst_v4l2_object_stop (GstV4l2Object *v4l2object);
/* probing */
const GList* gst_v4l2_probe_get_properties (GstPropertyProbe * probe);
void gst_v4l2_probe_probe_property (GstPropertyProbe * probe, guint prop_id,
const GParamSpec * pspec,
GList ** klass_devices);
gboolean gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, guint prop_id,
const GParamSpec * pspec,
GList ** klass_devices);
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_V4L2_OBJECT_H__ */

View file

@ -1,987 +0,0 @@
/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2src.c: Video4Linux2 source element
*
* 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.
*/
/**
* SECTION:element-v4l2src
*
* <refsect2>
* v4l2src can be used to capture video from v4l2 devices, like webcams and tv cards.
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch v4l2src ! xvimagesink
* </programlisting>
* This pipeline shows the video captured from /dev/video0 tv card and for
* webcams.
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <sys/time.h>
#include "v4l2src_calls.h"
#include <unistd.h>
#include "gstv4l2colorbalance.h"
#include "gstv4l2tuner.h"
#include "gstv4l2xoverlay.h"
#include "gstv4l2vidorient.h"
static const GstElementDetails gst_v4l2src_details =
GST_ELEMENT_DETAILS ("Video (video4linux2/raw) Source",
"Source/Video",
"Reads raw frames from a video4linux2 (BT8x8) device",
"Ronald Bultje <rbultje@ronald.bitfreak.net>,"
" Edgard Lima <edgard.lima@indt.org.br>");
GST_DEBUG_CATEGORY (v4l2src_debug);
#define GST_CAT_DEFAULT v4l2src_debug
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
};
static const guint32 gst_v4l2_formats[] = {
/* from Linux 2.6.15 videodev2.h */
V4L2_PIX_FMT_RGB332,
V4L2_PIX_FMT_RGB555,
V4L2_PIX_FMT_RGB565,
V4L2_PIX_FMT_RGB555X,
V4L2_PIX_FMT_RGB565X,
V4L2_PIX_FMT_BGR24,
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_BGR32,
V4L2_PIX_FMT_RGB32,
V4L2_PIX_FMT_GREY,
V4L2_PIX_FMT_YVU410,
V4L2_PIX_FMT_YVU420,
V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_YUV422P,
V4L2_PIX_FMT_YUV411P,
V4L2_PIX_FMT_Y41P,
/* two planes -- one Y, one Cr + Cb interleaved */
V4L2_PIX_FMT_NV12,
V4L2_PIX_FMT_NV21,
/* The following formats are not defined in the V4L2 specification */
V4L2_PIX_FMT_YUV410,
V4L2_PIX_FMT_YUV420,
V4L2_PIX_FMT_YYUV,
V4L2_PIX_FMT_HI240,
/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
#ifdef V4L2_PIX_FMT_SBGGR8
V4L2_PIX_FMT_SBGGR8,
#endif
/* compressed formats */
V4L2_PIX_FMT_MJPEG,
V4L2_PIX_FMT_JPEG,
V4L2_PIX_FMT_DV,
V4L2_PIX_FMT_MPEG,
/* Vendor-specific formats */
V4L2_PIX_FMT_WNVA,
#ifdef V4L2_PIX_FMT_SN9C10X
V4L2_PIX_FMT_SN9C10X,
#endif
#ifdef V4L2_PIX_FMT_PWC1
V4L2_PIX_FMT_PWC1,
#endif
#ifdef V4L2_PIX_FMT_PWC2
V4L2_PIX_FMT_PWC2,
#endif
};
#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src);
GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src);
#ifdef HAVE_XVIDEO
GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Src, gst_v4l2src);
#endif
GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Src, gst_v4l2src);
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 ||
iface_type == GST_TYPE_VIDEO_ORIENTATION);
#else
g_assert (iface_type == GST_TYPE_TUNER ||
iface_type == GST_TYPE_COLOR_BALANCE ||
iface_type == GST_TYPE_VIDEO_ORIENTATION);
#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_videoorientation_info = {
(GInterfaceInitFunc) gst_v4l2src_video_orientation_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_VIDEO_ORIENTATION, &v4l2_videoorientation_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);
/* basesrc methods */
static gboolean gst_v4l2src_start (GstBaseSrc * src);
static gboolean gst_v4l2src_stop (GstBaseSrc * src);
static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps);
static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
static void gst_v4l2src_fixate (GstPad * pad, GstCaps * caps);
static void gst_v4l2src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_v4l2src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstCaps *gst_v4l2src_get_all_caps (void);
static void
gst_v4l2src_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class);
gstv4l2src_class->v4l2_class_devices = NULL;
GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element");
gst_element_class_set_details (gstelement_class, &gst_v4l2src_details);
gst_element_class_add_pad_template
(gstelement_class,
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
gst_v4l2src_get_all_caps ()));
}
static void
gst_v4l2src_class_init (GstV4l2SrcClass * klass)
{
GObjectClass *gobject_class;
GstBaseSrcClass *basesrc_class;
GstPushSrcClass *pushsrc_class;
gobject_class = G_OBJECT_CLASS (klass);
basesrc_class = GST_BASE_SRC_CLASS (klass);
pushsrc_class = GST_PUSH_SRC_CLASS (klass);
gobject_class->dispose = gst_v4l2src_dispose;
gobject_class->set_property = gst_v4l2src_set_property;
gobject_class->get_property = gst_v4l2src_get_property;
gst_v4l2_object_install_properties_helper (gobject_class);
basesrc_class->get_caps = gst_v4l2src_get_caps;
basesrc_class->set_caps = gst_v4l2src_set_caps;
basesrc_class->start = gst_v4l2src_start;
basesrc_class->stop = gst_v4l2src_stop;
pushsrc_class->create = gst_v4l2src_create;
}
static void
gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
{
v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps);
v4l2src->breq.count = 0;
v4l2src->formats = NULL;
/* fps */
v4l2src->fps_n = 0;
v4l2src->fps_d = 1;
v4l2src->is_capturing = FALSE;
gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (v4l2src),
gst_v4l2src_fixate);
gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);
}
static void
gst_v4l2src_dispose (GObject * object)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (object);
if (v4l2src->formats) {
gst_v4l2src_clear_format_list (v4l2src);
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_v4l2src_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstV4l2Src *v4l2src;
g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object);
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
}
static void
gst_v4l2src_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstV4l2Src *v4l2src;
g_return_if_fail (GST_IS_V4L2SRC (object));
v4l2src = GST_V4L2SRC (object);
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
}
/* this function is a bit of a last resort */
static void
gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
{
GstStructure *structure;
gint i;
G_GNUC_UNUSED gchar *caps_str;
caps_str = gst_caps_to_string (caps);
GST_DEBUG_OBJECT (GST_PAD_PARENT (pad), "fixating caps %s", caps_str);
g_free (caps_str);
for (i = 0; i < gst_caps_get_size (caps); ++i) {
structure = gst_caps_get_structure (caps, i);
const GValue *v;
/* FIXME such sizes? we usually fixate to something in the 320x200
* range... */
/* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE)
and framarate closer to 15/2 that is common in web-cams */
gst_structure_fixate_field_nearest_int (structure, "width",
GST_V4L2_MAX_SIZE);
gst_structure_fixate_field_nearest_int (structure, "height",
GST_V4L2_MAX_SIZE);
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
v = gst_structure_get_value (structure, "format");
if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
guint32 fourcc;
g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
}
}
}
static GstStructure *
gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc)
{
GstStructure *structure = NULL;
switch (fourcc) {
case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */
structure = gst_structure_new ("image/jpeg", NULL);
break;
case V4L2_PIX_FMT_RGB332:
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_RGB555X:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:{
guint depth = 0, bpp = 0;
gint endianness = 0;
guint32 r_mask = 0, b_mask = 0, g_mask = 0;
switch (fourcc) {
case V4L2_PIX_FMT_RGB332:
bpp = depth = 8;
endianness = G_BYTE_ORDER; /* 'like, whatever' */
r_mask = 0xe0;
g_mask = 0x1c;
b_mask = 0x03;
break;
case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_RGB555X:
bpp = 16;
depth = 15;
endianness =
fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
r_mask = 0x7c00;
g_mask = 0x03e0;
b_mask = 0x001f;
break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
bpp = depth = 16;
endianness =
fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
r_mask = 0xf800;
g_mask = 0x07e0;
b_mask = 0x001f;
break;
case V4L2_PIX_FMT_RGB24:
bpp = depth = 24;
endianness = G_BIG_ENDIAN;
r_mask = 0xff0000;
g_mask = 0x00ff00;
b_mask = 0x0000ff;
break;
case V4L2_PIX_FMT_BGR24:
bpp = depth = 24;
endianness = G_BIG_ENDIAN;
r_mask = 0x0000ff;
g_mask = 0x00ff00;
b_mask = 0xff0000;
break;
case V4L2_PIX_FMT_RGB32:
bpp = depth = 32;
endianness = G_BIG_ENDIAN;
r_mask = 0xff000000;
g_mask = 0x00ff0000;
b_mask = 0x0000ff00;
break;
case V4L2_PIX_FMT_BGR32:
bpp = depth = 32;
endianness = G_BIG_ENDIAN;
r_mask = 0x000000ff;
g_mask = 0x0000ff00;
b_mask = 0x00ff0000;
break;
default:
g_assert_not_reached ();
break;
}
structure = gst_structure_new ("video/x-raw-rgb",
"bpp", G_TYPE_INT, bpp,
"depth", G_TYPE_INT, depth,
"red_mask", G_TYPE_INT, r_mask,
"green_mask", G_TYPE_INT, g_mask,
"blue_mask", G_TYPE_INT, b_mask,
"endianness", G_TYPE_INT, endianness, NULL);
break;
}
case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
/* FIXME: get correct fourccs here */
break;
case V4L2_PIX_FMT_YVU410:
case V4L2_PIX_FMT_YUV410:
case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_Y41P:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_YUV411P:{
guint32 fcc = 0;
switch (fourcc) {
case V4L2_PIX_FMT_YVU410:
fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9');
break;
case V4L2_PIX_FMT_YUV410:
fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
break;
case V4L2_PIX_FMT_YUV420:
fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
break;
case V4L2_PIX_FMT_YUYV:
fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
break;
case V4L2_PIX_FMT_YVU420:
fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
break;
case V4L2_PIX_FMT_UYVY:
fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
break;
case V4L2_PIX_FMT_Y41P:
fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
break;
case V4L2_PIX_FMT_YUV411P:
fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
break;
case V4L2_PIX_FMT_YUV422P:
fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
break;
default:
g_assert_not_reached ();
break;
}
structure = gst_structure_new ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, fcc, NULL);
break;
}
case V4L2_PIX_FMT_DV:
structure =
gst_structure_new ("video/x-dv", "systemstream", G_TYPE_BOOLEAN, TRUE,
NULL);
break;
case V4L2_PIX_FMT_MPEG: /* MPEG */
/* someone figure out the MPEG format used... */
break;
case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */
break;
default:
GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT,
fourcc, GST_FOURCC_ARGS (fourcc));
break;
}
return structure;
}
static guint32
gst_v4l2_fourcc_from_structure (GstStructure * structure)
{
guint32 fourcc = 0;
const gchar *mimetype = gst_structure_get_name (structure);
if (!strcmp (mimetype, "video/x-raw-yuv")) {
gst_structure_get_fourcc (structure, "format", &fourcc);
switch (fourcc) {
case GST_MAKE_FOURCC ('I', '4', '2', '0'):
case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
fourcc = V4L2_PIX_FMT_YUV420;
break;
case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
fourcc = V4L2_PIX_FMT_YUYV;
break;
case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
fourcc = V4L2_PIX_FMT_Y41P;
break;
case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
fourcc = V4L2_PIX_FMT_UYVY;
break;
case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
fourcc = V4L2_PIX_FMT_YVU420;
break;
case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
fourcc = V4L2_PIX_FMT_YUV411P;
break;
case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
fourcc = V4L2_PIX_FMT_YUV422P;
break;
}
} else if (!strcmp (mimetype, "video/x-raw-rgb")) {
gint depth, endianness, r_mask;
gst_structure_get_int (structure, "depth", &depth);
gst_structure_get_int (structure, "endianness", &endianness);
gst_structure_get_int (structure, "red_mask", &r_mask);
switch (depth) {
case 8:
fourcc = V4L2_PIX_FMT_RGB332;
break;
case 15:
fourcc = (endianness == G_LITTLE_ENDIAN) ?
V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X;
break;
case 16:
fourcc = (endianness == G_LITTLE_ENDIAN) ?
V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X;
break;
case 24:
fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24;
break;
case 32:
fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32;
break;
}
} else if (strcmp (mimetype, "video/x-dv") == 0) {
fourcc = V4L2_PIX_FMT_DV;
} else if (strcmp (mimetype, "image/jpeg") == 0) {
fourcc = V4L2_PIX_FMT_JPEG;
}
return fourcc;
}
static struct v4l2_fmtdesc *
gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc)
{
struct v4l2_fmtdesc *fmt;
GSList *walk;
if (fourcc == 0)
return NULL;
walk = v4l2src->formats;
while (walk) {
fmt = (struct v4l2_fmtdesc *) walk->data;
if (fmt->pixelformat == fourcc)
return fmt;
/* special case for jpeg */
if ((fmt->pixelformat == V4L2_PIX_FMT_MJPEG && fourcc == V4L2_PIX_FMT_JPEG)
|| (fmt->pixelformat == V4L2_PIX_FMT_JPEG
&& fourcc == V4L2_PIX_FMT_MJPEG)) {
return fmt;
}
walk = g_slist_next (walk);
}
return NULL;
}
static struct v4l2_fmtdesc *
gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src * v4l2src, GstStructure * structure)
{
return gst_v4l2src_get_format_from_fourcc (v4l2src,
gst_v4l2_fourcc_from_structure (structure));
}
static GstCaps *
gst_v4l2src_get_all_caps (void)
{
static GstCaps *caps = NULL;
if (caps == NULL) {
GstStructure *structure;
guint i;
caps = gst_caps_new_empty ();
for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
structure = gst_v4l2src_v4l2fourcc_to_caps (gst_v4l2_formats[i]);
if (structure) {
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
"height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 100, 1, NULL);
gst_caps_append_structure (caps, structure);
}
}
}
return caps;
}
static GstCaps *
gst_v4l2src_get_caps (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
GstCaps *caps;
struct v4l2_fmtdesc *format;
int min_w, max_w, min_h, max_h;
GSList *walk;
GstStructure *structure;
guint fps_n, fps_d;
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
return
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
(v4l2src)));
}
if (!v4l2src->formats)
gst_v4l2src_fill_format_list (v4l2src);
/* build our own capslist */
caps = gst_caps_new_empty ();
walk = v4l2src->formats;
if (!gst_v4l2src_get_fps (v4l2src, &fps_n, &fps_d)) {
GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown.");
fps_n = 0;
fps_d = 1;
}
while (walk) {
format = (struct v4l2_fmtdesc *) walk->data;
walk = g_slist_next (walk);
/* get size delimiters */
if (!gst_v4l2src_get_size_limits (v4l2src, format,
&min_w, &max_w, &min_h, &max_h)) {
continue;
}
/* template, FIXME, why limit if the device reported correct results? */
/* we are doing it right now to avoid unexpected results */
min_w = CLAMP (min_w, 1, GST_V4L2_MAX_SIZE);
min_h = CLAMP (min_h, 1, GST_V4L2_MAX_SIZE);
max_w = CLAMP (max_w, min_w, GST_V4L2_MAX_SIZE);
max_h = CLAMP (max_h, min_h, GST_V4L2_MAX_SIZE);
/* add to list */
structure = gst_v4l2src_v4l2fourcc_to_caps (format->pixelformat);
if (structure) {
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, min_w, max_w,
"height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
/* FIXME, why random range? */
/* AFAIK: in v4l2 standard we still don't have a good way to enum
for a range. Currently it is on discussion on v4l2 forum.
Currently, something more smart could be done for tvcard devices.
The maximum value could be determined by 'v4l2_standard.frameperiod'
and minimum also to the same if V4L2_CAP_TIMEPERFRAME is not set. */
/* another approach for web-cams would be to try to set a very
high(100/1) and low(1/1) FPSs and get the values returned */
gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
0, 1, 100, 1, NULL);
gst_caps_append_structure (caps, structure);
}
}
return caps;
}
static gboolean
gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
{
GstV4l2Src *v4l2src;
gint w, h;
GstStructure *structure;
struct v4l2_fmtdesc *format;
const GValue *framerate;
guint fps_n, fps_d;
v4l2src = GST_V4L2SRC (src);
/* if we're not open, punt -- we'll get setcaps'd later via negotiate */
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object))
return FALSE;
/* make sure we stop capturing and dealloc buffers */
if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
if (!gst_v4l2src_capture_stop (v4l2src))
return FALSE;
if (!gst_v4l2src_capture_deinit (v4l2src))
return FALSE;
}
structure = gst_caps_get_structure (caps, 0);
/* we want our own v4l2 type of fourcc codes */
if (!(format = gst_v4l2_caps_to_v4l2fourcc (v4l2src, structure))) {
return FALSE;
}
gst_structure_get_int (structure, "width", &w);
gst_structure_get_int (structure, "height", &h);
framerate = gst_structure_get_value (structure, "framerate");
GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d, format %s",
w, h, format->description);
if (framerate) {
fps_n = gst_value_get_fraction_numerator (framerate);
fps_d = gst_value_get_fraction_denominator (framerate);
} else {
fps_n = 0;
fps_d = 1;
}
if (!gst_v4l2src_set_capture (v4l2src, format, &w, &h, &fps_n, &fps_d)) {
GST_WARNING_OBJECT (v4l2src, "could not set_capture %dx%d, format %s",
w, h, format->description);
return FALSE;
}
if (fps_n) {
gst_structure_set (structure,
"width", G_TYPE_INT, w,
"height", G_TYPE_INT, h,
"framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
} else {
gst_structure_set (structure,
"width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL);
}
if (!gst_v4l2src_capture_init (v4l2src))
return FALSE;
if (!gst_v4l2src_capture_start (v4l2src))
return FALSE;
if (v4l2src->fps_n != fps_n || v4l2src->fps_d != fps_d) {
GST_WARNING_OBJECT (v4l2src,
"framerate changed after start capturing from %u/%u to %u/%u", fps_n,
fps_d, v4l2src->fps_n, v4l2src->fps_d);
if (fps_n) {
gst_structure_set (structure,
"width", G_TYPE_INT, w,
"height", G_TYPE_INT, h,
"framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL);
}
}
return TRUE;
}
/* start and stop are not symmetric -- start will open the device, but not start
* capture. it's setcaps that will start capture, which is called via basesrc's
* negotiate method. stop will both stop capture and close the device.
*/
static gboolean
gst_v4l2src_start (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
if (!gst_v4l2_object_start (v4l2src->v4l2object))
return FALSE;
v4l2src->offset = 0;
return TRUE;
}
static gboolean
gst_v4l2src_stop (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)
&& !gst_v4l2src_capture_stop (v4l2src))
return FALSE;
if (v4l2src->v4l2object->buffer != NULL) {
if (!gst_v4l2src_capture_deinit (v4l2src))
return FALSE;
}
if (!gst_v4l2_object_stop (v4l2src->v4l2object))
return FALSE;
return TRUE;
}
static GstFlowReturn
gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
{
gint amount;
gint buffersize;
buffersize = v4l2src->format.fmt.pix.sizeimage;
do {
*buf = gst_v4l2src_buffer_new (v4l2src, buffersize, NULL, NULL);
amount =
read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
buffersize);
if (amount == buffersize) {
break;
} else if (amount == -1) {
if (errno == EAGAIN || errno == EINTR) {
continue;
} else
goto read_error;
} else
goto short_read;
} while (TRUE);
return GST_FLOW_OK;
/* ERRORS */
read_error:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
(_("Error read()ing %d bytes on device %s."),
buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
short_read:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
("Error read()ing a buffer on device %s: got only %d bytes instead of expected %d.",
v4l2src->v4l2object->videodev, amount, buffersize));
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
{
gint i, num;
/* grab a frame from the device, post an error */
num = gst_v4l2src_grab_frame (v4l2src);
if (num == -1)
goto grab_failed;
i = v4l2src->format.fmt.pix.sizeimage;
/* check if this is the last buffer in the queue. If so do a memcpy to put it back asap
to avoid framedrops and deadlocks because of stupid elements */
if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) {
GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer");
*buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL);
memcpy (GST_BUFFER_DATA (*buf), v4l2src->pool->buffers[num].start, i);
/* posts an error message if something went wrong */
if (!gst_v4l2src_queue_frame (v4l2src, num))
goto queue_failed;
} else {
GST_LOG_OBJECT (v4l2src, "using mmap'd buffer");
*buf =
gst_v4l2src_buffer_new (v4l2src, i, v4l2src->pool->buffers[num].start,
&v4l2src->pool->buffers[num]);
/* no need to be careful here, both are > 0, because the element uses them */
g_atomic_int_inc (&v4l2src->pool->buffers[num].refcount);
g_atomic_int_inc (&v4l2src->pool->refcount);
}
return GST_FLOW_OK;
/* ERRORS */
grab_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to grab a frame");
return GST_FLOW_ERROR;
}
queue_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to queue frame");
gst_buffer_unref (*buf);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
GstFlowReturn ret;
if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) {
ret = gst_v4l2src_get_mmap (v4l2src, buf);
} else {
ret = gst_v4l2src_get_read (v4l2src, buf);
}
return ret;
}

View file

@ -1,117 +0,0 @@
/* GStreamer
*
* Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2src.h: BT8x8/V4L2 source element
*
* 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_V4L2SRC_H__
#define __GST_V4L2SRC_H__
#include <gstv4l2object.h>
GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug);
#define GST_V4L2_MAX_BUFFERS 16
#define GST_V4L2_MIN_BUFFERS 2
#define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */
G_BEGIN_DECLS
#define GST_TYPE_V4L2SRC \
(gst_v4l2src_get_type())
#define GST_V4L2SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4L2SRC,GstV4l2Src))
#define GST_V4L2SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4L2SRC,GstV4l2SrcClass))
#define GST_IS_V4L2SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4L2SRC))
#define GST_IS_V4L2SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2SRC))
typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
typedef struct _GstV4l2Buffer GstV4l2Buffer;
typedef struct _GstV4l2Src GstV4l2Src;
typedef struct _GstV4l2SrcClass GstV4l2SrcClass;
/* global info */
struct _GstV4l2BufferPool
{
gint refcount; /* number of users: 1 for every buffer, 1 for element */
gint video_fd;
guint buffer_count;
GstV4l2Buffer *buffers;
};
struct _GstV4l2Buffer
{
struct v4l2_buffer buffer;
guint8 *start;
guint length;
gint refcount; /* add 1 if in use by element, add 1 if in use by GstBuffer */
GstV4l2BufferPool *pool;
};
/**
* GstV4l2Src:
* @pushsrc: parent #GstPushSrc.
*
* Opaque object.
*/
struct _GstV4l2Src
{
GstPushSrc pushsrc;
/*< private >*/
GstV4l2Object * v4l2object;
/* pads */
GstPad *srcpad;
/* internal lists */
GSList *formats; /* list of available capture formats */
/* buffers */
GstV4l2BufferPool *pool;
struct v4l2_requestbuffers breq;
struct v4l2_format format;
/* True if we want to stop */
gboolean quit, is_capturing;
guint64 offset;
/* how are we going to push buffers? */
guint fps_n, fps_d;
};
struct _GstV4l2SrcClass
{
GstPushSrcClass parent_class;
GList *v4l2_class_devices;
};
GType gst_v4l2src_get_type (void);
G_END_DECLS
#endif /* __GST_V4L2SRC_H__ */

View file

@ -1,341 +0,0 @@
/* GStreamer
*
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2tuner.c: tuner interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include "gstv4l2tuner.h"
#include "gstv4l2object.h"
#include "v4l2_calls.h"
#include "v4l2src_calls.h"
static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *
klass);
static void gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel);
static void gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass * klass);
static void gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm);
static GstTunerNormClass *norm_parent_class = NULL;
static GstTunerChannelClass *channel_parent_class = NULL;
GType
gst_v4l2_tuner_channel_get_type (void)
{
static GType gst_v4l2_tuner_channel_type = 0;
if (!gst_v4l2_tuner_channel_type) {
static const GTypeInfo v4l2_tuner_channel_info = {
sizeof (GstV4l2TunerChannelClass),
NULL,
NULL,
(GClassInitFunc) gst_v4l2_tuner_channel_class_init,
NULL,
NULL,
sizeof (GstV4l2TunerChannel),
0,
(GInstanceInitFunc) gst_v4l2_tuner_channel_init,
NULL
};
gst_v4l2_tuner_channel_type =
g_type_register_static (GST_TYPE_TUNER_CHANNEL,
"GstV4l2TunerChannel", &v4l2_tuner_channel_info, 0);
}
return gst_v4l2_tuner_channel_type;
}
static void
gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass * klass)
{
channel_parent_class = g_type_class_peek_parent (klass);
}
static void
gst_v4l2_tuner_channel_init (GstV4l2TunerChannel * channel)
{
channel->index = (guint32) - 1;
channel->tuner = (guint32) - 1;
channel->audio = (guint32) - 1;
}
GType
gst_v4l2_tuner_norm_get_type (void)
{
static GType gst_v4l2_tuner_norm_type = 0;
if (!gst_v4l2_tuner_norm_type) {
static const GTypeInfo v4l2_tuner_norm_info = {
sizeof (GstV4l2TunerNormClass),
NULL,
NULL,
(GClassInitFunc) gst_v4l2_tuner_norm_class_init,
NULL,
NULL,
sizeof (GstV4l2TunerNorm),
0,
(GInstanceInitFunc) gst_v4l2_tuner_norm_init,
NULL
};
gst_v4l2_tuner_norm_type =
g_type_register_static (GST_TYPE_TUNER_NORM,
"GstV4l2TunerNorm", &v4l2_tuner_norm_info, 0);
}
return gst_v4l2_tuner_norm_type;
}
static void
gst_v4l2_tuner_norm_class_init (GstV4l2TunerNormClass * klass)
{
norm_parent_class = g_type_class_peek_parent (klass);
}
static void
gst_v4l2_tuner_norm_init (GstV4l2TunerNorm * norm)
{
norm->index = 0;
}
static G_GNUC_UNUSED gboolean
gst_v4l2_tuner_contains_channel (GstV4l2Object * v4l2object,
GstV4l2TunerChannel * v4l2channel)
{
const GList *item;
for (item = v4l2object->channels; item != NULL; item = item->next)
if (item->data == v4l2channel)
return TRUE;
return FALSE;
}
const GList *
gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object)
{
return v4l2object->channels;
}
void
gst_v4l2_tuner_set_channel_and_notify (GstV4l2Object * v4l2object,
GstTunerChannel * channel)
{
if (gst_v4l2_tuner_set_channel (v4l2object, channel)) {
g_object_notify (G_OBJECT (v4l2object->element), "channel");
}
}
gboolean
gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object,
GstTunerChannel * channel)
{
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
v4l2channel), FALSE);
if (v4l2object->set_in_out_func (v4l2object, v4l2channel->index)) {
gst_tuner_channel_changed (GST_TUNER (v4l2object->element), channel);
v4l2object->update_fps_func (v4l2object);
return TRUE;
}
return FALSE;
}
GstTunerChannel *
gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object)
{
GList *item;
gint channel;
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL);
v4l2object->get_in_out_func (v4l2object, &channel);
for (item = v4l2object->channels; item != NULL; item = item->next) {
if (channel == GST_V4L2_TUNER_CHANNEL (item->data)->index)
return (GstTunerChannel *) item->data;
}
return NULL;
}
static G_GNUC_UNUSED gboolean
gst_v4l2_tuner_contains_norm (GstV4l2Object * v4l2object,
GstV4l2TunerNorm * v4l2norm)
{
const GList *item;
for (item = v4l2object->norms; item != NULL; item = item->next)
if (item->data == v4l2norm)
return TRUE;
return FALSE;
}
const GList *
gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object)
{
return v4l2object->norms;
}
void
gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object,
GstTunerNorm * norm)
{
if (gst_v4l2_tuner_set_norm (v4l2object, norm)) {
g_object_notify (G_OBJECT (v4l2object->element), "norm");
}
}
gboolean
gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object, GstTunerNorm * norm)
{
GstV4l2TunerNorm *v4l2norm = GST_V4L2_TUNER_NORM (norm);
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
g_return_val_if_fail (gst_v4l2_tuner_contains_norm (v4l2object, v4l2norm),
FALSE);
if (gst_v4l2_set_norm (v4l2object, v4l2norm->index)) {
gst_tuner_norm_changed (GST_TUNER (v4l2object->element), norm);
v4l2object->update_fps_func (v4l2object);
return TRUE;
}
return FALSE;
}
GstTunerNorm *
gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object)
{
GList *item;
v4l2_std_id norm;
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), NULL);
gst_v4l2_get_norm (v4l2object, &norm);
for (item = v4l2object->norms; item != NULL; item = item->next) {
if (norm == GST_V4L2_TUNER_NORM (item->data)->index)
return (GstTunerNorm *) item->data;
}
return NULL;
}
void
gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object,
GstTunerChannel * channel, gulong frequency)
{
if (gst_v4l2_tuner_set_frequency (v4l2object, channel, frequency)) {
g_object_notify (G_OBJECT (v4l2object->element), "frequency");
}
}
gboolean
gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object,
GstTunerChannel * channel, gulong frequency)
{
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
gint chan;
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
GST_TUNER_CHANNEL_FREQUENCY), FALSE);
g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
v4l2channel), FALSE);
v4l2object->get_in_out_func (v4l2object, &chan);
if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
if (gst_v4l2_set_frequency (v4l2object, v4l2channel->tuner, frequency)) {
gst_tuner_frequency_changed (GST_TUNER (v4l2object->element), channel,
frequency);
return TRUE;
}
}
return FALSE;
}
gulong
gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object,
GstTunerChannel * channel)
{
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
gint chan;
gulong frequency = 0;
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0);
g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
GST_TUNER_CHANNEL_FREQUENCY), 0);
g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
v4l2channel), 0);
v4l2object->get_in_out_func (v4l2object, &chan);
if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
gst_v4l2_get_frequency (v4l2object, v4l2channel->tuner, &frequency);
}
return frequency;
}
gint
gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object,
GstTunerChannel * channel)
{
GstV4l2TunerChannel *v4l2channel = GST_V4L2_TUNER_CHANNEL (channel);
gint chan;
gulong signal = 0;
/* assert that we're opened and that we're using a known item */
g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), 0);
g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel,
GST_TUNER_CHANNEL_FREQUENCY), 0);
g_return_val_if_fail (gst_v4l2_tuner_contains_channel (v4l2object,
v4l2channel), 0);
v4l2object->get_in_out_func (v4l2object, &chan);
if (chan == GST_V4L2_TUNER_CHANNEL (channel)->index &&
GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) {
gst_v4l2_signal_strength (v4l2object, v4l2channel->tuner, &signal);
}
return signal;
}

View file

@ -1,195 +0,0 @@
/* GStreamer
*
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2tuner.h: tuner interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_V4L2_TUNER_H__
#define __GST_V4L2_TUNER_H__
#include <gst/gst.h>
#include <gst/interfaces/tuner.h>
#include "gstv4l2object.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_TUNER_CHANNEL \
(gst_v4l2_tuner_channel_get_type ())
#define GST_V4L2_TUNER_CHANNEL(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_CHANNEL, \
GstV4l2TunerChannel))
#define GST_V4L2_TUNER_CHANNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_CHANNEL, \
GstV4l2TunerChannelClass))
#define GST_IS_V4L2_TUNER_CHANNEL(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_CHANNEL))
#define GST_IS_V4L2_TUNER_CHANNEL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_CHANNEL))
typedef struct _GstV4l2TunerChannel {
GstTunerChannel parent;
guint32 index;
guint32 tuner;
guint32 audio;
} GstV4l2TunerChannel;
typedef struct _GstV4l2TunerChannelClass {
GstTunerChannelClass parent;
} GstV4l2TunerChannelClass;
#define GST_TYPE_V4L2_TUNER_NORM \
(gst_v4l2_tuner_norm_get_type ())
#define GST_V4L2_TUNER_NORM(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_TUNER_NORM, \
GstV4l2TunerNorm))
#define GST_V4L2_TUNER_NORM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L2_TUNER_NORM, \
GstV4l2TunerNormClass))
#define GST_IS_V4L2_TUNER_NORM(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_TUNER_NORM))
#define GST_IS_V4L2_TUNER_NORM_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L2_TUNER_NORM))
typedef struct _GstV4l2TunerNorm {
GstTunerNorm parent;
v4l2_std_id index;
} GstV4l2TunerNorm;
typedef struct _GstV4l2TunerNormClass {
GstTunerNormClass parent;
} GstV4l2TunerNormClass;
GType gst_v4l2_tuner_channel_get_type (void);
GType gst_v4l2_tuner_norm_get_type (void);
/* channels */
const GList* gst_v4l2_tuner_list_channels (GstV4l2Object * v4l2object);
void gst_v4l2_tuner_set_channel_and_notify (GstV4l2Object * v4l2object,
GstTunerChannel * channel);
GstTunerChannel* gst_v4l2_tuner_get_channel (GstV4l2Object * v4l2object);
gboolean gst_v4l2_tuner_set_channel (GstV4l2Object * v4l2object,
GstTunerChannel * channel);
/* norms */
const GList* gst_v4l2_tuner_list_norms (GstV4l2Object * v4l2object);
void gst_v4l2_tuner_set_norm_and_notify (GstV4l2Object * v4l2object,
GstTunerNorm * norm);
GstTunerNorm* gst_v4l2_tuner_get_norm (GstV4l2Object * v4l2object);
gboolean gst_v4l2_tuner_set_norm (GstV4l2Object * v4l2object,
GstTunerNorm * norm);
/* frequency */
void gst_v4l2_tuner_set_frequency_and_notify (GstV4l2Object * v4l2object,
GstTunerChannel * channel,
gulong frequency);
gint gst_v4l2_tuner_signal_strength (GstV4l2Object * v4l2object,
GstTunerChannel * channel);
gulong gst_v4l2_tuner_get_frequency (GstV4l2Object * v4l2object,
GstTunerChannel * channel);
gboolean gst_v4l2_tuner_set_frequency (GstV4l2Object * v4l2object,
GstTunerChannel * channel,
gulong frequency);
#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__ */

View file

@ -1,96 +0,0 @@
/* GStreamer
*
* Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2vidorient.c: video orientation interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include "gstv4l2vidorient.h"
#include "gstv4l2object.h"
#include "v4l2_calls.h"
#include "v4l2src_calls.h"
GST_DEBUG_CATEGORY_STATIC (v4l2vo_debug);
#define GST_CAT_DEFAULT v4l2vo_debug
void
gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * klass)
{
GST_DEBUG_CATEGORY_INIT (v4l2vo_debug, "v4l2vo", 0,
"V4L2 VideoOrientation interface debugging");
}
gboolean
gst_v4l2_video_orientation_get_hflip (GstV4l2Object * v4l2object,
gboolean * flip)
{
return gst_v4l2_get_attribute (v4l2object, V4L2_CID_HFLIP, flip);
}
gboolean
gst_v4l2_video_orientation_get_vflip (GstV4l2Object * v4l2object,
gboolean * flip)
{
return gst_v4l2_get_attribute (v4l2object, V4L2_CID_VFLIP, flip);
}
gboolean
gst_v4l2_video_orientation_get_hcenter (GstV4l2Object * v4l2object,
gint * center)
{
return gst_v4l2_get_attribute (v4l2object, V4L2_CID_HCENTER, center);
}
gboolean
gst_v4l2_video_orientation_get_vcenter (GstV4l2Object * v4l2object,
gint * center)
{
return gst_v4l2_get_attribute (v4l2object, V4L2_CID_VCENTER, center);
}
gboolean
gst_v4l2_video_orientation_set_hflip (GstV4l2Object * v4l2object, gboolean flip)
{
return gst_v4l2_set_attribute (v4l2object, V4L2_CID_HFLIP, flip);
}
gboolean
gst_v4l2_video_orientation_set_vflip (GstV4l2Object * v4l2object, gboolean flip)
{
return gst_v4l2_set_attribute (v4l2object, V4L2_CID_VFLIP, flip);
}
gboolean
gst_v4l2_video_orientation_set_hcenter (GstV4l2Object * v4l2object, gint center)
{
return gst_v4l2_set_attribute (v4l2object, V4L2_CID_HCENTER, center);
}
gboolean
gst_v4l2_video_orientation_set_vcenter (GstV4l2Object * v4l2object, gint center)
{
return gst_v4l2_set_attribute (v4l2object, V4L2_CID_VCENTER, center);
}

View file

@ -1,117 +0,0 @@
/* GStreamer
*
* Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2vidorient.h: video orientation interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_V4L2_VIDORIENT_H__
#define __GST_V4L2_VIDORIENT_H__
#include <gst/gst.h>
#include <gst/interfaces/videoorientation.h>
#include "gstv4l2object.h"
G_BEGIN_DECLS
void gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * klass);
gboolean gst_v4l2_video_orientation_get_hflip (GstV4l2Object *v4l2object, gboolean *flip);
gboolean gst_v4l2_video_orientation_get_vflip (GstV4l2Object *v4l2object, gboolean *flip);
gboolean gst_v4l2_video_orientation_get_hcenter (GstV4l2Object *v4l2object, gint *center);
gboolean gst_v4l2_video_orientation_get_vcenter (GstV4l2Object *v4l2object, gint *center);
gboolean gst_v4l2_video_orientation_set_hflip (GstV4l2Object *v4l2object, gboolean flip);
gboolean gst_v4l2_video_orientation_set_vflip (GstV4l2Object *v4l2object, gboolean flip);
gboolean gst_v4l2_video_orientation_set_hcenter (GstV4l2Object *v4l2object, gint center);
gboolean gst_v4l2_video_orientation_set_vcenter (GstV4l2Object *v4l2object, gint center);
#define GST_IMPLEMENT_V4L2_VIDORIENT_METHODS(Type, interface_as_function) \
\
static gboolean \
interface_as_function ## _video_orientation_get_hflip (GstVideoOrientation *vo, gboolean *flip) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_get_hflip (this->v4l2object, flip); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_get_vflip (GstVideoOrientation *vo, gboolean *flip) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_get_vflip (this->v4l2object, flip); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_get_hcenter (GstVideoOrientation *vo, gint *center) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_get_hcenter (this->v4l2object, center); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_get_vcenter (GstVideoOrientation *vo, gint *center) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_get_vcenter (this->v4l2object, center); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_set_hflip (GstVideoOrientation *vo, gboolean flip) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_set_hflip (this->v4l2object, flip); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_set_vflip (GstVideoOrientation *vo, gboolean flip) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_set_vflip (this->v4l2object, flip); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_set_hcenter (GstVideoOrientation *vo, gint center) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_set_hcenter (this->v4l2object, center); \
} \
\
static gboolean \
interface_as_function ## _video_orientation_set_vcenter (GstVideoOrientation *vo, gint center) \
{ \
Type *this = (Type*) vo; \
return gst_v4l2_video_orientation_set_vcenter (this->v4l2object, center); \
} \
\
void \
interface_as_function ## _video_orientation_interface_init (GstVideoOrientationInterface * klass) \
{ \
/* default virtual functions */ \
klass->get_hflip = interface_as_function ## _video_orientation_get_hflip; \
klass->get_vflip = interface_as_function ## _video_orientation_get_vflip; \
klass->get_hcenter = interface_as_function ## _video_orientation_get_hcenter; \
klass->get_vcenter = interface_as_function ## _video_orientation_get_vcenter; \
klass->set_hflip = interface_as_function ## _video_orientation_set_hflip; \
klass->set_vflip = interface_as_function ## _video_orientation_set_vflip; \
klass->set_hcenter = interface_as_function ## _video_orientation_set_hcenter; \
klass->set_vcenter = interface_as_function ## _video_orientation_set_vcenter; \
}
#endif /* __GST_V4L2_VIDORIENT_H__ */

View file

@ -1,251 +0,0 @@
/* GStreamer
*
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2xoverlay.c: X-based overlay interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
#include <sys/stat.h>
#include "gstv4l2xoverlay.h"
#include "gstv4l2object.h"
#include "v4l2_calls.h"
struct _GstV4l2Xv
{
Display *dpy;
gint port, idle_id;
GMutex *mutex;
};
GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug);
#define GST_CAT_DEFAULT v4l2xv_debug
static void gst_v4l2_xoverlay_set_xwindow_id (GstV4l2Object * v4l2object,
XID xwindow_id);
void
gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass)
{
GST_DEBUG_CATEGORY_INIT (v4l2xv_debug, "v4l2xv", 0,
"V4L2 XOverlay interface debugging");
}
static void
gst_v4l2_xoverlay_open (GstV4l2Object * v4l2object)
{
struct stat s;
GstV4l2Xv *v4l2xv;
const gchar *name = g_getenv ("DISPLAY");
unsigned int ver, rel, req, ev, err, anum;
int i, id = 0, first_id = 0, min;
XvAdaptorInfo *ai;
Display *dpy;
/* we need a display, obviously */
if (!name || !(dpy = XOpenDisplay (name))) {
GST_WARNING_OBJECT (v4l2object->element,
"No $DISPLAY set or failed to open - no overlay");
return;
}
/* First let's check that XVideo extension is available */
if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) {
GST_WARNING_OBJECT (v4l2object->element,
"Xv extension not available - no overlay");
XCloseDisplay (dpy);
return;
}
/* find port that belongs to this device */
if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) {
GST_WARNING_OBJECT (v4l2object->element,
"Xv extension not supported - no overlay");
XCloseDisplay (dpy);
return;
}
if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) {
GST_WARNING_OBJECT (v4l2object->element, "Failed to query Xv adaptors");
XCloseDisplay (dpy);
return;
}
if (fstat (v4l2object->video_fd, &s) < 0) {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Cannot identify device '%s'."), v4l2object->videodev),
GST_ERROR_SYSTEM);
XCloseDisplay (dpy);
return;
}
min = s.st_rdev & 0xff;
for (i = 0; i < anum; i++) {
if (!strcmp (ai[i].name, "video4linux2")) {
if (first_id == 0)
first_id = ai[i].base_id;
/* hmm... */
if (first_id != 0 && ai[i].base_id == first_id + min)
id = ai[i].base_id;
}
}
XvFreeAdaptorInfo (ai);
if (id == 0) {
GST_WARNING_OBJECT (v4l2object->element,
"Did not find XvPortID for device - no overlay");
XCloseDisplay (dpy);
return;
}
v4l2xv = g_new0 (GstV4l2Xv, 1);
v4l2xv->dpy = dpy;
v4l2xv->port = id;
v4l2xv->mutex = g_mutex_new ();
v4l2xv->idle_id = 0;
v4l2object->xv = v4l2xv;
if (v4l2object->xwindow_id) {
gst_v4l2_xoverlay_set_xwindow_id (v4l2object, v4l2object->xwindow_id);
}
}
static void
gst_v4l2_xoverlay_close (GstV4l2Object * v4l2object)
{
GstV4l2Xv *v4l2xv = v4l2object->xv;
if (!v4l2object->xv)
return;
if (v4l2object->xwindow_id) {
gst_v4l2_xoverlay_set_xwindow_id (v4l2object, 0);
}
XCloseDisplay (v4l2xv->dpy);
g_mutex_free (v4l2xv->mutex);
if (v4l2xv->idle_id)
g_source_remove (v4l2xv->idle_id);
g_free (v4l2xv);
v4l2object->xv = NULL;
}
void
gst_v4l2_xoverlay_start (GstV4l2Object * v4l2object)
{
if (v4l2object->xwindow_id) {
gst_v4l2_xoverlay_open (v4l2object);
}
}
void
gst_v4l2_xoverlay_stop (GstV4l2Object * v4l2object)
{
gst_v4l2_xoverlay_close (v4l2object);
}
static gboolean
idle_refresh (gpointer data)
{
GstV4l2Object *v4l2object = GST_V4L2_OBJECT (data);
GstV4l2Xv *v4l2xv = v4l2object->xv;
XWindowAttributes attr;
if (v4l2xv) {
g_mutex_lock (v4l2xv->mutex);
XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr);
XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id,
DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)),
0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
v4l2xv->idle_id = 0;
g_mutex_unlock (v4l2xv->mutex);
}
/* once */
return FALSE;
}
static void
gst_v4l2_xoverlay_set_xwindow_id (GstV4l2Object * v4l2object, XID xwindow_id)
{
GstV4l2Xv *v4l2xv;
XWindowAttributes attr;
gboolean change = (v4l2object->xwindow_id != xwindow_id);
GST_LOG_OBJECT (v4l2object->element, "Setting XID to %lx",
(gulong) xwindow_id);
if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object))
gst_v4l2_xoverlay_open (v4l2object);
v4l2xv = v4l2object->xv;
if (v4l2xv)
g_mutex_lock (v4l2xv->mutex);
if (change) {
if (v4l2object->xwindow_id && v4l2xv) {
GST_DEBUG_OBJECT (v4l2object->element,
"Deactivating old port %lx", v4l2object->xwindow_id);
XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 0);
XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 0);
XvStopVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id);
}
v4l2object->xwindow_id = xwindow_id;
}
if (!v4l2xv || xwindow_id == 0) {
if (v4l2xv)
g_mutex_unlock (v4l2xv->mutex);
return;
}
if (change) {
GST_DEBUG_OBJECT (v4l2object->element, "Activating new port %lx",
xwindow_id);
/* draw */
XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 1);
XvSelectVideoNotify (v4l2xv->dpy, v4l2object->xwindow_id, 1);
}
XGetWindowAttributes (v4l2xv->dpy, v4l2object->xwindow_id, &attr);
XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2object->xwindow_id,
DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)),
0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
if (v4l2xv->idle_id)
g_source_remove (v4l2xv->idle_id);
v4l2xv->idle_id = g_idle_add (idle_refresh, v4l2object);
g_mutex_unlock (v4l2xv->mutex);
}

View file

@ -1,62 +0,0 @@
/* GStreamer
*
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* gstv4l2xoverlay.h: tv mixer interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_V4L2_X_OVERLAY_H__
#define __GST_V4L2_X_OVERLAY_H__
#include <X11/X.h>
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
#include "gstv4l2object.h"
G_BEGIN_DECLS
void gst_v4l2_xoverlay_start (GstV4l2Object *v4l2object);
void gst_v4l2_xoverlay_stop (GstV4l2Object *v4l2object);
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); \
} \
\
#endif /* __GST_V4L2_X_OVERLAY_H__ */

View file

@ -1,748 +0,0 @@
/* GStreamer
*
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* v4l2_calls.c - generic V4L2 calls handling
*
* 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/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "v4l2_calls.h"
#include "gstv4l2tuner.h"
#include "gstv4l2xoverlay.h"
#include "gstv4l2colorbalance.h"
#include "gstv4l2src.h"
GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
#define GST_CAT_DEFAULT v4l2_debug
/******************************************************
* gst_v4l2_get_capabilities():
* get the device's capturing capabilities
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
{
GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities");
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
goto cap_failed;
return TRUE;
/* ERRORS */
cap_failed:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Error getting capabilities for device '%s': "
"It isn't a v4l2 driver. Check if it is a v4l1 driver."),
v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2_empty_lists() and gst_v4l2_fill_lists():
* fill/empty the lists of enumerations
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
{
gint n;
GST_DEBUG_OBJECT (v4l2object->element, "getting enumerations");
GST_V4L2_CHECK_OPEN (v4l2object);
GST_DEBUG_OBJECT (v4l2object->element, " channels");
/* and now, the channels */
for (n = 0;; n++) {
struct v4l2_input input;
GstV4l2TunerChannel *v4l2channel;
GstTunerChannel *channel;
input.index = n;
if (ioctl (v4l2object->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
if (errno == EINVAL)
break; /* end of enumeration */
else {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get %d in channel enumeration for %s."),
n, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
GST_DEBUG_OBJECT (v4l2object->element, " '%s'", input.name);
v4l2channel = g_object_new (GST_TYPE_V4L2_TUNER_CHANNEL, NULL);
channel = GST_TUNER_CHANNEL (v4l2channel);
channel->label = g_strdup ((const gchar *) input.name);
channel->flags = GST_TUNER_CHANNEL_INPUT;
v4l2channel->index = n;
if (input.type == V4L2_INPUT_TYPE_TUNER) {
struct v4l2_tuner vtun;
v4l2channel->tuner = input.tuner;
channel->flags |= GST_TUNER_CHANNEL_FREQUENCY;
vtun.index = input.tuner;
if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &vtun) < 0) {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get tuner %d settings on %s."),
input.tuner, v4l2object->videodev), GST_ERROR_SYSTEM);
g_object_unref (G_OBJECT (channel));
return FALSE;
}
channel->freq_multiplicator =
62.5 * ((vtun.capability & V4L2_TUNER_CAP_LOW) ? 1 : 1000);
channel->min_frequency = vtun.rangelow * channel->freq_multiplicator;
channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator;
channel->min_signal = 0;
channel->max_signal = 0xffff;
}
if (input.audioset) {
/* we take the first. We don't care for
* the others for now */
while (!(input.audioset & (1 << v4l2channel->audio)))
v4l2channel->audio++;
channel->flags |= GST_TUNER_CHANNEL_AUDIO;
}
v4l2object->channels =
g_list_append (v4l2object->channels, (gpointer) channel);
}
GST_DEBUG_OBJECT (v4l2object->element, " norms");
/* norms... */
for (n = 0;; n++) {
struct v4l2_standard standard;
GstV4l2TunerNorm *v4l2norm;
GstTunerNorm *norm;
/* fill in defaults */
standard.frameperiod.denominator = 0;
standard.frameperiod.numerator = 1;
standard.index = n;
if (ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
if (errno == EINVAL)
break; /* end of enumeration */
else {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get %d in norm enumeration for %s."),
n, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
GST_DEBUG_OBJECT (v4l2object->element, " '%s', fps: %d/%d",
standard.name, standard.frameperiod.denominator,
standard.frameperiod.numerator);
v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
norm = GST_TUNER_NORM (v4l2norm);
norm->label = g_strdup ((const gchar *) standard.name);
gst_value_set_fraction (&norm->framerate,
standard.frameperiod.denominator, standard.frameperiod.numerator);
v4l2norm->index = standard.id;
v4l2object->norms = g_list_append (v4l2object->norms, (gpointer) norm);
}
GST_DEBUG_OBJECT (v4l2object->element, " controls+menus");
/* and lastly, controls+menus (if appropriate) */
for (n = V4L2_CID_BASE;; n++) {
struct v4l2_queryctrl control;
GstV4l2ColorBalanceChannel *v4l2channel;
GstColorBalanceChannel *channel;
/* when we reached the last official CID, continue with private CIDs */
if (n == V4L2_CID_LASTP1) {
GST_DEBUG_OBJECT (v4l2object->element, "checking private CIDs");
n = V4L2_CID_PRIVATE_BASE;
/* FIXME: We are still not handling private controls. We need a new GstInterface
to export those controls */
break;
}
control.id = n;
if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
if (errno == EINVAL) {
if (n < V4L2_CID_PRIVATE_BASE)
/* continue so that we also check private controls */
continue;
else
break;
} else {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get %d in control enumeration for %s."),
n, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
if (control.flags & V4L2_CTRL_FLAG_DISABLED)
continue;
switch (n) {
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
case V4L2_CID_HUE:
case V4L2_CID_BLACK_LEVEL:
case V4L2_CID_AUTO_WHITE_BALANCE:
case V4L2_CID_DO_WHITE_BALANCE:
case V4L2_CID_RED_BALANCE:
case V4L2_CID_BLUE_BALANCE:
case V4L2_CID_GAMMA:
case V4L2_CID_EXPOSURE:
case V4L2_CID_AUTOGAIN:
case V4L2_CID_GAIN:
/* we only handle these for now (why?) */
break;
case V4L2_CID_HFLIP:
case V4L2_CID_VFLIP:
case V4L2_CID_HCENTER:
case V4L2_CID_VCENTER:
/* not handled here, handled by VideoOrientation interface */
control.id++;
break;
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_LOUDNESS:
/* FIXME: We should implement GstMixer interface */
/* fall through */
default:
GST_DEBUG_OBJECT (v4l2object->element,
"ControlID %s (%x) unhandled, FIXME", control.name, n);
control.id++;
break;
}
if (n != control.id)
continue;
GST_DEBUG_OBJECT (v4l2object->element,
"Adding ControlID %s (%x)", control.name, n);
v4l2channel = g_object_new (GST_TYPE_V4L2_COLOR_BALANCE_CHANNEL, NULL);
channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
channel->label = g_strdup ((const gchar *) control.name);
v4l2channel->id = n;
#if 0 /* FIXME: it will be need just when handling private controls
(currently none of base controls are of this type) */
if (control.type == V4L2_CTRL_TYPE_MENU) {
struct v4l2_querymenu menu, *mptr;
int i;
menu.id = n;
for (i = 0;; i++) {
menu.index = i;
if (ioctl (v4l2object->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
if (errno == EINVAL)
break; /* end of enumeration */
else {
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get %d in menu enumeration for %s"),
n, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
mptr = g_malloc (sizeof (menu));
memcpy (mptr, &menu, sizeof (menu));
menus = g_list_append (menus, mptr);
}
}
v4l2object->menus = g_list_append (v4l2object->menus, menus);
#endif
switch (control.type) {
case V4L2_CTRL_TYPE_INTEGER:
channel->min_value = control.minimum;
channel->max_value = control.maximum;
break;
case V4L2_CTRL_TYPE_BOOLEAN:
channel->min_value = FALSE;
channel->max_value = TRUE;
break;
default:
/* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON.
BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or
unset (0), but can't be queried */
GST_DEBUG_OBJECT (v4l2object->element,
"Control with non supported type %s (%x), type=%d",
control.name, n, control.type);
channel->min_value = channel->max_value = 0;
break;
}
v4l2object->colors = g_list_append (v4l2object->colors, (gpointer) channel);
}
GST_DEBUG_OBJECT (v4l2object->element, "done");
return TRUE;
}
static void
gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
{
GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations");
g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL);
g_list_free (v4l2object->channels);
v4l2object->channels = NULL;
g_list_foreach (v4l2object->norms, (GFunc) g_object_unref, NULL);
g_list_free (v4l2object->norms);
v4l2object->norms = NULL;
g_list_foreach (v4l2object->colors, (GFunc) g_object_unref, NULL);
g_list_free (v4l2object->colors);
v4l2object->colors = NULL;
}
/******************************************************
* gst_v4l2_open():
* open the video device (v4l2object->videodev)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_open (GstV4l2Object * v4l2object)
{
struct stat st;
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
v4l2object->videodev);
GST_V4L2_CHECK_NOT_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
/* be sure we have a device */
if (!v4l2object->videodev)
v4l2object->videodev = g_strdup ("/dev/video");
/* check if it is a device */
if (stat (v4l2object->videodev, &st) == -1)
goto stat_failed;
if (!S_ISCHR (st.st_mode))
goto no_device;
/* open the device */
v4l2object->video_fd =
open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
if (!GST_V4L2_IS_OPEN (v4l2object))
goto not_open;
/* get capabilities, error will be posted */
if (!gst_v4l2_get_capabilities (v4l2object))
goto error;
/* do we need to be a capture device? */
if (GST_IS_V4L2SRC (v4l2object) &&
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
goto not_capture;
/* create enumerations, posts errors. */
if (!gst_v4l2_fill_lists (v4l2object))
goto error;
GST_INFO_OBJECT (v4l2object->element,
"Opened device '%s' (%s) successfully",
v4l2object->vcap.card, v4l2object->videodev);
return TRUE;
/* ERRORS */
stat_failed:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Cannot identify device '%s'."), v4l2object->videodev),
GST_ERROR_SYSTEM);
goto error;
}
no_device:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("This isn't a device '%s'."), v4l2object->videodev),
GST_ERROR_SYSTEM);
goto error;
}
not_open:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
(_("Could not open device \"%s\" for reading and writing."),
v4l2object->videodev), GST_ERROR_SYSTEM);
goto error;
}
not_capture:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
(_("Device \"%s\" is not a capture device."),
v4l2object->videodev),
("Capabilities: 0x%x", v4l2object->vcap.capabilities));
goto error;
}
error:
{
if (GST_V4L2_IS_OPEN (v4l2object)) {
/* close device */
close (v4l2object->video_fd);
v4l2object->video_fd = -1;
}
/* empty lists */
gst_v4l2_empty_lists (v4l2object);
return FALSE;
}
}
/******************************************************
* gst_v4l2_close():
* close the video device (v4l2object->video_fd)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_close (GstV4l2Object * v4l2object)
{
GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
v4l2object->videodev);
GST_V4L2_CHECK_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
/* close device */
close (v4l2object->video_fd);
v4l2object->video_fd = -1;
/* empty lists */
gst_v4l2_empty_lists (v4l2object);
return TRUE;
}
/******************************************************
* gst_v4l2_get_norm()
* Get the norm of the current device
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
{
GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
goto std_failed;
return TRUE;
/* ERRORS */
std_failed:
{
GST_DEBUG ("Failed to get the current norm for device %s",
v4l2object->videodev);
return FALSE;
}
}
/******************************************************
* gst_v4l2_set_norm()
* Set the norm of the current device
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
{
GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm);
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
goto std_failed;
return TRUE;
/* ERRORS */
std_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set norm 0x%llx for device %s: %s."),
norm, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2_get_frequency():
* get the current frequency
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
gint tunernum, gulong * frequency)
{
struct v4l2_frequency freq;
GstTunerChannel *channel;
GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
freq.tuner = tunernum;
if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
goto freq_failed;
*frequency = freq.frequency * channel->freq_multiplicator;
return TRUE;
/* ERRORS */
freq_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get current tuner frequency for device %s."),
v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2_set_frequency():
* set frequency
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
gint tunernum, gulong frequency)
{
struct v4l2_frequency freq;
GstTunerChannel *channel;
GST_DEBUG_OBJECT (v4l2object->element,
"setting current tuner frequency to %lu", frequency);
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
freq.tuner = tunernum;
/* fill in type - ignore error */
ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
freq.frequency = frequency / channel->freq_multiplicator;
if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
goto freq_failed;
return TRUE;
/* ERRORS */
freq_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set current tuner frequency for device %s to %lu."),
v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2_signal_strength():
* get the strength of the signal on the current input
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
gint tunernum, gulong * signal_strength)
{
struct v4l2_tuner tuner;
GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
tuner.index = tunernum;
if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
goto tuner_failed;
*signal_strength = tuner.signal;
return TRUE;
/* ERRORS */
tuner_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get signal strength for device %s."),
v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2_get_attribute():
* try to get the value of one specific attribute
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
int attribute_num, int *value)
{
struct v4l2_control control;
GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
attribute_num);
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
control.id = attribute_num;
if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
goto ctrl_failed;
*value = control.value;
return TRUE;
/* ERRORS */
ctrl_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get value for control %d on device %s."),
attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2_set_attribute():
* try to set the value of one specific attribute
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
int attribute_num, const int value)
{
struct v4l2_control control;
GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
attribute_num, value);
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
control.id = attribute_num;
control.value = value;
if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
goto ctrl_failed;
return TRUE;
/* ERRORS */
ctrl_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set value %d for control %d on device %s."),
value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
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)
goto input_failed;
*input = n;
return TRUE;
/* ERRORS */
input_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to get current input on device %s."),
v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
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)
goto input_failed;
return TRUE;
/* ERRORS */
input_failed:
{
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
(_("Failed to set input %d on device %s."),
input, v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}

View file

@ -1,129 +0,0 @@
/* GStreamer
*
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* v4l2_calls.h - generic V4L2 calls handling
*
* 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 __V4L2_CALLS_H__
#define __V4L2_CALLS_H__
#include "gstv4l2object.h"
#include "gst/gst-i18n-plugin.h"
/* simple check whether the device is open */
#define GST_V4L2_IS_OPEN(v4l2object) \
(v4l2object->video_fd > 0)
/* check whether the device is 'active' */
#define GST_V4L2_IS_ACTIVE(v4l2object) \
(v4l2object->buffer != NULL)
#define GST_V4L2_IS_OVERLAY(v4l2object) \
(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
/* checks whether the current v4lv4l2object has already been open()'ed or not */
#define GST_V4L2_CHECK_OPEN(v4l2object) \
if (!GST_V4L2_IS_OPEN(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(_("Device is not open.")), (NULL)); \
return FALSE; \
}
/* checks whether the current v4lv4l2object is close()'ed or whether it is still open */
#define GST_V4L2_CHECK_NOT_OPEN(v4l2object) \
if (GST_V4L2_IS_OPEN(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(_("Device is open.")), (NULL)); \
return FALSE; \
}
/* checks whether the current v4lv4l2object does video overlay */
#define GST_V4L2_CHECK_OVERLAY(v4l2object) \
if (!GST_V4L2_IS_OVERLAY(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(NULL), ("Device cannot handle overlay")); \
return FALSE; \
}
/* checks whether we're in capture mode or not */
#define GST_V4L2_CHECK_ACTIVE(v4l2object) \
if (!GST_V4L2_IS_ACTIVE(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(NULL), ("Device is not in streaming mode")); \
return FALSE; \
}
/* checks whether we're out of capture mode or not */
#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2object) \
if (GST_V4L2_IS_ACTIVE(v4l2object)) \
{ \
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS, \
(NULL), ("Device is in streaming mode")); \
return FALSE; \
}
/* open/close the device */
gboolean gst_v4l2_open (GstV4l2Object *v4l2object);
gboolean gst_v4l2_close (GstV4l2Object *v4l2object);
/* norm/input/output */
gboolean gst_v4l2_get_norm (GstV4l2Object *v4l2object,
v4l2_std_id *norm);
gboolean gst_v4l2_set_norm (GstV4l2Object *v4l2object,
v4l2_std_id norm);
gboolean gst_v4l2_get_input (GstV4l2Object * v4l2object,
gint * input);
gboolean gst_v4l2_set_input (GstV4l2Object * v4l2object,
gint input);
#if 0 /* output not handled by now */
gboolean gst_v4l2_get_output (GstV4l2Object *v4l2object,
gint *output);
gboolean gst_v4l2_set_output (GstV4l2Object *v4l2object,
gint output);
#endif /* #if 0 - output not handled by now */
/* frequency control */
gboolean gst_v4l2_get_frequency (GstV4l2Object *v4l2object,
gint tunernum,
gulong *frequency);
gboolean gst_v4l2_set_frequency (GstV4l2Object *v4l2object,
gint tunernum,
gulong frequency);
gboolean gst_v4l2_signal_strength (GstV4l2Object *v4l2object,
gint tunernum,
gulong *signal);
/* attribute control */
gboolean gst_v4l2_get_attribute (GstV4l2Object *v4l2object,
int attribute,
int *value);
gboolean gst_v4l2_set_attribute (GstV4l2Object *v4l2object,
int attribute,
const int value);
gboolean gst_v4l2_get_capabilities (GstV4l2Object * v4l2object);
#endif /* __V4L2_CALLS_H__ */

View file

@ -1,977 +0,0 @@
/* GStreamer
*
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* v4l2src.c - system calls
*
* 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 <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include "v4l2src_calls.h"
#include <sys/time.h>
#include <unistd.h>
#include "gstv4l2tuner.h"
GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug);
#define GST_CAT_DEFAULT v4l2src_debug
/* lalala... */
#define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
#define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL
#define DEBUG(format, args...) \
GST_CAT_DEBUG_OBJECT (\
v4l2src_debug, v4l2src, \
"V4L2SRC: " format, ##args)
/* On some systems MAP_FAILED seems to be missing */
#ifndef MAP_FAILED
#define MAP_FAILED ((caddr_t) -1)
#endif
/******************************************************
* gst_v4l2src_fill_format_list():
* create list of supported capture formats
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
{
gint n;
struct v4l2_fmtdesc *format;
GST_DEBUG_OBJECT (v4l2src, "getting src format enumerations");
/* format enumeration */
for (n = 0;; n++) {
format = g_new (struct v4l2_fmtdesc, 1);
format->index = n;
format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
if (errno == EINVAL) {
break; /* end of enumeration */
} else
goto failed;
}
GST_LOG_OBJECT (v4l2src, "got format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format->pixelformat));
v4l2src->formats = g_slist_prepend (v4l2src->formats, format);
}
return TRUE;
/* ERRORS */
failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("Failed to get number %d in pixelformat enumeration for %s."),
n, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
g_free (format);
return FALSE;
}
}
/******************************************************
* gst_v4l2src_clear_format_list():
* free list of supported capture formats
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
{
g_slist_foreach (v4l2src->formats, (GFunc) g_free, NULL);
g_slist_free (v4l2src->formats);
v4l2src->formats = NULL;
return TRUE;
}
/******************************************************
* gst_v4l2src_queue_frame():
* queue a frame for capturing
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
{
GST_LOG_OBJECT (v4l2src, "queueing frame %u", i);
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF,
&v4l2src->pool->buffers[i].buffer) < 0)
goto failed;
return TRUE;
/* ERRORS */
failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
(_("Could not write to device '%s'."),
v4l2src->v4l2object->videodev),
("Error queueing buffer %u on device %s. system error: %s", i,
v4l2src->v4l2object->videodev, g_strerror (errno)));
return FALSE;
}
}
/******************************************************
* gst_v4l2src_grab_frame ():
* grab a frame for capturing
* return value: The captured frame number or -1 on error.
******************************************************/
gint
gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
{
struct v4l2_buffer buffer;
gint32 trials = 100;
memset (&buffer, 0x00, sizeof (buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = v4l2src->breq.memory;
while (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_DQBUF, &buffer) < 0) {
/* if the sync() got interrupted, we can retry */
switch (errno) {
case EAGAIN:
GST_DEBUG_OBJECT (v4l2src,
"Non-blocking I/O has been selected using O_NONBLOCK and"
" no buffer was in the outgoing queue. device %s",
v4l2src->v4l2object->videodev);
break;
case EINVAL:
goto einval;
case ENOMEM:
goto nomem;
case EIO:
GST_DEBUG_OBJECT (v4l2src,
"VIDIOC_DQBUF failed due to an internal error."
" Can also indicate temporary problems like signal loss."
" Note the driver might dequeue an (empty) buffer despite"
" returning an error, or even stop capturing."
" device %s", v4l2src->v4l2object->videodev);
break;
case EINTR:
GST_DEBUG_OBJECT (v4l2src,
"could not sync on a buffer on device %s",
v4l2src->v4l2object->videodev);
break;
default:
GST_ELEMENT_WARNING (v4l2src, RESOURCE, FAILED,
(_("Grabbing frame got interrupted on %s. No expected reason."),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
break;
}
if (--trials == -1) {
goto too_many_trials;
} else {
ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer);
memset (&buffer, 0x00, sizeof (buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = v4l2src->breq.memory;
}
}
GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index);
return buffer.index;
/* ERRORS */
einval:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get frames from device %s."),
v4l2src->v4l2object->videodev),
(_("The buffer type is not supported, or the index is out of bounds,"
" or no buffers have been allocated yet, or the userptr"
" or length are invalid. device %s"),
v4l2src->v4l2object->videodev));
return -1;
}
nomem:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get frames from device %s. Not enough memory."),
v4l2src->v4l2object->videodev),
(_("insufficient memory to enqueue a user pointer buffer. device %s."),
v4l2src->v4l2object->videodev));
return -1;
}
too_many_trials:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
(_("Failed trying to get frames from device %s."),
v4l2src->v4l2object->videodev),
(_("Failed after 100 tries. device %s."),
v4l2src->v4l2object->videodev));
return -1;
}
}
/******************************************************
* gst_v4l2src_get_capture():
* get capture parameters
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
{
DEBUG ("Getting capture format");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0)
goto fmt_failed;
return TRUE;
/* ERRORS */
fmt_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("Failed to get pixelformat for device %s."),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2src_set_capture():
* set capture parameters
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc * fmt, gint * width, gint * height,
guint * fps_n, guint * fps_d)
{
guint new_fps_n = *fps_n;
guint new_fps_d = *fps_d;
DEBUG ("Setting capture format to %dx%d, format %s",
*width, *height, fmt->description);
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
/* error was posted */
if (!gst_v4l2src_get_capture (v4l2src))
goto fail;
v4l2src->format.fmt.pix.width = *width;
v4l2src->format.fmt.pix.height = *height;
v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0)
goto fmt_failed;
if (*width != v4l2src->format.fmt.pix.width ||
*height != v4l2src->format.fmt.pix.height) {
DEBUG ("Updating size from %dx%d to %dx%d, format %s",
*width, *height, v4l2src->format.fmt.pix.width,
v4l2src->format.fmt.pix.height, fmt->description);
}
/* update internal info, posted error */
if (!gst_v4l2src_get_capture (v4l2src))
goto fail;
if (fmt->pixelformat != v4l2src->format.fmt.pix.pixelformat)
goto pixfmt_failed;
if (*fps_n) {
if (gst_v4l2src_set_fps (v4l2src, &new_fps_n, &new_fps_d)) {
if (new_fps_n != *fps_n || new_fps_d != *fps_d) {
DEBUG ("Updating framerate from %u/%u to %u%u",
*fps_n, *fps_d, new_fps_n, new_fps_d);
*fps_n = new_fps_n;
*fps_d = new_fps_d;
}
}
} else {
if (gst_v4l2src_get_fps (v4l2src, &new_fps_n, &new_fps_d)) {
DEBUG ("framerate is %u/%u", new_fps_n, new_fps_d);
*fps_n = new_fps_n;
*fps_d = new_fps_d;
}
}
*width = v4l2src->format.fmt.pix.width;
*height = v4l2src->format.fmt.pix.height;
return TRUE;
/* ERRORS */
fmt_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("Failed to set pixelformat to %s @ %dx%d for device %s: %s."),
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
GST_ERROR_SYSTEM);
return FALSE;
}
pixfmt_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
(_("Failed to set pixelformat to %s @ %dx%d for device %s: %s."),
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
GST_ERROR_SYSTEM);
return FALSE;
}
fail:
{
/* ERROR was posted */
return FALSE;
}
}
/******************************************************
* gst_v4l2src_capture_init():
* initialize the capture system
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
{
gint n;
guint buffers;
GstV4l2Buffer *buffer;
GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
/* request buffer info */
buffers = v4l2src->breq.count;
if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS)
v4l2src->breq.count = GST_V4L2_MAX_BUFFERS;
else if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS)
v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
v4l2src->breq.type = v4l2src->format.type;
if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
v4l2src->breq.memory = V4L2_MEMORY_MMAP;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_REQBUFS,
&v4l2src->breq) < 0)
goto reqbufs_failed;
GST_LOG_OBJECT (v4l2src, "using default mmap method");
} else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
v4l2src->breq.memory = 0;
GST_INFO_OBJECT (v4l2src, "using fallback read method");
} else
goto broken_driver;
/* Determine the device's framerate */
if (!gst_v4l2src_update_fps (v4l2src->v4l2object)) {
GST_DEBUG_OBJECT (v4l2src, "frame rate is unknown.");
v4l2src->fps_d = 1;
v4l2src->fps_n = 0;
}
if (v4l2src->breq.memory > 0) {
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS)
goto no_buffers;
if (v4l2src->breq.count != buffers)
g_object_notify (G_OBJECT (v4l2src), "num_buffers");
GST_INFO_OBJECT (v4l2src,
"Got %d buffers (%" GST_FOURCC_FORMAT ") of size %d KB",
v4l2src->breq.count,
GST_FOURCC_ARGS (v4l2src->format.fmt.pix.pixelformat),
v4l2src->format.fmt.pix.sizeimage / 1024);
/* Map the buffers */
GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
v4l2src->pool = g_new (GstV4l2BufferPool, 1);
gst_atomic_int_set (&v4l2src->pool->refcount, 1);
v4l2src->pool->video_fd = v4l2src->v4l2object->video_fd;
v4l2src->pool->buffer_count = v4l2src->breq.count;
v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count);
for (n = 0; n < v4l2src->breq.count; n++) {
buffer = &v4l2src->pool->buffers[n];
gst_atomic_int_set (&buffer->refcount, 1);
buffer->pool = v4l2src->pool;
memset (&buffer->buffer, 0x00, sizeof (buffer->buffer));
buffer->buffer.index = n;
buffer->buffer.type = v4l2src->breq.type;
buffer->buffer.memory = v4l2src->breq.memory;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QUERYBUF,
&buffer->buffer) < 0)
goto querybuf_failed;
buffer->start =
mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
v4l2src->v4l2object->video_fd, buffer->buffer.m.offset);
if (buffer->start == MAP_FAILED)
goto mmap_failed;
buffer->length = buffer->buffer.length;
if (!gst_v4l2src_queue_frame (v4l2src, n))
goto queue_failed;
}
} else {
GST_LOG_OBJECT (v4l2src, "no buffer pool used");
v4l2src->pool = NULL;
}
GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
return TRUE;
/* ERRORS */
reqbufs_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get buffers from device '%s'."),
v4l2src->v4l2object->videodev),
("error requesting %d buffers. system error: %s",
v4l2src->breq.count, g_strerror (errno)));
return FALSE;
}
broken_driver:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("The driver of device '%s' is broken."),
v4l2src->v4l2object->videodev),
("no supported read capability from %s",
v4l2src->v4l2object->videodev));
return FALSE;
}
no_buffers:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get enough buffers from device '%s'."),
v4l2src->v4l2object->videodev),
("we received %d, we want at least %d",
v4l2src->breq.count, GST_V4L2_MIN_BUFFERS));
v4l2src->breq.count = buffers;
return FALSE;
}
querybuf_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not get buffer properties of buffer %d."), n),
GST_ERROR_SYSTEM);
gst_v4l2src_capture_deinit (v4l2src);
return FALSE;
}
mmap_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
(_("Could not mmap video buffer %d."), n), GST_ERROR_SYSTEM);
gst_v4l2src_capture_deinit (v4l2src);
buffer->start = 0;
return FALSE;
}
queue_failed:
{
gst_v4l2src_capture_deinit (v4l2src);
return FALSE;
}
}
/******************************************************
* gst_v4l2src_capture_start():
* start streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
{
gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
v4l2src->quit = FALSE;
if (v4l2src->breq.memory != 0) {
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMON, &type) < 0)
goto streamon_failed;
}
v4l2src->is_capturing = TRUE;
return TRUE;
/* ERRORS */
streamon_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ,
(_("Error starting streaming capture from device %s."),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
/******************************************************
* gst_v4l2src_capture_stop():
* stop streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
{
gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
if (v4l2src->breq.memory != 0) {
/* we actually need to sync on all queued buffers but not
* on the non-queued ones */
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0)
goto streamoff_failed;
}
/* make an optional pending wait stop */
v4l2src->quit = TRUE;
v4l2src->is_capturing = FALSE;
return TRUE;
/* ERRORS */
streamoff_failed:
{
GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE,
(_("Error stopping streaming capture from device %s."),
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
return FALSE;
}
}
static void
gst_v4l2src_buffer_pool_free (GstV4l2BufferPool * pool, gboolean do_close)
{
guint i;
for (i = 0; i < pool->buffer_count; i++) {
gst_atomic_int_set (&pool->buffers[i].refcount, 0);
munmap (pool->buffers[i].start, pool->buffers[i].length);
}
g_free (pool->buffers);
gst_atomic_int_set (&pool->refcount, 0);
if (do_close)
close (pool->video_fd);
g_free (pool);
}
/******************************************************
* gst_v4l2src_capture_deinit():
* deinitialize the capture system
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
{
gint i;
gboolean try_reinit = FALSE;
GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
if (v4l2src->pool) {
/* free the buffers */
for (i = 0; i < v4l2src->breq.count; i++) {
if (g_atomic_int_dec_and_test (&v4l2src->pool->buffers[i].refcount)) {
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_DQBUF,
&v4l2src->pool->buffers[i].buffer) < 0)
GST_DEBUG_OBJECT (v4l2src,
"Could not dequeue buffer on uninitialization."
"system error: %s. Will try reinit instead", g_strerror (errno));
try_reinit = TRUE;
}
}
if (g_atomic_int_dec_and_test (&v4l2src->pool->refcount)) {
/* we're last thing that used all this */
gst_v4l2src_buffer_pool_free (v4l2src->pool, FALSE);
}
v4l2src->pool = NULL;
/* This is our second try to get the buffers dequeued.
* Since buffers are normally dequeued automatically when capturing is
* stopped, but may be enqueued before capturing has started, you get
* a problem when you abort before capturing started but have enqueued
* the buffers. We avoid that by starting/stopping capturing once so
* they get auto-dequeued.
*/
if (try_reinit) {
if (!gst_v4l2src_capture_start (v4l2src) ||
!gst_v4l2src_capture_stop (v4l2src)) {
GST_DEBUG_OBJECT (v4l2src, "failed reinit device");
return FALSE;
}
}
}
GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
return TRUE;
}
/*
*/
gboolean
gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc * format,
gint * min_w, gint * max_w, gint * min_h, gint * max_h)
{
struct v4l2_format fmt;
GST_LOG_OBJECT (v4l2src,
"getting size limits with format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (format->pixelformat));
/* get size delimiters */
memset (&fmt, 0, sizeof (fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 0;
fmt.fmt.pix.height = 0;
fmt.fmt.pix.pixelformat = format->pixelformat;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
GST_DEBUG_OBJECT (v4l2src, "failed to get min size: %s",
g_strerror (errno));
return FALSE;
}
if (min_w)
*min_w = fmt.fmt.pix.width;
if (min_h)
*min_h = fmt.fmt.pix.height;
GST_LOG_OBJECT (v4l2src,
"got min size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
fmt.fmt.pix.width = GST_V4L2_MAX_SIZE;
fmt.fmt.pix.height = GST_V4L2_MAX_SIZE;
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
GST_DEBUG_OBJECT (v4l2src, "failed to get max size: %s",
g_strerror (errno));
return FALSE;
}
if (max_w)
*max_w = fmt.fmt.pix.width;
if (max_h)
*max_h = fmt.fmt.pix.height;
GST_LOG_OBJECT (v4l2src,
"got max size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
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
gst_v4l2src_set_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
{
GstV4l2Object *v4l2object = v4l2src->v4l2object;
struct v4l2_streamparm stream;
GST_LOG_OBJECT (v4l2src, "setting fps %d, %d", *fps_n, *fps_d);
memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) < 0)
goto gparm_failed;
if (!(stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME))
goto no_timeperframe;
stream.parm.capture.timeperframe.denominator = *fps_n;
stream.parm.capture.timeperframe.numerator = *fps_d;
if (ioctl (v4l2object->video_fd, VIDIOC_S_PARM, &stream) < 0)
goto sparm_failed;
*fps_n = stream.parm.capture.timeperframe.denominator;
*fps_d = stream.parm.capture.timeperframe.numerator;
GST_LOG_OBJECT (v4l2src, "fps set to %d, %d", *fps_n, *fps_d);
return TRUE;
/* ERRORS */
gparm_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno));
return FALSE;
}
no_timeperframe:
{
GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME");
return FALSE;
}
sparm_failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to set PARM: %s", g_strerror (errno));
return FALSE;
}
}
gboolean
gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
{
GstV4l2Object *v4l2object = v4l2src->v4l2object;
v4l2_std_id norm;
struct v4l2_streamparm stream;
const GList *item;
gboolean found;
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
/* Try to get the frame rate directly from the device using VIDIOC_G_PARM */
memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) < 0) {
GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno));
goto try_stds;
}
if (!(stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME");
goto try_stds;
}
/* Note: V4L2 gives us the frame interval, we need the frame rate */
*fps_n = stream.parm.capture.timeperframe.denominator;
*fps_d = stream.parm.capture.timeperframe.numerator;
GST_DEBUG_OBJECT (v4l2src,
"frame rate returned by G_PARM: %d/%d fps", *fps_n, *fps_d);
/* and we are done now */
goto done;
try_stds:
/* If G_PARM failed, try to get the same information from the video standard */
if (!gst_v4l2_get_norm (v4l2object, &norm))
return FALSE;
found = FALSE;
for (item = v4l2object->norms; item != NULL; item = item->next) {
GstV4l2TunerNorm *v4l2norm = item->data;
if (v4l2norm->index == norm) {
GValue *framerate = &GST_TUNER_NORM (v4l2norm)->framerate;
*fps_n = gst_value_get_fraction_numerator (framerate);
*fps_d = gst_value_get_fraction_denominator (framerate);
GST_DEBUG_OBJECT (v4l2src,
"frame rate returned by get_norm: %d/%d fps", *fps_n, *fps_d);
found = TRUE;
break;
}
}
/* nothing found, that's an error */
if (!found)
goto failed;
done:
return TRUE;
/* ERRORS */
failed:
{
GST_DEBUG_OBJECT (v4l2src, "failed to get framerate");
return FALSE;
}
}
#define GST_TYPE_V4L2SRC_BUFFER (gst_v4l2src_buffer_get_type())
#define GST_IS_V4L2SRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2SRC_BUFFER))
#define GST_V4L2SRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2SRC_BUFFER, GstV4l2SrcBuffer))
typedef struct _GstV4l2SrcBuffer
{
GstBuffer buffer;
GstV4l2Buffer *buf;
} GstV4l2SrcBuffer;
static void gst_v4l2src_buffer_class_init (gpointer g_class,
gpointer class_data);
static void gst_v4l2src_buffer_init (GTypeInstance * instance,
gpointer g_class);
static void gst_v4l2src_buffer_finalize (GstV4l2SrcBuffer * v4l2src_buffer);
GType
gst_v4l2src_buffer_get_type (void)
{
static GType _gst_v4l2src_buffer_type;
if (G_UNLIKELY (_gst_v4l2src_buffer_type == 0)) {
static const GTypeInfo v4l2src_buffer_info = {
sizeof (GstBufferClass),
NULL,
NULL,
gst_v4l2src_buffer_class_init,
NULL,
NULL,
sizeof (GstV4l2SrcBuffer),
0,
gst_v4l2src_buffer_init,
NULL
};
_gst_v4l2src_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
"GstV4l2SrcBuffer", &v4l2src_buffer_info, 0);
}
return _gst_v4l2src_buffer_type;
}
static void
gst_v4l2src_buffer_class_init (gpointer g_class, gpointer class_data)
{
GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
gst_v4l2src_buffer_finalize;
}
static void
gst_v4l2src_buffer_init (GTypeInstance * instance, gpointer g_class)
{
}
static void
gst_v4l2src_buffer_finalize (GstV4l2SrcBuffer * v4l2src_buffer)
{
GstV4l2Buffer *buf = v4l2src_buffer->buf;
if (buf) {
GST_LOG ("freeing buffer %p (nr. %d)", buf, buf->buffer.index);
if (!g_atomic_int_dec_and_test (&buf->refcount)) {
/* we're still in use, add to queue again
note: this might fail because the device is already stopped (race) */
if (ioctl (buf->pool->video_fd, VIDIOC_QBUF, &buf->buffer) < 0)
GST_INFO ("readding to queue failed, assuming video device is stopped");
}
if (g_atomic_int_dec_and_test (&buf->pool->refcount)) {
/* we're last thing that used all this */
gst_v4l2src_buffer_pool_free (buf->pool, TRUE);
}
}
}
/* Create a V4l2Src buffer from our mmap'd data area */
GstBuffer *
gst_v4l2src_buffer_new (GstV4l2Src * v4l2src, guint size, guint8 * data,
GstV4l2Buffer * srcbuf)
{
GstBuffer *buf;
GstClockTime timestamp, duration;
GstClock *clock;
if (data == NULL) {
buf = gst_buffer_new_and_alloc (size);
} else {
buf = (GstBuffer *) gst_mini_object_new (GST_TYPE_V4L2SRC_BUFFER);
GST_BUFFER_DATA (buf) = data;
GST_V4L2SRC_BUFFER (buf)->buf = srcbuf;
GST_LOG_OBJECT (v4l2src,
"creating buffer %p (nr. %d)", srcbuf, srcbuf->buffer.index);
}
GST_BUFFER_SIZE (buf) = size;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
/* timestamps, LOCK to get clock and base time. */
GST_OBJECT_LOCK (v4l2src);
if ((clock = GST_ELEMENT_CLOCK (v4l2src))) {
/* we have a clock, get base time and ref clock */
timestamp = GST_ELEMENT (v4l2src)->base_time;
gst_object_ref (clock);
} else {
/* no clock, can't set timestamps */
timestamp = GST_CLOCK_TIME_NONE;
}
GST_OBJECT_UNLOCK (v4l2src);
if (clock) {
/* the time now is the time of the clock minus the base time */
timestamp = gst_clock_get_time (clock) - timestamp;
gst_object_unref (clock);
}
if (v4l2src->fps_n > 0) {
duration =
gst_util_uint64_scale_int (GST_SECOND, v4l2src->fps_d, v4l2src->fps_n);
} else {
duration = GST_CLOCK_TIME_NONE;
}
GST_BUFFER_TIMESTAMP (buf) = timestamp;
GST_BUFFER_DURATION (buf) = duration;
/* offsets */
GST_BUFFER_OFFSET (buf) = v4l2src->offset++;
GST_BUFFER_OFFSET_END (buf) = v4l2src->offset;
/* the negotiate() method already set caps on the source pad */
gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (v4l2src)));
return buf;
}

View file

@ -1,67 +0,0 @@
/* GStreamer
*
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
* v4l2src.h - system calls
*
* 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 __V4L2SRC_CALLS_H__
#define __V4L2SRC_CALLS_H__
#include "gstv4l2src.h"
#include "v4l2_calls.h"
gboolean gst_v4l2src_get_capture (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc *fmt,
gint * width, gint * height,
guint *fps_n, guint * fps_d);
gboolean gst_v4l2src_capture_init (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_capture_start (GstV4l2Src * v4l2src);
gint gst_v4l2src_grab_frame (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i);
gboolean gst_v4l2src_capture_stop (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src);
gboolean gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
struct v4l2_fmtdesc *fmt,
gint * min_w, gint * max_w,
gint * min_h, gint * max_h);
/* buffers */
GstBuffer* gst_v4l2src_buffer_new (GstV4l2Src * v4l2src,
guint size, guint8 * data,
GstV4l2Buffer * srcbuf);
void gst_v4l2src_free_buffer (GstBuffer * buffer);
/* FPS stuff */
gboolean gst_v4l2src_update_fps (GstV4l2Object * v4l2object);
gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src,
guint * fps_n, guint * fps_d);
gboolean gst_v4l2src_set_fps (GstV4l2Src * v4l2src,
guint * fps_n, guint * fps_d);
GValue* gst_v4l2src_get_fps_list (GstV4l2Src * v4l2src);
#endif /* __V4L2SRC_CALLS_H__ */