mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
v4l2bufferpool: Port to bufferpool flush_start/stop method
This commit is contained in:
parent
f0b99d96a9
commit
2e0fb42e86
8 changed files with 250 additions and 332 deletions
|
@ -1219,6 +1219,10 @@ gst_v4l2_allocator_qbuf (GstV4l2Allocator * allocator,
|
||||||
gboolean ret = TRUE;
|
gboolean ret = TRUE;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
|
/* Buffer already queued */
|
||||||
|
if (IS_QUEUED (group->buffer))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
/* update sizes */
|
/* update sizes */
|
||||||
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
|
if (V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
|
||||||
for (i = 0; i < group->n_mem; i++)
|
for (i = 0; i < group->n_mem; i++)
|
||||||
|
|
|
@ -520,78 +520,67 @@ wrong_config:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
start_streaming (GstV4l2BufferPool * pool)
|
gst_v4l2_buffer_pool_streamon (GstV4l2BufferPool * pool)
|
||||||
{
|
{
|
||||||
GstV4l2Object *obj = pool->obj;
|
GstV4l2Object *obj = pool->obj;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "start streaming");
|
|
||||||
|
|
||||||
if (pool->streaming)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
switch (obj->mode) {
|
switch (obj->mode) {
|
||||||
case GST_V4L2_IO_RW:
|
|
||||||
break;
|
|
||||||
case GST_V4L2_IO_MMAP:
|
case GST_V4L2_IO_MMAP:
|
||||||
case GST_V4L2_IO_USERPTR:
|
case GST_V4L2_IO_USERPTR:
|
||||||
case GST_V4L2_IO_DMABUF:
|
case GST_V4L2_IO_DMABUF:
|
||||||
case GST_V4L2_IO_DMABUF_IMPORT:
|
case GST_V4L2_IO_DMABUF_IMPORT:
|
||||||
{
|
if (!pool->streaming) {
|
||||||
/* For capture device, we need to re-enqueue buffers before be can let
|
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
|
||||||
* the driver stream again */
|
goto streamon_failed;
|
||||||
if (!V4L2_TYPE_IS_OUTPUT (obj->type) && pool->vallocator) {
|
|
||||||
GstBufferPool *bpool = GST_BUFFER_POOL (pool);
|
|
||||||
GstBufferPoolAcquireParams params = { 0 };
|
|
||||||
gsize num_allocated, num_to_queue;
|
|
||||||
GstFlowReturn ret;
|
|
||||||
|
|
||||||
num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator);
|
pool->streaming = TRUE;
|
||||||
num_to_queue = num_allocated - pool->num_queued;
|
|
||||||
|
|
||||||
while (num_to_queue > 0) {
|
GST_DEBUG_OBJECT (pool, "Started streaming");
|
||||||
GstBuffer *buf;
|
|
||||||
|
|
||||||
params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
|
|
||||||
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
|
|
||||||
&buf, ¶ms);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK)
|
|
||||||
goto requeue_failed;
|
|
||||||
|
|
||||||
gst_v4l2_buffer_pool_release_buffer (bpool, buf);
|
|
||||||
num_to_queue--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_allocated != pool->num_queued)
|
|
||||||
goto requeue_failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
|
|
||||||
goto start_failed;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "STREAMON");
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool->streaming = TRUE;
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
streamon_failed:
|
||||||
start_failed:
|
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
|
GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
|
||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
requeue_failed:
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_v4l2_buffer_pool_streamoff (GstV4l2BufferPool * pool)
|
||||||
|
{
|
||||||
|
GstV4l2Object *obj = pool->obj;
|
||||||
|
|
||||||
|
switch (obj->mode) {
|
||||||
|
case GST_V4L2_IO_MMAP:
|
||||||
|
case GST_V4L2_IO_USERPTR:
|
||||||
|
case GST_V4L2_IO_DMABUF:
|
||||||
|
case GST_V4L2_IO_DMABUF_IMPORT:
|
||||||
|
if (pool->streaming) {
|
||||||
|
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
|
||||||
|
goto streamoff_failed;
|
||||||
|
|
||||||
|
pool->streaming = FALSE;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (pool, "Stopped streaming");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
streamoff_failed:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (pool, "failed to re-enqueue buffers");
|
GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
|
||||||
|
g_strerror (errno));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -618,6 +607,7 @@ static gboolean
|
||||||
gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
|
gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
|
||||||
{
|
{
|
||||||
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
||||||
|
GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
|
||||||
GstV4l2Object *obj = pool->obj;
|
GstV4l2Object *obj = pool->obj;
|
||||||
GstStructure *config;
|
GstStructure *config;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
@ -741,7 +731,7 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
|
||||||
|
|
||||||
gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
|
gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
|
||||||
max_buffers);
|
max_buffers);
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);
|
pclass->set_config (bpool, config);
|
||||||
gst_structure_free (config);
|
gst_structure_free (config);
|
||||||
|
|
||||||
if (pool->other_pool)
|
if (pool->other_pool)
|
||||||
|
@ -749,22 +739,14 @@ gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
|
||||||
goto other_pool_failed;
|
goto other_pool_failed;
|
||||||
|
|
||||||
/* now, allocate the buffers: */
|
/* now, allocate the buffers: */
|
||||||
if (!GST_BUFFER_POOL_CLASS (parent_class)->start (bpool))
|
if (!pclass->start (bpool))
|
||||||
goto start_failed;
|
goto start_failed;
|
||||||
|
|
||||||
/* we can start capturing now, we wait for the playback case until we queued
|
|
||||||
* the first buffer */
|
|
||||||
if (!V4L2_TYPE_IS_OUTPUT (obj->type))
|
|
||||||
if (!start_streaming (pool))
|
|
||||||
goto start_failed;
|
|
||||||
|
|
||||||
if (!V4L2_TYPE_IS_OUTPUT (obj->type))
|
if (!V4L2_TYPE_IS_OUTPUT (obj->type))
|
||||||
pool->group_released_handler =
|
pool->group_released_handler =
|
||||||
g_signal_connect_swapped (pool->vallocator, "group-released",
|
g_signal_connect_swapped (pool->vallocator, "group-released",
|
||||||
G_CALLBACK (gst_v4l2_buffer_pool_group_released), pool);
|
G_CALLBACK (gst_v4l2_buffer_pool_group_released), pool);
|
||||||
|
|
||||||
gst_poll_set_flushing (obj->poll, FALSE);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -795,26 +777,103 @@ other_pool_failed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
stop_streaming (GstV4l2BufferPool * pool)
|
gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
|
||||||
{
|
{
|
||||||
|
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
||||||
|
GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
|
||||||
|
gboolean ret;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (pool, "stopping pool");
|
||||||
|
|
||||||
|
if (pool->group_released_handler > 0) {
|
||||||
|
g_signal_handler_disconnect (pool->vallocator,
|
||||||
|
pool->group_released_handler);
|
||||||
|
pool->group_released_handler = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pool->other_pool) {
|
||||||
|
gst_object_unref (pool->other_pool);
|
||||||
|
pool->other_pool = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_v4l2_buffer_pool_streamoff (pool))
|
||||||
|
goto streamoff_failed;
|
||||||
|
|
||||||
|
gst_v4l2_allocator_flush (pool->vallocator);
|
||||||
|
|
||||||
|
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
|
||||||
|
if (pool->buffers[i]) {
|
||||||
|
GstBuffer *buffer = pool->buffers[i];
|
||||||
|
|
||||||
|
pool->buffers[i] = NULL;
|
||||||
|
|
||||||
|
if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
else
|
||||||
|
pclass->release_buffer (bpool, buffer);
|
||||||
|
|
||||||
|
g_atomic_int_add (&pool->num_queued, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
GstV4l2Return vret;
|
||||||
|
|
||||||
|
vret = gst_v4l2_allocator_stop (pool->vallocator);
|
||||||
|
|
||||||
|
if (vret == GST_V4L2_BUSY)
|
||||||
|
GST_WARNING_OBJECT (pool, "some buffers are still outstanding");
|
||||||
|
|
||||||
|
ret = (vret == GST_V4L2_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
streamoff_failed:
|
||||||
|
GST_ERROR_OBJECT (pool, "device refused to stop streaming");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_v4l2_buffer_pool_flush_start (GstBufferPool * bpool)
|
||||||
|
{
|
||||||
|
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (pool, "start flushing");
|
||||||
|
|
||||||
|
gst_poll_set_flushing (pool->poll, TRUE);
|
||||||
|
|
||||||
|
if (pool->other_pool)
|
||||||
|
gst_buffer_pool_set_flushing (pool->other_pool, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_v4l2_buffer_pool_flush_stop (GstBufferPool * bpool)
|
||||||
|
{
|
||||||
|
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
||||||
GstV4l2Object *obj = pool->obj;
|
GstV4l2Object *obj = pool->obj;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "stopping stream");
|
GST_DEBUG_OBJECT (pool, "stop flushing");
|
||||||
|
|
||||||
gst_poll_set_flushing (obj->poll, TRUE);
|
/* If we haven't started streaming yet, simply call streamon */
|
||||||
|
if (!pool->streaming)
|
||||||
|
goto streamon;
|
||||||
|
|
||||||
if (!pool->streaming) {
|
if (pool->other_pool)
|
||||||
/* it avoid error: STREAMOFF 22 (Invalid argument) when
|
gst_buffer_pool_set_flushing (pool->other_pool, FALSE);
|
||||||
* attempting to stop a stream not previously started */
|
|
||||||
GST_DEBUG_OBJECT (pool, "no need to stop, was not previously started");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool->flushing = TRUE;
|
if (!gst_v4l2_buffer_pool_streamoff (pool))
|
||||||
|
goto stop_failed;
|
||||||
|
|
||||||
|
gst_v4l2_allocator_flush (pool->vallocator);
|
||||||
|
|
||||||
|
/* Reset our state */
|
||||||
switch (obj->mode) {
|
switch (obj->mode) {
|
||||||
case GST_V4L2_IO_RW:
|
case GST_V4L2_IO_RW:
|
||||||
break;
|
break;
|
||||||
|
@ -825,118 +884,69 @@ stop_streaming (GstV4l2BufferPool * pool)
|
||||||
{
|
{
|
||||||
gsize num_allocated;
|
gsize num_allocated;
|
||||||
|
|
||||||
if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
|
|
||||||
goto stop_failed;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "STREAMOFF");
|
|
||||||
|
|
||||||
gst_v4l2_allocator_flush (pool->vallocator);
|
|
||||||
|
|
||||||
num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator);
|
num_allocated = gst_v4l2_allocator_num_allocated (pool->vallocator);
|
||||||
|
|
||||||
for (i = 0; i < num_allocated; i++) {
|
for (i = 0; i < num_allocated; i++) {
|
||||||
|
/* Re-enqueue buffers */
|
||||||
if (pool->buffers[i]) {
|
if (pool->buffers[i]) {
|
||||||
GstBufferPool *bpool = (GstBufferPool *) pool;
|
GstBufferPool *bpool = (GstBufferPool *) pool;
|
||||||
GstBuffer *buffer = pool->buffers[i];
|
GstBuffer *buffer = pool->buffers[i];
|
||||||
|
|
||||||
pool->buffers[i] = NULL;
|
pool->buffers[i] = NULL;
|
||||||
pool->num_queued--;
|
|
||||||
|
|
||||||
/* Remove qdata, this will unmap any map data in userptr */
|
/* Remove qdata, this will unmap any map data in
|
||||||
|
* userptr/dmabuf-import */
|
||||||
gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
|
gst_mini_object_set_qdata (GST_MINI_OBJECT (buffer),
|
||||||
GST_V4L2_IMPORT_QUARK, NULL, NULL);
|
GST_V4L2_IMPORT_QUARK, NULL, NULL);
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_OUTPUT (obj->type))
|
if (V4L2_TYPE_IS_OUTPUT (obj->type))
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
else
|
else
|
||||||
/* Give back the outstanding buffer to the pool */
|
gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
|
|
||||||
buffer);
|
g_atomic_int_add (&pool->num_queued, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_return_val_if_fail (pool->num_queued == 0, FALSE);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
g_return_val_if_reached (FALSE);
|
g_assert_not_reached ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool->flushing = FALSE;
|
streamon:
|
||||||
pool->streaming = FALSE;
|
/* Start streaming on capture device only */
|
||||||
|
if (!V4L2_TYPE_IS_OUTPUT (obj->type))
|
||||||
|
gst_v4l2_buffer_pool_streamon (pool);
|
||||||
|
|
||||||
return TRUE;
|
gst_poll_set_flushing (pool->poll, FALSE);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
stop_failed:
|
stop_failed:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
|
GST_ERROR_OBJECT (pool, "device refused to flush");
|
||||||
g_strerror (errno));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
|
|
||||||
{
|
|
||||||
gboolean ret;
|
|
||||||
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
|
||||||
GstV4l2Object *obj = pool->obj;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "stopping pool");
|
|
||||||
|
|
||||||
if (pool->group_released_handler > 0) {
|
|
||||||
g_signal_handler_disconnect (pool->vallocator,
|
|
||||||
pool->group_released_handler);
|
|
||||||
pool->group_released_handler = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_poll_set_flushing (obj->poll, TRUE);
|
|
||||||
if (!stop_streaming (pool))
|
|
||||||
goto stop_failed;
|
|
||||||
|
|
||||||
ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
GstV4l2Return vret;
|
|
||||||
|
|
||||||
vret = gst_v4l2_allocator_stop (pool->vallocator);
|
|
||||||
|
|
||||||
if (vret == GST_V4L2_BUSY) {
|
|
||||||
GST_WARNING_OBJECT (pool, "allocated buffer need to be reclaimed");
|
|
||||||
/* FIXME deal with reclaiming */
|
|
||||||
} else if (vret == GST_V4L2_ERROR) {
|
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
stop_failed:
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
|
|
||||||
g_strerror (errno));
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_v4l2_object_poll (GstV4l2Object * v4l2object)
|
gst_v4l2_buffer_pool_poll (GstV4l2BufferPool * pool)
|
||||||
{
|
{
|
||||||
gint ret;
|
gint ret;
|
||||||
|
|
||||||
if (v4l2object->can_poll_device) {
|
if (pool->can_poll_device) {
|
||||||
GST_LOG_OBJECT (v4l2object->element, "polling device");
|
GST_LOG_OBJECT (pool, "polling device");
|
||||||
ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
|
ret = gst_poll_wait (pool->poll, GST_CLOCK_TIME_NONE);
|
||||||
|
GST_LOG_OBJECT (pool, "device polled %i %s", ret, g_strerror (errno));
|
||||||
if (G_UNLIKELY (ret < 0)) {
|
if (G_UNLIKELY (ret < 0)) {
|
||||||
if (errno == EBUSY)
|
if (errno == EBUSY)
|
||||||
goto stopped;
|
goto stopped;
|
||||||
if (errno == ENXIO) {
|
if (errno == ENXIO) {
|
||||||
GST_WARNING_OBJECT (v4l2object->element,
|
GST_WARNING_OBJECT (pool,
|
||||||
"v4l2 device doesn't support polling. Disabling");
|
"v4l2 device doesn't support polling. Disabling");
|
||||||
v4l2object->can_poll_device = FALSE;
|
pool->can_poll_device = FALSE;
|
||||||
} else {
|
} else {
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
if (errno != EAGAIN && errno != EINTR)
|
||||||
goto select_error;
|
goto select_error;
|
||||||
|
@ -948,12 +958,12 @@ gst_v4l2_object_poll (GstV4l2Object * v4l2object)
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
stopped:
|
stopped:
|
||||||
{
|
{
|
||||||
GST_DEBUG ("stop called");
|
GST_DEBUG_OBJECT (pool, "stop called");
|
||||||
return GST_FLOW_FLUSHING;
|
return GST_FLOW_FLUSHING;
|
||||||
}
|
}
|
||||||
select_error:
|
select_error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
|
GST_ELEMENT_ERROR (pool->obj->element, RESOURCE, READ, (NULL),
|
||||||
("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
|
("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -982,7 +992,7 @@ gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
|
||||||
goto queue_failed;
|
goto queue_failed;
|
||||||
|
|
||||||
pool->buffers[index] = buf;
|
pool->buffers[index] = buf;
|
||||||
pool->num_queued++;
|
g_atomic_int_inc (&pool->num_queued);
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
@ -1010,7 +1020,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
|
||||||
GstV4l2MemoryGroup *group;
|
GstV4l2MemoryGroup *group;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
|
if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
|
||||||
goto poll_failed;
|
goto poll_failed;
|
||||||
|
|
||||||
GST_LOG_OBJECT (pool, "dequeueing a buffer");
|
GST_LOG_OBJECT (pool, "dequeueing a buffer");
|
||||||
|
@ -1028,7 +1038,7 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
|
||||||
|
|
||||||
/* mark the buffer outstanding */
|
/* mark the buffer outstanding */
|
||||||
pool->buffers[group->buffer.index] = NULL;
|
pool->buffers[group->buffer.index] = NULL;
|
||||||
pool->num_queued--;
|
g_atomic_int_add (&pool->num_queued, -1);
|
||||||
|
|
||||||
timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp);
|
timestamp = GST_TIMEVAL_TO_TIME (group->buffer.timestamp);
|
||||||
|
|
||||||
|
@ -1092,17 +1102,14 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
||||||
|
GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
|
||||||
GstV4l2Object *obj = pool->obj;
|
GstV4l2Object *obj = pool->obj;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "acquire");
|
GST_DEBUG_OBJECT (pool, "acquire");
|
||||||
|
|
||||||
if (GST_BUFFER_POOL_IS_FLUSHING (bpool))
|
|
||||||
goto flushing;
|
|
||||||
|
|
||||||
/* If this is being called to resurect a lost buffer */
|
/* If this is being called to resurect a lost buffer */
|
||||||
if (params && params->flags & GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT) {
|
if (params && params->flags & GST_V4L2_POOL_ACQUIRE_FLAG_RESURECT) {
|
||||||
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool, buffer,
|
ret = pclass->acquire_buffer (bpool, buffer, params);
|
||||||
params);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,8 +1121,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
|
||||||
case GST_V4L2_IO_RW:
|
case GST_V4L2_IO_RW:
|
||||||
{
|
{
|
||||||
/* take empty buffer from the pool */
|
/* take empty buffer from the pool */
|
||||||
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
|
ret = pclass->acquire_buffer (bpool, buffer, params);
|
||||||
buffer, params);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_V4L2_IO_DMABUF:
|
case GST_V4L2_IO_DMABUF:
|
||||||
|
@ -1129,12 +1135,11 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* start copying buffers when we are running low on buffers */
|
/* start copying buffers when we are running low on buffers */
|
||||||
if (pool->num_queued < pool->copy_threshold) {
|
if (g_atomic_int_get (&pool->num_queued) < pool->copy_threshold) {
|
||||||
GstBuffer *copy;
|
GstBuffer *copy;
|
||||||
|
|
||||||
if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
|
if (GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, MMAP)) {
|
||||||
if (GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
|
if (pclass->acquire_buffer (bpool, ©, params) == GST_FLOW_OK) {
|
||||||
©, params) == GST_FLOW_OK) {
|
|
||||||
gst_v4l2_buffer_pool_release_buffer (bpool, copy);
|
gst_v4l2_buffer_pool_release_buffer (bpool, copy);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1172,8 +1177,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
|
||||||
switch (obj->mode) {
|
switch (obj->mode) {
|
||||||
case GST_V4L2_IO_RW:
|
case GST_V4L2_IO_RW:
|
||||||
/* get an empty buffer */
|
/* get an empty buffer */
|
||||||
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
|
ret = pclass->acquire_buffer (bpool, buffer, params);
|
||||||
buffer, params);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_V4L2_IO_MMAP:
|
case GST_V4L2_IO_MMAP:
|
||||||
|
@ -1181,8 +1185,7 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
|
||||||
case GST_V4L2_IO_USERPTR:
|
case GST_V4L2_IO_USERPTR:
|
||||||
case GST_V4L2_IO_DMABUF_IMPORT:
|
case GST_V4L2_IO_DMABUF_IMPORT:
|
||||||
/* get a free unqueued buffer */
|
/* get a free unqueued buffer */
|
||||||
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
|
ret = pclass->acquire_buffer (bpool, buffer, params);
|
||||||
buffer, params);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1199,19 +1202,13 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
flushing:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (pool, "We are flushing");
|
|
||||||
return GST_FLOW_FLUSHING;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
|
||||||
|
GstBufferPoolClass *pclass = GST_BUFFER_POOL_CLASS (parent_class);
|
||||||
GstV4l2Object *obj = pool->obj;
|
GstV4l2Object *obj = pool->obj;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pool, "release buffer %p", buffer);
|
GST_DEBUG_OBJECT (pool, "release buffer %p", buffer);
|
||||||
|
@ -1224,7 +1221,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
||||||
switch (obj->mode) {
|
switch (obj->mode) {
|
||||||
case GST_V4L2_IO_RW:
|
case GST_V4L2_IO_RW:
|
||||||
/* release back in the pool */
|
/* release back in the pool */
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
|
pclass->release_buffer (bpool, buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_V4L2_IO_DMABUF:
|
case GST_V4L2_IO_DMABUF:
|
||||||
|
@ -1232,23 +1229,17 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
||||||
case GST_V4L2_IO_USERPTR:
|
case GST_V4L2_IO_USERPTR:
|
||||||
case GST_V4L2_IO_DMABUF_IMPORT:
|
case GST_V4L2_IO_DMABUF_IMPORT:
|
||||||
{
|
{
|
||||||
if (pool->flushing) {
|
if (gst_v4l2_is_buffer_valid (buffer, NULL)) {
|
||||||
/* put back on outstanding list */
|
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
|
|
||||||
buffer);
|
|
||||||
} else if (gst_v4l2_is_buffer_valid (buffer, NULL)) {
|
|
||||||
/* queue back in the device */
|
/* queue back in the device */
|
||||||
if (pool->other_pool)
|
if (pool->other_pool)
|
||||||
gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL);
|
gst_v4l2_buffer_pool_prepare_buffer (pool, buffer, NULL);
|
||||||
if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK)
|
if (gst_v4l2_buffer_pool_qbuf (pool, buffer) != GST_FLOW_OK)
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
|
pclass->release_buffer (bpool, buffer);
|
||||||
buffer);
|
|
||||||
} else {
|
} else {
|
||||||
/* Simply release invalide/modified buffer, the allocator will
|
/* Simply release invalide/modified buffer, the allocator will
|
||||||
* give it back later */
|
* give it back later */
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
|
pclass->release_buffer (bpool, buffer);
|
||||||
buffer);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1263,7 +1254,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
||||||
switch (obj->mode) {
|
switch (obj->mode) {
|
||||||
case GST_V4L2_IO_RW:
|
case GST_V4L2_IO_RW:
|
||||||
/* release back in the pool */
|
/* release back in the pool */
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
|
pclass->release_buffer (bpool, buffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_V4L2_IO_MMAP:
|
case GST_V4L2_IO_MMAP:
|
||||||
|
@ -1278,8 +1269,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
||||||
/* Simply release invalide/modified buffer, the allocator will
|
/* Simply release invalide/modified buffer, the allocator will
|
||||||
* give it back later */
|
* give it back later */
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
|
pclass->release_buffer (bpool, buffer);
|
||||||
buffer);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,8 +1287,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
|
||||||
gst_v4l2_allocator_reset_group (pool->vallocator, group);
|
gst_v4l2_allocator_reset_group (pool->vallocator, group);
|
||||||
|
|
||||||
/* playback, put the buffer back in the queue to refill later. */
|
/* playback, put the buffer back in the queue to refill later. */
|
||||||
GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
|
pclass->release_buffer (bpool, buffer);
|
||||||
buffer);
|
|
||||||
} else {
|
} else {
|
||||||
/* We keep a ref on queued buffer, so this should never happen */
|
/* We keep a ref on queued buffer, so this should never happen */
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
@ -1332,6 +1321,8 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
|
||||||
if (pool->video_fd >= 0)
|
if (pool->video_fd >= 0)
|
||||||
v4l2_close (pool->video_fd);
|
v4l2_close (pool->video_fd);
|
||||||
|
|
||||||
|
gst_poll_free (pool->poll);
|
||||||
|
|
||||||
if (pool->vallocator)
|
if (pool->vallocator)
|
||||||
gst_object_unref (pool->vallocator);
|
gst_object_unref (pool->vallocator);
|
||||||
|
|
||||||
|
@ -1352,6 +1343,8 @@ gst_v4l2_buffer_pool_finalize (GObject * object)
|
||||||
static void
|
static void
|
||||||
gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
|
gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
|
||||||
{
|
{
|
||||||
|
pool->poll = gst_poll_new (TRUE);
|
||||||
|
pool->can_poll_device = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1368,6 +1361,8 @@ gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
|
||||||
bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
|
bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
|
||||||
bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
|
bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
|
||||||
bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
|
bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
|
||||||
|
bufferpool_class->flush_start = gst_v4l2_buffer_pool_flush_start;
|
||||||
|
bufferpool_class->flush_stop = gst_v4l2_buffer_pool_flush_stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1385,6 +1380,7 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
|
||||||
GstStructure *config;
|
GstStructure *config;
|
||||||
gchar *name, *parent_name;
|
gchar *name, *parent_name;
|
||||||
gint fd;
|
gint fd;
|
||||||
|
GstPollFD pollfd = GST_POLL_FD_INIT;
|
||||||
|
|
||||||
fd = v4l2_dup (obj->video_fd);
|
fd = v4l2_dup (obj->video_fd);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
@ -1400,8 +1396,16 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
|
||||||
"name", name, NULL);
|
"name", name, NULL);
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
|
pollfd.fd = fd;
|
||||||
|
gst_poll_add_fd (pool->poll, &pollfd);
|
||||||
|
if (V4L2_TYPE_IS_OUTPUT (obj->type))
|
||||||
|
gst_poll_fd_ctl_write (pool->poll, &pollfd, TRUE);
|
||||||
|
else
|
||||||
|
gst_poll_fd_ctl_read (pool->poll, &pollfd, TRUE);
|
||||||
|
|
||||||
pool->video_fd = fd;
|
pool->video_fd = fd;
|
||||||
pool->obj = obj;
|
pool->obj = obj;
|
||||||
|
pool->can_poll_device = TRUE;
|
||||||
|
|
||||||
pool->vallocator =
|
pool->vallocator =
|
||||||
gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format);
|
gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format);
|
||||||
|
@ -1440,7 +1444,7 @@ gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf)
|
||||||
gst_buffer_map (buf, &map, GST_MAP_WRITE);
|
gst_buffer_map (buf, &map, GST_MAP_WRITE);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
|
if ((res = gst_v4l2_buffer_pool_poll (pool)) != GST_FLOW_OK)
|
||||||
goto poll_error;
|
goto poll_error;
|
||||||
|
|
||||||
amount = v4l2_read (obj->video_fd, map.data, toread);
|
amount = v4l2_read (obj->video_fd, map.data, toread);
|
||||||
|
@ -1508,6 +1512,9 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
|
||||||
|
|
||||||
g_return_val_if_fail (gst_buffer_pool_is_active (bpool), GST_FLOW_ERROR);
|
g_return_val_if_fail (gst_buffer_pool_is_active (bpool), GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
if (GST_BUFFER_POOL_IS_FLUSHING (pool))
|
||||||
|
return GST_FLOW_FLUSHING;
|
||||||
|
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
||||||
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
||||||
|
@ -1626,14 +1633,12 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf)
|
||||||
|
|
||||||
/* if we are not streaming yet (this is the first buffer, start
|
/* if we are not streaming yet (this is the first buffer, start
|
||||||
* streaming now */
|
* streaming now */
|
||||||
if (!pool->streaming) {
|
if (!gst_v4l2_buffer_pool_streamon (pool)) {
|
||||||
if (!start_streaming (pool)) {
|
gst_buffer_unref (to_queue);
|
||||||
gst_buffer_unref (to_queue);
|
goto start_failed;
|
||||||
goto start_failed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pool->num_queued ==
|
if (g_atomic_int_get (&pool->num_queued) ==
|
||||||
gst_v4l2_allocator_num_allocated (pool->vallocator)) {
|
gst_v4l2_allocator_num_allocated (pool->vallocator)) {
|
||||||
GstBuffer *out;
|
GstBuffer *out;
|
||||||
/* all buffers are queued, try to dequeue one and release it back
|
/* all buffers are queued, try to dequeue one and release it back
|
||||||
|
@ -1692,53 +1697,6 @@ start_failed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_v4l2_buffer_pool_stop_streaming:
|
|
||||||
* @bpool: a #GstBufferPool
|
|
||||||
*
|
|
||||||
* First, set obj->poll to be flushing
|
|
||||||
* Call STREAMOFF to clear QUEUED flag on every driver buffers.
|
|
||||||
* Then release all buffers that are in pool->buffers array.
|
|
||||||
*
|
|
||||||
* Returns: TRUE on success.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
gst_v4l2_buffer_pool_stop_streaming (GstV4l2BufferPool * pool)
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (pool, "stop streaming");
|
|
||||||
|
|
||||||
if (!stop_streaming (pool))
|
|
||||||
goto stop_failed;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
stop_failed:
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (pool, "failed to stop streaming");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
gst_v4l2_buffer_pool_start_streaming (GstV4l2BufferPool * pool)
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (pool, "start straming");
|
|
||||||
|
|
||||||
if (!start_streaming (pool))
|
|
||||||
goto start_failed;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
start_failed:
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (pool, "failed to start streaming");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
|
gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
|
||||||
GstBufferPool * other_pool)
|
GstBufferPool * other_pool)
|
||||||
|
|
|
@ -50,6 +50,8 @@ struct _GstV4l2BufferPool
|
||||||
|
|
||||||
GstV4l2Object *obj; /* the v4l2 object */
|
GstV4l2Object *obj; /* the v4l2 object */
|
||||||
gint video_fd; /* a dup(2) of the v4l2object's video_fd */
|
gint video_fd; /* a dup(2) of the v4l2object's video_fd */
|
||||||
|
GstPoll *poll; /* a poll for video_fd */
|
||||||
|
gboolean can_poll_device;
|
||||||
|
|
||||||
GstV4l2Allocator *vallocator;
|
GstV4l2Allocator *vallocator;
|
||||||
GstAllocator *allocator;
|
GstAllocator *allocator;
|
||||||
|
@ -84,9 +86,6 @@ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object *obj, GstCaps *c
|
||||||
|
|
||||||
GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * bpool, GstBuffer ** buf);
|
GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * bpool, GstBuffer ** buf);
|
||||||
|
|
||||||
gboolean gst_v4l2_buffer_pool_stop_streaming (GstV4l2BufferPool * pool);
|
|
||||||
gboolean gst_v4l2_buffer_pool_start_streaming (GstV4l2BufferPool * pool);
|
|
||||||
|
|
||||||
void gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
|
void gst_v4l2_buffer_pool_set_other_pool (GstV4l2BufferPool * pool,
|
||||||
GstBufferPool * other_pool);
|
GstBufferPool * other_pool);
|
||||||
|
|
||||||
|
|
|
@ -431,7 +431,6 @@ gst_v4l2_object_new (GstElement * element,
|
||||||
v4l2object->update_fps_func = update_fps_func;
|
v4l2object->update_fps_func = update_fps_func;
|
||||||
|
|
||||||
v4l2object->video_fd = -1;
|
v4l2object->video_fd = -1;
|
||||||
v4l2object->poll = gst_poll_new (TRUE);
|
|
||||||
v4l2object->active = FALSE;
|
v4l2object->active = FALSE;
|
||||||
v4l2object->videodev = g_strdup (default_device);
|
v4l2object->videodev = g_strdup (default_device);
|
||||||
|
|
||||||
|
@ -461,9 +460,6 @@ gst_v4l2_object_destroy (GstV4l2Object * v4l2object)
|
||||||
if (v4l2object->videodev)
|
if (v4l2object->videodev)
|
||||||
g_free (v4l2object->videodev);
|
g_free (v4l2object->videodev);
|
||||||
|
|
||||||
if (v4l2object->poll)
|
|
||||||
gst_poll_free (v4l2object->poll);
|
|
||||||
|
|
||||||
if (v4l2object->channel)
|
if (v4l2object->channel)
|
||||||
g_free (v4l2object->channel);
|
g_free (v4l2object->channel);
|
||||||
|
|
||||||
|
@ -3043,19 +3039,27 @@ gst_v4l2_object_caps_equal (GstV4l2Object * v4l2object, GstCaps * caps)
|
||||||
gboolean
|
gboolean
|
||||||
gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
|
gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
|
||||||
{
|
{
|
||||||
GST_LOG_OBJECT (v4l2object->element, "flush poll");
|
gboolean ret = TRUE;
|
||||||
gst_poll_set_flushing (v4l2object->poll, TRUE);
|
|
||||||
|
|
||||||
return TRUE;
|
GST_LOG_OBJECT (v4l2object->element, "start flushing");
|
||||||
|
|
||||||
|
if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
|
||||||
|
gst_buffer_pool_set_flushing (v4l2object->pool, TRUE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
|
gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
|
||||||
{
|
{
|
||||||
GST_LOG_OBJECT (v4l2object->element, "flush stop poll");
|
gboolean ret = TRUE;
|
||||||
gst_poll_set_flushing (v4l2object->poll, FALSE);
|
|
||||||
|
|
||||||
return TRUE;
|
GST_LOG_OBJECT (v4l2object->element, "stop flushing");
|
||||||
|
|
||||||
|
if (v4l2object->pool && gst_buffer_pool_is_active (v4l2object->pool))
|
||||||
|
gst_buffer_pool_set_flushing (v4l2object->pool, FALSE);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|
|
@ -88,8 +88,6 @@ struct _GstV4l2Object {
|
||||||
/* the video-device's file descriptor */
|
/* the video-device's file descriptor */
|
||||||
gint video_fd;
|
gint video_fd;
|
||||||
GstV4l2IOMode mode;
|
GstV4l2IOMode mode;
|
||||||
GstPoll * poll;
|
|
||||||
gboolean can_poll_device;
|
|
||||||
|
|
||||||
gboolean active;
|
gboolean active;
|
||||||
gboolean streaming;
|
gboolean streaming;
|
||||||
|
|
|
@ -533,19 +533,6 @@ gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
|
||||||
gst_v4l2_object_unlock (self->v4l2output);
|
gst_v4l2_object_unlock (self->v4l2output);
|
||||||
gst_v4l2_object_unlock (self->v4l2capture);
|
gst_v4l2_object_unlock (self->v4l2capture);
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_FLUSH_STOP:
|
|
||||||
GST_DEBUG_OBJECT (self, "flush stop");
|
|
||||||
|
|
||||||
if (self->v4l2output->pool) {
|
|
||||||
gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
|
|
||||||
(self->v4l2output->pool));
|
|
||||||
gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
|
|
||||||
(self->v4l2capture->pool));
|
|
||||||
gst_v4l2_object_unlock_stop (self->v4l2output);
|
|
||||||
}
|
|
||||||
if (self->v4l2capture->pool)
|
|
||||||
gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
|
|
||||||
(self->v4l2capture->pool));
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -555,12 +542,9 @@ gst_v4l2_transform_sink_event (GstBaseTransform * trans, GstEvent * event)
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_FLUSH_STOP:
|
case GST_EVENT_FLUSH_STOP:
|
||||||
/* Buffer should be back now */
|
/* Buffer should be back now */
|
||||||
if (self->v4l2capture->pool) {
|
GST_DEBUG_OBJECT (self, "flush stop");
|
||||||
gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
|
gst_v4l2_object_unlock_stop (self->v4l2capture);
|
||||||
(self->v4l2capture->pool));
|
gst_v4l2_object_unlock_stop (self->v4l2output);
|
||||||
gst_v4l2_object_unlock_stop (self->v4l2capture);
|
|
||||||
}
|
|
||||||
GST_DEBUG_OBJECT (self, "flush stop done");
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -259,23 +259,23 @@ gst_v4l2_video_dec_flush (GstVideoDecoder * decoder)
|
||||||
{
|
{
|
||||||
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
|
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Flushing");
|
GST_DEBUG_OBJECT (self, "Flushed");
|
||||||
|
|
||||||
/* Wait for capture thread to stop */
|
/* Ensure the processing thread has stopped for the reverse playback
|
||||||
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
* discount case */
|
||||||
gst_v4l2_object_unlock (self->v4l2capture);
|
if (g_atomic_int_get (&self->processing)) {
|
||||||
gst_pad_stop_task (decoder->srcpad);
|
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
||||||
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
|
|
||||||
|
gst_v4l2_object_unlock (self->v4l2output);
|
||||||
|
gst_v4l2_object_unlock (self->v4l2capture);
|
||||||
|
gst_pad_stop_task (decoder->srcpad);
|
||||||
|
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
||||||
|
}
|
||||||
|
|
||||||
self->output_flow = GST_FLOW_OK;
|
self->output_flow = GST_FLOW_OK;
|
||||||
|
|
||||||
if (self->v4l2output->pool)
|
gst_v4l2_object_unlock_stop (self->v4l2output);
|
||||||
gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
|
gst_v4l2_object_unlock_stop (self->v4l2capture);
|
||||||
(self->v4l2output->pool));
|
|
||||||
|
|
||||||
if (self->v4l2capture->pool)
|
|
||||||
gst_v4l2_buffer_pool_stop_streaming (GST_V4L2_BUFFER_POOL
|
|
||||||
(self->v4l2capture->pool));
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -308,14 +308,12 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
|
||||||
v4l2output->pool), &buffer);
|
v4l2output->pool), &buffer);
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
}
|
}
|
||||||
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
|
|
||||||
|
|
||||||
/* Ensure the processing thread has stopped */
|
/* and ensure the processing thread has stopped in case another error
|
||||||
if (g_atomic_int_get (&self->processing)) {
|
* occured. */
|
||||||
gst_v4l2_object_unlock (self->v4l2capture);
|
gst_v4l2_object_unlock (self->v4l2capture);
|
||||||
gst_pad_stop_task (decoder->srcpad);
|
gst_pad_stop_task (decoder->srcpad);
|
||||||
g_assert (g_atomic_int_get (&self->processing) == FALSE);
|
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == GST_FLOW_FLUSHING)
|
if (ret == GST_FLOW_FLUSHING)
|
||||||
ret = self->output_flow;
|
ret = self->output_flow;
|
||||||
|
@ -475,11 +473,9 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
|
||||||
gst_v4l2_object_unlock_stop (self->v4l2output);
|
|
||||||
ret =
|
ret =
|
||||||
gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
|
gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL (self->
|
||||||
v4l2output->pool), &codec_data);
|
v4l2output->pool), &codec_data);
|
||||||
gst_v4l2_object_unlock (self->v4l2output);
|
|
||||||
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
|
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
|
||||||
|
|
||||||
gst_buffer_unref (codec_data);
|
gst_buffer_unref (codec_data);
|
||||||
|
@ -517,14 +513,6 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Starting decoding thread");
|
GST_DEBUG_OBJECT (self, "Starting decoding thread");
|
||||||
|
|
||||||
/* Enable processing input */
|
|
||||||
if (!gst_v4l2_buffer_pool_start_streaming (GST_V4L2_BUFFER_POOL
|
|
||||||
(self->v4l2capture->pool)))
|
|
||||||
goto start_streaming_failed;
|
|
||||||
|
|
||||||
gst_v4l2_object_unlock_stop (self->v4l2output);
|
|
||||||
gst_v4l2_object_unlock_stop (self->v4l2capture);
|
|
||||||
|
|
||||||
/* Start the processing task, when it quits, the task will disable input
|
/* Start the processing task, when it quits, the task will disable input
|
||||||
* processing to unlock input if draining, or prevent potential block */
|
* processing to unlock input if draining, or prevent potential block */
|
||||||
g_atomic_int_set (&self->processing, TRUE);
|
g_atomic_int_set (&self->processing, TRUE);
|
||||||
|
@ -558,13 +546,6 @@ not_negotiated:
|
||||||
ret = GST_FLOW_NOT_NEGOTIATED;
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
start_streaming_failed:
|
|
||||||
{
|
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
|
|
||||||
(_("Failed to re-enabled decoder.")),
|
|
||||||
("Could not re-enqueue and start streaming on decide."));
|
|
||||||
return GST_FLOW_ERROR;
|
|
||||||
}
|
|
||||||
activate_failed:
|
activate_failed:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
|
GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
|
||||||
|
@ -686,16 +667,29 @@ static gboolean
|
||||||
gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
|
gst_v4l2_video_dec_sink_event (GstVideoDecoder * decoder, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
|
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (decoder);
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_FLUSH_START:
|
case GST_EVENT_FLUSH_START:
|
||||||
gst_v4l2_object_unlock (self->v4l2output);
|
gst_v4l2_object_unlock (self->v4l2output);
|
||||||
gst_v4l2_object_unlock (self->v4l2capture);
|
gst_v4l2_object_unlock (self->v4l2capture);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
|
ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_FLUSH_START:
|
||||||
|
/* The processing thread should stop now, wait for it */
|
||||||
|
gst_pad_stop_task (decoder->srcpad);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
|
@ -703,11 +697,13 @@ gst_v4l2_video_dec_change_state (GstElement * element,
|
||||||
GstStateChange transition)
|
GstStateChange transition)
|
||||||
{
|
{
|
||||||
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
|
GstV4l2VideoDec *self = GST_V4L2_VIDEO_DEC (element);
|
||||||
|
GstVideoDecoder *decoder = GST_VIDEO_DECODER (element);
|
||||||
|
|
||||||
if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
|
if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
|
||||||
g_atomic_int_set (&self->active, FALSE);
|
g_atomic_int_set (&self->active, FALSE);
|
||||||
gst_v4l2_object_unlock (self->v4l2output);
|
gst_v4l2_object_unlock (self->v4l2output);
|
||||||
gst_v4l2_object_unlock (self->v4l2capture);
|
gst_v4l2_object_unlock (self->v4l2capture);
|
||||||
|
gst_pad_stop_task (decoder->srcpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||||
|
|
|
@ -514,7 +514,6 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int libv4l2_fd;
|
int libv4l2_fd;
|
||||||
GstPollFD pollfd = GST_POLL_FD_INIT;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
|
GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
|
||||||
v4l2object->videodev);
|
v4l2object->videodev);
|
||||||
|
@ -551,8 +550,6 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
||||||
if (libv4l2_fd != -1)
|
if (libv4l2_fd != -1)
|
||||||
v4l2object->video_fd = libv4l2_fd;
|
v4l2object->video_fd = libv4l2_fd;
|
||||||
|
|
||||||
v4l2object->can_poll_device = TRUE;
|
|
||||||
|
|
||||||
/* get capabilities, error will be posted */
|
/* get capabilities, error will be posted */
|
||||||
if (!gst_v4l2_get_capabilities (v4l2object))
|
if (!gst_v4l2_get_capabilities (v4l2object))
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -589,14 +586,6 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
|
||||||
"Opened device '%s' (%s) successfully",
|
"Opened device '%s' (%s) successfully",
|
||||||
v4l2object->vcap.card, v4l2object->videodev);
|
v4l2object->vcap.card, v4l2object->videodev);
|
||||||
|
|
||||||
pollfd.fd = v4l2object->video_fd;
|
|
||||||
gst_poll_add_fd (v4l2object->poll, &pollfd);
|
|
||||||
if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
|
|
||||||
|| v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
|
|
||||||
gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
|
|
||||||
else
|
|
||||||
gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
|
|
||||||
|
|
||||||
if (v4l2object->extra_controls)
|
if (v4l2object->extra_controls)
|
||||||
gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
|
gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
|
||||||
|
|
||||||
|
@ -672,8 +661,6 @@ error:
|
||||||
gboolean
|
gboolean
|
||||||
gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
|
gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
|
||||||
{
|
{
|
||||||
GstPollFD pollfd = GST_POLL_FD_INIT;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (v4l2object->element, "Trying to dup device %s",
|
GST_DEBUG_OBJECT (v4l2object->element, "Trying to dup device %s",
|
||||||
other->videodev);
|
other->videodev);
|
||||||
|
|
||||||
|
@ -696,16 +683,7 @@ gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
|
||||||
"Cloned device '%s' (%s) successfully",
|
"Cloned device '%s' (%s) successfully",
|
||||||
v4l2object->vcap.card, v4l2object->videodev);
|
v4l2object->vcap.card, v4l2object->videodev);
|
||||||
|
|
||||||
pollfd.fd = v4l2object->video_fd;
|
|
||||||
gst_poll_add_fd (v4l2object->poll, &pollfd);
|
|
||||||
if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE
|
|
||||||
|| v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
|
|
||||||
gst_poll_fd_ctl_read (v4l2object->poll, &pollfd, TRUE);
|
|
||||||
else
|
|
||||||
gst_poll_fd_ctl_write (v4l2object->poll, &pollfd, TRUE);
|
|
||||||
|
|
||||||
v4l2object->never_interlaced = other->never_interlaced;
|
v4l2object->never_interlaced = other->never_interlaced;
|
||||||
v4l2object->can_poll_device = TRUE;
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -728,7 +706,6 @@ not_open:
|
||||||
gboolean
|
gboolean
|
||||||
gst_v4l2_close (GstV4l2Object * v4l2object)
|
gst_v4l2_close (GstV4l2Object * v4l2object)
|
||||||
{
|
{
|
||||||
GstPollFD pollfd = GST_POLL_FD_INIT;
|
|
||||||
GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
|
GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
|
||||||
v4l2object->videodev);
|
v4l2object->videodev);
|
||||||
|
|
||||||
|
@ -737,8 +714,6 @@ gst_v4l2_close (GstV4l2Object * v4l2object)
|
||||||
|
|
||||||
/* close device */
|
/* close device */
|
||||||
v4l2_close (v4l2object->video_fd);
|
v4l2_close (v4l2object->video_fd);
|
||||||
pollfd.fd = v4l2object->video_fd;
|
|
||||||
gst_poll_remove_fd (v4l2object->poll, &pollfd);
|
|
||||||
v4l2object->video_fd = -1;
|
v4l2object->video_fd = -1;
|
||||||
|
|
||||||
/* empty lists */
|
/* empty lists */
|
||||||
|
|
Loading…
Reference in a new issue