summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Elder <paul.elder@ideasonboard.com>2022-11-22 10:54:52 +0000
committerKieran Bingham <kieran.bingham@ideasonboard.com>2022-11-22 16:02:25 +0000
commitd11fa45c11dfce99a737f46d7d6e41f280e01ae0 (patch)
treee5823539a8e41772848c3f071978237ebdb7c6d4
parent6fe259939e375ed8e8bd604e93cabbf664a20de5 (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.c83
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);
}