mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 11:10:37 +00:00
this adds video4linux2 source and element plugins. The division in v4l2* plugins is the same as for v4l1 - i.e. an el...
Original commit message from CVS: this adds video4linux2 source and element plugins. The division in v4l2* plugins is the same as for v4l1 - i.e. an element, a src and a sink, but there won't be separate encoding plugins (like v4lmjpegsrc) - all functionality is (thanks to video4linux2) integrated in one plugin: v4l2src. v4l2sink is still to be done, that'll come later.
This commit is contained in:
parent
7d260c0d41
commit
9413402bc6
12 changed files with 3160 additions and 1 deletions
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit 355c616d5f6779ea194f8b61704229c6fb04ae7b
|
||||
Subproject commit 2f6d9cfdaaa83ab454d263d6eba88046debadc2d
|
18
sys/v4l2/Makefile.am
Normal file
18
sys/v4l2/Makefile.am
Normal file
|
@ -0,0 +1,18 @@
|
|||
plugindir = $(libdir)/gst
|
||||
|
||||
plugin_LTLIBRARIES = \
|
||||
libgstv4l2element.la \
|
||||
libgstv4l2src.la
|
||||
|
||||
libgstv4l2element_la_SOURCES = gstv4l2element.c v4l2_calls.c v4l2-overlay_calls.c
|
||||
libgstv4l2element_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstv4l2element_la_LIBADD =
|
||||
libgstv4l2element_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
libgstv4l2src_la_SOURCES = gstv4l2src.c v4l2src_calls.c
|
||||
libgstv4l2src_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstv4l2src_la_LIBADD = libgstv4l2element.la
|
||||
libgstv4l2src_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = gstv4l2element.h v4l2_calls.h \
|
||||
gstv4l2src.h v4l2src_calls.h
|
24
sys/v4l2/README
Normal file
24
sys/v4l2/README
Normal file
|
@ -0,0 +1,24 @@
|
|||
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 applicaiton 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://thedirks.org/v4l2/. Kernel patches available from
|
||||
http://bytesex.org/patches/.
|
493
sys/v4l2/gstv4l2element.c
Normal file
493
sys/v4l2/gstv4l2element.c
Normal file
|
@ -0,0 +1,493 @@
|
|||
/* G-Streamer generic V4L2 element
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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 "v4l2_calls.h"
|
||||
|
||||
|
||||
static GstElementDetails gst_v4l2element_details = {
|
||||
"Generic video4linux2 Element",
|
||||
"None/Video",
|
||||
"Generic plugin for handling common video4linux2 calls",
|
||||
VERSION,
|
||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>",
|
||||
"(C) 2002",
|
||||
};
|
||||
|
||||
/* V4l2Element signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_CHANNEL,
|
||||
ARG_CHANNEL_NAMES,
|
||||
ARG_OUTPUT,
|
||||
ARG_OUTPUT_NAMES,
|
||||
ARG_NORM,
|
||||
ARG_NORM_NAMES,
|
||||
ARG_HAS_TUNER,
|
||||
ARG_FREQUENCY,
|
||||
ARG_SIGNAL_STRENGTH,
|
||||
ARG_HAS_AUDIO,
|
||||
ARG_ATTRIBUTE,
|
||||
ARG_ATTRIBUTE_SETS,
|
||||
ARG_DEVICE,
|
||||
ARG_DEVICE_NAME,
|
||||
ARG_DEVICE_HAS_CAPTURE,
|
||||
ARG_DEVICE_HAS_OVERLAY,
|
||||
ARG_DEVICE_HAS_CODEC,
|
||||
ARG_DISPLAY,
|
||||
ARG_VIDEOWINDOW,
|
||||
ARG_CLIPPING,
|
||||
ARG_DO_OVERLAY,
|
||||
};
|
||||
|
||||
|
||||
static void gst_v4l2element_class_init (GstV4l2ElementClass *klass);
|
||||
static void gst_v4l2element_init (GstV4l2Element *v4lelement);
|
||||
static void gst_v4l2element_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gst_v4l2element_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static GstElementStateReturn gst_v4l2element_change_state (GstElement *element);
|
||||
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
/*static guint gst_v4l2element_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
|
||||
GType
|
||||
gst_v4l2element_get_type (void)
|
||||
{
|
||||
static GType v4l2element_type = 0;
|
||||
|
||||
if (!v4l2element_type) {
|
||||
static const GTypeInfo v4l2element_info = {
|
||||
sizeof(GstV4l2ElementClass),
|
||||
NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_v4l2element_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(GstV4l2Element),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_v4l2element_init,
|
||||
NULL
|
||||
};
|
||||
v4l2element_type = g_type_register_static(GST_TYPE_ELEMENT,
|
||||
"GstV4l2Element", &v4l2element_info, 0);
|
||||
}
|
||||
return v4l2element_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2element_class_init (GstV4l2ElementClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass*)klass;
|
||||
gstelement_class = (GstElementClass*)klass;
|
||||
|
||||
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL,
|
||||
g_param_spec_int("channel","channel","channel",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL_NAMES,
|
||||
g_param_spec_pointer("channel_names","channel_names","channel_names",
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT,
|
||||
g_param_spec_int("output","output","output",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT_NAMES,
|
||||
g_param_spec_pointer("output_names","output_names","output_names",
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM,
|
||||
g_param_spec_int("norm","norm","norm",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM_NAMES,
|
||||
g_param_spec_pointer("norm_names","norm_names","norm_names",
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_TUNER,
|
||||
g_param_spec_boolean("has_tuner","has_tuner","has_tuner",
|
||||
0,G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
|
||||
g_param_spec_ulong("frequency","frequency","frequency",
|
||||
0,G_MAXULONG,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SIGNAL_STRENGTH,
|
||||
g_param_spec_ulong("signal_strength","signal_strength","signal_strength",
|
||||
0,G_MAXULONG,0,G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_AUDIO,
|
||||
g_param_spec_boolean("has_audio","has_audio","has_audio",
|
||||
0,G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ATTRIBUTE,
|
||||
g_param_spec_pointer("attribute","attribute","attribute",
|
||||
G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ATTRIBUTE_SETS,
|
||||
g_param_spec_pointer("attribute_sets","attribute_sets","attribute_sets",
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
|
||||
g_param_spec_string("device","device","device",
|
||||
NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_NAME,
|
||||
g_param_spec_string("device_name","device_name","device_name",
|
||||
NULL, G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CAPTURE,
|
||||
g_param_spec_boolean("can_capture","can_capture","can_capture",
|
||||
0,G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_OVERLAY,
|
||||
g_param_spec_boolean("has_overlay","has_overlay","has_overlay",
|
||||
0,G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_HAS_CODEC,
|
||||
g_param_spec_boolean("has_compression","has_compression","has_compression",
|
||||
0,G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DISPLAY,
|
||||
g_param_spec_string("display","display","display",
|
||||
NULL, G_PARAM_WRITABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DO_OVERLAY,
|
||||
g_param_spec_boolean("do_overlay","do_overlay","do_overlay",
|
||||
0,G_PARAM_WRITABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VIDEOWINDOW,
|
||||
g_param_spec_pointer("videowindow","videowindow","videowindow",
|
||||
G_PARAM_WRITABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CLIPPING,
|
||||
g_param_spec_pointer("videowindowclip","videowindowclip","videowindowclip",
|
||||
G_PARAM_WRITABLE));
|
||||
|
||||
gobject_class->set_property = gst_v4l2element_set_property;
|
||||
gobject_class->get_property = gst_v4l2element_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_v4l2element_change_state;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2element_init (GstV4l2Element *v4l2element)
|
||||
{
|
||||
/* some default values */
|
||||
v4l2element->video_fd = -1;
|
||||
v4l2element->buffer = NULL;
|
||||
v4l2element->device = NULL;
|
||||
|
||||
v4l2element->norm = -1;
|
||||
v4l2element->channel = -1;
|
||||
v4l2element->output = -1;
|
||||
v4l2element->frequency = 0;
|
||||
|
||||
v4l2element->controls = NULL;
|
||||
v4l2element->formats = NULL;
|
||||
v4l2element->outputs = NULL;
|
||||
v4l2element->inputs = NULL;
|
||||
v4l2element->norms = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2element_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GstV4l2Element *v4l2element;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail(GST_IS_V4L2ELEMENT(object));
|
||||
v4l2element = GST_V4L2ELEMENT(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_CHANNEL:
|
||||
v4l2element->channel = g_value_get_int(value);
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
|
||||
if (!gst_v4l2_set_input(v4l2element, g_value_get_int(value)))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ARG_OUTPUT:
|
||||
v4l2element->output = g_value_get_int(value);
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
|
||||
if (!gst_v4l2_set_output(v4l2element, g_value_get_int(value)))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ARG_NORM:
|
||||
v4l2element->norm = g_value_get_int(value);
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
|
||||
if (!gst_v4l2_set_norm(v4l2element, g_value_get_int(value)))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ARG_FREQUENCY:
|
||||
v4l2element->frequency = g_value_get_ulong(value);
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) && !GST_V4L2_IS_ACTIVE(v4l2element)) {
|
||||
if (!gst_v4l2_set_frequency(v4l2element, g_value_get_ulong(value)))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ARG_ATTRIBUTE:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
gst_v4l2_set_attribute(v4l2element,
|
||||
((GstV4l2Attribute*)g_value_get_pointer(value))->index,
|
||||
((GstV4l2Attribute*)g_value_get_pointer(value))->value);
|
||||
}
|
||||
break;
|
||||
case ARG_DEVICE:
|
||||
if (!GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
if (v4l2element->device)
|
||||
g_free(v4l2element->device);
|
||||
v4l2element->device = g_strdup(g_value_get_string(value));
|
||||
}
|
||||
break;
|
||||
case ARG_DISPLAY:
|
||||
if (!gst_v4l2_set_display(v4l2element, g_value_get_string(value)))
|
||||
return;
|
||||
break;
|
||||
case ARG_VIDEOWINDOW:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
gst_v4l2_set_window(v4l2element,
|
||||
((GstV4l2Rect*)g_value_get_pointer(value))->x,
|
||||
((GstV4l2Rect*)g_value_get_pointer(value))->y,
|
||||
((GstV4l2Rect*)g_value_get_pointer(value))->w,
|
||||
((GstV4l2Rect*)g_value_get_pointer(value))->h);
|
||||
}
|
||||
break;
|
||||
case ARG_CLIPPING:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
gint i;
|
||||
struct v4l2_clip *clips;
|
||||
GList *list = (GList*)g_value_get_pointer(value);
|
||||
clips = g_malloc(sizeof(struct v4l2_clip) * g_list_length(list));
|
||||
for (i=0;i<g_list_length(list);i++)
|
||||
{
|
||||
clips[i].x = ((GstV4l2Rect*)g_list_nth_data(list, i))->x;
|
||||
clips[i].y = ((GstV4l2Rect*)g_list_nth_data(list, i))->y;
|
||||
clips[i].width = ((GstV4l2Rect*)g_list_nth_data(list, i))->w;
|
||||
clips[i].height = ((GstV4l2Rect*)g_list_nth_data(list, i))->h;
|
||||
}
|
||||
gst_v4l2_set_clips(v4l2element, clips, g_list_length(list));
|
||||
g_free(clips);
|
||||
}
|
||||
break;
|
||||
case ARG_DO_OVERLAY:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
if (!gst_v4l2_enable_overlay(v4l2element, g_value_get_boolean(value)))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2element_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GstV4l2Element *v4l2element;
|
||||
gint temp_i = 0;
|
||||
gulong temp_ul = 0;
|
||||
GList *list = NULL;
|
||||
|
||||
/* it's not null if we got it, but it might not be ours */
|
||||
g_return_if_fail(GST_IS_V4L2ELEMENT(object));
|
||||
v4l2element = GST_V4L2ELEMENT(object);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_CHANNEL:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
gst_v4l2_get_input(v4l2element, &temp_i);
|
||||
g_value_set_int(value, temp_i);
|
||||
break;
|
||||
case ARG_CHANNEL_NAMES:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
list = gst_v4l2_get_input_names(v4l2element);
|
||||
g_value_set_pointer(value, list);
|
||||
break;
|
||||
case ARG_OUTPUT:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
gst_v4l2_get_output(v4l2element, &temp_i);
|
||||
g_value_set_int(value, temp_i);
|
||||
break;
|
||||
case ARG_OUTPUT_NAMES:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
list = gst_v4l2_get_output_names(v4l2element);
|
||||
g_value_set_pointer(value, list);
|
||||
break;
|
||||
case ARG_NORM:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
gst_v4l2_get_norm(v4l2element, &temp_i);
|
||||
g_value_set_int(value, temp_i);
|
||||
break;
|
||||
case ARG_NORM_NAMES:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
list = gst_v4l2_get_norm_names(v4l2element);
|
||||
g_value_set_pointer(value, list);
|
||||
break;
|
||||
case ARG_HAS_TUNER:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
temp_i = gst_v4l2_has_tuner(v4l2element);
|
||||
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
|
||||
break;
|
||||
case ARG_FREQUENCY:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
gst_v4l2_get_frequency(v4l2element, &temp_ul);
|
||||
g_value_set_ulong(value, temp_ul);
|
||||
break;
|
||||
case ARG_SIGNAL_STRENGTH:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
gst_v4l2_signal_strength(v4l2element, &temp_ul);
|
||||
g_value_set_ulong(value, temp_ul);
|
||||
break;
|
||||
case ARG_HAS_AUDIO:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
temp_i = gst_v4l2_has_audio(v4l2element);
|
||||
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
|
||||
break;
|
||||
case ARG_ATTRIBUTE:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
gst_v4l2_get_attribute(v4l2element,
|
||||
((GstV4l2Attribute*)g_value_get_pointer(value))->index, &temp_i);
|
||||
((GstV4l2Attribute*)g_value_get_pointer(value))->value = temp_i;
|
||||
break;
|
||||
case ARG_ATTRIBUTE_SETS:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
list = gst_v4l2_get_attributes(v4l2element);
|
||||
g_value_set_pointer(value, list);
|
||||
break;
|
||||
case ARG_DEVICE:
|
||||
g_value_set_string(value, g_strdup(v4l2element->device));
|
||||
break;
|
||||
case ARG_DEVICE_NAME:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element))
|
||||
g_value_set_string(value, g_strdup(v4l2element->vcap.name));
|
||||
break;
|
||||
case ARG_DEVICE_HAS_CAPTURE:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) &&
|
||||
(v4l2element->vcap.type == V4L2_TYPE_CODEC ||
|
||||
v4l2element->vcap.type == V4L2_TYPE_CAPTURE) &&
|
||||
v4l2element->vcap.flags & V4L2_FLAG_STREAMING)
|
||||
temp_i = 1;
|
||||
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
|
||||
break;
|
||||
case ARG_DEVICE_HAS_OVERLAY:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) &&
|
||||
v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)
|
||||
temp_i = 1;
|
||||
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
|
||||
break;
|
||||
case ARG_DEVICE_HAS_CODEC:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element) &&
|
||||
v4l2element->vcap.type == V4L2_TYPE_CODEC)
|
||||
temp_i = 1;
|
||||
g_value_set_boolean(value, temp_i>0?TRUE:FALSE);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_v4l2element_change_state (GstElement *element)
|
||||
{
|
||||
GstV4l2Element *v4l2element;
|
||||
|
||||
g_return_val_if_fail(GST_IS_V4L2ELEMENT(element), GST_STATE_FAILURE);
|
||||
|
||||
v4l2element = GST_V4L2ELEMENT(element);
|
||||
|
||||
/* if going down into NULL state, close the device if it's open
|
||||
* if going to READY, open the device (and set some options)
|
||||
*/
|
||||
switch (GST_STATE_TRANSITION(element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
if (!gst_v4l2_open(v4l2element))
|
||||
return GST_STATE_FAILURE;
|
||||
|
||||
/* now, sync options */
|
||||
if (v4l2element->norm >= 0)
|
||||
if (!gst_v4l2_set_norm(v4l2element, v4l2element->norm))
|
||||
return GST_STATE_FAILURE;
|
||||
if (v4l2element->channel >= 0)
|
||||
if (!gst_v4l2_set_input(v4l2element, v4l2element->channel))
|
||||
return GST_STATE_FAILURE;
|
||||
if (v4l2element->output >= 0)
|
||||
if (!gst_v4l2_set_output(v4l2element, v4l2element->output))
|
||||
return GST_STATE_FAILURE;
|
||||
if (v4l2element->frequency > 0)
|
||||
if (!gst_v4l2_set_frequency(v4l2element, v4l2element->frequency))
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
if (!gst_v4l2_close(v4l2element))
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS(parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
plugin_init (GModule *module,
|
||||
GstPlugin *plugin)
|
||||
{
|
||||
GstElementFactory *factory;
|
||||
|
||||
/* create an elementfactory for the v4l2element */
|
||||
factory = gst_element_factory_new("v4l2element", GST_TYPE_V4L2ELEMENT,
|
||||
&gst_v4l2element_details);
|
||||
g_return_val_if_fail(factory != NULL, FALSE);
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GstPluginDesc plugin_desc = {
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"v4l2element",
|
||||
plugin_init
|
||||
};
|
110
sys/v4l2/gstv4l2element.h
Normal file
110
sys/v4l2/gstv4l2element.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* G-Streamer generic V4L2 element
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_V4L2ELEMENT_H__
|
||||
#define __GST_V4L2ELEMENT_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
|
||||
#define GST_TYPE_V4L2ELEMENT \
|
||||
(gst_v4l2element_get_type())
|
||||
#define GST_V4L2ELEMENT(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_V4L2ELEMENT, GstV4l2Element))
|
||||
#define GST_V4L2ELEMENT_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_V4L2ELEMENT, GstV4l2ElementClass))
|
||||
#define GST_IS_V4L2ELEMENT(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_V4L2ELEMENT))
|
||||
#define GST_IS_V4L2ELEMENT_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_V4L2ELEMENT))
|
||||
|
||||
|
||||
typedef struct _GstV4l2Element GstV4l2Element;
|
||||
typedef struct _GstV4l2ElementClass GstV4l2ElementClass;
|
||||
|
||||
typedef struct _GstV4l2Rect {
|
||||
gint x, y, w, h;
|
||||
} GstV4l2Rect;
|
||||
|
||||
typedef enum {
|
||||
GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT,
|
||||
GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN,
|
||||
GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON,
|
||||
GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST,
|
||||
} GstV4l2AttributeValueType;
|
||||
|
||||
typedef enum {
|
||||
GST_V4L2_ATTRIBUTE_TYPE_VIDEO,
|
||||
GST_V4L2_ATTRIBUTE_TYPE_AUDIO,
|
||||
GST_V4L2_ATTRIBUTE_TYPE_EFFECT,
|
||||
} GstV4l2AttributeType;
|
||||
|
||||
typedef struct _GstV4l2Attribute {
|
||||
gint index;
|
||||
gchar *name;
|
||||
GstV4l2AttributeType type;
|
||||
GstV4l2AttributeValueType val_type;
|
||||
gint min, max, value;
|
||||
GList *list_items; /* in case of 'list' */
|
||||
} GstV4l2Attribute;
|
||||
|
||||
struct _GstV4l2Element {
|
||||
GstElement element;
|
||||
|
||||
/* the video device */
|
||||
char *device;
|
||||
|
||||
/* 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 toys available to us */
|
||||
GList /*v4l2_fmtdesc*/ *formats; /* list of available capture formats */
|
||||
GList /*v4l2_input*/ *inputs;
|
||||
GList /*v4l2_output*/ *outputs;
|
||||
GList /*v4l2_enumstd*/ *norms;
|
||||
GList /*v4l2_queryctrl*/ *controls;
|
||||
GList /*GList:v4l2_querymenu*/ *menus;
|
||||
|
||||
/* and last but not least, the current video window */
|
||||
struct v4l2_window vwin;
|
||||
|
||||
/* caching values */
|
||||
gint channel;
|
||||
gint output;
|
||||
gint norm;
|
||||
gulong frequency;
|
||||
};
|
||||
|
||||
struct _GstV4l2ElementClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType gst_v4l2element_get_type (void);
|
||||
|
||||
#endif /* __GST_V4L2ELEMENT_H__ */
|
837
sys/v4l2/gstv4l2src.c
Normal file
837
sys/v4l2/gstv4l2src.c
Normal file
|
@ -0,0 +1,837 @@
|
|||
/* G-Streamer Video4linux2 video-capture plugin
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include "v4l2src_calls.h"
|
||||
|
||||
|
||||
static GstElementDetails gst_v4l2src_details = {
|
||||
"Video (video4linux2) Source",
|
||||
"Source/Video",
|
||||
"Reads frames (compressed or uncompressed) from a video4linux2 device",
|
||||
VERSION,
|
||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>",
|
||||
"(C) 2002",
|
||||
};
|
||||
|
||||
/* V4l2Src signals and args */
|
||||
enum {
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
/* arguments */
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_WIDTH,
|
||||
ARG_HEIGHT,
|
||||
ARG_PALETTE,
|
||||
ARG_PALETTE_NAMES,
|
||||
ARG_FOURCC,
|
||||
ARG_FOURCC_LIST,
|
||||
ARG_NUMBUFS,
|
||||
ARG_BUFSIZE
|
||||
};
|
||||
|
||||
|
||||
/* init functions */
|
||||
static void gst_v4l2src_class_init (GstV4l2SrcClass *klass);
|
||||
static void gst_v4l2src_init (GstV4l2Src *v4l2src);
|
||||
|
||||
/* pad/buffer functions */
|
||||
static GstPadConnectReturn gst_v4l2src_srcconnect (GstPad *pad,
|
||||
GstCaps *caps);
|
||||
static GstBuffer * gst_v4l2src_get (GstPad *pad);
|
||||
|
||||
/* get/set params */
|
||||
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);
|
||||
|
||||
/* state handling */
|
||||
static GstElementStateReturn gst_v4l2src_change_state (GstElement *element);
|
||||
|
||||
/* bufferpool functions */
|
||||
static GstBuffer * gst_v4l2src_buffer_new (GstBufferPool *pool,
|
||||
guint64 offset,
|
||||
guint size,
|
||||
gpointer user_data);
|
||||
static GstBuffer * gst_v4l2src_buffer_copy (GstBufferPool *pool,
|
||||
const GstBuffer *srcbuf,
|
||||
gpointer user_data);
|
||||
static void gst_v4l2src_buffer_free (GstBufferPool *pool,
|
||||
GstBuffer *buf,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
static GstPadTemplate *src_template;
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
/*static guint gst_v4l2src_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
|
||||
GType
|
||||
gst_v4l2src_get_type (void)
|
||||
{
|
||||
static GType v4l2src_type = 0;
|
||||
|
||||
if (!v4l2src_type) {
|
||||
static const GTypeInfo v4l2src_info = {
|
||||
sizeof(GstV4l2SrcClass),
|
||||
NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_v4l2src_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(GstV4l2Src),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_v4l2src_init,
|
||||
NULL
|
||||
};
|
||||
v4l2src_type = g_type_register_static(GST_TYPE_V4L2ELEMENT,
|
||||
"GstV4l2Src", &v4l2src_info, 0);
|
||||
}
|
||||
return v4l2src_type;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2src_class_init (GstV4l2SrcClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass*)klass;
|
||||
gstelement_class = (GstElementClass*)klass;
|
||||
|
||||
parent_class = g_type_class_ref(GST_TYPE_V4L2ELEMENT);
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
|
||||
g_param_spec_int("width","width","width",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
|
||||
g_param_spec_int("height","height","height",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE,
|
||||
g_param_spec_int("palette","palette","palette",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE_NAMES,
|
||||
g_param_spec_pointer("palette_name","palette_name","palette_name",
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FOURCC,
|
||||
g_param_spec_string("fourcc","fourcc","fourcc",
|
||||
NULL,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FOURCC_LIST,
|
||||
g_param_spec_pointer("fourcc_list","fourcc_list","fourcc_list",
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
|
||||
g_param_spec_int("num_buffers","num_buffers","num_buffers",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
|
||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
|
||||
g_param_spec_int("buffer_size","buffer_size","buffer_size",
|
||||
G_MININT,G_MAXINT,0,G_PARAM_READABLE));
|
||||
|
||||
gobject_class->set_property = gst_v4l2src_set_property;
|
||||
gobject_class->get_property = gst_v4l2src_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_v4l2src_change_state;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2src_init (GstV4l2Src *v4l2src)
|
||||
{
|
||||
v4l2src->srcpad = gst_pad_new_from_template(src_template, "src");
|
||||
gst_element_add_pad(GST_ELEMENT(v4l2src), v4l2src->srcpad);
|
||||
|
||||
gst_pad_set_get_function(v4l2src->srcpad, gst_v4l2src_get);
|
||||
gst_pad_set_connect_function(v4l2src->srcpad, gst_v4l2src_srcconnect);
|
||||
|
||||
v4l2src->bufferpool = gst_buffer_pool_new(NULL, NULL,
|
||||
gst_v4l2src_buffer_new,
|
||||
gst_v4l2src_buffer_copy,
|
||||
gst_v4l2src_buffer_free,
|
||||
v4l2src);
|
||||
|
||||
v4l2src->palette = 0; /* means 'any' - user can specify a specific palette */
|
||||
v4l2src->width = 160;
|
||||
v4l2src->height = 120;
|
||||
v4l2src->breq.count = 0;
|
||||
}
|
||||
|
||||
|
||||
static GstCaps *
|
||||
gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc,
|
||||
gint width,
|
||||
gint height,
|
||||
gboolean compressed)
|
||||
{
|
||||
GstCaps *capslist = NULL, *caps;
|
||||
|
||||
switch (fourcc) {
|
||||
case V4L2_PIX_FMT_MJPEG: /* v4l2_fourcc('M','J','P','G') */
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
"video/jpeg",
|
||||
gst_props_new(
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
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;
|
||||
gulong 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:
|
||||
bpp = 16; depth = 15;
|
||||
endianness = G_LITTLE_ENDIAN;
|
||||
r_mask = 0x7c00; g_mask = 0x03e0; b_mask = 0x001f;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB555X:
|
||||
bpp = 16; depth = 15;
|
||||
endianness = G_BIG_ENDIAN;
|
||||
r_mask = 0x7c00; g_mask = 0x03e0; b_mask = 0x001f;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
bpp = depth = 16;
|
||||
endianness = G_LITTLE_ENDIAN;
|
||||
r_mask = 0xf800; g_mask = 0x07e0; b_mask = 0x001f;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565X:
|
||||
bpp = depth = 16;
|
||||
endianness = G_BIG_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_LITTLE_ENDIAN;
|
||||
r_mask = 0xff0000; g_mask = 0x00ff00; b_mask = 0x0000ff;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB32:
|
||||
bpp = depth = 32;
|
||||
endianness = G_BIG_ENDIAN;
|
||||
r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff;
|
||||
break;
|
||||
case V4L2_PIX_FMT_BGR32:
|
||||
endianness = G_LITTLE_ENDIAN;
|
||||
bpp = depth = 32;
|
||||
r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff;
|
||||
break;
|
||||
}
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
"video/raw",
|
||||
gst_props_new(
|
||||
"format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('R','G','B',' ')),
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
"bpp", GST_PROPS_INT(bpp),
|
||||
"depth", GST_PROPS_INT(depth),
|
||||
"red_mask", GST_PROPS_INT(r_mask),
|
||||
"green_mask", GST_PROPS_INT(g_mask),
|
||||
"blue_mask", GST_PROPS_INT(b_mask),
|
||||
"endianness", GST_PROPS_INT(endianness),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
break; }
|
||||
case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
"video/raw",
|
||||
gst_props_new(
|
||||
"format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('I','4','2','0')),
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
"video/raw",
|
||||
gst_props_new(
|
||||
"format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('I','Y','U','V')),
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
"video/raw",
|
||||
gst_props_new(
|
||||
"format", GST_PROPS_FOURCC(GST_MAKE_FOURCC('Y','U','Y','2')),
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* add the standard one */
|
||||
if (compressed) {
|
||||
guint32 print_format = GUINT32_FROM_LE(fourcc);
|
||||
gchar *print_format_str = (gchar *) &print_format, *string_format;
|
||||
gint i;
|
||||
for (i=0;i<4;i++)
|
||||
print_format_str[i] = g_ascii_tolower(print_format_str[i]);
|
||||
string_format = g_strdup_printf("video/%4.4s", print_format_str);
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
string_format,
|
||||
gst_props_new(
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
g_free(string_format);
|
||||
} else {
|
||||
caps = gst_caps_new("v4l2src_caps",
|
||||
"video/raw",
|
||||
gst_props_new(
|
||||
"format", GST_PROPS_FOURCC(fourcc),
|
||||
"width", GST_PROPS_INT(width),
|
||||
"height", GST_PROPS_INT(height),
|
||||
NULL));
|
||||
capslist = gst_caps_append(capslist, caps);
|
||||
}
|
||||
|
||||
return capslist;
|
||||
}
|
||||
|
||||
|
||||
static GList *
|
||||
gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src,
|
||||
GstCaps *capslist)
|
||||
{
|
||||
GList *fourcclist = NULL;
|
||||
GstCaps *caps;
|
||||
guint32 fourcc;
|
||||
gint i;
|
||||
|
||||
for (caps = capslist;caps != NULL; caps = caps->next) {
|
||||
const gchar *format = gst_caps_get_mime(caps);
|
||||
|
||||
if (!strcmp(format, "video/raw")) {
|
||||
/* non-compressed */
|
||||
gst_caps_get_fourcc_int(caps, "format", &fourcc);
|
||||
switch (fourcc) {
|
||||
case GST_MAKE_FOURCC('I','4','2','0'):
|
||||
case GST_MAKE_FOURCC('I','Y','U','V'):
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_YUV420);
|
||||
break;
|
||||
case GST_MAKE_FOURCC('Y','U','Y','2'):
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_YUYV);
|
||||
break;
|
||||
case GST_MAKE_FOURCC('R','G','B',' '): {
|
||||
gint depth, endianness;
|
||||
gst_caps_get_int(caps, "depth", &depth);
|
||||
gst_caps_get_int(caps, "endianness", &endianness);
|
||||
if (depth == 8) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB332);
|
||||
} else if (depth == 15 && endianness == G_LITTLE_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB555);
|
||||
} else if (depth == 15 && endianness == G_BIG_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB555X);
|
||||
} else if (depth == 16 && endianness == G_LITTLE_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB565);
|
||||
} else if (depth == 16 && endianness == G_BIG_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB565X);
|
||||
} else if (depth == 24 && endianness == G_LITTLE_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_BGR24);
|
||||
} else if (depth == 24 && endianness == G_BIG_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB24);
|
||||
} else if (depth == 32 && endianness == G_LITTLE_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_BGR32);
|
||||
} else if (depth == 32 && endianness == G_BIG_ENDIAN) {
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_RGB32);
|
||||
}
|
||||
break; }
|
||||
}
|
||||
|
||||
for (i=0;i<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);i++) {
|
||||
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, i);
|
||||
if (fmt->pixelformat == fourcc)
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)fourcc);
|
||||
}
|
||||
} else {
|
||||
/* compressed */
|
||||
gchar *format_us;
|
||||
gint i;
|
||||
if (strncmp(format, "video/", 6))
|
||||
continue;
|
||||
format = &format[6];
|
||||
if (strlen(format) != 4)
|
||||
continue;
|
||||
format_us = g_strdup(format);
|
||||
for (i=0;i<4;i++)
|
||||
format_us[i] = g_ascii_toupper(format_us[i]);
|
||||
fourcc = GST_MAKE_FOURCC(format_us[0],format_us[1],format_us[2],format_us[3]);
|
||||
switch (fourcc) {
|
||||
case GST_MAKE_FOURCC('J','P','E','G'):
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)V4L2_PIX_FMT_MJPEG);
|
||||
break;
|
||||
}
|
||||
fourcclist = g_list_append(fourcclist, (gpointer)fourcc);
|
||||
}
|
||||
}
|
||||
|
||||
return fourcclist;
|
||||
}
|
||||
|
||||
|
||||
static GstCaps *
|
||||
gst_v4l2src_caps_intersect (GstCaps *caps1,
|
||||
GstCaps *_caps2)
|
||||
{
|
||||
GstCaps *_list = NULL;
|
||||
|
||||
if (!_caps2)
|
||||
return caps1;
|
||||
|
||||
for (;caps1!=NULL;caps1=caps1->next) {
|
||||
GstCaps *caps2 = _caps2;
|
||||
|
||||
for (;caps2!=NULL;caps2=caps2->next) {
|
||||
if (!strcmp(gst_caps_get_mime(caps1), gst_caps_get_mime(caps2))) {
|
||||
if (!strcmp(gst_caps_get_mime(caps1), "video/raw")) {
|
||||
guint32 fmt1, fmt2;
|
||||
gst_caps_get_fourcc_int(caps1, "format", &fmt1);
|
||||
gst_caps_get_fourcc_int(caps2, "format", &fmt2);
|
||||
if (fmt1 == fmt2)
|
||||
goto try_it_out;
|
||||
} else if (!strncmp(gst_caps_get_mime(caps1), "video/", 6)) {
|
||||
goto try_it_out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
try_it_out:
|
||||
if (!strcmp(gst_caps_get_mime(caps1), "video/raw")) {
|
||||
GstCaps *list = _list;
|
||||
for (;list!=NULL;list=list->next) {
|
||||
if (!strcmp(gst_caps_get_mime(list), gst_caps_get_mime(caps1))) {
|
||||
guint32 fmt1, fmt2;
|
||||
gst_caps_get_fourcc_int(caps1, "format", &fmt1);
|
||||
gst_caps_get_fourcc_int(list, "format", &fmt2);
|
||||
if (fmt1 == fmt2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (list == NULL)
|
||||
goto add_it;
|
||||
} else {
|
||||
GstCaps *list = _list;
|
||||
for (;list!=NULL;list=list->next) {
|
||||
if (!strcmp(gst_caps_get_mime(list), gst_caps_get_mime(caps1))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (list == NULL)
|
||||
goto add_it;
|
||||
}
|
||||
continue;
|
||||
|
||||
add_it:
|
||||
_list = gst_caps_append(_list, gst_caps_copy_1(caps1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _list;
|
||||
}
|
||||
|
||||
|
||||
static GstPadConnectReturn
|
||||
gst_v4l2src_srcconnect (GstPad *pad,
|
||||
GstCaps *vscapslist)
|
||||
{
|
||||
GstV4l2Src *v4l2src;
|
||||
GstV4l2Element *v4l2element;
|
||||
GstCaps *owncapslist;
|
||||
GstCaps *caps;
|
||||
GList *fourccs;
|
||||
gint i;
|
||||
|
||||
v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
|
||||
v4l2element = GST_V4L2ELEMENT(v4l2src);
|
||||
|
||||
/* clean up if we still haven't cleaned up our previous
|
||||
* capture session */
|
||||
if (GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src)))
|
||||
if (!gst_v4l2src_capture_deinit(v4l2src))
|
||||
return GST_PAD_CONNECT_REFUSED;
|
||||
|
||||
/* build our own capslist */
|
||||
if (v4l2src->palette) {
|
||||
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, v4l2src->palette);
|
||||
owncapslist = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
|
||||
v4l2src->width, v4l2src->height,
|
||||
format->flags & V4L2_FMT_FLAG_COMPRESSED);
|
||||
} else {
|
||||
gint i;
|
||||
owncapslist = NULL;
|
||||
for (i=0;i<g_list_length(v4l2element->formats);i++) {
|
||||
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, i);
|
||||
caps = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
|
||||
v4l2src->width, v4l2src->height,
|
||||
format->flags & V4L2_FMT_FLAG_COMPRESSED);
|
||||
owncapslist = gst_caps_append(owncapslist, caps);
|
||||
}
|
||||
}
|
||||
|
||||
/* and now, get the caps that we have in common */
|
||||
if (!(caps = gst_v4l2src_caps_intersect(owncapslist, vscapslist)))
|
||||
return GST_PAD_CONNECT_REFUSED;
|
||||
|
||||
/* and get them back to V4L2-compatible fourcc codes */
|
||||
if (!(fourccs = gst_v4l2_caps_to_v4l2fourcc(v4l2src, caps)))
|
||||
return GST_PAD_CONNECT_REFUSED;
|
||||
|
||||
/* we now have the fourcc codes. try out each of them */
|
||||
for (i=0;i<g_list_length(fourccs);i++) {
|
||||
guint32 fourcc = (guint32)g_list_nth_data(fourccs, i);
|
||||
gint n;
|
||||
for (n=0;n<g_list_length(v4l2element->formats);n++) {
|
||||
struct v4l2_fmtdesc *format = g_list_nth_data(v4l2element->formats, n);
|
||||
if (format->pixelformat == fourcc) {
|
||||
/* we found the pixelformat! - try it out */
|
||||
if (gst_v4l2src_set_capture(v4l2src, format,
|
||||
v4l2src->width, v4l2src->height)) {
|
||||
/* it fits! Now, get the proper counterpart and retry
|
||||
* it on the other side (again...) - if it works, we're
|
||||
* done -> GST_PAD_CONNECT_OK */
|
||||
GstCaps *lastcaps = gst_v4l2src_v4l2fourcc_to_caps(format->pixelformat,
|
||||
v4l2src->format.fmt.pix.width, v4l2src->format.fmt.pix.height,
|
||||
format->flags & V4L2_FMT_FLAG_COMPRESSED);
|
||||
GstCaps *onecaps;
|
||||
for (;lastcaps != NULL; lastcaps = lastcaps->next) {
|
||||
onecaps = gst_caps_copy_1(lastcaps);
|
||||
if (gst_pad_try_set_caps(v4l2src->srcpad, onecaps))
|
||||
if (gst_v4l2src_capture_init(v4l2src))
|
||||
return GST_PAD_CONNECT_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GST_PAD_CONNECT_REFUSED;
|
||||
}
|
||||
|
||||
|
||||
static GstBuffer*
|
||||
gst_v4l2src_get (GstPad *pad)
|
||||
{
|
||||
GstV4l2Src *v4l2src;
|
||||
GstBuffer *buf;
|
||||
gint num;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
|
||||
v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
|
||||
|
||||
buf = gst_buffer_new_from_pool(v4l2src->bufferpool, 0, 0);
|
||||
if (!buf) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Failed to create a new GstBuffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* grab a frame from the device */
|
||||
if (!gst_v4l2src_grab_frame(v4l2src, &num))
|
||||
return NULL;
|
||||
GST_BUFFER_DATA(buf) = GST_V4L2ELEMENT(v4l2src)->buffer[num];
|
||||
GST_BUFFER_SIZE(buf) = v4l2src->bufsettings.bytesused;
|
||||
GST_BUFFER_MAXSIZE(buf) = v4l2src->bufsettings.length;
|
||||
if (!v4l2src->first_timestamp)
|
||||
v4l2src->first_timestamp = v4l2src->bufsettings.timestamp;
|
||||
GST_BUFFER_TIMESTAMP(buf) = v4l2src->bufsettings.length - v4l2src->first_timestamp;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_WIDTH:
|
||||
if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
|
||||
v4l2src->width = g_value_get_int(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_HEIGHT:
|
||||
if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
|
||||
v4l2src->height = g_value_get_int(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_PALETTE:
|
||||
if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
|
||||
v4l2src->palette = g_value_get_int(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_FOURCC:
|
||||
if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
|
||||
gint i;
|
||||
const gchar *formatstr = g_value_get_string(value);
|
||||
guint32 fourcc = GST_MAKE_FOURCC(formatstr[0],formatstr[1],formatstr[2],formatstr[3]);
|
||||
for (i=0;i<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);i++) {
|
||||
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, i);
|
||||
if (fmt->pixelformat == fourcc)
|
||||
v4l2src->palette = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_NUMBUFS:
|
||||
if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
|
||||
v4l2src->breq.count = g_value_get_int(value);
|
||||
}
|
||||
break;
|
||||
|
||||
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);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_WIDTH:
|
||||
g_value_set_int(value, v4l2src->width);
|
||||
break;
|
||||
|
||||
case ARG_HEIGHT:
|
||||
g_value_set_int(value, v4l2src->height);
|
||||
break;
|
||||
|
||||
case ARG_PALETTE:
|
||||
g_value_set_int(value, v4l2src->palette);
|
||||
break;
|
||||
|
||||
case ARG_PALETTE_NAMES:
|
||||
g_value_set_pointer(value, gst_v4l2src_get_format_list(v4l2src));
|
||||
break;
|
||||
|
||||
case ARG_FOURCC: {
|
||||
struct v4l2_fmtdesc *fmt = g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, v4l2src->palette);
|
||||
guint32 print_format = GUINT32_FROM_LE(fmt->pixelformat);
|
||||
gchar *print_format_str = (gchar *) &print_format;
|
||||
g_value_set_string(value, g_strndup(print_format_str, 4));
|
||||
break; }
|
||||
|
||||
case ARG_FOURCC_LIST:
|
||||
g_value_set_pointer(value, gst_v4l2src_get_fourcc_list(v4l2src));
|
||||
break;
|
||||
|
||||
case ARG_NUMBUFS:
|
||||
g_value_set_int(value, v4l2src->breq.count);
|
||||
break;
|
||||
|
||||
case ARG_BUFSIZE:
|
||||
g_value_set_int(value, v4l2src->format.fmt.pix.sizeimage);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_v4l2src_change_state (GstElement *element)
|
||||
{
|
||||
GstV4l2Src *v4l2src;
|
||||
gint transition = GST_STATE_TRANSITION (element);
|
||||
GstElementStateReturn parent_return;
|
||||
|
||||
g_return_val_if_fail(GST_IS_V4L2SRC(element), GST_STATE_FAILURE);
|
||||
v4l2src = GST_V4L2SRC(element);
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
|
||||
parent_return = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
if (parent_return != GST_STATE_SUCCESS)
|
||||
return parent_return;
|
||||
}
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
if (!gst_v4l2src_get_capture(v4l2src))
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
v4l2src->first_timestamp = 0;
|
||||
/* buffer setup moved to capsnego */
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* queue all buffer, start streaming capture */
|
||||
if (!gst_v4l2src_capture_start(v4l2src))
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
/* de-queue all queued buffers */
|
||||
if (!gst_v4l2src_capture_stop(v4l2src))
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
/* stop capturing, unmap all buffers */
|
||||
if (!gst_v4l2src_capture_deinit(v4l2src))
|
||||
return GST_STATE_FAILURE;
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static GstBuffer*
|
||||
gst_v4l2src_buffer_new (GstBufferPool *pool,
|
||||
guint64 offset,
|
||||
guint size,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
|
||||
buffer = gst_buffer_new();
|
||||
if (!buffer) return NULL;
|
||||
/* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static GstBuffer*
|
||||
gst_v4l2src_buffer_copy (GstBufferPool *pool,
|
||||
const GstBuffer *srcbuf,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
|
||||
buffer = gst_buffer_new();
|
||||
if (!buffer) return NULL;
|
||||
GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
|
||||
if (!GST_BUFFER_DATA(buffer)) return NULL;
|
||||
GST_BUFFER_MAXSIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
|
||||
GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
|
||||
memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
|
||||
GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2src_buffer_free (GstBufferPool *pool,
|
||||
GstBuffer *buf,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstV4l2Src *v4l2src = GST_V4L2SRC(user_data);
|
||||
int n;
|
||||
|
||||
for (n=0;n<v4l2src->breq.count;n++)
|
||||
if (GST_BUFFER_DATA(buf) == GST_V4L2ELEMENT(v4l2src)->buffer[n]) {
|
||||
gst_v4l2src_requeue_frame(v4l2src, n);
|
||||
return;
|
||||
}
|
||||
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Couldn\'t find the buffer");
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
plugin_init (GModule *module,
|
||||
GstPlugin *plugin)
|
||||
{
|
||||
GstElementFactory *factory;
|
||||
|
||||
/* create an elementfactory for the v4l2src */
|
||||
factory = gst_element_factory_new("v4l2src", GST_TYPE_V4L2SRC,
|
||||
&gst_v4l2src_details);
|
||||
g_return_val_if_fail(factory != NULL, FALSE);
|
||||
|
||||
src_template = gst_pad_template_new("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
NULL);
|
||||
|
||||
gst_element_factory_add_pad_template(factory, src_template);
|
||||
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE(factory));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
GstPluginDesc plugin_desc = {
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"v4l2src",
|
||||
plugin_init
|
||||
};
|
69
sys/v4l2/gstv4l2src.h
Normal file
69
sys/v4l2/gstv4l2src.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* G-Streamer Video4linux2 video-capture plugin
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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 <gstv4l2element.h>
|
||||
|
||||
|
||||
#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(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4L2SRC))
|
||||
|
||||
|
||||
typedef struct _GstV4l2Src GstV4l2Src;
|
||||
typedef struct _GstV4l2SrcClass GstV4l2SrcClass;
|
||||
|
||||
struct _GstV4l2Src {
|
||||
GstV4l2Element v4l2element;
|
||||
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
/* buffer properties */
|
||||
struct v4l2_buffer bufsettings;
|
||||
struct v4l2_requestbuffers breq;
|
||||
struct v4l2_format format;
|
||||
stamp_t first_timestamp;
|
||||
|
||||
/* bufferpool for the buffers we're gonna use */
|
||||
GstBufferPool *bufferpool;
|
||||
|
||||
/* caching values */
|
||||
gint width;
|
||||
gint height;
|
||||
gint palette;
|
||||
};
|
||||
|
||||
struct _GstV4l2SrcClass {
|
||||
GstV4l2ElementClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType gst_v4l2src_get_type(void);
|
||||
|
||||
#endif /* __GST_V4L2SRC_H__ */
|
168
sys/v4l2/v4l2-overlay_calls.c
Normal file
168
sys/v4l2/v4l2-overlay_calls.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/* G-Streamer generic V4L2 element - generic V4L2 overlay handling
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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 "v4l2_calls.h"
|
||||
|
||||
#define DEBUG(format, args...) \
|
||||
GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
|
||||
GST_ELEMENT(v4l2element), \
|
||||
"V4L2-overlay: " format "\n", ##args)
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_set_display():
|
||||
* calls v4l-conf
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_display (GstV4l2Element *v4l2element,
|
||||
const gchar *display)
|
||||
{
|
||||
gchar *buff;
|
||||
|
||||
DEBUG("trying to set overlay to '%s'", display);
|
||||
|
||||
/* start v4l-conf */
|
||||
buff = g_strdup_printf("v4l-conf -q -c %s -d %s",
|
||||
v4l2element->device?v4l2element->device:"/dev/video", display);
|
||||
|
||||
switch (system(buff)) {
|
||||
case -1:
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Could not start v4l-conf: %s", sys_errlist[errno]);
|
||||
g_free(buff);
|
||||
return FALSE;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"v4l-conf failed to run correctly: %s", sys_errlist[errno]);
|
||||
g_free(buff);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free(buff);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_set_vwin():
|
||||
* does the VIDIOC_S_WIN ioctl()
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_set_vwin (GstV4l2Element *v4l2element)
|
||||
{
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_S_WIN, &(v4l2element->vwin)) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set the video window on device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_set_window():
|
||||
* sets the window where to display the video overlay
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_window (GstV4l2Element *v4l2element,
|
||||
gint x, gint y,
|
||||
gint w, gint h)
|
||||
{
|
||||
DEBUG("trying to set video window to %dx%d,%d,%d", x,y,w,h);
|
||||
GST_V4L2_CHECK_OVERLAY(v4l2element);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
v4l2element->vwin.clipcount = 0;
|
||||
v4l2element->vwin.x = x;
|
||||
v4l2element->vwin.y = y;
|
||||
v4l2element->vwin.width = w;
|
||||
v4l2element->vwin.height = h;
|
||||
|
||||
return gst_v4l2_set_vwin(v4l2element);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_set_clips():
|
||||
* sets video overlay clips
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_clips (GstV4l2Element *v4l2element,
|
||||
struct v4l2_clip *clips,
|
||||
gint num_clips)
|
||||
{
|
||||
DEBUG("trying to set video clipping information");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_OVERLAY(v4l2element);
|
||||
|
||||
v4l2element->vwin.clips = clips;
|
||||
v4l2element->vwin.clipcount = num_clips;
|
||||
|
||||
return gst_v4l2_set_vwin(v4l2element);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_set_overlay():
|
||||
* enables/disables actual video overlay display
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_enable_overlay (GstV4l2Element *v4l2element,
|
||||
gboolean enable)
|
||||
{
|
||||
gint doit = enable?1:0;
|
||||
|
||||
DEBUG("trying to %s overlay display", enable?"enable":"disable");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_OVERLAY(v4l2element);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_PREVIEW, &doit) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to %s overlay display for device %s: %s",
|
||||
enable?"enable":"disable", v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
863
sys/v4l2/v4l2_calls.c
Normal file
863
sys/v4l2/v4l2_calls.c
Normal file
|
@ -0,0 +1,863 @@
|
|||
/* G-Streamer generic V4L2 element - generic V4L2 calls handling
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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 "v4l2_calls.h"
|
||||
|
||||
#define DEBUG(format, args...) \
|
||||
GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
|
||||
GST_ELEMENT(v4l2element), \
|
||||
"V4L2: " format "\n", ##args)
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_capabilities():
|
||||
* get the device's capturing capabilities
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_get_capabilities (GstV4l2Element *v4l2element)
|
||||
{
|
||||
DEBUG("getting capabilities");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCAP, &(v4l2element->vcap)) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Error getting %s capabilities: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* 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 (GstV4l2Element *v4l2element)
|
||||
{
|
||||
gint n;
|
||||
|
||||
DEBUG("getting enumerations");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
/* create enumeration lists - let's start with format enumeration */
|
||||
for (n=0;;n++) {
|
||||
struct v4l2_fmtdesc format, *fmtptr;
|
||||
format.index = n;
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_ENUM_PIXFMT, &format) < 0) {
|
||||
if (errno == EINVAL)
|
||||
break; /* end of enumeration */
|
||||
else {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get no. %d in pixelformat enumeration for %s: %s",
|
||||
n, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
fmtptr = g_malloc(sizeof(format));
|
||||
memcpy(fmtptr, &format, sizeof(format));
|
||||
v4l2element->formats = g_list_append(v4l2element->formats, fmtptr);
|
||||
}
|
||||
|
||||
/* and now, the inputs */
|
||||
for (n=0;;n++) {
|
||||
struct v4l2_input input, *inpptr;
|
||||
input.index = n;
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_ENUMINPUT, &input) < 0) {
|
||||
if (errno == EINVAL)
|
||||
break; /* end of enumeration */
|
||||
else {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get no. %d in input enumeration for %s: %s",
|
||||
n, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
inpptr = g_malloc(sizeof(input));
|
||||
memcpy(inpptr, &input, sizeof(input));
|
||||
v4l2element->inputs = g_list_append(v4l2element->inputs, inpptr);
|
||||
}
|
||||
|
||||
/* outputs */
|
||||
for (n=0;;n++) {
|
||||
struct v4l2_output output, *outptr;
|
||||
output.index = n;
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_ENUMOUTPUT, &output) < 0) {
|
||||
if (errno == EINVAL)
|
||||
break; /* end of enumeration */
|
||||
else {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get no. %d in output enumeration for %s: %s",
|
||||
n, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
outptr = g_malloc(sizeof(output));
|
||||
memcpy(outptr, &output, sizeof(output));
|
||||
v4l2element->outputs = g_list_append(v4l2element->outputs, outptr);
|
||||
}
|
||||
|
||||
/* norms... */
|
||||
for (n=0;;n++) {
|
||||
struct v4l2_enumstd standard, *stdptr;
|
||||
standard.index = n;
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
|
||||
if (errno == EINVAL)
|
||||
break; /* end of enumeration */
|
||||
else {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get no. %d in norm enumeration for %s: %s",
|
||||
n, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
stdptr = g_malloc(sizeof(standard));
|
||||
memcpy(stdptr, &standard, sizeof(standard));
|
||||
v4l2element->norms = g_list_append(v4l2element->norms, stdptr);
|
||||
}
|
||||
|
||||
/* and lastly, controls+menus (if appropriate) */
|
||||
for (n=0;;n++) {
|
||||
struct v4l2_queryctrl control, *ctrlptr;
|
||||
GList *menus = NULL;
|
||||
control.id = n;
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
|
||||
if (errno == EINVAL)
|
||||
break; /* end of enumeration */
|
||||
else {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get no. %d in control enumeration for %s: %s",
|
||||
n, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
ctrlptr = g_malloc(sizeof(control));
|
||||
memcpy(ctrlptr, &control, sizeof(control));
|
||||
v4l2element->controls = g_list_append(v4l2element->controls, ctrlptr);
|
||||
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(v4l2element->video_fd, VIDIOC_QUERYMENU, &menu) < 0) {
|
||||
if (errno == EINVAL)
|
||||
break; /* end of enumeration */
|
||||
else {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get no. %d in menu %d enumeration for %s: %s",
|
||||
i, n, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
mptr = g_malloc(sizeof(menu));
|
||||
memcpy(mptr, &menu, sizeof(menu));
|
||||
menus = g_list_append(menus, mptr);
|
||||
}
|
||||
}
|
||||
v4l2element->menus = g_list_append(v4l2element->menus, menus);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_v4l2_empty_lists (GstV4l2Element *v4l2element)
|
||||
{
|
||||
DEBUG("deleting enumerations");
|
||||
|
||||
/* empty lists */
|
||||
while (g_list_length(v4l2element->inputs) > 0) {
|
||||
gpointer data = g_list_nth_data(v4l2element->inputs, 0);
|
||||
v4l2element->inputs = g_list_remove(v4l2element->inputs, data);
|
||||
g_free(data);
|
||||
}
|
||||
while (g_list_length(v4l2element->outputs) > 0) {
|
||||
gpointer data = g_list_nth_data(v4l2element->outputs, 0);
|
||||
v4l2element->outputs = g_list_remove(v4l2element->outputs, data);
|
||||
g_free(data);
|
||||
}
|
||||
while (g_list_length(v4l2element->norms) > 0) {
|
||||
gpointer data = g_list_nth_data(v4l2element->norms, 0);
|
||||
v4l2element->norms = g_list_remove(v4l2element->norms, data);
|
||||
g_free(data);
|
||||
}
|
||||
while (g_list_length(v4l2element->formats) > 0) {
|
||||
gpointer data = g_list_nth_data(v4l2element->formats, 0);
|
||||
v4l2element->formats = g_list_remove(v4l2element->formats, data);
|
||||
g_free(data);
|
||||
}
|
||||
while (g_list_length(v4l2element->controls) > 0) {
|
||||
gpointer data = g_list_nth_data(v4l2element->controls, 0);
|
||||
v4l2element->controls = g_list_remove(v4l2element->controls, data);
|
||||
g_free(data);
|
||||
}
|
||||
v4l2element->menus = g_list_remove_all(v4l2element->menus, NULL);
|
||||
while (g_list_length(v4l2element->menus) > 0) {
|
||||
GList *items = (GList *) g_list_nth_data(v4l2element->menus, 0);
|
||||
v4l2element->inputs = g_list_remove(v4l2element->inputs, items);
|
||||
while (g_list_length(items) > 0) {
|
||||
gpointer data = g_list_nth_data(v4l2element->menus, 0);
|
||||
items = g_list_remove(items, data);
|
||||
g_free(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_open():
|
||||
* open the video device (v4l2element->device)
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_open (GstV4l2Element *v4l2element)
|
||||
{
|
||||
DEBUG("Trying to open device %s", v4l2element->device);
|
||||
GST_V4L2_CHECK_NOT_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
|
||||
|
||||
/* be sure we have a device */
|
||||
if (!v4l2element->device)
|
||||
v4l2element->device = g_strdup("/dev/video");
|
||||
|
||||
/* open the device */
|
||||
v4l2element->video_fd = open(v4l2element->device, O_RDWR);
|
||||
if (!GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to open device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* get capabilities */
|
||||
if (!gst_v4l2_get_capabilities(v4l2element)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* and get the video window */
|
||||
if (GST_V4L2_IS_OVERLAY(v4l2element)) {
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_WIN, &(v4l2element->vwin)) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get video window properties of %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* create enumerations */
|
||||
if (!gst_v4l2_fill_lists(v4l2element))
|
||||
goto error;
|
||||
|
||||
gst_info("Opened device '%s' (%s) successfully\n",
|
||||
v4l2element->vcap.name, v4l2element->device);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (GST_V4L2_IS_OPEN(v4l2element)) {
|
||||
/* close device */
|
||||
close(v4l2element->video_fd);
|
||||
v4l2element->video_fd = -1;
|
||||
}
|
||||
/* empty lists */
|
||||
gst_v4l2_empty_lists(v4l2element);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_close():
|
||||
* close the video device (v4l2element->video_fd)
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_close (GstV4l2Element *v4l2element)
|
||||
{
|
||||
DEBUG("Trying to close %s", v4l2element->device);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
|
||||
|
||||
/* close device */
|
||||
close(v4l2element->video_fd);
|
||||
v4l2element->video_fd = -1;
|
||||
|
||||
/* empty lists */
|
||||
gst_v4l2_empty_lists(v4l2element);
|
||||
|
||||
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 (GstV4l2Element *v4l2element,
|
||||
gint *norm)
|
||||
{
|
||||
struct v4l2_standard standard;
|
||||
gint n;
|
||||
|
||||
DEBUG("getting norm");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_STD, &standard) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get the current norm for device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* try to find out what norm number this actually is */
|
||||
for (n=0;n<g_list_length(v4l2element->norms);n++) {
|
||||
struct v4l2_enumstd *stdptr = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
|
||||
if (!strcmp(stdptr->std.name, standard.name)) {
|
||||
*norm = n;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to find norm '%s' in our list of available norms for device %s",
|
||||
standard.name, v4l2element->device);
|
||||
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 (GstV4l2Element *v4l2element,
|
||||
gint norm)
|
||||
{
|
||||
struct v4l2_enumstd *standard;
|
||||
|
||||
DEBUG("trying to set norm to %d", norm);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
|
||||
|
||||
if (norm < 0 || norm >= g_list_length(v4l2element->norms)) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Invalid norm number %d (%d-%d)",
|
||||
norm, 0, g_list_length(v4l2element->norms));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, norm);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_S_STD, &standard->std) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set norm '%s' (%d) for device %s: %s",
|
||||
standard->std.name, norm, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_norm_names()
|
||||
* Get the list of available norms
|
||||
* return value: the list
|
||||
******************************************************/
|
||||
|
||||
GList *
|
||||
gst_v4l2_get_norm_names (GstV4l2Element *v4l2element)
|
||||
{
|
||||
GList *names = NULL;
|
||||
gint n;
|
||||
|
||||
DEBUG("getting a list of norm names");
|
||||
|
||||
for (n=0;n<g_list_length(v4l2element->norms);n++) {
|
||||
struct v4l2_enumstd *standard = (struct v4l2_enumstd *) g_list_nth_data(v4l2element->norms, n);
|
||||
names = g_list_append(names, g_strdup(standard->std.name));
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_input()
|
||||
* Get the input of the current device
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_input (GstV4l2Element *v4l2element,
|
||||
gint *input)
|
||||
{
|
||||
gint n;
|
||||
|
||||
DEBUG("trying to get input");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_INPUT, &n) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get current input on device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*input = n;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_set_input()
|
||||
* Set the input of the current device
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_input (GstV4l2Element *v4l2element,
|
||||
gint input)
|
||||
{
|
||||
DEBUG("trying to set input to %d", input);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
|
||||
|
||||
if (input < 0 || input >= g_list_length(v4l2element->inputs)) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Invalid input number %d (%d-%d)",
|
||||
input, 0, g_list_length(v4l2element->inputs));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_S_INPUT, &input) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set input %d on device %s: %s",
|
||||
input, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_input_names()
|
||||
* Get the list of available input channels
|
||||
* return value: the list
|
||||
******************************************************/
|
||||
|
||||
GList *
|
||||
gst_v4l2_get_input_names (GstV4l2Element *v4l2element)
|
||||
{
|
||||
GList *names = NULL;
|
||||
gint n;
|
||||
|
||||
DEBUG("getting a list of input names");
|
||||
|
||||
for (n=0;n<g_list_length(v4l2element->inputs);n++) {
|
||||
struct v4l2_input *input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, n);
|
||||
names = g_list_append(names, g_strdup(input->name));
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_output()
|
||||
* Get the output of the current device
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_output (GstV4l2Element *v4l2element,
|
||||
gint *output)
|
||||
{
|
||||
gint n;
|
||||
|
||||
DEBUG("trying to get output");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_OUTPUT, &n) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get current output on device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*output = n;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_set_output()
|
||||
* Set the output of the current device
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_output (GstV4l2Element *v4l2element,
|
||||
gint output)
|
||||
{
|
||||
DEBUG("trying to set output to %d", output);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
|
||||
|
||||
if (output < 0 || output >= g_list_length(v4l2element->outputs)) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Invalid output number %d (%d-%d)",
|
||||
output, 0, g_list_length(v4l2element->outputs));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_S_OUTPUT, &output) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set output %d on device %s: %s",
|
||||
output, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_output_names()
|
||||
* Get the list of available output channels
|
||||
* return value: the list, or NULL on error
|
||||
******************************************************/
|
||||
|
||||
GList *
|
||||
gst_v4l2_get_output_names (GstV4l2Element *v4l2element)
|
||||
{
|
||||
GList *names = NULL;
|
||||
gint n;
|
||||
|
||||
DEBUG("getting a list of output names");
|
||||
|
||||
for (n=0;n<g_list_length(v4l2element->outputs);n++) {
|
||||
struct v4l2_output *output = (struct v4l2_output *) g_list_nth_data(v4l2element->outputs, n);
|
||||
names = g_list_append(names, g_strdup(output->name));
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_has_tuner():
|
||||
* Check whether the device has a tuner
|
||||
* return value: TRUE if it has a tuner, else FALSE
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_has_tuner (GstV4l2Element *v4l2element)
|
||||
{
|
||||
gint input_num;
|
||||
struct v4l2_input *input;
|
||||
|
||||
DEBUG("detecting whether device has a tuner");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (!gst_v4l2_get_input(v4l2element, &input_num))
|
||||
return FALSE;
|
||||
|
||||
input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
|
||||
|
||||
return (input->type == V4L2_INPUT_TYPE_TUNER &&
|
||||
v4l2element->vcap.flags & V4L2_FLAG_TUNER);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_get_frequency():
|
||||
* get the current frequency
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
|
||||
gulong *frequency)
|
||||
{
|
||||
gint n;
|
||||
|
||||
DEBUG("getting current tuner frequency");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (!gst_v4l2_has_tuner(v4l2element))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get current tuner frequency for device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*frequency = n;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_set_frequency():
|
||||
* set frequency
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
|
||||
gulong frequency)
|
||||
{
|
||||
gint n = frequency;
|
||||
|
||||
DEBUG("setting current tuner frequency to %lu", frequency);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(v4l2element);
|
||||
|
||||
if (!gst_v4l2_has_tuner(v4l2element))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_FREQ, &n) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set tuner frequency to %lu for device %s: %s",
|
||||
frequency, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_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 (GstV4l2Element *v4l2element,
|
||||
gulong *signal_strength)
|
||||
{
|
||||
struct v4l2_tuner tuner;
|
||||
|
||||
DEBUG("trying to get signal strength");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set signal strength for device %s: %s",
|
||||
v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*signal_strength = tuner.signal;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_has_audio():
|
||||
* Check whether the device has audio capabilities
|
||||
* return value: TRUE if it has a tuner, else FALSE
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_has_audio (GstV4l2Element *v4l2element)
|
||||
{
|
||||
gint input_num;
|
||||
struct v4l2_input *input;
|
||||
|
||||
DEBUG("detecting whether device has audio");
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (!gst_v4l2_get_input(v4l2element, &input_num))
|
||||
return FALSE;
|
||||
|
||||
input = (struct v4l2_input *) g_list_nth_data(v4l2element->inputs, input_num);
|
||||
|
||||
return (input->capability & V4L2_INPUT_CAP_AUDIO);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_get_attributes():
|
||||
* get a list of attributes available on this device
|
||||
* return value: the list
|
||||
******************************************************/
|
||||
|
||||
GList *
|
||||
gst_v4l2_get_attributes (GstV4l2Element *v4l2element)
|
||||
{
|
||||
gint i;
|
||||
GList *list = NULL;
|
||||
|
||||
DEBUG("getting a list of available attributes");
|
||||
|
||||
for (i=0;i<g_list_length(v4l2element->controls);i++) {
|
||||
struct v4l2_queryctrl *control = (struct v4l2_queryctrl *) g_list_nth_data(v4l2element->controls, i);
|
||||
GstV4l2Attribute* attribute = g_malloc(sizeof(GstV4l2Attribute));
|
||||
attribute->name = g_strdup(control->name);
|
||||
attribute->index = i;
|
||||
attribute->list_items = NULL;
|
||||
switch (control->type) {
|
||||
case V4L2_CTRL_TYPE_INTEGER:
|
||||
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_INT;
|
||||
break;
|
||||
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BOOLEAN;
|
||||
break;
|
||||
case V4L2_CTRL_TYPE_MENU: {
|
||||
/* list items */
|
||||
gint n;
|
||||
GList *menus = (GList *) g_list_nth_data(v4l2element->menus, i);
|
||||
for (n=0;n<g_list_length(menus);n++) {
|
||||
struct v4l2_querymenu *menu = g_list_nth_data(menus, n);
|
||||
attribute->list_items = g_list_append(attribute->list_items, g_strdup(menu->name));
|
||||
}
|
||||
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_LIST;
|
||||
break; }
|
||||
case V4L2_CTRL_TYPE_BUTTON:
|
||||
attribute->val_type = GST_V4L2_ATTRIBUTE_VALUE_TYPE_BUTTON;
|
||||
break;
|
||||
}
|
||||
switch (control->category) {
|
||||
case V4L2_CTRL_CAT_VIDEO:
|
||||
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_VIDEO;
|
||||
break;
|
||||
case V4L2_CTRL_CAT_AUDIO:
|
||||
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_AUDIO;
|
||||
break;
|
||||
case V4L2_CTRL_CAT_EFFECT:
|
||||
attribute->type = GST_V4L2_ATTRIBUTE_TYPE_EFFECT;
|
||||
break;
|
||||
}
|
||||
gst_v4l2_get_attribute(v4l2element, i, &attribute->value);
|
||||
attribute->min = control->minimum;
|
||||
attribute->max = control->maximum;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_get_attribute():
|
||||
* try to get the value of one specific attribute
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
|
||||
gint attribute_num,
|
||||
gint *value)
|
||||
{
|
||||
struct v4l2_control control;
|
||||
|
||||
DEBUG("getting value of attribute %d", attribute_num);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Invalid control ID %d", attribute_num);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
control.id = attribute_num;
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_G_CTRL, &control) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to get value for control %d on device %s: %s",
|
||||
attribute_num, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*value = control.value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l_set_attribute():
|
||||
* try to set the value of one specific attribute
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
|
||||
gint attribute_num,
|
||||
gint value)
|
||||
{
|
||||
struct v4l2_control control;
|
||||
|
||||
DEBUG("setting value of attribute %d to %d", attribute_num, value);
|
||||
GST_V4L2_CHECK_OPEN(v4l2element);
|
||||
|
||||
if (attribute_num < 0 || attribute_num >= g_list_length(v4l2element->controls)) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Invalid control ID %d", attribute_num);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
control.id = attribute_num;
|
||||
control.value = value;
|
||||
|
||||
if (ioctl(v4l2element->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2element),
|
||||
"Failed to set value %d for control %d on device %s: %s",
|
||||
value, attribute_num, v4l2element->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
135
sys/v4l2/v4l2_calls.h
Normal file
135
sys/v4l2/v4l2_calls.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* G-Streamer generic V4L2 element - generic V4L2 calls handling
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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 "gstv4l2element.h"
|
||||
|
||||
|
||||
/* simple check whether the device is open */
|
||||
#define GST_V4L2_IS_OPEN(v4l2element) \
|
||||
(v4l2element->video_fd > 0)
|
||||
|
||||
/* check whether the device is 'active' */
|
||||
#define GST_V4L2_IS_ACTIVE(v4l2element) \
|
||||
(v4l2element->buffer != NULL)
|
||||
|
||||
#define GST_V4L2_IS_OVERLAY(v4l2element) \
|
||||
(v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)
|
||||
|
||||
/* checks whether the current v4lelement has already been open()'ed or not */
|
||||
#define GST_V4L2_CHECK_OPEN(v4l2element) \
|
||||
if (v4l2element->video_fd <= 0) \
|
||||
{ \
|
||||
gst_element_error(GST_ELEMENT(v4l2element), \
|
||||
"Device is not open"); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
/* checks whether the current v4lelement is close()'ed or whether it is still open */
|
||||
#define GST_V4L2_CHECK_NOT_OPEN(v4l2element) \
|
||||
if (v4l2element->video_fd != -1) \
|
||||
{ \
|
||||
gst_element_error(GST_ELEMENT(v4l2element), \
|
||||
"Device is open"); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
/* checks whether the current v4lelement does video overlay */
|
||||
#define GST_V4L2_CHECK_OVERLAY(v4l2element) \
|
||||
if (!(v4l2element->vcap.flags & V4L2_FLAG_PREVIEW)) \
|
||||
{ \
|
||||
gst_element_error(GST_ELEMENT(v4l2element), \
|
||||
"Device doesn't do overlay"); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
/* checks whether we're in capture mode or not */
|
||||
#define GST_V4L2_CHECK_ACTIVE(v4l2element) \
|
||||
if (v4l2element->buffer == NULL) \
|
||||
{ \
|
||||
gst_element_error(GST_ELEMENT(v4l2element), \
|
||||
"Device is not in streaming mode"); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
/* checks whether we're out of capture mode or not */
|
||||
#define GST_V4L2_CHECK_NOT_ACTIVE(v4l2element) \
|
||||
if (v4l2element->buffer != NULL) \
|
||||
{ \
|
||||
gst_element_error(GST_ELEMENT(v4l2element), \
|
||||
"Device is in streaming mode"); \
|
||||
return FALSE; \
|
||||
}
|
||||
|
||||
|
||||
/* open/close the device */
|
||||
gboolean gst_v4l2_open (GstV4l2Element *v4l2element);
|
||||
gboolean gst_v4l2_close (GstV4l2Element *v4l2element);
|
||||
|
||||
/* norm/input/output */
|
||||
gboolean gst_v4l2_get_norm (GstV4l2Element *v4l2element,
|
||||
gint *norm);
|
||||
gboolean gst_v4l2_set_norm (GstV4l2Element *v4l2element,
|
||||
gint norm);
|
||||
GList * gst_v4l2_get_norm_names (GstV4l2Element *v4l2element);
|
||||
gboolean gst_v4l2_get_input (GstV4l2Element *v4l2element,
|
||||
gint *input);
|
||||
gboolean gst_v4l2_set_input (GstV4l2Element *v4l2element,
|
||||
gint input);
|
||||
GList * gst_v4l2_get_input_names (GstV4l2Element *v4l2element);
|
||||
gboolean gst_v4l2_get_output (GstV4l2Element *v4l2element,
|
||||
gint *output);
|
||||
gboolean gst_v4l2_set_output (GstV4l2Element *v4l2element,
|
||||
gint output);
|
||||
GList * gst_v4l2_get_output_names (GstV4l2Element *v4l2element);
|
||||
|
||||
/* frequency control */
|
||||
gboolean gst_v4l2_has_tuner (GstV4l2Element *v4l2element);
|
||||
gboolean gst_v4l2_get_frequency (GstV4l2Element *v4l2element,
|
||||
gulong *frequency);
|
||||
gboolean gst_v4l2_set_frequency (GstV4l2Element *v4l2element,
|
||||
gulong frequency);
|
||||
gboolean gst_v4l2_signal_strength (GstV4l2Element *v4l2element,
|
||||
gulong *signal_strength);
|
||||
|
||||
/* attribute control */
|
||||
gboolean gst_v4l2_has_audio (GstV4l2Element *v4l2element);
|
||||
GList * gst_v4l2_get_attributes (GstV4l2Element *v4l2element);
|
||||
gboolean gst_v4l2_get_attribute (GstV4l2Element *v4l2element,
|
||||
gint attribute_num,
|
||||
gint *value);
|
||||
gboolean gst_v4l2_set_attribute (GstV4l2Element *v4l2element,
|
||||
gint attribute_num,
|
||||
gint value);
|
||||
|
||||
/* overlay */
|
||||
gboolean gst_v4l2_set_display (GstV4l2Element *v4l2element,
|
||||
const gchar *display);
|
||||
gboolean gst_v4l2_set_window (GstV4l2Element *v4l2element,
|
||||
gint x, gint y,
|
||||
gint w, gint h);
|
||||
gboolean gst_v4l2_set_clips (GstV4l2Element *v4l2element,
|
||||
struct v4l2_clip *clips,
|
||||
gint num_clips);
|
||||
gboolean gst_v4l2_enable_overlay (GstV4l2Element *v4l2element,
|
||||
gboolean enable);
|
||||
|
||||
#endif /* __V4L2_CALLS_H__ */
|
397
sys/v4l2/v4l2src_calls.c
Normal file
397
sys/v4l2/v4l2src_calls.c
Normal file
|
@ -0,0 +1,397 @@
|
|||
/* G-Streamer Video4linux2 video-capture plugin - system calls
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
#define DEBUG(format, args...) \
|
||||
GST_DEBUG_ELEMENT(GST_CAT_PLUGIN_INFO, \
|
||||
GST_ELEMENT(v4l2src), \
|
||||
"V4L2SRC: " format "\n", ##args)
|
||||
|
||||
#define MIN_BUFFERS_QUEUED 2
|
||||
|
||||
/* On some systems MAP_FAILED seems to be missing */
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ( (caddr_t) -1 )
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_queue_frame():
|
||||
* queue a frame for capturing
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_queue_frame (GstV4l2Src *v4l2src,
|
||||
gint num)
|
||||
{
|
||||
DEBUG("queueing frame %d", num);
|
||||
|
||||
v4l2src->bufsettings.index = num;
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_QBUF, &v4l2src->bufsettings) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Error queueing buffer %d on device %s: %s",
|
||||
num, GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4lsrc_sync_frame():
|
||||
* sync on a frame for capturing
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_sync_next_frame (GstV4l2Src *v4l2src,
|
||||
gint *num)
|
||||
{
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_DQBUF, &v4l2src->bufsettings) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Error syncing on a buffer on device %s: %s",
|
||||
GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
DEBUG("synced on frame %d", v4l2src->bufsettings.index);
|
||||
*num = v4l2src->bufsettings.index;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* 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(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Failed to get pixel format for device %s: %s",
|
||||
GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* 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)
|
||||
{
|
||||
DEBUG("Setting capture format to %dx%d, format %s",
|
||||
width, height, fmt->description);
|
||||
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
memset(&v4l2src->format, 0, sizeof(struct v4l2_format));
|
||||
v4l2src->format.fmt.pix.width = width;
|
||||
v4l2src->format.fmt.pix.height = height;
|
||||
v4l2src->format.fmt.pix.pixelformat = fmt->pixelformat;
|
||||
if (fmt->flags & V4L2_FMT_FLAG_COMPRESSED) {
|
||||
v4l2src->format.fmt.pix.flags = V4L2_FMT_FLAG_COMPRESSED;
|
||||
v4l2src->format.type = V4L2_BUF_TYPE_CODECIN;
|
||||
} else {
|
||||
v4l2src->format.type = V4L2_BUF_TYPE_CAPTURE;
|
||||
}
|
||||
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Failed to set pixel format to %s @ %dx%d for device %s: %s",
|
||||
fmt->description, width, height,
|
||||
GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* 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;
|
||||
gchar *desc = NULL;
|
||||
|
||||
DEBUG("initting the capture system");
|
||||
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_NOT_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
/* request buffer info */
|
||||
if (v4l2src->breq.count < MIN_BUFFERS_QUEUED)
|
||||
v4l2src->breq.count = MIN_BUFFERS_QUEUED;
|
||||
v4l2src->breq.type = v4l2src->format.type;
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_REQBUFS, &v4l2src->breq) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Error requesting buffers (%d) for %s: %s",
|
||||
v4l2src->breq.count, GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (v4l2src->breq.count < MIN_BUFFERS_QUEUED) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Too little buffers. We got %d, we want at least %d",
|
||||
v4l2src->breq.count, MIN_BUFFERS_QUEUED);
|
||||
return FALSE;
|
||||
}
|
||||
v4l2src->bufsettings.type = v4l2src->format.type;
|
||||
|
||||
for (n=0;n<g_list_length(GST_V4L2ELEMENT(v4l2src)->formats);n++) {
|
||||
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->formats, n);
|
||||
if (v4l2src->format.fmt.pix.pixelformat == fmt->pixelformat) {
|
||||
desc = fmt->description;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gst_info("Got %d buffers (%s) of size %d KB\n",
|
||||
v4l2src->breq.count, desc, v4l2src->format.fmt.pix.sizeimage/1024);
|
||||
|
||||
/* Map the buffers */
|
||||
GST_V4L2ELEMENT(v4l2src)->buffer = (guint8 **) g_malloc(sizeof(guint8*) * v4l2src->breq.count);
|
||||
for (n=0;n<v4l2src->breq.count;n++) {
|
||||
GST_V4L2ELEMENT(v4l2src)->buffer[n] = mmap(0, v4l2src->format.fmt.pix.sizeimage,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED, GST_V4L2ELEMENT(v4l2src)->video_fd, v4l2src->format.fmt.pix.sizeimage*n);
|
||||
if (GST_V4L2ELEMENT(v4l2src)->buffer[n] == MAP_FAILED) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Error mapping video buffer %d on device %s: %s",
|
||||
n, GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
GST_V4L2ELEMENT(v4l2src)->buffer[n] = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_start():
|
||||
* start streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_start (GstV4l2Src *v4l2src)
|
||||
{
|
||||
gint n;
|
||||
|
||||
DEBUG("starting the capturing");
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
/* queue all buffers, this starts streaming capture */
|
||||
for (n=0;n<v4l2src->breq.count;n++)
|
||||
if (!gst_v4l2src_queue_frame(v4l2src, n))
|
||||
return FALSE;
|
||||
n = 1;
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_STREAMON, &n) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Error starting streaming capture for %s: %s",
|
||||
GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_grab_frame():
|
||||
* capture one frame during streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_grab_frame (GstV4l2Src *v4l2src,
|
||||
gint *num)
|
||||
{
|
||||
DEBUG("syncing on the next frame");
|
||||
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
/* syncing on the buffer grabs it */
|
||||
if (!gst_v4l2src_sync_next_frame(v4l2src, num))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_requeue_frame():
|
||||
* re-queue a frame after we're done with the buffer
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_requeue_frame (GstV4l2Src *v4l2src,
|
||||
gint num)
|
||||
{
|
||||
DEBUG("requeueing frame %d", num);
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
/* and let's queue the buffer */
|
||||
if (!gst_v4l2src_queue_frame(v4l2src, num))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_stop():
|
||||
* stop streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_stop (GstV4l2Src *v4l2src)
|
||||
{
|
||||
gint n = 0;
|
||||
|
||||
DEBUG("stopping capturing");
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
/* we actually need to sync on all queued buffers but not on the non-queued ones */
|
||||
if (ioctl(GST_V4L2ELEMENT(v4l2src)->video_fd, VIDIOC_STREAMOFF, &n) < 0) {
|
||||
gst_element_error(GST_ELEMENT(v4l2src),
|
||||
"Error stopping streaming capture for %s: %s",
|
||||
GST_V4L2ELEMENT(v4l2src)->device, sys_errlist[errno]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_deinit():
|
||||
* deinitialize the capture system
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_deinit (GstV4l2Src *v4l2src)
|
||||
{
|
||||
gint n;
|
||||
|
||||
DEBUG("deinitting capture system");
|
||||
GST_V4L2_CHECK_OPEN(GST_V4L2ELEMENT(v4l2src));
|
||||
GST_V4L2_CHECK_ACTIVE(GST_V4L2ELEMENT(v4l2src));
|
||||
|
||||
/* unmap the buffer */
|
||||
for (n=0;n<v4l2src->breq.count;n++) {
|
||||
if (!GST_V4L2ELEMENT(v4l2src)->buffer[n])
|
||||
break;
|
||||
munmap(GST_V4L2ELEMENT(v4l2src)->buffer[n], v4l2src->format.fmt.pix.sizeimage);
|
||||
GST_V4L2ELEMENT(v4l2src)->buffer[n] = NULL;
|
||||
}
|
||||
g_free(GST_V4L2ELEMENT(v4l2src)->buffer);
|
||||
GST_V4L2ELEMENT(v4l2src)->buffer = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_get_fourcc_list():
|
||||
* create a list of all available fourccs
|
||||
* return value: the list
|
||||
******************************************************/
|
||||
|
||||
GList *
|
||||
gst_v4l2src_get_fourcc_list (GstV4l2Src *v4l2src)
|
||||
{
|
||||
GList *list = NULL;
|
||||
GstV4l2Element *v4l2element = GST_V4L2ELEMENT(v4l2src);
|
||||
gint n;
|
||||
|
||||
for (n=0;n<g_list_length(v4l2element->formats);n++) {
|
||||
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2element->formats, n);
|
||||
guint32 print_format = GUINT32_FROM_LE(fmt->pixelformat);
|
||||
gchar *print_format_str = (gchar *) &print_format;
|
||||
|
||||
list = g_list_append(list, g_strndup(print_format_str, 4));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_get_format_list():
|
||||
* create a list of all available capture formats
|
||||
* return value: the list
|
||||
******************************************************/
|
||||
|
||||
GList *
|
||||
gst_v4l2src_get_format_list (GstV4l2Src *v4l2src)
|
||||
{
|
||||
GList *list = NULL;
|
||||
GstV4l2Element *v4l2element = GST_V4L2ELEMENT(v4l2src);
|
||||
gint n;
|
||||
|
||||
for (n=0;n<g_list_length(v4l2element->formats);n++) {
|
||||
struct v4l2_fmtdesc *fmt = (struct v4l2_fmtdesc *) g_list_nth_data(v4l2element->formats, n);
|
||||
|
||||
list = g_list_append(list, g_strdup(fmt->description));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
45
sys/v4l2/v4l2src_calls.h
Normal file
45
sys/v4l2/v4l2src_calls.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* G-Streamer Video4linux2 video-capture plugin - system calls
|
||||
* Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
*
|
||||
* 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_SRC_CALLS_H__
|
||||
#define __V4L2_SRC_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);
|
||||
gboolean gst_v4l2src_capture_init (GstV4l2Src *v4l2src);
|
||||
gboolean gst_v4l2src_capture_start (GstV4l2Src *v4l2src);
|
||||
gboolean gst_v4l2src_grab_frame (GstV4l2Src *v4l2src,
|
||||
gint *num);
|
||||
gboolean gst_v4l2src_requeue_frame (GstV4l2Src *v4l2src,
|
||||
gint num);
|
||||
gboolean gst_v4l2src_capture_stop (GstV4l2Src *v4l2src);
|
||||
gboolean gst_v4l2src_capture_deinit (GstV4l2Src *v4l2src);
|
||||
|
||||
GList * gst_v4l2src_get_fourcc_list (GstV4l2Src *v4l2src);
|
||||
GList * gst_v4l2src_get_format_list (GstV4l2Src *v4l2src);
|
||||
|
||||
|
||||
#endif /* __V4L2_SRC_CALLS_H__ */
|
Loading…
Reference in a new issue