From df651c5b397a4b6648695cdf725a8243ff512dcd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 9 Jun 2018 12:11:25 +0300 Subject: v4l2: Extract video buffer structure to separate file The v4l2_video_buffer structure describes a video buffer. It is used by the v4l2_device class only, but isn't otherwise tied to V4L2. To prepare for non-V4L2 video sources, extract it to a separate file and rename it to video_buffer. At the same time, add a new video_buffer_set structure to represent as set of video buffers. Signed-off-by: Laurent Pinchart --- Makefile | 3 ++- stream.c | 10 ++++---- v4l2.c | 71 ++++++++++++++++++++++++++++----------------------------- v4l2.h | 49 +++++++++------------------------------ video-buffers.c | 40 ++++++++++++++++++++++++++++++++ video-buffers.h | 48 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 141 insertions(+), 80 deletions(-) create mode 100644 video-buffers.c create mode 100644 video-buffers.h diff --git a/Makefile b/Makefile index 3785140..484f533 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,8 @@ OBJS := \ main.o \ stream.o \ uvc.o \ - v4l2.o + v4l2.o \ + video-buffers.o all: uvc-gadget diff --git a/stream.c b/stream.c index 13b8493..e08aca7 100644 --- a/stream.c +++ b/stream.c @@ -47,7 +47,7 @@ struct uvc_stream static void capture_video_process(void *d) { struct uvc_stream *stream = d; - struct v4l2_video_buffer buf; + struct video_buffer buf; int ret; ret = v4l2_dequeue_buffer(stream->cap, &buf); @@ -60,7 +60,7 @@ static void capture_video_process(void *d) static void uvc_video_process(void *d) { struct uvc_stream *stream = d; - struct v4l2_video_buffer buf; + struct video_buffer buf; int ret; ret = v4l2_dequeue_buffer(stream->uvc->vdev, &buf); @@ -92,7 +92,7 @@ static int uvc_video_enable(struct uvc_stream *stream, int enable) return ret; } - ret = v4l2_import_buffers(dev->vdev, dev->vdev->nbufs, cap->buffers); + ret = v4l2_import_buffers(dev->vdev, &cap->buffers); if (ret < 0) { printf("Failed to import buffers: %s (%d)\n", strerror(-ret), -ret); goto error; @@ -137,8 +137,8 @@ static int capture_video_stream(struct uvc_stream *stream, int enable) goto error; } - for (i = 0; i < cap->nbufs; ++i) { - struct v4l2_video_buffer *buf = &cap->buffers[i]; + for (i = 0; i < cap->buffers.nbufs; ++i) { + struct video_buffer *buf = &cap->buffers.buffers[i]; ret = v4l2_queue_buffer(cap, buf); if (ret < 0) diff --git a/v4l2.c b/v4l2.c index 6b1c753..9030270 100644 --- a/v4l2.c +++ b/v4l2.c @@ -30,6 +30,7 @@ #include "list.h" #include "tools.h" #include "v4l2.h" +#include "video-buffers.h" #ifndef V4L2_BUF_FLAG_ERROR #define V4L2_BUF_FLAG_ERROR 0x0040 @@ -510,7 +511,7 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype, unsigned int i; int ret; - if (dev->nbufs != 0) + if (dev->buffers.nbufs != 0) return -EBUSY; if (memtype != V4L2_MEMORY_MMAP && memtype != V4L2_MEMORY_DMABUF) @@ -541,19 +542,17 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype, /* Allocate the buffer objects. */ dev->memtype = memtype; - dev->nbufs = rb.count; + dev->buffers.nbufs = rb.count; - dev->buffers = malloc(sizeof *dev->buffers * nbufs); - if (dev->buffers == NULL) { + dev->buffers.buffers = calloc(nbufs, sizeof *dev->buffers.buffers); + if (dev->buffers.buffers == NULL) { ret = -ENOMEM; goto done; } - memset(dev->buffers, 0, sizeof *dev->buffers * nbufs); - - for (i = 0; i < dev->nbufs; ++i) { - dev->buffers[i].index = i; - dev->buffers[i].dmabuf = -1; + for (i = 0; i < dev->buffers.nbufs; ++i) { + dev->buffers.buffers[i].index = i; + dev->buffers.buffers[i].dmabuf = -1; } ret = 0; @@ -571,11 +570,11 @@ int v4l2_free_buffers(struct v4l2_device *dev) unsigned int i; int ret; - if (dev->nbufs == 0) + if (dev->buffers.nbufs == 0) return 0; - for (i = 0; i < dev->nbufs; ++i) { - struct v4l2_video_buffer *buffer = &dev->buffers[i]; + for (i = 0; i < dev->buffers.nbufs; ++i) { + struct video_buffer *buffer = &dev->buffers.buffers[i]; if (buffer->mem) { ret = munmap(buffer->mem, buffer->size); @@ -608,9 +607,9 @@ int v4l2_free_buffers(struct v4l2_device *dev) return -errno; } - free(dev->buffers); - dev->buffers = NULL; - dev->nbufs = 0; + free(dev->buffers.buffers); + dev->buffers.buffers = NULL; + dev->buffers.nbufs = 0; return 0; } @@ -620,13 +619,13 @@ int v4l2_export_buffers(struct v4l2_device *dev) unsigned int i; int ret; - if (dev->nbufs == 0) + if (dev->buffers.nbufs == 0) return -EINVAL; if (dev->memtype != V4L2_MEMORY_MMAP) return -EINVAL; - for (i = 0; i < dev->nbufs; ++i) { + for (i = 0; i < dev->buffers.nbufs; ++i) { struct v4l2_exportbuffer expbuf = { .type = dev->type, .index = i, @@ -650,30 +649,30 @@ int v4l2_export_buffers(struct v4l2_device *dev) return -errno; } - dev->buffers[i].size = buf.length; - dev->buffers[i].dmabuf = expbuf.fd; + dev->buffers.buffers[i].size = buf.length; + dev->buffers.buffers[i].dmabuf = expbuf.fd; printf("%s: buffer %u exported with fd %u.\n", - dev->name, i, dev->buffers[i].dmabuf); + dev->name, i, dev->buffers.buffers[i].dmabuf); } return 0; } -int v4l2_import_buffers(struct v4l2_device *dev, unsigned int nbufs, - const struct v4l2_video_buffer *buffers) +int v4l2_import_buffers(struct v4l2_device *dev, + const struct video_buffer_set *buffers) { unsigned int i; int ret; - if (dev->nbufs == 0 || dev->nbufs > nbufs) + if (dev->buffers.nbufs == 0 || dev->buffers.nbufs > buffers->nbufs) return -EINVAL; if (dev->memtype != V4L2_MEMORY_DMABUF) return -EINVAL; - for (i = 0; i < dev->nbufs; ++i) { - const struct v4l2_video_buffer *buffer = &buffers[i]; + for (i = 0; i < dev->buffers.nbufs; ++i) { + const struct video_buffer *buffer = &buffers->buffers[i]; struct v4l2_buffer buf = { .index = i, .type = dev->type, @@ -703,8 +702,8 @@ int v4l2_import_buffers(struct v4l2_device *dev, unsigned int nbufs, printf("%s: buffer %u valid.\n", dev->name, i); - dev->buffers[i].dmabuf = fd; - dev->buffers[i].size = buffer->size; + dev->buffers.buffers[i].dmabuf = fd; + dev->buffers.buffers[i].size = buffer->size; } return 0; @@ -718,8 +717,8 @@ int v4l2_mmap_buffers(struct v4l2_device *dev) if (dev->memtype != V4L2_MEMORY_MMAP) return -EINVAL; - for (i = 0; i < dev->nbufs; ++i) { - struct v4l2_video_buffer *buffer = &dev->buffers[i]; + for (i = 0; i < dev->buffers.nbufs; ++i) { + struct video_buffer *buffer = &dev->buffers.buffers[i]; struct v4l2_buffer buf = { .index = i, .type = dev->type, @@ -752,7 +751,7 @@ int v4l2_mmap_buffers(struct v4l2_device *dev) return 0; } -int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) +int v4l2_dequeue_buffer(struct v4l2_device *dev, struct video_buffer *buffer) { struct v4l2_buffer buf; int ret; @@ -764,11 +763,11 @@ int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffe ret = ioctl(dev->fd, VIDIOC_DQBUF, &buf); if (ret < 0) { printf("%s: unable to dequeue buffer index %u/%u (%d)\n", - dev->name, buf.index, dev->nbufs, errno); + dev->name, buf.index, dev->buffers.nbufs, errno); return -errno; } - *buffer = dev->buffers[buf.index]; + buffer->index = buf.index; buffer->bytesused = buf.bytesused; buffer->timestamp = buf.timestamp; buffer->error = !!(buf.flags & V4L2_BUF_FLAG_ERROR); @@ -776,12 +775,12 @@ int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffe return 0; } -int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) +int v4l2_queue_buffer(struct v4l2_device *dev, struct video_buffer *buffer) { struct v4l2_buffer buf; int ret; - if (buffer->index >= dev->nbufs) + if (buffer->index >= dev->buffers.nbufs) return -EINVAL; memset(&buf, 0, sizeof buf); @@ -790,7 +789,7 @@ int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) buf.memory = dev->memtype; if (dev->memtype == V4L2_MEMORY_DMABUF) - buf.m.fd = (unsigned long)dev->buffers[buffer->index].dmabuf; + buf.m.fd = (unsigned long)dev->buffers.buffers[buffer->index].dmabuf; if (dev->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) buf.bytesused = buffer->bytesused; @@ -798,7 +797,7 @@ int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) ret = ioctl(dev->fd, VIDIOC_QBUF, &buf); if (ret < 0) { printf("%s: unable to queue buffer index %u/%u (%d)\n", - dev->name, buf.index, dev->nbufs, errno); + dev->name, buf.index, dev->buffers.nbufs, errno); return -errno; } diff --git a/v4l2.h b/v4l2.h index f9da5aa..8d7b3c5 100644 --- a/v4l2.h +++ b/v4l2.h @@ -14,36 +14,11 @@ #ifndef __V4L2_H #define __V4L2_H -#include - #include - -#include +#include #include "list.h" - -/* - * struct v4l2_video_buffer - Video buffer information - * @index: Zero-based buffer index, limited to the number of buffers minus one - * @size: Size of the video memory, in bytes - * @bytesused: Number of bytes used by video data, smaller or equal to @size - * @timestamp: Time stamp at which the buffer has been captured - * @error: True if an error occured while capturing video data for the buffer - * @allocated: True if memory for the buffer has been allocated - * @mem: Video data memory - * @dmabuf: Video data dmabuf handle - */ -struct v4l2_video_buffer -{ - unsigned int index; - unsigned int size; - unsigned int bytesused; - struct timeval timestamp; - bool error; - bool allocated; - void *mem; - int dmabuf; -}; +#include "video-buffers.h" struct v4l2_device { @@ -57,8 +32,7 @@ struct v4l2_device struct v4l2_pix_format format; struct v4l2_rect crop; - unsigned int nbufs; - struct v4l2_video_buffer *buffers; + struct video_buffer_set buffers; }; /* @@ -144,7 +118,7 @@ int v4l2_set_crop(struct v4l2_device *dev, struct v4l2_rect *rect); * * Request the driver to allocate @nbufs buffers. The driver can modify the * number of buffers depending on its needs. The number of allocated buffers - * will be stored in the @dev::nbufs field. + * will be stored in the @dev->buffers.nbufs field. * * When @memtype is set to V4L2_MEMORY_MMAP the buffers are allocated by the * driver. They can then be mapped to userspace by calling v4l2_mmap_buffers(). @@ -166,7 +140,7 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype, * objects are freed, and the caller is responsible for freeing the video frames * memory if required. * - * When successful this function sets the @dev::nbufs field to zero. + * When successful this function sets the @dev->buffers.nbufs field to zero. * * Return 0 on success or a negative error code on failure. */ @@ -194,14 +168,13 @@ int v4l2_export_buffers(struct v4l2_device *dev); /* * v4l2_import_buffers - Import buffer backing store as dmabuf objects * @dev: Device instance - * @nbufs: Number of buffers in the @buffers array * @buffers: Buffers to be imported * * Import the dmabuf objects from @buffers as backing store for the device * buffers previously allocated by v4l2_alloc_buffers(). * * The dmabuf file handles are duplicated and stored in the dmabuf field of the - * @dev::buffers array. The handles from the @buffers array can thus be closed + * @dev::buffers array. The handles from the @buffers set can thus be closed * independently without impacting usage of the imported dmabuf objects. The * duplicated file handles will be automatically closed when the buffers are * freed with v4l2_free_buffers(). @@ -209,12 +182,12 @@ int v4l2_export_buffers(struct v4l2_device *dev); * This function can only be called when buffers have been allocated with the * memory type set to V4L2_MEMORY_DMABUF. If the memory type is different, if no * buffers have been allocated, or if the number of allocated buffers is larger - * than @nbufs, it will return -EINVAL. + * than @buffers->nbufs, it will return -EINVAL. * * Return 0 on success or a negative error code on failure. */ -int v4l2_import_buffers(struct v4l2_device *dev, unsigned int nbufs, - const struct v4l2_video_buffer *buffers); +int v4l2_import_buffers(struct v4l2_device *dev, + const struct video_buffer_set *buffers); /* * v4l2_mmap_buffers - Map buffers to application memory space @@ -263,7 +236,7 @@ int v4l2_mmap_buffers(struct v4l2_device *dev); * * Return 0 on success or a negative error code on failure. */ -int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer); +int v4l2_queue_buffer(struct v4l2_device *dev, struct video_buffer *buffer); /* * v4l2_dequeue_buffer - Dequeue the next buffer @@ -287,7 +260,7 @@ int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) * results in @buffer:error being set is not considered as a failure condition * for the purpose of the return value. */ -int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer); +int v4l2_dequeue_buffer(struct v4l2_device *dev, struct video_buffer *buffer); /* * v4l2_stream_on - Start video streaming diff --git a/video-buffers.c b/video-buffers.c new file mode 100644 index 0000000..f5dc6ec --- /dev/null +++ b/video-buffers.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Video buffers + * + * Copyright (C) 2018 Laurent Pinchart + * + * Contact: Laurent Pinchart + */ + +#include "video-buffers.h" + +#include +#include + +struct video_buffer_set *video_buffer_set_new(unsigned int nbufs) +{ + struct video_buffer_set *buffers; + + buffers = malloc(sizeof *buffers); + if (!buffers) + return NULL; + + buffers->nbufs = nbufs; + buffers->buffers = calloc(nbufs, sizeof *buffers->buffers); + if (!buffers->buffers) { + free(buffers); + return NULL; + } + + return buffers; +} + +void video_buffer_set_delete(struct video_buffer_set *buffers) +{ + if (!buffers) + return; + + free(buffers->buffers); + free(buffers); +} diff --git a/video-buffers.h b/video-buffers.h new file mode 100644 index 0000000..001f75e --- /dev/null +++ b/video-buffers.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Video buffers + * + * Copyright (C) 2018 Laurent Pinchart + * + * Contact: Laurent Pinchart + */ +#ifndef __VIDEO_BUFFERS_H__ +#define __VIDEO_BUFFERS_H__ + +#include +#include +#include + +/* + * + * struct video_buffer - Video buffer information + * @index: Zero-based buffer index, limited to the number of buffers minus one + * @size: Size of the video memory, in bytes + * @bytesused: Number of bytes used by video data, smaller or equal to @size + * @timestamp: Time stamp at which the buffer has been captured + * @error: True if an error occured while capturing video data for the buffer + * @allocated: True if memory for the buffer has been allocated + * @mem: Video data memory + * @dmabuf: Video data dmabuf handle + */ +struct video_buffer +{ + unsigned int index; + unsigned int size; + unsigned int bytesused; + struct timeval timestamp; + bool error; + void *mem; + int dmabuf; +}; + +struct video_buffer_set +{ + struct video_buffer *buffers; + unsigned int nbufs; +}; + +struct video_buffer_set *video_buffer_set_new(unsigned int nbufs); +void video_buffer_set_delete(struct video_buffer_set *buffers); + +#endif /* __VIDEO_BUFFERS_H__ */ -- cgit v1.2.3