diff options
author | Michael Olbrich <m.olbrich@pengutronix.de> | 2012-04-23 18:00:01 +0200 |
---|---|---|
committer | Michael Olbrich <m.olbrich@pengutronix.de> | 2013-09-13 16:38:29 +0200 |
commit | 80ce167431612e22de35238a6df49121b0e13678 (patch) | |
tree | 4d9a61f1672303aca51f273acd2e6a26eb41d478 | |
parent | b280671581a17c96b3cad5f6e498f5a494b6b672 (diff) | |
download | gst-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.c | 162 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.c | 9 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.h | 3 |
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); |