summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Olbrich <m.olbrich@pengutronix.de>2012-04-23 18:00:01 +0200
committerMichael Olbrich <m.olbrich@pengutronix.de>2013-09-13 16:38:29 +0200
commit80ce167431612e22de35238a6df49121b0e13678 (patch)
tree4d9a61f1672303aca51f273acd2e6a26eb41d478
parentb280671581a17c96b3cad5f6e498f5a494b6b672 (diff)
downloadgst-plugins-good-80ce167431612e22de35238a6df49121b0e13678.tar.gz
gst-plugins-good-80ce167431612e22de35238a6df49121b0e13678.tar.xz
v4l2: initial sink USERPTR support
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
-rw-r--r--sys/v4l2/gstv4l2bufferpool.c162
-rw-r--r--sys/v4l2/gstv4l2object.c9
-rw-r--r--sys/v4l2/gstv4l2object.h3
3 files changed, 157 insertions, 17 deletions
diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c
index b786e8a7d..d3372e6e5 100644
--- a/sys/v4l2/gstv4l2bufferpool.c
+++ b/sys/v4l2/gstv4l2bufferpool.c
@@ -157,6 +157,9 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
gst_buffer_new_allocate (pool->allocator, pool->size, &pool->params);
break;
}
+ case GST_V4L2_IO_STREAM:
+ obj->mode = GST_V4L2_IO_MMAP;
+ /* fall through */
case GST_V4L2_IO_MMAP:
case GST_V4L2_IO_DMABUF:
{
@@ -265,6 +268,9 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
break;
}
case GST_V4L2_IO_USERPTR:
+ GST_ERROR_OBJECT (pool, "Unexpected alloc for USERPTR!");
+ return GST_FLOW_ERROR;
+
default:
newbuf = NULL;
g_assert_not_reached ();
@@ -366,6 +372,8 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
break;
case GST_V4L2_IO_DMABUF:
case GST_V4L2_IO_MMAP:
+ case GST_V4L2_IO_USERPTR:
+ case GST_V4L2_IO_STREAM:
{
/* request a reasonable number of buffers when no max specified. We will
* copy when we run out of buffers */
@@ -375,16 +383,27 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
num_buffers = max_buffers;
/* first, lets request buffers, and see how many we can get: */
- GST_DEBUG_OBJECT (pool, "starting, requesting %d MMAP buffers",
- num_buffers);
+ GST_DEBUG_OBJECT (pool, "starting, requesting %d %s buffers",
+ num_buffers, obj->mode != GST_V4L2_IO_USERPTR ? "MMAP" : "USERPTR");
memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
breq.type = obj->type;
- breq.count = num_buffers;
- breq.memory = V4L2_MEMORY_MMAP;
+ if (obj->mode != GST_V4L2_IO_USERPTR) {
+ breq.count = num_buffers;
+ breq.memory = V4L2_MEMORY_MMAP;
+ } else {
+ breq.count = 50;
+ breq.memory = V4L2_MEMORY_DMABUF;
+ }
- if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0)
- goto reqbufs_failed;
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0) {
+ if (obj->mode != GST_V4L2_IO_STREAM)
+ goto reqbufs_failed;
+ obj->mode = GST_V4L2_IO_MMAP;
+ breq.memory = V4L2_MEMORY_MMAP;
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+ goto reqbufs_failed;
+ }
GST_LOG_OBJECT (pool, " count: %u", breq.count);
GST_LOG_OBJECT (pool, " type: %d", breq.type);
@@ -400,7 +419,10 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
/* update min buffers with the amount of buffers we just reserved. We need
* to configure this value in the bufferpool so that the default start
* implementation calls our allocate function */
- min_buffers = breq.count;
+ if (obj->mode != GST_V4L2_IO_USERPTR)
+ min_buffers = breq.count;
+ else
+ min_buffers = 0;
if (max_buffers == 0 || num_buffers < max_buffers) {
/* if we are asked to provide more buffers than we have allocated, start
@@ -413,7 +435,6 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
}
break;
}
- case GST_V4L2_IO_USERPTR:
default:
num_buffers = 0;
copy_threshold = 0;
@@ -586,8 +607,12 @@ gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
/* then free the remaining buffers */
for (n = 0; n < pool->num_buffers; n++) {
- if (pool->buffers[n])
+ if (!pool->buffers[n])
+ continue;
+ if (pool->obj->mode == GST_V4L2_IO_MMAP)
gst_v4l2_buffer_pool_free_buffer (bpool, pool->buffers[n]);
+ else
+ gst_buffer_unref (pool->buffers[n]);
}
pool->num_queued = 0;
g_free (pool->buffers);
@@ -646,15 +671,41 @@ select_error:
static GstFlowReturn
gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
{
- GstV4l2Meta *meta;
+ GstV4l2Meta *meta, tmp_meta;
gint index;
+ gsize size;
meta = GST_V4L2_META_GET (buf);
if (meta == NULL) {
- GST_LOG_OBJECT (pool, "unref copied buffer %p", buf);
- /* no meta, it was a copied buffer that we can unref */
- gst_buffer_unref (buf);
- return GST_FLOW_OK;
+ if (pool->obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ GST_DEBUG_OBJECT (pool, "unref copied buffer %p", buf);
+ /* no meta, it was a copied buffer that we can unref */
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+ } else if (pool->obj->mode != GST_V4L2_IO_USERPTR) {
+ GST_ERROR_OBJECT (pool, "Got broken buffer %p", buf);
+ return GST_FLOW_ERROR;
+ }
+ }
+ if (pool->obj->mode == GST_V4L2_IO_USERPTR) {
+ GstMemory *mem = gst_buffer_peek_memory (buf, 0);
+ if (!gst_is_dmabuf_memory (mem)) {
+ GST_WARNING_OBJECT (pool, "DMABUF memory expected!");
+ return GST_FLOW_ERROR;
+ }
+
+ memset (&tmp_meta, 0, sizeof (GstV4l2Meta));
+
+ meta = &tmp_meta;
+ meta->vbuffer.type = pool->obj->type;
+ meta->vbuffer.memory = V4L2_MEMORY_DMABUF;
+ meta->vbuffer.m.fd = gst_dmabuf_memory_get_fd (mem);
+ gst_buffer_get_sizes (buf, NULL, &size);
+ meta->vbuffer.length = size;
+ /* find an unused index */
+ meta->vbuffer.index = meta->vbuffer.m.fd % pool->num_buffers;
+ while (pool->buffers[meta->vbuffer.index])
+ meta->vbuffer.index = (meta->vbuffer.index + 1) % pool->num_buffers;
}
index = meta->vbuffer.index;
@@ -710,7 +761,10 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
vbuffer.memory = V4L2_MEMORY_DMABUF;
else
#endif
+ if (obj->mode != GST_V4L2_IO_USERPTR)
vbuffer.memory = V4L2_MEMORY_MMAP;
+ else
+ vbuffer.memory = V4L2_MEMORY_DMABUF;
GST_LOG_OBJECT (pool, "doing DQBUF");
if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &vbuffer) < 0)
@@ -888,6 +942,10 @@ gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
buffer, params);
break;
+ case GST_V4L2_IO_STREAM:
+ /* a buffer was requested, so we use MMAP */
+ obj->mode = GST_V4L2_IO_MMAP;
+ /* fall through */
case GST_V4L2_IO_MMAP:
/* get a free unqueued buffer */
ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
@@ -1269,7 +1327,83 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf)
break;
}
+ case GST_V4L2_IO_STREAM:
case GST_V4L2_IO_USERPTR:
+ {
+ GstStructure *config;
+ GstCaps *caps;
+ guint size, old_min, old_max;
+
+ gboolean retry = FALSE;
+
+ if (!gst_buffer_pool_is_active (bpool)) {
+ guint max;
+
+ if (buf->pool) {
+ config = gst_buffer_pool_get_config (buf->pool);
+ gst_buffer_pool_config_get_params (config,
+ NULL, NULL, NULL, &max);
+ } else {
+ max = 0;
+ }
+
+ /* this pool was not activated, configure and activate */
+ GST_DEBUG_OBJECT (pool, "activating pool");
+
+ retry = (obj->mode == GST_V4L2_IO_STREAM);
+ obj->mode = GST_V4L2_IO_USERPTR;
+
+ config = gst_buffer_pool_get_config (bpool);
+ gst_buffer_pool_config_add_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
+ gst_buffer_pool_config_get_params (config, &caps, &size, &old_min,
+ &old_max);
+ /* We want the same number of max buffers as the source
+ * and 0 min buffers to avoid allocating buffers */
+ gst_buffer_pool_config_set_params (config, caps, size, 0, max);
+ gst_buffer_pool_set_config (bpool, config);
+
+ if (!gst_buffer_pool_set_active (bpool, TRUE))
+ goto activate_failed;
+ }
+ if ((ret = gst_v4l2_buffer_pool_qbuf (pool, buf)) != GST_FLOW_OK) {
+ if (!retry)
+ goto done;
+
+ if (!gst_buffer_pool_set_active (bpool, FALSE))
+ goto activate_failed;
+
+ config = gst_buffer_pool_get_config (bpool);
+ gst_buffer_pool_config_set_params (config, caps, size, old_min,
+ old_max);
+
+ obj->mode = GST_V4L2_IO_MMAP;
+ gst_buffer_pool_set_config (bpool, config);
+
+ return gst_v4l2_buffer_pool_process (pool, buf);
+ }
+ gst_buffer_ref (buf);
+
+ /* if we are not streaming yet (this is the first buffer, start
+ * streaming now */
+ if (!pool->streaming)
+ if (!start_streaming (pool))
+ goto start_failed;
+
+ if (pool->num_queued > 1) {
+ /* >1 buffer 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, &buf);
+ if (ret != GST_FLOW_OK)
+ goto done;
+
+ /* release the rendered buffer back into the pool. This wakes up any
+ * thread waiting for a buffer in _acquire() */
+ gst_buffer_unref (buf);
+ }
+ break;
+ }
+
default:
g_assert_not_reached ();
break;
diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
index f3985d40c..d4cbd4f04 100644
--- a/sys/v4l2/gstv4l2object.c
+++ b/sys/v4l2/gstv4l2object.c
@@ -390,6 +390,7 @@ gst_v4l2_io_mode_get_type (void)
{GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
{GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
{GST_V4L2_IO_DMABUF, "GST_V4L2_IO_DMABUF", "dmabuf"},
+ {GST_V4L2_IO_STREAM, "GST_V4L2_IO_STREAM", "streaming"},
{0, NULL, NULL}
};
@@ -2262,8 +2263,12 @@ gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps)
goto method_not_supported;
if (v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
- if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
- mode = GST_V4L2_IO_MMAP;
+ if (v4l2object->req_mode == GST_V4L2_IO_AUTO) {
+ if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ mode = GST_V4L2_IO_STREAM;
+ else
+ mode = GST_V4L2_IO_MMAP;
+ }
} else if (v4l2object->req_mode == GST_V4L2_IO_MMAP)
goto method_not_supported;
diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h
index 2505f4796..322f74990 100644
--- a/sys/v4l2/gstv4l2object.h
+++ b/sys/v4l2/gstv4l2object.h
@@ -76,7 +76,8 @@ typedef enum {
GST_V4L2_IO_RW = 1,
GST_V4L2_IO_MMAP = 2,
GST_V4L2_IO_USERPTR = 3,
- GST_V4L2_IO_DMABUF = 4
+ GST_V4L2_IO_DMABUF = 4,
+ GST_V4L2_IO_STREAM = 5
} GstV4l2IOMode;
typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input);