GST_DEBUG_OBJECT (pool, "start flushing");
- gst_poll_set_flushing (pool->poll, TRUE);
+ gst_poll_set_flushing (pool->obj->poll, TRUE);
GST_OBJECT_LOCK (pool);
pool->empty = FALSE;
if (pool->other_pool && gst_buffer_pool_is_active (pool->other_pool))
gst_buffer_pool_set_flushing (pool->other_pool, FALSE);
- gst_poll_set_flushing (pool->poll, FALSE);
+ gst_poll_set_flushing (pool->obj->poll, FALSE);
}
static GstFlowReturn
gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool, gboolean wait)
{
- gint ret;
GstClockTime timeout;
if (wait)
if (!wait && pool->empty) {
GST_OBJECT_UNLOCK (pool);
- goto no_buffers;
+ return GST_V4L2_FLOW_LAST_BUFFER;
}
while (pool->empty)
GST_OBJECT_UNLOCK (pool);
}
- if (!pool->can_poll_device) {
+ if (!pool->obj->can_poll_device) {
if (wait)
- goto done;
+ return GST_FLOW_OK;
else
- goto no_buffers;
- }
-
- GST_LOG_OBJECT (pool, "polling device");
-
-again:
- ret = gst_poll_wait (pool->poll, timeout);
- if (G_UNLIKELY (ret < 0)) {
- switch (errno) {
- case EBUSY:
- goto stopped;
- case EAGAIN:
- case EINTR:
- goto again;
- case ENXIO:
- GST_WARNING_OBJECT (pool,
- "v4l2 device doesn't support polling. Disabling"
- " using libv4l2 in this case may cause deadlocks");
- pool->can_poll_device = FALSE;
- goto done;
- default:
- goto select_error;
- }
- }
-
- if (gst_poll_fd_has_error (pool->poll, &pool->pollfd))
- goto select_error;
-
- /* PRI is used to signal that events are available */
- if (gst_poll_fd_has_pri (pool->poll, &pool->pollfd)) {
- struct v4l2_event event = { 0, };
-
- if (!gst_v4l2_dequeue_event (pool->obj, &event))
- goto dqevent_failed;
-
- if (event.type != V4L2_EVENT_SOURCE_CHANGE) {
- GST_INFO_OBJECT (pool, "Received unhandled event, ignoring.");
- goto again;
- }
-
- if ((event.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) == 0) {
- GST_DEBUG_OBJECT (pool,
- "Received non-resolution source-change, ignoring.");
- goto again;
- }
-
- return GST_V4L2_FLOW_RESOLUTION_CHANGE;
+ return GST_V4L2_FLOW_LAST_BUFFER;
}
- if (ret == 0)
- goto no_buffers;
-
-done:
- return GST_FLOW_OK;
-
- /* ERRORS */
-stopped:
- {
- GST_DEBUG_OBJECT (pool, "stop called");
- return GST_FLOW_FLUSHING;
- }
-select_error:
- {
- GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL),
- ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
- return GST_FLOW_ERROR;
- }
-no_buffers:
- {
- return GST_V4L2_FLOW_LAST_BUFFER;
- }
-dqevent_failed:
- {
- GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL),
- ("dqevent error: %s (%d)", g_strerror (errno), errno));
- return GST_FLOW_ERROR;
- }
+ return gst_v4l2_object_poll (pool->obj, timeout);
}
static GstFlowReturn
if (pool->video_fd >= 0)
pool->obj->close (pool->video_fd);
- gst_poll_free (pool->poll);
-
/* This can't be done in dispose method because we must not set pointer
* to NULL as it is part of the v4l2object and dispose could be called
* multiple times */
static void
gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
{
- pool->poll = gst_poll_new (TRUE);
- pool->can_poll_device = TRUE;
g_cond_init (&pool->empty_cond);
pool->empty = TRUE;
pool->orphaned = FALSE;
g_object_ref_sink (pool);
g_free (name);
- gst_poll_fd_init (&pool->pollfd);
- pool->pollfd.fd = fd;
- gst_poll_add_fd (pool->poll, &pool->pollfd);
- if (V4L2_TYPE_IS_OUTPUT (obj->type))
- gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE);
- else
- gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE);
-
pool->video_fd = fd;
pool->obj = obj;
- pool->can_poll_device = TRUE;
pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj);
if (pool->vallocator == NULL)
void
gst_v4l2_buffer_pool_enable_resolution_change (GstV4l2BufferPool * pool)
{
- guint32 input_id = 0;
-
- /* Make sure we subscribe for the current input */
- gst_v4l2_get_input (pool->obj, &input_id);
-
- if (gst_v4l2_subscribe_event (pool->obj, V4L2_EVENT_SOURCE_CHANGE, input_id))
- gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
+ gst_v4l2_object_subscribe_event (pool->obj, V4L2_EVENT_SOURCE_CHANGE);
}
v4l2object->no_initial_format = FALSE;
+ v4l2object->poll = gst_poll_new (TRUE);
+ v4l2object->can_poll_device = TRUE;
+
/* We now disable libv4l2 by default, but have an env to enable it. */
#ifdef HAVE_LIBV4L2
if (g_getenv ("GST_V4L2_USE_LIBV4L2")) {
g_free (v4l2object->par);
g_free (v4l2object->channel);
+ gst_poll_free (v4l2object->poll);
+
if (v4l2object->formats) {
gst_v4l2_object_clear_format_list (v4l2object);
}
}
}
+static void
+gst_v4l2_object_init_poll (GstV4l2Object * v4l2object)
+{
+ gst_poll_fd_init (&v4l2object->pollfd);
+ v4l2object->pollfd.fd = v4l2object->video_fd;
+ gst_poll_add_fd (v4l2object->poll, &v4l2object->pollfd);
+ if (V4L2_TYPE_IS_OUTPUT (v4l2object->type))
+ gst_poll_fd_ctl_write (v4l2object->poll, &v4l2object->pollfd, TRUE);
+ else
+ gst_poll_fd_ctl_read (v4l2object->poll, &v4l2object->pollfd, TRUE);
+
+ v4l2object->can_poll_device = TRUE;
+}
+
gboolean
gst_v4l2_object_open (GstV4l2Object * v4l2object, GstV4l2Error * error)
{
else
return FALSE;
+ gst_v4l2_object_init_poll (v4l2object);
+
return TRUE;
}
gboolean
gst_v4l2_object_open_shared (GstV4l2Object * v4l2object, GstV4l2Object * other)
{
- gboolean ret;
-
- ret = gst_v4l2_dup (v4l2object, other);
+ if (gst_v4l2_dup (v4l2object, other)) {
+ gst_v4l2_object_init_poll (v4l2object);
+ return TRUE;
+ }
- return ret;
+ return FALSE;
}
gboolean
GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
+ gst_poll_set_flushing (v4l2object->poll, TRUE);
+
if (!pool)
return ret;
GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
+ gst_poll_set_flushing (v4l2object->poll, FALSE);
+
if (!pool)
return ret;
if (!GST_V4L2_IS_ACTIVE (v4l2object))
goto done;
+ gst_poll_set_flushing (v4l2object->poll, TRUE);
+
pool = gst_v4l2_object_get_buffer_pool (v4l2object);
if (pool) {
if (!gst_v4l2_buffer_pool_orphan (v4l2object)) {
return ret;
}
+
+/**
+ * gst_v4l2_object_poll:
+ * @v4l2object: a #GstV4l2Object
+ * @timeout: timeout of type #GstClockTime
+ *
+ * Poll the video file descriptor for read when this is a capture, write when
+ * this is an output. It will also watch for errors and source change events.
+ * If a source change event is received, %GST_V4L2_FLOW_RESOLUTION_CHANGE will
+ * be returned. If the poll was interrupted, %GST_FLOW_FLUSHING is returned.
+ * If there was no read or write indicator, %GST_V4L2_FLOW_LAST_BUFFER is
+ * returned. It may also return %GST_FLOW_ERROR if some unexpected error
+ * occured.
+ *
+ * Returns: GST_FLOW_OK if buffers are ready to be queued or dequeued.
+ */
+GstFlowReturn
+gst_v4l2_object_poll (GstV4l2Object * v4l2object, GstClockTime timeout)
+{
+ gint ret;
+
+ if (!v4l2object->can_poll_device) {
+ if (timeout != 0)
+ goto done;
+ else
+ goto no_buffers;
+ }
+
+ GST_LOG_OBJECT (v4l2object->dbg_obj, "polling device");
+
+again:
+ ret = gst_poll_wait (v4l2object->poll, timeout);
+ if (G_UNLIKELY (ret < 0)) {
+ switch (errno) {
+ case EBUSY:
+ goto stopped;
+ case EAGAIN:
+ case EINTR:
+ goto again;
+ case ENXIO:
+ GST_WARNING_OBJECT (v4l2object->dbg_obj,
+ "v4l2 device doesn't support polling. Disabling"
+ " using libv4l2 in this case may cause deadlocks");
+ v4l2object->can_poll_device = FALSE;
+ goto done;
+ default:
+ goto select_error;
+ }
+ }
+
+ if (gst_poll_fd_has_error (v4l2object->poll, &v4l2object->pollfd))
+ goto select_error;
+
+ /* PRI is used to signal that events are available */
+ if (gst_poll_fd_has_pri (v4l2object->poll, &v4l2object->pollfd)) {
+ struct v4l2_event event = { 0, };
+
+ if (!gst_v4l2_dequeue_event (v4l2object, &event))
+ goto dqevent_failed;
+
+ if (event.type != V4L2_EVENT_SOURCE_CHANGE) {
+ GST_INFO_OBJECT (v4l2object->dbg_obj,
+ "Received unhandled event, ignoring.");
+ goto again;
+ }
+
+ if ((event.u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) == 0) {
+ GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+ "Received non-resolution source-change, ignoring.");
+ goto again;
+ }
+
+ return GST_V4L2_FLOW_RESOLUTION_CHANGE;
+ }
+
+ if (ret == 0)
+ goto no_buffers;
+
+done:
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+stopped:
+ {
+ GST_DEBUG_OBJECT (v4l2object->dbg_obj, "stop called");
+ return GST_FLOW_FLUSHING;
+ }
+select_error:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
+ ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
+ return GST_FLOW_ERROR;
+ }
+no_buffers:
+ {
+ return GST_V4L2_FLOW_LAST_BUFFER;
+ }
+dqevent_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
+ ("dqevent error: %s (%d)", g_strerror (errno), errno));
+ return GST_FLOW_ERROR;
+ }
+}
+
+/**
+ * gst_v4l2_object_subscribe_event:
+ * @v4l2object: a #GstV4l2Object
+ * @event: the event ID
+ *
+ * Subscribe to an event, and enable polling for these. Note that only
+ * %V4L2_EVENT_SOURCE_CHANGE is currently supported by the poll helper.
+ *
+ * Returns: %TRUE if the driver supports this event
+ */
+gboolean
+gst_v4l2_object_subscribe_event (GstV4l2Object * v4l2object, guint32 event)
+{
+ guint32 id = 0;
+
+ g_return_val_if_fail (v4l2object != NULL, FALSE);
+ g_return_val_if_fail (GST_V4L2_IS_OPEN (v4l2object), FALSE);
+
+ v4l2object->get_in_out_func (v4l2object, &id);
+
+ if (gst_v4l2_subscribe_event (v4l2object, event, id)) {
+ gst_poll_fd_ctl_pri (v4l2object->poll, &v4l2object->pollfd, TRUE);
+ return TRUE;
+ }
+
+ return FALSE;
+}