From 20c48607c531cd04b948a717ef962f526ceac639 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 10 Apr 2022 11:09:42 +0200 Subject: [PATCH] Make buffer handling to be made via `device/v4l2` --- device/hw/buffer.c | 53 +------------ device/hw/buffer_queue.c | 89 ++------------------- device/hw/device.h | 7 ++ device/v4l2/buffer.c | 165 ++++++++++++++++++++++++++++++++++++--- device/v4l2/debug.c | 37 +++++++++ device/v4l2/device.c | 15 ++-- device/v4l2/v4l2.h | 14 +++- 7 files changed, 229 insertions(+), 151 deletions(-) create mode 100644 device/v4l2/debug.c diff --git a/device/hw/buffer.c b/device/hw/buffer.c index bdc8029..9c385e5 100644 --- a/device/hw/buffer.c +++ b/device/hw/buffer.c @@ -14,50 +14,8 @@ buffer_t *buffer_open(const char *name, buffer_list_t *buf_list, int index) { buf->mmap_reflinks = 1; buf->used = 0; - struct v4l2_buffer v4l2_buf = {0}; - struct v4l2_plane v4l2_plane = {0}; - - v4l2_buf.type = buf_list->v4l2.type; - v4l2_buf.index = index; - - if (buf_list->v4l2.do_mplanes) { - v4l2_buf.length = 1; - v4l2_buf.m.planes = &v4l2_plane; - v4l2_plane.data_offset = 0; - } - - if (buf_list->do_mmap) { - v4l2_buf.memory = V4L2_MEMORY_MMAP; - } else { - v4l2_buf.memory = V4L2_MEMORY_DMABUF; - } - - E_XIOCTL(buf_list, dev->fd, VIDIOC_QUERYBUF, &v4l2_buf, "Cannot query buffer %d", index); - - uint64_t mem_offset = 0; - - if (buf_list->v4l2.do_mplanes) { - mem_offset = v4l2_plane.m.mem_offset; - buf->length = v4l2_plane.length; - } else { - mem_offset = v4l2_buf.m.offset; - buf->length = v4l2_buf.length; - } - - if (buf_list->do_mmap) { - buf->start = mmap(NULL, buf->length, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, mem_offset); - if (buf->start == MAP_FAILED) { - goto error; - } - } - - if (buf_list->do_dma) { - struct v4l2_exportbuffer v4l2_exp = {0}; - v4l2_exp.type = v4l2_buf.type; - v4l2_exp.index = index; - v4l2_exp.plane = 0; - E_XIOCTL(buf_list, dev->fd, VIDIOC_EXPBUF, &v4l2_exp, "Can't export queue buffer=%u to DMA", index); - buf->dma_fd = v4l2_exp.fd; + if (dev->hw->buffer_open(buf) < 0) { + goto error; } return buf; @@ -73,12 +31,7 @@ void buffer_close(buffer_t *buf) return; } - if (buf->start && buf->start != MAP_FAILED) { - munmap(buf->start, buf->length); - } - if (buf->dma_fd >= 0) { - close(buf->dma_fd); - } + buf->buf_list->device->hw->buffer_close(buf); free(buf->name); free(buf); } diff --git a/device/hw/buffer_queue.c b/device/hw/buffer_queue.c index fb99723..66c6719 100644 --- a/device/hw/buffer_queue.c +++ b/device/hw/buffer_queue.c @@ -37,57 +37,10 @@ bool buffer_consumed(buffer_t *buf, const char *who) buf->mmap_reflinks--; if (!buf->enqueued && buf->mmap_reflinks == 0) { - struct v4l2_buffer v4l2_buf = {0}; - struct v4l2_plane v4l2_plane = {0}; - - v4l2_buf.type = buf->buf_list->v4l2.type; - v4l2_buf.index = buf->index; - v4l2_buf.flags = buf->v4l2.flags; - - if (buf->buf_list->do_mmap) { - assert(buf->dma_source == NULL); - v4l2_buf.memory = V4L2_MEMORY_MMAP; - } else { - assert(buf->dma_source != NULL); - v4l2_buf.memory = V4L2_MEMORY_DMABUF; + if (buf->buf_list->device->hw->buffer_enqueue(buf, who) < 0) { + goto error; } - // update used bytes - if (buf->buf_list->v4l2.do_mplanes) { - v4l2_buf.length = 1; - v4l2_buf.m.planes = &v4l2_plane; - v4l2_plane.bytesused = buf->used; - v4l2_plane.length = buf->length; - v4l2_plane.data_offset = 0; - - if (buf->dma_source) { - assert(!buf->buf_list->do_mmap); - v4l2_plane.m.fd = buf->dma_source->dma_fd; - } - } else { - v4l2_buf.bytesused = buf->used; - - if (buf->dma_source) { - assert(!buf->buf_list->do_mmap); - v4l2_buf.m.fd = buf->dma_source->dma_fd; - } - } - - E_LOG_DEBUG(buf, "Queuing buffer... used=%zu length=%zu (linked=%s) by %s", - buf->used, - buf->length, - buf->dma_source ? buf->dma_source->name : NULL, - who); - - // Assign or clone timestamp - if (buf->buf_list->do_timestamps) { - get_monotonic_time_us(NULL, &v4l2_buf.timestamp); - } else { - v4l2_buf.timestamp.tv_sec = buf->captured_time_us / (1000LL * 1000LL); - v4l2_buf.timestamp.tv_usec = buf->captured_time_us % (1000LL * 1000LL); - } - - E_XIOCTL(buf, buf->buf_list->device->fd, VIDIOC_QBUF, &v4l2_buf, "Can't queue buffer."); buf->enqueued = true; buf->enqueue_time_us = buf->buf_list->last_enqueued_us = get_monotonic_time_us(NULL, NULL); } @@ -184,28 +137,12 @@ error: buffer_t *buffer_list_dequeue(buffer_list_t *buf_list) { - struct v4l2_buffer v4l2_buf = {0}; - struct v4l2_plane v4l2_plane = {0}; + buffer_t *buf = NULL; - v4l2_buf.type = buf_list->v4l2.type; - v4l2_buf.memory = V4L2_MEMORY_MMAP; - - if (buf_list->v4l2.do_mplanes) { - v4l2_buf.length = 1; - v4l2_buf.m.planes = &v4l2_plane; - } - - E_XIOCTL(buf_list, buf_list->device->fd, VIDIOC_DQBUF, &v4l2_buf, "Can't grab capture buffer (flags=%08x)", v4l2_buf.flags); - - buffer_t *buf = buf_list->bufs[v4l2_buf.index]; - if (buf_list->v4l2.do_mplanes) { - buf->used = v4l2_plane.bytesused; - } else { - buf->used = v4l2_buf.bytesused; + if (buf_list->device->hw->buffer_list_dequeue(buf_list, &buf) < 0) { + goto error; } - // TODO: Copy flags - buf->v4l2.flags = v4l2_buf.flags; - buf->captured_time_us = get_time_us(CLOCK_FROM_PARAMS, NULL, &v4l2_buf.timestamp, 0); + buf_list->last_dequeued_us = get_monotonic_time_us(NULL, NULL); if (buf->mmap_reflinks > 0) { @@ -238,17 +175,5 @@ error: int buffer_list_pollfd(buffer_list_t *buf_list, struct pollfd *pollfd, bool can_dequeue) { - int count_enqueued = buffer_list_count_enqueued(buf_list); - - // Can something be dequeued? - pollfd->fd = buf_list->device->fd; - pollfd->events = POLLHUP; - if (count_enqueued > 0 && can_dequeue) { - if (buf_list->do_capture) - pollfd->events |= POLLIN; - else - pollfd->events |= POLLOUT; - } - pollfd->revents = 0; - return 0; + return buf_list->device->hw->buffer_list_pollfd(buf_list, pollfd, can_dequeue); } diff --git a/device/hw/device.h b/device/hw/device.h index 9b971a4..6607464 100644 --- a/device/hw/device.h +++ b/device/hw/device.h @@ -4,10 +4,17 @@ #include #include +typedef struct buffer_s buffer_t; typedef struct buffer_list_s buffer_list_t; typedef struct device_s device_t; +struct pollfd; typedef struct device_hw_s { + int (*buffer_open)(buffer_t *buf); + void (*buffer_close)(buffer_t *buf); + int (*buffer_enqueue)(buffer_t *buf, const char *who); + int (*buffer_list_dequeue)(buffer_list_t *buf_list, buffer_t **bufp); + int (*buffer_list_pollfd)(buffer_list_t *buf_list, struct pollfd *pollfd, bool can_dequeue); } device_hw_t; typedef struct device_s { diff --git a/device/v4l2/buffer.c b/device/v4l2/buffer.c index d5e7f97..0c5e750 100644 --- a/device/v4l2/buffer.c +++ b/device/v4l2/buffer.c @@ -1,22 +1,23 @@ #include "device/v4l2/v4l2.h" -#include "device/hw/v4l2.h" +#include "device/hw/buffer.h" #include "device/hw/buffer_list.h" #include "device/hw/device.h" -int buffer_list_v4l2_refresh_states(buffer_list_t *buf_list) +int v4l2_buffer_open(buffer_t *buf) { - if (!buf_list) { - return -1; - } - struct v4l2_buffer v4l2_buf = {0}; struct v4l2_plane v4l2_plane = {0}; + buffer_list_t *buf_list = buf->buf_list; + device_t *dev = buf_list->device; + v4l2_buf.type = buf_list->v4l2.type; + v4l2_buf.index = buf->index; if (buf_list->v4l2.do_mplanes) { v4l2_buf.length = 1; v4l2_buf.m.planes = &v4l2_plane; + v4l2_plane.data_offset = 0; } if (buf_list->do_mmap) { @@ -25,14 +26,156 @@ int buffer_list_v4l2_refresh_states(buffer_list_t *buf_list) v4l2_buf.memory = V4L2_MEMORY_DMABUF; } - for (int i = 0; i < buf_list->nbufs; i++) { - v4l2_buf.index = i; + E_XIOCTL(buf_list, dev->fd, VIDIOC_QUERYBUF, &v4l2_buf, "Cannot query buffer %d", index); - E_XIOCTL(buf_list, buf_list->device->fd, VIDIOC_QUERYBUF, &v4l2_buf, "Can't query buffer (flags=%08x)", i); - E_LOG_INFO(buf_list, "Buffer: %d, Flags: %08x. Offset: %d", i, v4l2_buf.flags, - buf_list->v4l2.do_mplanes ? v4l2_plane.m.mem_offset : v4l2_buf.m.offset); + uint64_t mem_offset = 0; + + if (buf_list->v4l2.do_mplanes) { + mem_offset = v4l2_plane.m.mem_offset; + buf->length = v4l2_plane.length; + } else { + mem_offset = v4l2_buf.m.offset; + buf->length = v4l2_buf.length; } + if (buf_list->do_mmap) { + buf->start = mmap(NULL, buf->length, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, mem_offset); + if (buf->start == MAP_FAILED) { + goto error; + } + } + + if (buf_list->do_dma) { + struct v4l2_exportbuffer v4l2_exp = {0}; + v4l2_exp.type = v4l2_buf.type; + v4l2_exp.index = buf->index; + v4l2_exp.plane = 0; + E_XIOCTL(buf_list, dev->fd, VIDIOC_EXPBUF, &v4l2_exp, "Can't export queue buffer=%u to DMA", index); + buf->dma_fd = v4l2_exp.fd; + } + + return 0; + +error: + v4l2_buffer_close(buf); + return -1; +} + +void v4l2_buffer_close(buffer_t *buf) +{ + if (buf->start && buf->start != MAP_FAILED) { + munmap(buf->start, buf->length); + buf->start = NULL; + } + if (buf->dma_fd >= 0) { + close(buf->dma_fd); + buf->dma_fd = -1; + } +} + +int v4l2_buffer_enqueue(buffer_t *buf, const char *who) +{ + struct v4l2_buffer v4l2_buf = {0}; + struct v4l2_plane v4l2_plane = {0}; + + v4l2_buf.type = buf->buf_list->v4l2.type; + v4l2_buf.index = buf->index; + v4l2_buf.flags = buf->v4l2.flags; + + if (buf->buf_list->do_mmap) { + assert(buf->dma_source == NULL); + v4l2_buf.memory = V4L2_MEMORY_MMAP; + } else { + assert(buf->dma_source != NULL); + v4l2_buf.memory = V4L2_MEMORY_DMABUF; + } + + // update used bytes + if (buf->buf_list->v4l2.do_mplanes) { + v4l2_buf.length = 1; + v4l2_buf.m.planes = &v4l2_plane; + v4l2_plane.bytesused = buf->used; + v4l2_plane.length = buf->length; + v4l2_plane.data_offset = 0; + + if (buf->dma_source) { + assert(!buf->buf_list->do_mmap); + v4l2_plane.m.fd = buf->dma_source->dma_fd; + } + } else { + v4l2_buf.bytesused = buf->used; + + if (buf->dma_source) { + assert(!buf->buf_list->do_mmap); + v4l2_buf.m.fd = buf->dma_source->dma_fd; + } + } + + E_LOG_DEBUG(buf, "Queuing buffer... used=%zu length=%zu (linked=%s) by %s", + buf->used, + buf->length, + buf->dma_source ? buf->dma_source->name : NULL, + who); + + // Assign or clone timestamp + if (buf->buf_list->do_timestamps) { + get_monotonic_time_us(NULL, &v4l2_buf.timestamp); + } else { + v4l2_buf.timestamp.tv_sec = buf->captured_time_us / (1000LL * 1000LL); + v4l2_buf.timestamp.tv_usec = buf->captured_time_us % (1000LL * 1000LL); + } + + E_XIOCTL(buf, buf->buf_list->device->fd, VIDIOC_QBUF, &v4l2_buf, "Can't queue buffer."); + + return 0; + error: return -1; } + +int v4l2_buffer_list_dequeue(buffer_list_t *buf_list, buffer_t **bufp) +{ + struct v4l2_buffer v4l2_buf = {0}; + struct v4l2_plane v4l2_plane = {0}; + + v4l2_buf.type = buf_list->v4l2.type; + v4l2_buf.memory = V4L2_MEMORY_MMAP; + + if (buf_list->v4l2.do_mplanes) { + v4l2_buf.length = 1; + v4l2_buf.m.planes = &v4l2_plane; + } + + E_XIOCTL(buf_list, buf_list->device->fd, VIDIOC_DQBUF, &v4l2_buf, "Can't grab capture buffer (flags=%08x)", v4l2_buf.flags); + + buffer_t *buf = *bufp = buf_list->bufs[v4l2_buf.index]; + if (buf_list->v4l2.do_mplanes) { + buf->used = v4l2_plane.bytesused; + } else { + buf->used = v4l2_buf.bytesused; + } + + buf->v4l2.flags = v4l2_buf.flags; + buf->captured_time_us = get_time_us(CLOCK_FROM_PARAMS, NULL, &v4l2_buf.timestamp, 0); + return 0; + +error: + return -1; +} + +int v4l2_buffer_list_pollfd(buffer_list_t *buf_list, struct pollfd *pollfd, bool can_dequeue) +{ + int count_enqueued = buffer_list_count_enqueued(buf_list); + + // Can something be dequeued? + pollfd->fd = buf_list->device->fd; + pollfd->events = POLLHUP; + if (count_enqueued > 0 && can_dequeue) { + if (buf_list->do_capture) + pollfd->events |= POLLIN; + else + pollfd->events |= POLLOUT; + } + pollfd->revents = 0; + return 0; +} diff --git a/device/v4l2/debug.c b/device/v4l2/debug.c new file mode 100644 index 0000000..c59be35 --- /dev/null +++ b/device/v4l2/debug.c @@ -0,0 +1,37 @@ +#include "device/v4l2/v4l2.h" +#include "device/hw/buffer_list.h" +#include "device/hw/device.h" + +int v4l2_buffer_list_refresh_states(buffer_list_t *buf_list) +{ + if (!buf_list) { + return -1; + } + + struct v4l2_buffer v4l2_buf = {0}; + struct v4l2_plane v4l2_plane = {0}; + + v4l2_buf.type = buf_list->v4l2.type; + + if (buf_list->v4l2.do_mplanes) { + v4l2_buf.length = 1; + v4l2_buf.m.planes = &v4l2_plane; + } + + if (buf_list->do_mmap) { + v4l2_buf.memory = V4L2_MEMORY_MMAP; + } else { + v4l2_buf.memory = V4L2_MEMORY_DMABUF; + } + + for (int i = 0; i < buf_list->nbufs; i++) { + v4l2_buf.index = i; + + E_XIOCTL(buf_list, buf_list->device->fd, VIDIOC_QUERYBUF, &v4l2_buf, "Can't query buffer (flags=%08x)", i); + E_LOG_INFO(buf_list, "Buffer: %d, Flags: %08x. Offset: %d", i, v4l2_buf.flags, + buf_list->v4l2.do_mplanes ? v4l2_plane.m.mem_offset : v4l2_buf.m.offset); + } + +error: + return -1; +} diff --git a/device/v4l2/device.c b/device/v4l2/device.c index 9366b39..d2c7ab0 100644 --- a/device/v4l2/device.c +++ b/device/v4l2/device.c @@ -1,13 +1,16 @@ +#include "device/v4l2/v4l2.h" #include "device/hw/v4l2.h" #include "device/hw/device.h" -extern device_hw_t device_hw_v4l2; +device_hw_t v4l2_device_hw = { + .buffer_open = v4l2_buffer_open, + .buffer_close = v4l2_buffer_close, + .buffer_enqueue = v4l2_buffer_enqueue, + .buffer_list_dequeue = v4l2_buffer_list_dequeue, + .buffer_list_pollfd = v4l2_buffer_list_pollfd, +}; device_t *device_v4l2_open(const char *name, const char *path) { - return device_open(name, path, &device_hw_v4l2); + return device_open(name, path, &v4l2_device_hw); } - -device_hw_t device_hw_v4l2 = { - -}; diff --git a/device/v4l2/v4l2.h b/device/v4l2/v4l2.h index d2b7667..dbfca2c 100644 --- a/device/v4l2/v4l2.h +++ b/device/v4l2/v4l2.h @@ -1,5 +1,15 @@ #pragma once -typedef struct buffer_list_s buffer_list_t; +// TODO: temporary +#include "device/hw/v4l2.h" -int buffer_list_v4l2_refresh_states(buffer_list_t *buf_list); +typedef struct buffer_s buffer_t; +typedef struct buffer_list_s buffer_list_t; +struct pollfd; + +int v4l2_buffer_open(buffer_t *buf); +void v4l2_buffer_close(buffer_t *buf); +int v4l2_buffer_enqueue(buffer_t *buf, const char *who); +int v4l2_buffer_list_dequeue(buffer_list_t *buf_list, buffer_t **bufp); +int v4l2_buffer_list_refresh_states(buffer_list_t *buf_list); +int v4l2_buffer_list_pollfd(buffer_list_t *buf_list, struct pollfd *pollfd, bool can_dequeue);