diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-06-09 14:29:41 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-06-12 21:19:58 +0300 |
commit | 2bb0cfbf8137e02cc32aae3b36f85ef7300e8936 (patch) | |
tree | 42899dbeb32459722d27606bd79848a25a8c5e16 /lib/v4l2-source.c | |
parent | df21a9349a256fd2bea1f8701af198b312682d39 (diff) |
Split UVC gadget into a library and test application
Split the project into a UVC gadget library and a test application. To
avoid rolling out a custom build system, switch to CMake.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'lib/v4l2-source.c')
-rw-r--r-- | lib/v4l2-source.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/lib/v4l2-source.c b/lib/v4l2-source.c new file mode 100644 index 0000000..7eced6a --- /dev/null +++ b/lib/v4l2-source.c @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * V4L2 video source + * + * Copyright (C) 2018 Laurent Pinchart + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "events.h" +#include "tools.h" +#include "v4l2.h" +#include "v4l2-source.h" +#include "video-buffers.h" + +struct v4l2_source { + struct video_source src; + + struct v4l2_device *vdev; +}; + +#define to_v4l2_source(s) container_of(s, struct v4l2_source, src) + +static void v4l2_source_video_process(void *d) +{ + struct v4l2_source *src = d; + struct video_buffer buf; + int ret; + + ret = v4l2_dequeue_buffer(src->vdev, &buf); + if (ret < 0) + return; + + src->src.handler(src->src.handler_data, &src->src, &buf); +} + +static void v4l2_source_destroy(struct video_source *s) +{ + struct v4l2_source *src = to_v4l2_source(s); + + v4l2_close(src->vdev); + free(src); +} + +static int v4l2_source_set_format(struct video_source *s, + struct v4l2_pix_format *fmt) +{ + struct v4l2_source *src = to_v4l2_source(s); + + return v4l2_set_format(src->vdev, fmt); +} + +static int v4l2_source_alloc_buffers(struct video_source *s, unsigned int nbufs) +{ + struct v4l2_source *src = to_v4l2_source(s); + + return v4l2_alloc_buffers(src->vdev, V4L2_MEMORY_MMAP, nbufs); +} + +static int v4l2_source_export_buffers(struct video_source *s, + struct video_buffer_set **bufs) +{ + struct v4l2_source *src = to_v4l2_source(s); + struct video_buffer_set *buffers; + unsigned int i; + int ret; + + ret = v4l2_export_buffers(src->vdev); + if (ret < 0) + return ret; + + buffers = video_buffer_set_new(src->vdev->buffers.nbufs); + if (!buffers) + return -ENOMEM; + + for (i = 0; i < src->vdev->buffers.nbufs; ++i) { + struct video_buffer *buffer = &src->vdev->buffers.buffers[i]; + + buffers->buffers[i].size = buffer->size; + buffers->buffers[i].dmabuf = buffer->dmabuf; + } + + *bufs = buffers; + return 0; +} + +static int v4l2_source_free_buffers(struct video_source *s) +{ + struct v4l2_source *src = to_v4l2_source(s); + + return v4l2_free_buffers(src->vdev); +} + +static int v4l2_source_stream_on(struct video_source *s) +{ + struct v4l2_source *src = to_v4l2_source(s); + unsigned int i; + int ret; + + /* Queue all buffers. */ + for (i = 0; i < src->vdev->buffers.nbufs; ++i) { + struct video_buffer buf = { + .index = i, + .size = src->vdev->buffers.buffers[i].size, + .dmabuf = src->vdev->buffers.buffers[i].dmabuf, + }; + + ret = v4l2_queue_buffer(src->vdev, &buf); + if (ret < 0) + return ret; + } + + ret = v4l2_stream_on(src->vdev); + if (ret < 0) + return ret; + + events_watch_fd(src->src.events, src->vdev->fd, EVENT_READ, + v4l2_source_video_process, src); + + return 0; +} + +static int v4l2_source_stream_off(struct video_source *s) +{ + struct v4l2_source *src = to_v4l2_source(s); + + events_unwatch_fd(src->src.events, src->vdev->fd, EVENT_READ); + + return v4l2_stream_off(src->vdev); +} + +static int v4l2_source_queue_buffer(struct video_source *s, + struct video_buffer *buf) +{ + struct v4l2_source *src = to_v4l2_source(s); + + return v4l2_queue_buffer(src->vdev, buf); +} + +static const struct video_source_ops v4l2_source_ops = { + .destroy = v4l2_source_destroy, + .set_format = v4l2_source_set_format, + .alloc_buffers = v4l2_source_alloc_buffers, + .export_buffers = v4l2_source_export_buffers, + .free_buffers = v4l2_source_free_buffers, + .stream_on = v4l2_source_stream_on, + .stream_off = v4l2_source_stream_off, + .queue_buffer = v4l2_source_queue_buffer, +}; + +struct video_source *v4l2_video_source_create(const char *devname) +{ + struct v4l2_source *src; + + src = malloc(sizeof *src); + if (!src) + return NULL; + + memset(src, 0, sizeof *src); + src->src.ops = &v4l2_source_ops; + + src->vdev = v4l2_open(devname); + if (!src->vdev) { + free(src); + return NULL; + } + + return &src->src; +} + +void v4l2_video_source_init(struct video_source *s, struct events *events) +{ + struct v4l2_source *src = to_v4l2_source(s); + + src->src.events = events; +} |