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);  } | 
