Commit 1f99b152 authored by Song Bing's avatar Song Bing

v4l2videodec: Add resolution change support

Support resolution change event.

https://bugzilla.gnome.org/show_bug.cgi?id=752962
parent f6b91fe3
Pipeline #42255 failed with stages
in 7 minutes and 58 seconds
......@@ -1201,8 +1201,35 @@ queue_failed:
}
static GstFlowReturn
gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer,
gboolean wait)
gst_v4l2_buffer_pool_dqevent (GstV4l2BufferPool * pool)
{
GstV4l2Object *obj = pool->obj;
struct v4l2_event evt;
memset (&evt, 0x00, sizeof (struct v4l2_event));
if (obj->ioctl (pool->video_fd, VIDIOC_DQEVENT, &evt) < 0)
goto dqevent_failed;
switch (evt.type) {
case V4L2_EVENT_SOURCE_CHANGE:
return GST_V4L2_FLOW_SOURCE_CHANGE;
case V4L2_EVENT_EOS:
return GST_V4L2_FLOW_LAST_BUFFER;
default:
break;
}
return GST_FLOW_OK;
/* ERRORS */
dqevent_failed:
{
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
{
GstFlowReturn res;
GstBuffer *outbuf = NULL;
......@@ -1213,16 +1240,6 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer,
gsize size;
gint i;
if ((res = gst_v4l2_buffer_pool_poll (pool, wait)) < GST_FLOW_OK)
goto poll_failed;
if (res == GST_FLOW_CUSTOM_SUCCESS) {
GST_LOG_OBJECT (pool, "nothing to dequeue");
goto done;
}
GST_LOG_OBJECT (pool, "dequeueing a buffer");
res = gst_v4l2_allocator_dqbuf (pool->vallocator, &group);
if (res == GST_FLOW_EOS)
goto eos;
......@@ -1350,11 +1367,6 @@ done:
return res;
/* ERRORS */
poll_failed:
{
GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
return res;
}
eos:
{
return GST_FLOW_EOS;
......@@ -1371,6 +1383,40 @@ no_buffer:
}
}
static GstFlowReturn
gst_v4l2_buffer_pool_dequeue (GstV4l2BufferPool * pool, GstBuffer ** buffer,
gboolean wait)
{
GstFlowReturn res;
GstV4l2Object *obj = pool->obj;
if ((res = gst_v4l2_buffer_pool_poll (pool, wait)) < GST_FLOW_OK)
goto poll_failed;
if (res == GST_FLOW_CUSTOM_SUCCESS) {
GST_LOG_OBJECT (pool, "nothing to dequeue");
goto done;
}
GST_LOG_OBJECT (pool, "dequeueing a buffer");
if (obj->can_wait_event && gst_poll_fd_has_pri (pool->poll, &pool->pollfd)) {
return gst_v4l2_buffer_pool_dqevent (pool);
}
GST_LOG_OBJECT (pool, "dequeueing a buffer");
return gst_v4l2_buffer_pool_dqbuf (pool, buffer);
/* ERRORS */
poll_failed:
{
GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
return res;
}
done:
return res;
}
static GstFlowReturn
gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
GstBufferPoolAcquireParams * params)
......@@ -1407,7 +1453,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
/* just dequeue a buffer, we basically use the queue of v4l2 as the
* storage for our buffers. This function does poll first so we can
* interrupt it fine. */
ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer, TRUE);
ret = gst_v4l2_buffer_pool_dequeue (pool, buffer, TRUE);
break;
}
default:
......@@ -1680,8 +1726,10 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
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
else {
gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE);
gst_poll_fd_ctl_pri (pool->poll, &pool->pollfd, TRUE);
}
pool->video_fd = fd;
pool->obj = obj;
......@@ -1866,8 +1914,9 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
}
/* buffer not from our pool, grab a frame and copy it into the target */
if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp, TRUE))
!= GST_FLOW_OK)
if ((ret =
gst_v4l2_buffer_pool_dequeue (pool, &tmp,
TRUE)) != GST_FLOW_OK)
goto done;
/* An empty buffer on capture indicates the end of stream */
......@@ -2022,7 +2071,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
gst_buffer_unref (to_queue);
/* release as many buffer as possible */
while (gst_v4l2_buffer_pool_dqbuf (pool, &buffer, FALSE) ==
while (gst_v4l2_buffer_pool_dequeue (pool, &buffer, FALSE) ==
GST_FLOW_OK) {
if (buffer->pool == NULL)
gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
......@@ -2031,7 +2080,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
if (g_atomic_int_get (&pool->num_queued) >= pool->min_latency) {
/* all buffers are queued, try to dequeue one and release it back
* into the pool so that _acquire can get to it again. */
ret = gst_v4l2_buffer_pool_dqbuf (pool, &buffer, TRUE);
ret = gst_v4l2_buffer_pool_dequeue (pool, &buffer, TRUE);
if (ret == GST_FLOW_OK && buffer->pool == NULL)
/* release the rendered buffer back into the pool. This wakes up any
* thread waiting for a buffer in _acquire(). */
......
......@@ -42,8 +42,8 @@ G_BEGIN_DECLS
#define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj))
/* This flow return is used to indicated that the last buffer of a
* drain or a resoltuion change has been found. This should normally
* only occure for mem-2-mem devices. */
* drain has been found. This should normally only occure for
* mem-2-mem devices. */
#define GST_V4L2_FLOW_LAST_BUFFER GST_FLOW_CUSTOM_SUCCESS
/* This flow return is used to indicated that the returned buffer was marked
......@@ -51,6 +51,11 @@ G_BEGIN_DECLS
* simply waiting for next buffer. */
#define GST_V4L2_FLOW_CORRUPTED_BUFFER GST_FLOW_CUSTOM_SUCCESS_1
/* This flow return is used to indicated that the last buffer of a
* resoltuion change has been found. This should normally only
* occure for mem-2-mem devices. */
#define GST_V4L2_FLOW_SOURCE_CHANGE GST_FLOW_CUSTOM_SUCCESS_2
struct _GstV4l2BufferPool
{
GstBufferPool parent;
......
......@@ -535,6 +535,10 @@ gst_v4l2_object_new (GstElement * element,
v4l2object->munmap = munmap;
}
v4l2object->poll = gst_poll_new (TRUE);
v4l2object->can_wait_event = FALSE;
v4l2object->can_poll_device = TRUE;
return v4l2object;
}
......@@ -546,6 +550,8 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
{
g_return_if_fail (v4l2object != NULL);
gst_poll_free (v4l2object->poll);
g_free (v4l2object->videodev);
g_free (v4l2object->channel);
......@@ -906,6 +912,15 @@ gst_v4l2_object_open_shared (GstV4l2Object * v4l2object, GstV4l2Object * other)
ret = gst_v4l2_dup (v4l2object, other);
if (ret && !V4L2_TYPE_IS_OUTPUT (v4l2object->type)) {
gst_poll_fd_init (&v4l2object->pollfd);
v4l2object->pollfd.fd = v4l2object->video_fd;
gst_poll_add_fd (v4l2object->poll, &v4l2object->pollfd);
/* used for dequeue event */
gst_poll_fd_ctl_read (v4l2object->poll, &v4l2object->pollfd, TRUE);
gst_poll_fd_ctl_pri (v4l2object->poll, &v4l2object->pollfd, TRUE);
}
return ret;
}
......@@ -3881,6 +3896,93 @@ gst_v4l2_object_try_format (GstV4l2Object * v4l2object, GstCaps * caps,
return gst_v4l2_object_set_format_full (v4l2object, caps, TRUE, error);
}
GstFlowReturn
gst_v4l2_object_poll (GstV4l2Object * v4l2object)
{
gint ret;
if (!v4l2object->can_poll_device)
goto done;
GST_LOG_OBJECT (v4l2object, "polling device");
again:
ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
if (G_UNLIKELY (ret < 0)) {
switch (errno) {
case EBUSY:
goto stopped;
case EAGAIN:
case EINTR:
goto again;
case ENXIO:
GST_WARNING_OBJECT (v4l2object,
"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;
done:
return GST_FLOW_OK;
/* ERRORS */
stopped:
{
GST_DEBUG_OBJECT (v4l2object, "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;
}
}
GstFlowReturn
gst_v4l2_object_dqevent (GstV4l2Object * v4l2object)
{
GstFlowReturn res;
struct v4l2_event evt;
if ((res = gst_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
goto poll_failed;
memset (&evt, 0x00, sizeof (struct v4l2_event));
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_DQEVENT, &evt) < 0)
goto dqevent_failed;
switch (evt.type) {
case V4L2_EVENT_SOURCE_CHANGE:
return GST_V4L2_FLOW_SOURCE_CHANGE;
case V4L2_EVENT_EOS:
return GST_V4L2_FLOW_LAST_BUFFER;
default:
break;
}
return GST_FLOW_OK;
/* ERRORS */
poll_failed:
{
GST_DEBUG_OBJECT (v4l2object, "poll error %s", gst_flow_get_name (res));
return res;
}
dqevent_failed:
{
return GST_FLOW_ERROR;
}
}
/**
* gst_v4l2_object_acquire_format:
* @v4l2object: the object
......@@ -4128,6 +4230,8 @@ gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
GST_LOG_OBJECT (v4l2object->dbg_obj, "start flushing");
gst_poll_set_flushing (v4l2object->poll, TRUE);
if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
gst_buffer_pool_set_flushing (v4l2object->pool, TRUE);
......@@ -4144,6 +4248,8 @@ gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
gst_buffer_pool_set_flushing (v4l2object->pool, FALSE);
gst_poll_set_flushing (v4l2object->poll, FALSE);
return ret;
}
......
......@@ -130,6 +130,9 @@ struct _GstV4l2Object {
/* the video-device's file descriptor */
gint video_fd;
GstV4l2IOMode mode;
GstPoll *poll; /* a poll for video_fd */
GstPollFD pollfd;
gboolean can_poll_device;
gboolean active;
gboolean streaming;
......@@ -216,6 +219,8 @@ struct _GstV4l2Object {
* on slow USB firmwares. When this is set, gst_v4l2_set_format() will modify
* the caps to reflect what was negotiated during fixation */
gboolean skip_try_fmt_probes;
gboolean can_wait_event;
gboolean need_wait_event;
};
struct _GstV4l2ObjectClassHelper {
......@@ -299,6 +304,7 @@ gboolean gst_v4l2_object_stop (GstV4l2Object * v4l2object);
GstCaps * gst_v4l2_object_probe_caps (GstV4l2Object * v4l2object, GstCaps * filter);
GstCaps * gst_v4l2_object_get_caps (GstV4l2Object * v4l2object, GstCaps * filter);
GstFlowReturn gst_v4l2_object_dqevent (GstV4l2Object * v4l2object);
gboolean gst_v4l2_object_acquire_format (GstV4l2Object * v4l2object, GstVideoInfo * info);
gboolean gst_v4l2_object_set_crop (GstV4l2Object * obj);
......
This diff is collapsed.
......@@ -509,6 +509,43 @@ gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object)
}
}
gboolean
gst_v4l2_subscribe_event (GstV4l2Object * v4l2object)
{
GstElement *e;
struct v4l2_event_subscription sub;
e = v4l2object->element;
GST_DEBUG_OBJECT (e, "subscribe event");
if (!GST_V4L2_IS_OPEN (v4l2object))
return FALSE;
memset (&sub, 0, sizeof (struct v4l2_event_subscription));
sub.type = V4L2_EVENT_SOURCE_CHANGE;
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_SUBSCRIBE_EVENT,
&sub) < 0)
goto failed;
sub.type = V4L2_EVENT_EOS;
if (v4l2object->ioctl (v4l2object->video_fd, VIDIOC_SUBSCRIBE_EVENT,
&sub) < 0)
goto failed;
v4l2object->can_wait_event = TRUE;
return TRUE;
/* ERRORS */
failed:
{
GST_WARNING_OBJECT (e, "Cannot subscribe V4L2_EVENT_SOURCE_CHANGE or "
"V4L2_EVENT_EOS event for device '%s'.", v4l2object->videodev);
return TRUE;
}
}
/******************************************************
* gst_v4l2_open():
* open the video device (v4l2object->videodev)
......@@ -591,6 +628,8 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
if (v4l2object->extra_controls)
gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
gst_v4l2_subscribe_event (v4l2object);
/* UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
* causes expensive and slow USB IO, so don't probe them for interlaced
*/
......@@ -689,6 +728,7 @@ gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
v4l2object->never_interlaced = other->never_interlaced;
v4l2object->no_initial_format = other->no_initial_format;
v4l2object->can_wait_event = other->can_wait_event;
return TRUE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment