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:
Wim Taymans 2006-09-26 11:06:17 +00:00
parent 651b00563e
commit b90e11a094
6 changed files with 544 additions and 355 deletions

View file

@ -1,3 +1,35 @@
2006-09-26 Wim Taymans <wim@fluendo.com>
* 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.
2006-09-23 Wim Taymans <wim@fluendo.com>
* ext/cdaudio/gstcdaudio.c: (gst_cdaudio_class_init),

View file

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

View file

@ -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, \

View file

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

View file

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

View file

@ -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) =