diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2006-09-26 11:06:17 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2006-09-26 11:06:17 +0000 |
commit | b90e11a094296aaae07ff496b8b7631d4c96134a (patch) | |
tree | 0238633c646832d2d826da178c783398ff991018 /sys | |
parent | 651b00563e2027f69e37a7d3a81c9d18498d451a (diff) | |
download | gst-plugins-bad-b90e11a094296aaae07ff496b8b7631d4c96134a.tar.gz gst-plugins-bad-b90e11a094296aaae07ff496b8b7631d4c96134a.tar.bz2 gst-plugins-bad-b90e11a094296aaae07ff496b8b7631d4c96134a.zip |
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.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/v4l2/gstv4l2object.c | 53 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.h | 6 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.c | 113 | ||||
-rw-r--r-- | sys/v4l2/v4l2_calls.c | 249 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.c | 442 |
5 files changed, 510 insertions, 353 deletions
diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index d67dfe53..bec30eb6 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -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 diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index 54d799d4..2695abd3 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -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, \ diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index f652539e..0e5300e2 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -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; + } } diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index ba93e6e5..1d287d17 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -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,65 +374,80 @@ gst_v4l2_open (GstV4l2Object * v4l2object) v4l2object->videodev = g_strdup ("/dev/video"); /* check if it is a device */ - if (-1 == stat (v4l2object->videodev, &st)) { + if (stat (v4l2object->videodev, &st) == -1) + goto stat_failed; + + if (!S_ISCHR (st.st_mode)) + goto no_device; + + /* open the device */ + v4l2object->video_fd = + open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ ); + + if (!GST_V4L2_IS_OPEN (v4l2object)) + goto not_open; + + /* get capabilities, error will be posted */ + if (!gst_v4l2_get_capabilities (v4l2object)) + goto error; + + /* do we need to be a capture device? */ + if (GST_IS_V4L2SRC (v4l2object) && + !(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + goto not_capture; + + /* create enumerations, posts errors. */ + if (!gst_v4l2_fill_lists (v4l2object)) + goto error; + + GST_INFO_OBJECT (v4l2object->element, + "Opened device '%s' (%s) successfully", + v4l2object->vcap.card, v4l2object->videodev); + + return TRUE; + + /* ERRORS */ +stat_failed: + { GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, (_("Cannot identify device '%s'"), v4l2object->videodev), GST_ERROR_SYSTEM); goto error; } - if (!S_ISCHR (st.st_mode)) { +no_device: + { GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND, (_("This isn't a device '%s'"), v4l2object->videodev), GST_ERROR_SYSTEM); goto error; } - - /* open the device */ - v4l2object->video_fd = - open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ ); - - if (!GST_V4L2_IS_OPEN (v4l2object)) { +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; } - - /* get capabilities */ - 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)) { +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; } - - /* create enumerations */ - if (!gst_v4l2_fill_lists (v4l2object)) - goto error; - - GST_INFO_OBJECT (v4l2object->element, - "Opened device '%s' (%s) successfully", - v4l2object->vcap.card, v4l2object->videodev); - - return TRUE; - error: - if (GST_V4L2_IS_OPEN (v4l2object)) { - /* close device */ - close (v4l2object->video_fd); - v4l2object->video_fd = -1; - } - /* empty lists */ - gst_v4l2_empty_lists (v4l2object); + { + 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; + + return TRUE; - if (ioctl (v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + /* 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; } diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 7e6e09e7..21b07f5c 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -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,29 +748,49 @@ 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; - return FALSE; + if (ioctl (v4l2object->video_fd, VIDIOC_S_PARM, &stream) < 0) + goto sparm_failed; -} + *fps_n = stream.parm.capture.timeperframe.denominator; + *fps_d = stream.parm.capture.timeperframe.numerator; + GST_LOG_OBJECT (v4l2src, "fps set to %d, %d", *fps_n, *fps_d); + + return TRUE; + + /* ERRORS */ +gparm_failed: + { + GST_DEBUG_OBJECT (v4l2src, "failed to get PARM: %s", g_strerror (errno)); + return FALSE; + } +no_timeperframe: + { + GST_DEBUG_OBJECT (v4l2src, "no V4L2_CAP_TIMEPERFRAME"); + return FALSE; + } +sparm_failed: + { + GST_DEBUG_OBJECT (v4l2src, "failed to set PARM: %s", g_strerror (errno)); + return FALSE; + } +} gboolean gst_v4l2src_get_fps (GstV4l2Src * v4l2src, guint * fps_n, guint * fps_d) @@ -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) = |