mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
v4l2: object: Move the GstPoll into v4l2object
Moves the GstPoll from the buffer pool into v4l2object. This will be needed to poll for events before the pool has been created. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4525>
This commit is contained in:
parent
d4a428e61f
commit
7599821c42
4 changed files with 178 additions and 108 deletions
|
@ -1077,7 +1077,7 @@ gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool)
|
|||
|
||||
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;
|
||||
|
@ -1098,13 +1098,12 @@ gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool)
|
|||
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)
|
||||
|
@ -1119,7 +1118,7 @@ gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool, gboolean wait)
|
|||
|
||||
if (!wait && pool->empty) {
|
||||
GST_OBJECT_UNLOCK (pool);
|
||||
goto no_buffers;
|
||||
return GST_V4L2_FLOW_LAST_BUFFER;
|
||||
}
|
||||
|
||||
while (pool->empty)
|
||||
|
@ -1128,87 +1127,14 @@ gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool, gboolean wait)
|
|||
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;
|
||||
return GST_V4L2_FLOW_LAST_BUFFER;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1757,8 +1683,6 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
|
|||
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 */
|
||||
|
@ -1774,8 +1698,6 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
|
|||
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;
|
||||
|
@ -1838,17 +1760,8 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
|
|||
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)
|
||||
|
@ -2331,11 +2244,5 @@ gst_v4l2_buffer_pool_flush (GstV4l2Object * v4l2object)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -64,9 +64,6 @@ struct _GstV4l2BufferPool
|
|||
|
||||
GstV4l2Object *obj; /* the v4l2 object */
|
||||
gint video_fd; /* a dup(2) of the v4l2object's video_fd */
|
||||
GstPoll *poll; /* a poll for video_fd */
|
||||
GstPollFD pollfd;
|
||||
gboolean can_poll_device;
|
||||
|
||||
gboolean empty;
|
||||
GCond empty_cond;
|
||||
|
|
|
@ -525,6 +525,9 @@ gst_v4l2_object_new (GstElement * element,
|
|||
|
||||
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")) {
|
||||
|
@ -572,6 +575,8 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
|
|||
g_free (v4l2object->par);
|
||||
g_free (v4l2object->channel);
|
||||
|
||||
gst_poll_free (v4l2object->poll);
|
||||
|
||||
if (v4l2object->formats) {
|
||||
gst_v4l2_object_clear_format_list (v4l2object);
|
||||
}
|
||||
|
@ -900,6 +905,20 @@ gst_v4l2_set_defaults (GstV4l2Object * 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)
|
||||
{
|
||||
|
@ -908,17 +927,20 @@ 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;
|
||||
if (gst_v4l2_dup (v4l2object, other)) {
|
||||
gst_v4l2_object_init_poll (v4l2object);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ret = gst_v4l2_dup (v4l2object, other);
|
||||
|
||||
return ret;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -4598,6 +4620,8 @@ gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
|
|||
|
||||
GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
|
||||
|
||||
gst_poll_set_flushing (v4l2object->poll, TRUE);
|
||||
|
||||
if (!pool)
|
||||
return ret;
|
||||
|
||||
|
@ -4616,6 +4640,8 @@ gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
|
|||
|
||||
GST_LOG_OBJECT (v4l2object->dbg_obj, "stop flushing");
|
||||
|
||||
gst_poll_set_flushing (v4l2object->poll, FALSE);
|
||||
|
||||
if (!pool)
|
||||
return ret;
|
||||
|
||||
|
@ -4637,6 +4663,8 @@ gst_v4l2_object_stop (GstV4l2Object * v4l2object)
|
|||
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)) {
|
||||
|
@ -5467,3 +5495,135 @@ gst_v4l2_object_get_buffer_pool (GstV4l2Object * 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;
|
||||
}
|
||||
|
|
|
@ -134,6 +134,9 @@ struct _GstV4l2Object {
|
|||
/* the video-device's file descriptor */
|
||||
gint video_fd;
|
||||
GstV4l2IOMode mode;
|
||||
GstPoll *poll;
|
||||
GstPollFD pollfd;
|
||||
gboolean can_poll_device;
|
||||
|
||||
gboolean active;
|
||||
|
||||
|
@ -314,6 +317,9 @@ GstBufferPool * gst_v4l2_object_get_buffer_pool (GstV4l2Object * v4l2object);
|
|||
|
||||
GstStructure * gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc);
|
||||
|
||||
GstFlowReturn gst_v4l2_object_poll (GstV4l2Object * v4l2object, GstClockTime timeout);
|
||||
gboolean gst_v4l2_object_subscribe_event (GstV4l2Object * v4l2object, guint32 event);
|
||||
|
||||
/* crop / compose */
|
||||
gboolean gst_v4l2_object_set_crop (GstV4l2Object * obj, struct v4l2_rect *result);
|
||||
gboolean gst_v4l2_object_get_crop_bounds (GstV4l2Object * obj, struct v4l2_rect *bounds);
|
||||
|
|
Loading…
Reference in a new issue