diff options
author | Paul Elder <paul.elder@ideasonboard.com> | 2022-11-22 10:54:52 +0000 |
---|---|---|
committer | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2022-11-22 16:02:25 +0000 |
commit | d11fa45c11dfce99a737f46d7d6e41f280e01ae0 (patch) | |
tree | e5823539a8e41772848c3f071978237ebdb7c6d4 | |
parent | 6fe259939e375ed8e8bd604e93cabbf664a20de5 (diff) |
stream: allow buffers to be allocated on uvc side
We want to allow video sources whose data is generated in userspace.
Currently buffers are allocated on the V4L2-backed video source and
exported to the uvc-gadget's V4L2 device. Since a video source with
data generated in userspace will not be backed by a V4L2 device, we
allow a way for buffers to be allocated on uvc-gadget's V4L2 device.
As a corollary, the way the buffers are passed has to be changed as
well. Previously they were queued and dequeued between the V4L2 video
source and uvc and vice versa. To allow a video source not backed by
a V4L2 device, we allow an alternative flow where they are dequeued and
queued from and to uvc, and giving a chance to the video source to fill
the buffer in between.
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r-- | lib/stream.c | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/lib/stream.c b/lib/stream.c index 1988e7c..63ccb1b 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -60,13 +60,28 @@ static void uvc_stream_uvc_process(void *d) video_source_queue_buffer(stream->src, &buf); } -static int uvc_stream_start(struct uvc_stream *stream) +static void uvc_stream_uvc_process_no_buf(void *d) { + struct uvc_stream *stream = d; struct v4l2_device *sink = uvc_v4l2_device(stream->uvc); - struct video_buffer_set *buffers = NULL; + struct video_buffer buf; int ret; - printf("Starting video stream.\n"); + ret = v4l2_dequeue_buffer(sink, &buf); + if (ret < 0) + return; + + video_source_fill_buffer(stream->src, &buf); + + v4l2_queue_buffer(sink, &buf); +} + + +static int uvc_stream_start_alloc(struct uvc_stream *stream) +{ + struct v4l2_device *sink = uvc_v4l2_device(stream->uvc); + struct video_buffer_set *buffers = NULL; + int ret; /* Allocate and export the buffers on the source. */ ret = video_source_alloc_buffers(stream->src, 4); @@ -116,6 +131,64 @@ error_free_source: return ret; } +static int uvc_stream_start_no_alloc(struct uvc_stream *stream) +{ + struct v4l2_device *sink = uvc_v4l2_device(stream->uvc); + int ret; + unsigned int i; + + /* Allocate buffers on the sink. */ + ret = v4l2_alloc_buffers(sink, V4L2_MEMORY_MMAP, 4); + if (ret < 0) { + printf("Failed to allocate sink buffers: %s (%d)\n", + strerror(-ret), -ret); + return ret; + } + + /* mmap buffers. */ + ret = v4l2_mmap_buffers(sink); + if (ret < 0) { + printf("Failed to query sink buffers: %s (%d)\n", + strerror(-ret), -ret); + return ret; + } + + /* Queue buffers to sink. */ + for (i = 0; i < sink->buffers.nbufs; ++i) { + struct video_buffer buf = { + .index = i, + .size = sink->buffers.buffers[i].size, + .mem = sink->buffers.buffers[i].mem, + }; + + video_source_fill_buffer(stream->src, &buf); + ret = v4l2_queue_buffer(sink, &buf); + if (ret < 0) + return ret; + } + + /* Start the source and sink. */ + video_source_stream_on(stream->src); + ret = v4l2_stream_on(sink); + if (ret < 0) + return ret; + + events_watch_fd(stream->events, sink->fd, EVENT_WRITE, + uvc_stream_uvc_process_no_buf, stream); + + return 0; +} + +static int uvc_stream_start(struct uvc_stream *stream) +{ + printf("Starting video stream.\n"); + + if (stream->src->ops->alloc_buffers) + return uvc_stream_start_alloc(stream); + else + return uvc_stream_start_no_alloc(stream); +} + static int uvc_stream_stop(struct uvc_stream *stream) { struct v4l2_device *sink = uvc_v4l2_device(stream->uvc); @@ -216,5 +289,7 @@ void uvc_stream_set_video_source(struct uvc_stream *stream, { stream->src = src; - video_source_set_buffer_handler(src, uvc_stream_source_process, stream); + if (stream->src->ops->alloc_buffers) + video_source_set_buffer_handler(src, uvc_stream_source_process, + stream); } |