mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
sys/v4l2/: Fix pass at code cleanups, move errors cases out of the normal flow for additional code clarity.
Original commit message from CVS: * sys/v4l2/gstv4l2object.c: (gst_v4l2_class_probe_devices), (gst_v4l2_probe_needs_probe), (gst_v4l2_object_install_properties_helper), (gst_v4l2_object_new), (gst_v4l2_object_destroy), (gst_v4l2_object_set_property_helper), (gst_v4l2_object_get_property_helper), (gst_v4l2_set_defaults), (gst_v4l2_object_start), (gst_v4l2_object_stop): * sys/v4l2/gstv4l2object.h: * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), (gst_v4l2src_init), (gst_v4l2src_dispose), (gst_v4l2src_set_property), (gst_v4l2src_get_property), (gst_v4l2src_fixate), (gst_v4l2src_get_caps), (gst_v4l2src_set_caps), (gst_v4l2src_get_read), (gst_v4l2src_get_mmap), (gst_v4l2src_create): * sys/v4l2/v4l2_calls.c: (gst_v4l2_get_capabilities), (gst_v4l2_open), (gst_v4l2_close), (gst_v4l2_get_norm), (gst_v4l2_set_norm), (gst_v4l2_get_frequency), (gst_v4l2_set_frequency), (gst_v4l2_signal_strength), (gst_v4l2_get_attribute), (gst_v4l2_set_attribute), (gst_v4l2_get_input), (gst_v4l2_set_input): * sys/v4l2/v4l2src_calls.c: (gst_v4l2src_fill_format_list), (gst_v4l2src_queue_frame), (gst_v4l2src_grab_frame), (gst_v4l2src_get_capture), (gst_v4l2src_set_capture), (gst_v4l2src_capture_init), (gst_v4l2src_capture_start), (gst_v4l2src_capture_stop), (gst_v4l2src_capture_deinit), (gst_v4l2src_get_size_limits), (gst_v4l2src_set_fps), (gst_v4l2src_get_fps), (gst_v4l2src_buffer_finalize), (gst_v4l2src_buffer_new): Fix pass at code cleanups, move errors cases out of the normal flow for additional code clarity.
This commit is contained in:
parent
9cadd004a8
commit
d9db447dfa
5 changed files with 512 additions and 355 deletions
|
@ -110,7 +110,6 @@ gst_v4l2_class_probe_devices (GstElementClass * klass, gboolean check,
|
|||
g_free (device);
|
||||
}
|
||||
}
|
||||
|
||||
init = TRUE;
|
||||
}
|
||||
|
||||
|
@ -150,9 +149,7 @@ gst_v4l2_probe_needs_probe (GstPropertyProbe * probe,
|
|||
G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static GValueArray *
|
||||
|
@ -254,19 +251,18 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class)
|
|||
GST_TYPE_V4L2_DEVICE_FLAGS, 0, G_PARAM_READABLE));
|
||||
g_object_class_install_property
|
||||
(gobject_class, PROP_STD,
|
||||
g_param_spec_string ("std", "std",
|
||||
"standard (norm) to use", NULL, G_PARAM_READWRITE));
|
||||
g_param_spec_string ("std", "Std",
|
||||
"Standard (norm) to use", NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property
|
||||
(gobject_class, PROP_INPUT,
|
||||
g_param_spec_string ("input",
|
||||
"input",
|
||||
"input/output (channel) to switch to", NULL, G_PARAM_READWRITE));
|
||||
"Input",
|
||||
"Input/output (channel) to switch to", NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property
|
||||
(gobject_class, PROP_FREQUENCY,
|
||||
g_param_spec_ulong ("frequency",
|
||||
"frequency",
|
||||
"frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
|
||||
|
||||
"Frequency",
|
||||
"Frequency to tune to (in Hz)", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
GstV4l2Object *
|
||||
|
@ -275,13 +271,11 @@ gst_v4l2_object_new (GstElement * element,
|
|||
GstV4l2SetInOutFunction set_in_out_func,
|
||||
GstV4l2UpdateFpsFunction update_fps_func)
|
||||
{
|
||||
|
||||
GstV4l2Object *v4l2object;
|
||||
|
||||
/*
|
||||
* some default values
|
||||
*/
|
||||
|
||||
v4l2object = g_new0 (GstV4l2Object, 1);
|
||||
|
||||
v4l2object->element = element;
|
||||
|
@ -300,16 +294,12 @@ gst_v4l2_object_new (GstElement * element,
|
|||
v4l2object->xwindow_id = 0;
|
||||
|
||||
return v4l2object;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
|
||||
{
|
||||
|
||||
if (*v4l2object) {
|
||||
|
||||
if ((*v4l2object)->videodev) {
|
||||
g_free ((*v4l2object)->videodev);
|
||||
(*v4l2object)->videodev = NULL;
|
||||
|
@ -317,29 +307,24 @@ gst_v4l2_object_destroy (GstV4l2Object ** v4l2object)
|
|||
|
||||
g_free (*v4l2object);
|
||||
*v4l2object = NULL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICE:
|
||||
if (v4l2object->videodev)
|
||||
g_free (v4l2object->videodev);
|
||||
v4l2object->videodev = g_strdup (g_value_get_string (value));
|
||||
v4l2object->videodev = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_STD:
|
||||
if (GST_V4L2_IS_OPEN (v4l2object)) {
|
||||
GstTuner *tuner = GST_TUNER (v4l2object->element);
|
||||
GstTunerNorm *norm = gst_tuner_find_norm_by_name (tuner,
|
||||
(gchar *)
|
||||
g_value_get_string (value));
|
||||
(gchar *) g_value_get_string (value));
|
||||
|
||||
if (norm) {
|
||||
/* like gst_tuner_set_norm (tuner, norm)
|
||||
|
@ -355,8 +340,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
|
|||
if (GST_V4L2_IS_OPEN (v4l2object)) {
|
||||
GstTuner *tuner = GST_TUNER (v4l2object->element);
|
||||
GstTunerChannel *channel = gst_tuner_find_channel_by_name (tuner,
|
||||
(gchar *)
|
||||
g_value_get_string (value));
|
||||
(gchar *) g_value_get_string (value));
|
||||
|
||||
if (channel) {
|
||||
/* like gst_tuner_set_channel (tuner, channel)
|
||||
|
@ -389,9 +373,7 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
|
|||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -405,15 +387,15 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
|
|||
break;
|
||||
case PROP_DEVICE_NAME:
|
||||
{
|
||||
gchar *new = NULL;
|
||||
const guchar *new = NULL;
|
||||
|
||||
if (GST_V4L2_IS_OPEN (v4l2object)) {
|
||||
new = (gchar *) v4l2object->vcap.card;
|
||||
new = v4l2object->vcap.card;
|
||||
} else if (gst_v4l2_open (v4l2object)) {
|
||||
new = (gchar *) v4l2object->vcap.card;
|
||||
new = v4l2object->vcap.card;
|
||||
gst_v4l2_close (v4l2object);
|
||||
}
|
||||
g_value_set_string (value, new);
|
||||
g_value_set_string (value, (gchar *) new);
|
||||
break;
|
||||
}
|
||||
case PROP_FLAGS:
|
||||
|
@ -425,6 +407,8 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
|
|||
(V4L2_CAP_VIDEO_CAPTURE |
|
||||
V4L2_CAP_VIDEO_OUTPUT |
|
||||
V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_TUNER | V4L2_CAP_AUDIO);
|
||||
/* FIXME. if there is something with AUDIO we add something with
|
||||
* video? this needs some explanation.. */
|
||||
if (v4l2object->vcap.capabilities & V4L2_CAP_AUDIO)
|
||||
flags |= V4L2_FBUF_CAP_CHROMAKEY;
|
||||
}
|
||||
|
@ -444,9 +428,7 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
|
|||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -464,6 +446,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
|
|||
norm =
|
||||
GST_TUNER_NORM (gst_tuner_get_norm (GST_TUNER (v4l2object->element)));
|
||||
if (norm) {
|
||||
/* FIXME, free old? */
|
||||
v4l2object->std = g_strdup (norm->label);
|
||||
gst_tuner_norm_changed (tuner, norm);
|
||||
g_object_notify (G_OBJECT (v4l2object->element), "std");
|
||||
|
@ -478,6 +461,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
|
|||
channel =
|
||||
GST_TUNER_CHANNEL (gst_tuner_get_channel (GST_TUNER (v4l2object->
|
||||
element)));
|
||||
/* FIXME, free old? */
|
||||
v4l2object->input = g_strdup (channel->label);
|
||||
gst_tuner_channel_changed (tuner, channel);
|
||||
g_object_notify (G_OBJECT (v4l2object->element), "input");
|
||||
|
@ -498,7 +482,6 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gst_v4l2_object_start (GstV4l2Object * v4l2object)
|
||||
{
|
||||
|
@ -507,7 +490,6 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
|
|||
else
|
||||
return FALSE;
|
||||
|
||||
|
||||
#ifdef HAVE_XVIDEO
|
||||
gst_v4l2_xoverlay_start (v4l2object);
|
||||
#endif
|
||||
|
@ -518,7 +500,6 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
|
|||
gboolean
|
||||
gst_v4l2_object_stop (GstV4l2Object * v4l2object)
|
||||
{
|
||||
|
||||
#ifdef HAVE_XVIDEO
|
||||
gst_v4l2_xoverlay_stop (v4l2object);
|
||||
#endif
|
||||
|
|
|
@ -99,21 +99,17 @@ struct _GstV4l2Object {
|
|||
GstV4l2GetInOutFunction get_in_out_func;
|
||||
GstV4l2SetInOutFunction set_in_out_func;
|
||||
GstV4l2UpdateFpsFunction update_fps_func;
|
||||
|
||||
};
|
||||
|
||||
struct _GstV4l2ObjectClassHelper {
|
||||
/* probed devices */
|
||||
GList *devices;
|
||||
|
||||
};
|
||||
|
||||
|
||||
GType gst_v4l2_object_get_type(void);
|
||||
|
||||
|
||||
#define V4L2_STD_OBJECT_PROPS \
|
||||
PROP_DEVICE, \
|
||||
PROP_DEVICE, \
|
||||
PROP_DEVICE_NAME, \
|
||||
PROP_FLAGS, \
|
||||
PROP_STD, \
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
* <programlisting>
|
||||
* gst-launch v4l2src use-fixed-fps=true ! xvimagesink
|
||||
* </programlisting>
|
||||
* This exemple should be used to capture from web-cams
|
||||
* This example should be used to capture from web-cams
|
||||
* </para>
|
||||
* </refsect2>
|
||||
*/
|
||||
|
@ -130,7 +130,6 @@ static const guint32 gst_v4l2_formats[] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
#define GST_V4L2_FORMAT_COUNT (G_N_ELEMENTS (gst_v4l2_formats))
|
||||
|
||||
GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
|
||||
|
@ -297,13 +296,11 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
|
|||
pushsrc_class->create = gst_v4l2src_create;
|
||||
|
||||
gobject_class->dispose = gst_v4l2src_dispose;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
|
||||
{
|
||||
|
||||
v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
|
||||
gst_v4l2_get_input, gst_v4l2_set_input, gst_v4l2src_update_fps);
|
||||
|
||||
|
@ -335,8 +332,7 @@ gst_v4l2src_dispose (GObject * object)
|
|||
gst_v4l2src_clear_format_list (v4l2src);
|
||||
}
|
||||
|
||||
if (((GObjectClass *) parent_class)->dispose)
|
||||
((GObjectClass *) parent_class)->dispose (object);
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
||||
|
@ -349,24 +345,19 @@ gst_v4l2src_set_property (GObject * object,
|
|||
g_return_if_fail (GST_IS_V4L2SRC (object));
|
||||
v4l2src = GST_V4L2SRC (object);
|
||||
|
||||
|
||||
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
|
||||
prop_id, value, pspec)) {
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_USE_FIXED_FPS:
|
||||
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
|
||||
v4l2src->use_fixed_fps = g_value_get_boolean (value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -381,18 +372,15 @@ gst_v4l2src_get_property (GObject * object,
|
|||
|
||||
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
|
||||
prop_id, value, pspec)) {
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_USE_FIXED_FPS:
|
||||
g_value_set_boolean (value, v4l2src->use_fixed_fps);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -412,6 +400,8 @@ gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)
|
|||
structure = gst_caps_get_structure (caps, i);
|
||||
const GValue *v;
|
||||
|
||||
/* FIXME such sizes? we usually fixate to something in the 320x200
|
||||
* range... */
|
||||
gst_structure_fixate_field_nearest_int (structure, "width", 4096);
|
||||
gst_structure_fixate_field_nearest_int (structure, "height", 4096);
|
||||
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
|
||||
|
@ -755,7 +745,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
|
|||
&min_w, &max_w, &min_h, &max_h)) {
|
||||
continue;
|
||||
}
|
||||
/* template */
|
||||
/* template, FIXME, why limit if the device reported correct results. */
|
||||
min_w = CLAMP (min_w, 1, 4096);
|
||||
min_h = CLAMP (min_h, 1, 4096);
|
||||
max_w = CLAMP (max_w, min_w, 4096);
|
||||
|
@ -769,11 +759,11 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
|
|||
"width", GST_TYPE_INT_RANGE, min_w, max_w,
|
||||
"height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
|
||||
|
||||
/* FIXME, why random range? */
|
||||
gst_structure_set (structure, "framerate", GST_TYPE_FRACTION_RANGE,
|
||||
1, 1, 100, 1, NULL);
|
||||
|
||||
gst_caps_append_structure (caps, structure);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -860,14 +850,13 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
|
|||
"framerate", GST_TYPE_FRACTION, v4l2src->fps_n, v4l2src->fps_d, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* start and stop are not symmetric -- start will open the device, but not start
|
||||
capture. it's setcaps that will start capture, which is called via basesrc's
|
||||
negotiate method. stop will both stop capture and close the device.
|
||||
*/
|
||||
* capture. it's setcaps that will start capture, which is called via basesrc's
|
||||
* negotiate method. stop will both stop capture and close the device.
|
||||
*/
|
||||
static gboolean
|
||||
gst_v4l2src_start (GstBaseSrc * src)
|
||||
{
|
||||
|
@ -920,37 +909,42 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
|||
} else if (amount == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
|
||||
(_("error read()ing %d bytes on device %s"),
|
||||
buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
gst_buffer_unref (*buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
|
||||
("error read()ing a buffer on device %s: got only %d bytes instead of expected %d",
|
||||
v4l2src->v4l2object->videodev, amount, buffersize));
|
||||
gst_buffer_unref (*buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
} else
|
||||
goto read_error;
|
||||
} else
|
||||
goto short_read;
|
||||
} while (TRUE);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* ERRORS */
|
||||
read_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC,
|
||||
(_("error read()ing %d bytes on device %s"),
|
||||
buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
gst_buffer_unref (*buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
short_read:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SYNC, (NULL),
|
||||
("error read()ing a buffer on device %s: got only %d bytes instead of expected %d",
|
||||
v4l2src->v4l2object->videodev, amount, buffersize));
|
||||
gst_buffer_unref (*buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static GstFlowReturn
|
||||
gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
||||
{
|
||||
gint i, num = -1;
|
||||
gint i, num;
|
||||
|
||||
|
||||
/* grab a frame from the device */
|
||||
/* grab a frame from the device, post an error */
|
||||
num = gst_v4l2src_grab_frame (v4l2src);
|
||||
if (num == -1)
|
||||
return GST_FLOW_ERROR;
|
||||
goto grab_failed;
|
||||
|
||||
i = v4l2src->format.fmt.pix.sizeimage;
|
||||
|
||||
|
@ -958,23 +952,37 @@ gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
|||
to avoid framedrops and deadlocks because of stupid elements */
|
||||
if (g_atomic_int_get (&v4l2src->pool->refcount) == v4l2src->breq.count) {
|
||||
GST_LOG_OBJECT (v4l2src, "using memcpy'd buffer");
|
||||
|
||||
*buf = gst_v4l2src_buffer_new (v4l2src, i, NULL, NULL);
|
||||
memcpy (GST_BUFFER_DATA (*buf), v4l2src->pool->buffers[num].start, i);
|
||||
if (!gst_v4l2src_queue_frame (v4l2src, num)) {
|
||||
gst_buffer_unref (*buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
/* posts an error message if something went wrong */
|
||||
if (!gst_v4l2src_queue_frame (v4l2src, num))
|
||||
goto queue_failed;
|
||||
} else {
|
||||
GST_LOG_OBJECT (v4l2src, "using mmap'd buffer");
|
||||
*buf =
|
||||
gst_v4l2src_buffer_new (v4l2src, i, v4l2src->pool->buffers[num].start,
|
||||
&v4l2src->pool->buffers[num]);
|
||||
|
||||
/* no need to be careful here, both are > 0, because the element uses them */
|
||||
g_atomic_int_inc (&v4l2src->pool->buffers[num].refcount);
|
||||
g_atomic_int_inc (&v4l2src->pool->refcount);
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
||||
/* ERRORS */
|
||||
grab_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to grab a frame");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
queue_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to queue frame");
|
||||
gst_buffer_unref (*buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -983,17 +991,22 @@ gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
|
|||
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
||||
GstFlowReturn ret;
|
||||
|
||||
if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("could not get frame rate for %s, try to set use-fixed-fps property to false"), v4l2src->v4l2object->videodev), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (v4l2src->use_fixed_fps && v4l2src->fps_n == 0)
|
||||
goto no_framerate;
|
||||
|
||||
if (v4l2src->breq.memory == V4L2_MEMORY_MMAP) {
|
||||
ret = gst_v4l2src_get_mmap (v4l2src, buf);
|
||||
} else {
|
||||
ret = gst_v4l2src_get_read (v4l2src, buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERRORS */
|
||||
no_framerate:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("could not get frame rate for %s, try to set use-fixed-fps "
|
||||
"property to false"), v4l2src->v4l2object->videodev), (NULL));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,23 +48,28 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
|
|||
* get the device's capturing capabilities
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "getting capabilities");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &(v4l2object->vcap)) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
|
||||
goto cap_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
cap_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Error getting capabilities for device '%s':"
|
||||
" It isn't a v4l2 driver. Check if it is a v4l1 driver"),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,7 +78,6 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
|
|||
* fill/empty the lists of enumerations
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
|
||||
{
|
||||
|
@ -354,7 +358,6 @@ gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
|
|||
* open the video device (v4l2object->videodev)
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_open (GstV4l2Object * v4l2object)
|
||||
{
|
||||
|
@ -362,6 +365,7 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
|||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
|
||||
v4l2object->videodev);
|
||||
|
||||
GST_V4L2_CHECK_NOT_OPEN (v4l2object);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
|
||||
|
||||
|
@ -370,46 +374,29 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
|||
v4l2object->videodev = g_strdup ("/dev/video");
|
||||
|
||||
/* check if it is a device */
|
||||
if (-1 == stat (v4l2object->videodev, &st)) {
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
|
||||
(_("Cannot identify device '%s'"), v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto error;
|
||||
}
|
||||
if (!S_ISCHR (st.st_mode)) {
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
|
||||
(_("This isn't a device '%s'"), v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto error;
|
||||
}
|
||||
if (stat (v4l2object->videodev, &st) == -1)
|
||||
goto stat_failed;
|
||||
|
||||
if (!S_ISCHR (st.st_mode))
|
||||
goto no_device;
|
||||
|
||||
/* open the device */
|
||||
v4l2object->video_fd =
|
||||
open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object)) {
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
|
||||
(_("Could not open device \"%s\" for reading and writing."),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
goto error;
|
||||
}
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
goto not_open;
|
||||
|
||||
/* get capabilities */
|
||||
if (!gst_v4l2_get_capabilities (v4l2object)) {
|
||||
/* get capabilities, error will be posted */
|
||||
if (!gst_v4l2_get_capabilities (v4l2object))
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* do we need to be a capture device? */
|
||||
if (GST_IS_V4L2SRC (v4l2object) &&
|
||||
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
|
||||
(_("Device \"%s\" is not a capture device."),
|
||||
v4l2object->videodev),
|
||||
("Capabilities: 0x%x", v4l2object->vcap.capabilities));
|
||||
goto error;
|
||||
}
|
||||
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
goto not_capture;
|
||||
|
||||
/* create enumerations */
|
||||
/* create enumerations, posts errors. */
|
||||
if (!gst_v4l2_fill_lists (v4l2object))
|
||||
goto error;
|
||||
|
||||
|
@ -419,16 +406,48 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
|||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (GST_V4L2_IS_OPEN (v4l2object)) {
|
||||
/* close device */
|
||||
close (v4l2object->video_fd);
|
||||
v4l2object->video_fd = -1;
|
||||
/* ERRORS */
|
||||
stat_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
|
||||
(_("Cannot identify device '%s'"), v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto error;
|
||||
}
|
||||
/* empty lists */
|
||||
gst_v4l2_empty_lists (v4l2object);
|
||||
no_device:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
|
||||
(_("This isn't a device '%s'"), v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto error;
|
||||
}
|
||||
not_open:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ_WRITE,
|
||||
(_("Could not open device \"%s\" for reading and writing."),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
goto error;
|
||||
}
|
||||
not_capture:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
|
||||
(_("Device \"%s\" is not a capture device."),
|
||||
v4l2object->videodev),
|
||||
("Capabilities: 0x%x", v4l2object->vcap.capabilities));
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
{
|
||||
if (GST_V4L2_IS_OPEN (v4l2object)) {
|
||||
/* close device */
|
||||
close (v4l2object->video_fd);
|
||||
v4l2object->video_fd = -1;
|
||||
}
|
||||
/* empty lists */
|
||||
gst_v4l2_empty_lists (v4l2object);
|
||||
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -437,12 +456,12 @@ error:
|
|||
* close the video device (v4l2object->video_fd)
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_close (GstV4l2Object * v4l2object)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
|
||||
v4l2object->videodev);
|
||||
|
||||
GST_V4L2_CHECK_OPEN (v4l2object);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
|
||||
|
||||
|
@ -462,24 +481,27 @@ gst_v4l2_close (GstV4l2Object * v4l2object)
|
|||
* Get the norm of the current device
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_STD, norm) < 0)
|
||||
goto std_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
std_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to get the current norm for device %s"),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -488,22 +510,27 @@ gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
|
|||
* Set the norm of the current device
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to %llx", norm);
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_STD, &norm) < 0)
|
||||
goto std_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
std_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to set norm 0x%llx for device %s: %s"),
|
||||
norm, v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
|
@ -511,7 +538,6 @@ gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
|
|||
* get the current frequency
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
|
||||
gint tunernum, gulong * frequency)
|
||||
|
@ -520,22 +546,28 @@ gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
|
|||
GstTunerChannel *channel;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
channel = gst_tuner_get_channel (GST_TUNER (v4l2object->element));
|
||||
|
||||
freq.tuner = tunernum;
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq) < 0)
|
||||
goto freq_failed;
|
||||
|
||||
*frequency = freq.frequency * channel->freq_multiplicator;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
freq_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to get current tuner frequency for device %s"),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*frequency = freq.frequency * channel->freq_multiplicator;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -544,7 +576,6 @@ gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
|
|||
* set frequency
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
|
||||
gint tunernum, gulong frequency)
|
||||
|
@ -554,6 +585,7 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
|
|||
|
||||
GST_DEBUG_OBJECT (v4l2object->element,
|
||||
"setting current tuner frequency to %lu", frequency);
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
|
@ -564,23 +596,26 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
|
|||
ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
|
||||
freq.frequency = frequency / channel->freq_multiplicator;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
|
||||
goto freq_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
freq_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to set current tuner frequency for device %s to %lu"),
|
||||
v4l2object->videodev, frequency), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_signal_strength():
|
||||
* get the strength of the signal on the current input
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
|
||||
gint tunernum, gulong * signal_strength)
|
||||
|
@ -588,53 +623,62 @@ gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
|
|||
struct v4l2_tuner tuner;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
tuner.index = tunernum;
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_TUNER, &tuner) < 0)
|
||||
goto tuner_failed;
|
||||
|
||||
*signal_strength = tuner.signal;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
tuner_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to get signal strength for device %s"),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*signal_strength = tuner.signal;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2_get_attribute():
|
||||
* try to get the value of one specific attribute
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
|
||||
int attribute_num, int *value)
|
||||
{
|
||||
struct v4l2_control control;
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
|
||||
attribute_num);
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
control.id = attribute_num;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0)
|
||||
goto ctrl_failed;
|
||||
|
||||
*value = control.value;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
ctrl_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to get value for control %d on device %s"),
|
||||
attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*value = control.value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -643,30 +687,33 @@ gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
|
|||
* try to set the value of one specific attribute
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
|
||||
int attribute_num, const int value)
|
||||
{
|
||||
struct v4l2_control control;
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
|
||||
attribute_num, value);
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
control.id = attribute_num;
|
||||
control.value = value;
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0)
|
||||
goto ctrl_failed;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) {
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
ctrl_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to set value %d for control %d on device %s"),
|
||||
value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -675,36 +722,48 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
|
|||
gint n;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "trying to get input");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_INPUT, &n) < 0)
|
||||
goto input_failed;
|
||||
|
||||
*input = n;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
input_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to get current input on device %s"),
|
||||
v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*input = n;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_INPUT, &input) < 0)
|
||||
goto input_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
input_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Failed to set input %d on device %s"),
|
||||
input, v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug);
|
|||
|
||||
/* On some systems MAP_FAILED seems to be missing */
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ( (caddr_t) -1 )
|
||||
#define MAP_FAILED ((caddr_t) -1)
|
||||
#endif
|
||||
|
||||
/******************************************************
|
||||
|
@ -61,7 +61,6 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug);
|
|||
* create list of supported capture formats
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
|
||||
{
|
||||
|
@ -79,29 +78,32 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)
|
|||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
|
||||
if (errno == EINVAL) {
|
||||
break; /* end of enumeration */
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to get number %d in pixelformat enumeration for %s: %s"),
|
||||
n, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
g_free (format);
|
||||
return FALSE;
|
||||
}
|
||||
} else
|
||||
goto failed;
|
||||
}
|
||||
GST_LOG_OBJECT (v4l2src, "got format %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (format->pixelformat));
|
||||
|
||||
v4l2src->formats = g_slist_prepend (v4l2src->formats, format);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ERRORS */
|
||||
failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to get number %d in pixelformat enumeration for %s: %s"),
|
||||
n, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
g_free (format);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_clear_format_list():
|
||||
* free list of supported capture formats
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
|
||||
{
|
||||
|
@ -118,14 +120,20 @@ gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src)
|
|||
* queue a frame for capturing
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
|
||||
{
|
||||
GST_LOG_OBJECT (v4l2src, "queueing frame %u", i);
|
||||
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF,
|
||||
&v4l2src->pool->buffers[i].buffer) < 0) {
|
||||
&v4l2src->pool->buffers[i].buffer) < 0)
|
||||
goto failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, WRITE,
|
||||
(_("Could not write to device '%s'."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
|
@ -133,17 +141,13 @@ gst_v4l2src_queue_frame (GstV4l2Src * v4l2src, guint i)
|
|||
v4l2src->v4l2object->videodev, g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_grab_frame ():
|
||||
* grab a frame for capturing
|
||||
* return value: TRUE on success, FALSE on error
|
||||
* return value: The captured frame number or -1 on error.
|
||||
******************************************************/
|
||||
|
||||
gint
|
||||
gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
|
||||
{
|
||||
|
@ -163,17 +167,9 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
|
|||
v4l2src->v4l2object->videodev);
|
||||
break;
|
||||
case EINVAL:
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
|
||||
(_("Failed trying to get frames from device %s"),
|
||||
v4l2src->v4l2object->videodev),
|
||||
(_("The buffer type is not supported, or the index is out of bounds," " or no buffers have been allocated yet, or the userptr" " or length are invalid. device %s"), v4l2src->v4l2object->videodev));
|
||||
break;
|
||||
goto einval;
|
||||
case ENOMEM:
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
|
||||
(_("Failed trying to get frames from device %s. Not enough memory"),
|
||||
v4l2src->v4l2object->videodev),
|
||||
(_("isufficient memory to enqueue a user pointer buffer. device %s"), v4l2src->v4l2object->videodev));
|
||||
break;
|
||||
goto nomem;
|
||||
case EIO:
|
||||
GST_DEBUG_OBJECT (v4l2src,
|
||||
"VIDIOC_DQBUF failed due to an internal error."
|
||||
|
@ -195,19 +191,49 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
|
|||
}
|
||||
|
||||
if (--trials == -1) {
|
||||
return -1;
|
||||
goto too_many_trials;
|
||||
} else {
|
||||
ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QBUF, &buffer);
|
||||
memset (&buffer, 0x00, sizeof (buffer));
|
||||
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buffer.memory = v4l2src->breq.memory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (v4l2src, "grabbed frame %d", buffer.index);
|
||||
|
||||
return buffer.index;
|
||||
|
||||
/* ERRORS */
|
||||
einval:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
|
||||
(_("Failed trying to get frames from device %s"),
|
||||
v4l2src->v4l2object->videodev),
|
||||
(_("The buffer type is not supported, or the index is out of bounds,"
|
||||
" or no buffers have been allocated yet, or the userptr"
|
||||
" or length are invalid. device %s"),
|
||||
v4l2src->v4l2object->videodev));
|
||||
return -1;
|
||||
}
|
||||
nomem:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
|
||||
(_("Failed trying to get frames from device %s. Not enough memory"),
|
||||
v4l2src->v4l2object->videodev),
|
||||
(_("insufficient memory to enqueue a user pointer buffer. device %s"),
|
||||
v4l2src->v4l2object->videodev));
|
||||
return -1;
|
||||
}
|
||||
too_many_trials:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, FAILED,
|
||||
(_("Failed trying to get frames from device %s"),
|
||||
v4l2src->v4l2object->videodev),
|
||||
(_("Failed after 100 tries. device %s"),
|
||||
v4l2src->v4l2object->videodev));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -216,7 +242,6 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src)
|
|||
* get capture parameters
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
|
||||
{
|
||||
|
@ -226,14 +251,20 @@ gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
|
|||
|
||||
memset (&v4l2src->format, 0, sizeof (struct v4l2_format));
|
||||
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0) {
|
||||
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_FMT, &v4l2src->format) < 0)
|
||||
goto fmt_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
fmt_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to get pixelformat for device %s"),
|
||||
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -242,13 +273,11 @@ gst_v4l2src_get_capture (GstV4l2Src * v4l2src)
|
|||
* set capture parameters
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
|
||||
struct v4l2_fmtdesc * fmt, gint * width, gint * height,
|
||||
guint * fps_n, guint * fps_d)
|
||||
{
|
||||
|
||||
guint new_fps_n = *fps_n;
|
||||
guint new_fps_d = *fps_d;
|
||||
|
||||
|
@ -258,9 +287,9 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
|
|||
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
if (!gst_v4l2src_get_capture (v4l2src)) {
|
||||
/* error was posted */
|
||||
if (!gst_v4l2src_get_capture (v4l2src))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
v4l2src->format.fmt.pix.width = *width;
|
||||
v4l2src->format.fmt.pix.height = *height;
|
||||
|
@ -268,13 +297,8 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
|
|||
v4l2src->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
v4l2src->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
|
||||
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto fail;
|
||||
}
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_FMT, &v4l2src->format) < 0)
|
||||
goto fmt_failed;
|
||||
|
||||
if (*width != v4l2src->format.fmt.pix.width ||
|
||||
*height != v4l2src->format.fmt.pix.height) {
|
||||
|
@ -283,18 +307,12 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
|
|||
v4l2src->format.fmt.pix.height, fmt->description);
|
||||
}
|
||||
|
||||
/* update internal info */
|
||||
if (!gst_v4l2src_get_capture (v4l2src)) {
|
||||
/* update internal info, posted error */
|
||||
if (!gst_v4l2src_get_capture (v4l2src))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fmt->pixelformat != v4l2src->format.fmt.pix.pixelformat) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
|
||||
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto fail;
|
||||
}
|
||||
if (fmt->pixelformat != v4l2src->format.fmt.pix.pixelformat)
|
||||
goto pixfmt_failed;
|
||||
|
||||
if (*fps_n) {
|
||||
if (gst_v4l2src_set_fps (v4l2src, &new_fps_n, &new_fps_d)) {
|
||||
|
@ -313,30 +331,45 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
*width = v4l2src->format.fmt.pix.width;
|
||||
*height = v4l2src->format.fmt.pix.height;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
fmt_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
|
||||
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
pixfmt_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, SETTINGS,
|
||||
(_("failed to set pixelformat to %s @ %dx%d for device %s: %s"),
|
||||
fmt->description, *width, *height, v4l2src->v4l2object->videodev),
|
||||
GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
fail:
|
||||
|
||||
return FALSE;
|
||||
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_init():
|
||||
* initialize the capture system
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
||||
{
|
||||
gint n;
|
||||
guint buffers;
|
||||
GstV4l2Buffer *buffer;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2src, "initting the capture system");
|
||||
|
||||
|
@ -345,36 +378,25 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
|||
|
||||
/* request buffer info */
|
||||
buffers = v4l2src->breq.count;
|
||||
if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS) {
|
||||
|
||||
if (v4l2src->breq.count > GST_V4L2_MAX_BUFFERS)
|
||||
v4l2src->breq.count = GST_V4L2_MAX_BUFFERS;
|
||||
}
|
||||
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
|
||||
else if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS)
|
||||
v4l2src->breq.count = GST_V4L2_MIN_BUFFERS;
|
||||
}
|
||||
|
||||
v4l2src->breq.type = v4l2src->format.type;
|
||||
if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
|
||||
v4l2src->breq.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_REQBUFS,
|
||||
&v4l2src->breq) < 0) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not get buffers from device '%s'."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("error requesting %d buffers. system error: %s",
|
||||
v4l2src->breq.count, g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
&v4l2src->breq) < 0)
|
||||
goto reqbufs_failed;
|
||||
|
||||
GST_LOG_OBJECT (v4l2src, "using default mmap method");
|
||||
} else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
|
||||
v4l2src->breq.memory = 0;
|
||||
GST_INFO_OBJECT (v4l2src, "using fallback read method");
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("the driver of device '%s' is broken."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("no supported read capability from %s",
|
||||
v4l2src->v4l2object->videodev));
|
||||
return FALSE;
|
||||
}
|
||||
} else
|
||||
goto broken_driver;
|
||||
|
||||
/* Determine the device's framerate */
|
||||
if (!gst_v4l2src_update_fps (v4l2src->v4l2object)) {
|
||||
|
@ -384,15 +406,9 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
|||
}
|
||||
|
||||
if (v4l2src->breq.memory > 0) {
|
||||
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not get enough buffers from device '%s'."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("we received %d, we want at least %d",
|
||||
v4l2src->breq.count, GST_V4L2_MIN_BUFFERS));
|
||||
v4l2src->breq.count = buffers;
|
||||
return FALSE;
|
||||
}
|
||||
if (v4l2src->breq.count < GST_V4L2_MIN_BUFFERS)
|
||||
goto no_buffers;
|
||||
|
||||
if (v4l2src->breq.count != buffers)
|
||||
g_object_notify (G_OBJECT (v4l2src), "num_buffers");
|
||||
|
||||
|
@ -412,7 +428,7 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
|||
v4l2src->pool->buffers = g_new0 (GstV4l2Buffer, v4l2src->breq.count);
|
||||
|
||||
for (n = 0; n < v4l2src->breq.count; n++) {
|
||||
GstV4l2Buffer *buffer = &v4l2src->pool->buffers[n];
|
||||
buffer = &v4l2src->pool->buffers[n];
|
||||
|
||||
gst_atomic_int_set (&buffer->refcount, 1);
|
||||
buffer->pool = v4l2src->pool;
|
||||
|
@ -422,28 +438,19 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
|||
buffer->buffer.memory = v4l2src->breq.memory;
|
||||
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_QUERYBUF,
|
||||
&buffer->buffer) < 0) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not get buffer properties of buffer %d"), n),
|
||||
GST_ERROR_SYSTEM);
|
||||
gst_v4l2src_capture_deinit (v4l2src);
|
||||
return FALSE;
|
||||
}
|
||||
&buffer->buffer) < 0)
|
||||
goto querybuf_failed;
|
||||
|
||||
buffer->start =
|
||||
mmap (0, buffer->buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
v4l2src->v4l2object->video_fd, buffer->buffer.m.offset);
|
||||
if (buffer->start == MAP_FAILED) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not mmap video buffer %d: %s"), n), GST_ERROR_SYSTEM);
|
||||
buffer->start = 0;
|
||||
gst_v4l2src_capture_deinit (v4l2src);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (buffer->start == MAP_FAILED)
|
||||
goto mmap_failed;
|
||||
|
||||
buffer->length = buffer->buffer.length;
|
||||
if (!gst_v4l2src_queue_frame (v4l2src, n)) {
|
||||
gst_v4l2src_capture_deinit (v4l2src);
|
||||
return FALSE;
|
||||
}
|
||||
if (!gst_v4l2src_queue_frame (v4l2src, n))
|
||||
goto queue_failed;
|
||||
}
|
||||
} else {
|
||||
GST_LOG_OBJECT (v4l2src, "no buffer pool used");
|
||||
|
@ -453,6 +460,57 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
|||
GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
reqbufs_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not get buffers from device '%s'."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("error requesting %d buffers. system error: %s",
|
||||
v4l2src->breq.count, g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
broken_driver:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("the driver of device '%s' is broken."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("no supported read capability from %s",
|
||||
v4l2src->v4l2object->videodev));
|
||||
return FALSE;
|
||||
}
|
||||
no_buffers:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not get enough buffers from device '%s'."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("we received %d, we want at least %d",
|
||||
v4l2src->breq.count, GST_V4L2_MIN_BUFFERS));
|
||||
v4l2src->breq.count = buffers;
|
||||
return FALSE;
|
||||
}
|
||||
querybuf_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not get buffer properties of buffer %d"), n),
|
||||
GST_ERROR_SYSTEM);
|
||||
gst_v4l2src_capture_deinit (v4l2src);
|
||||
return FALSE;
|
||||
}
|
||||
mmap_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not mmap video buffer %d: %s"), n), GST_ERROR_SYSTEM);
|
||||
gst_v4l2src_capture_deinit (v4l2src);
|
||||
buffer->start = 0;
|
||||
return FALSE;
|
||||
}
|
||||
queue_failed:
|
||||
{
|
||||
gst_v4l2src_capture_deinit (v4l2src);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -461,7 +519,6 @@ gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
|||
* start streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
|
||||
{
|
||||
|
@ -470,52 +527,49 @@ gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
|
|||
GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
|
||||
|
||||
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
|
||||
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
|
||||
/* gst_pad_renegotiate (v4l2src->srcpad); FIX: is it still required in 0.10 */
|
||||
}
|
||||
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
v4l2src->quit = FALSE;
|
||||
|
||||
if (v4l2src->breq.memory != 0) {
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMON, &type) < 0) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ,
|
||||
(_("Error starting streaming capture from device %s"),
|
||||
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMON, &type) < 0)
|
||||
goto streamon_failed;
|
||||
}
|
||||
|
||||
v4l2src->is_capturing = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ERRORS */
|
||||
streamon_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, OPEN_READ,
|
||||
(_("Error starting streaming capture from device %s"),
|
||||
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_stop():
|
||||
* stop streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
|
||||
{
|
||||
gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
|
||||
|
||||
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
|
||||
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
if (v4l2src->breq.memory != 0) {
|
||||
/* we actually need to sync on all queued buffers but not
|
||||
* on the non-queued ones */
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0) {
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE,
|
||||
(_("Error stopping streaming capture from device %s: %s"),
|
||||
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_STREAMOFF, &type) < 0)
|
||||
goto streamoff_failed;
|
||||
}
|
||||
|
||||
/* make an optional pending wait stop */
|
||||
|
@ -523,6 +577,15 @@ gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
|
|||
v4l2src->is_capturing = FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
streamoff_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, CLOSE,
|
||||
(_("Error stopping streaming capture from device %s: %s"),
|
||||
v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -570,7 +633,6 @@ gst_v4l2src_free_buffer (GstBuffer * buffer)
|
|||
* deinitialize the capture system
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
|
||||
{
|
||||
|
@ -608,20 +670,20 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
|
|||
*/
|
||||
if (try_reinit) {
|
||||
if (!gst_v4l2src_capture_start (v4l2src) ||
|
||||
!gst_v4l2src_capture_stop (v4l2src))
|
||||
!gst_v4l2src_capture_stop (v4l2src)) {
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed reinit device");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
|
||||
struct v4l2_fmtdesc * format,
|
||||
|
@ -642,6 +704,8 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
|
|||
fmt.fmt.pix.pixelformat = format->pixelformat;
|
||||
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to get min size: %s",
|
||||
g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -649,12 +713,15 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
|
|||
*min_w = fmt.fmt.pix.width;
|
||||
if (min_h)
|
||||
*min_h = fmt.fmt.pix.height;
|
||||
|
||||
GST_LOG_OBJECT (v4l2src,
|
||||
"got min size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||
|
||||
fmt.fmt.pix.width = 4096;
|
||||
fmt.fmt.pix.height = 4096;
|
||||
if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_TRY_FMT, &fmt) < 0) {
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to get max size: %s",
|
||||
g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -662,6 +729,7 @@ gst_v4l2src_get_size_limits (GstV4l2Src * v4l2src,
|
|||
*max_w = fmt.fmt.pix.width;
|
||||
if (max_h)
|
||||
*max_h = fmt.fmt.pix.height;
|
||||
|
||||
GST_LOG_OBJECT (v4l2src,
|
||||
"got max size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
|
||||
|
||||
|
@ -680,30 +748,50 @@ gst_v4l2src_update_fps (GstV4l2Object * v4l2object)
|
|||
gboolean
|
||||
gst_v4l2src_set_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
|
||||
{
|
||||
|
||||
GstV4l2Object *v4l2object = v4l2src->v4l2object;
|
||||
struct v4l2_streamparm stream;
|
||||
|
||||
GST_LOG_OBJECT (v4l2src, "setting fps %d, %d", *fps_n, *fps_d);
|
||||
|
||||
memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
|
||||
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) == 0 &&
|
||||
stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) < 0)
|
||||
goto gparm_failed;
|
||||
|
||||
stream.parm.capture.timeperframe.denominator = *fps_n;
|
||||
stream.parm.capture.timeperframe.numerator = *fps_d;
|
||||
if (!(stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME))
|
||||
goto no_timeperframe;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_PARM, &stream) == 0) {
|
||||
*fps_n = stream.parm.capture.timeperframe.denominator;
|
||||
*fps_d = stream.parm.capture.timeperframe.numerator;
|
||||
return TRUE;
|
||||
}
|
||||
stream.parm.capture.timeperframe.denominator = *fps_n;
|
||||
stream.parm.capture.timeperframe.numerator = *fps_d;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_S_PARM, &stream) < 0)
|
||||
goto sparm_failed;
|
||||
|
||||
*fps_n = stream.parm.capture.timeperframe.denominator;
|
||||
*fps_d = stream.parm.capture.timeperframe.numerator;
|
||||
|
||||
GST_LOG_OBJECT (v4l2src, "fps set to %d, %d", *fps_n, *fps_d);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
gparm_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
no_timeperframe:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME");
|
||||
return FALSE;
|
||||
}
|
||||
sparm_failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to set PARM: %s", g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
|
||||
{
|
||||
|
@ -711,6 +799,7 @@ gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
|
|||
v4l2_std_id std;
|
||||
struct v4l2_streamparm stream;
|
||||
const GList *item;
|
||||
gboolean found;
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
return FALSE;
|
||||
|
@ -718,36 +807,60 @@ gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d)
|
|||
/* Try to get the frame rate directly from the device using VIDIOC_G_PARM */
|
||||
memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
|
||||
stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) == 0 &&
|
||||
stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
|
||||
/* Note: V4L2 gives us the frame interval, we need the frame rate */
|
||||
*fps_n = stream.parm.capture.timeperframe.denominator;
|
||||
*fps_d = stream.parm.capture.timeperframe.numerator;
|
||||
GST_DEBUG_OBJECT (v4l2src,
|
||||
"frame rate returned by G_PARM: %d/%d fps", *fps_n, *fps_d);
|
||||
return TRUE;
|
||||
|
||||
if (ioctl (v4l2object->video_fd, VIDIOC_G_PARM, &stream) < 0) {
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno));
|
||||
goto try_stds;
|
||||
}
|
||||
|
||||
if (!(stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
|
||||
GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME");
|
||||
goto try_stds;
|
||||
}
|
||||
|
||||
/* Note: V4L2 gives us the frame interval, we need the frame rate */
|
||||
*fps_n = stream.parm.capture.timeperframe.denominator;
|
||||
*fps_d = stream.parm.capture.timeperframe.numerator;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2src,
|
||||
"frame rate returned by G_PARM: %d/%d fps", *fps_n, *fps_d);
|
||||
/* and we are done now */
|
||||
goto done;
|
||||
|
||||
try_stds:
|
||||
/* If G_PARM failed, try to get the same information from the video standard */
|
||||
if (!gst_v4l2_get_norm (v4l2object, &std))
|
||||
return FALSE;
|
||||
|
||||
found = FALSE;
|
||||
for (item = v4l2object->stds; item != NULL; item = item->next) {
|
||||
GstV4l2TunerNorm *v4l2norm = item->data;
|
||||
|
||||
if (v4l2norm->index == std) {
|
||||
*fps_n =
|
||||
gst_value_get_fraction_numerator (&GST_TUNER_NORM (v4l2norm)->
|
||||
framerate);
|
||||
*fps_d =
|
||||
gst_value_get_fraction_denominator (&GST_TUNER_NORM (v4l2norm)->
|
||||
framerate);
|
||||
GValue *framerate = &GST_TUNER_NORM (v4l2norm)->framerate;
|
||||
|
||||
*fps_n = gst_value_get_fraction_numerator (framerate);
|
||||
*fps_d = gst_value_get_fraction_denominator (framerate);
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2src,
|
||||
"frame rate returned by get_norm: %d/%d fps", *fps_n, *fps_d);
|
||||
return TRUE;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
/* nothing found, that's an error */
|
||||
if (!found)
|
||||
goto failed;
|
||||
|
||||
done:
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
failed:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "failed to get framerate");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#define GST_TYPE_V4L2SRC_BUFFER (gst_v4l2src_buffer_get_type())
|
||||
|
@ -812,7 +925,6 @@ gst_v4l2src_buffer_finalize (GstV4l2SrcBuffer * v4l2src_buffer)
|
|||
GstV4l2Buffer *buf = v4l2src_buffer->buf;
|
||||
|
||||
if (buf) {
|
||||
|
||||
GST_LOG ("freeing buffer %p (nr. %d)", buf, buf->buffer.index);
|
||||
|
||||
if (!g_atomic_int_dec_and_test (&buf->refcount)) {
|
||||
|
@ -825,7 +937,6 @@ gst_v4l2src_buffer_finalize (GstV4l2SrcBuffer * v4l2src_buffer)
|
|||
/* we're last thing that used all this */
|
||||
gst_v4l2src_buffer_pool_free (buf->pool, TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,9 +956,6 @@ gst_v4l2src_buffer_new (GstV4l2Src * v4l2src, guint size, guint8 * data,
|
|||
GST_LOG_OBJECT (v4l2src,
|
||||
"creating buffer %p (nr. %d)", srcbuf, srcbuf->buffer.index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GST_BUFFER_SIZE (buf) = size;
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) =
|
||||
|
|
Loading…
Reference in a new issue