This is an automatic generated email to let you know that the following patch were queued at the http://git.linuxtv.org/v4l-utils.git tree:
Subject: libv4l2: Lazily allocate convert_mmap_buf Author: Gregor Jasny <[email protected]> Date: Sat Jul 26 21:36:16 2014 +0200 >From Hans de Goede: Originally this was not possible, which is why I went with the fixed buffer (IIRC). But later on we started dis-allowing changing various parameters with buffers mapped, because allowing that was just a bad idea. In order to allow dynamic allocation of convert_mmap_buf, we need to make sure that: a) It is not used whenever dest_fmt changes, since it is used to store destination fmt data and should always be at least dest_fmt.fmt.pix.sizeimage bytes. I've just checked and all places which change dest_fmt first call v4l2_check_buffer_change_ok() which ensures that convert_mmap_buf is not used, frees it and marks it as MAP_FAILED. b) It is not allocated before dest_fmt gets set. It is allocated in 2 places: 1) On DQBUF, which only can be done after a stream-on, at which point dest_fmt must be set. 2) on v4l2_mmap, which requires the caller having done a QUERYBUF, and thus a REQBUFS, so dest_fmt must be set at this point. So long story short, yes doing dynamic alloc should work fine. I suggest introducing a v4l2_ensure_convert_mmap_buf function for this which checks if convert_mmap_buf == MAP_FAILED and when it is allocs a buffer of dest_fmt.fmt.pix.sizeimage bytes rounded up to a multiple PAGE_SIZE. If convert_mmap_buf != MAP_FAILED and thus the buffer is already allocated it should simply return success. Signed-off-by: Gregor Jasny <[email protected]> Signed-off-by: Hans de Goede <[email protected]> lib/libv4l2/libv4l2-priv.h | 3 +- lib/libv4l2/libv4l2.c | 102 ++++++++++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 37 deletions(-) --- http://git.linuxtv.org/v4l-utils.git?a=commitdiff;h=10213c975afdfcc90aa7de39e66c40cd7e8a57f7 diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h index ff4c8d2..fdd5ff0 100644 --- a/lib/libv4l2/libv4l2-priv.h +++ b/lib/libv4l2/libv4l2-priv.h @@ -31,7 +31,6 @@ be adjusted! */ #define V4L2_MAX_NO_FRAMES 32 #define V4L2_DEFAULT_NREADBUFFERS 4 -#define V4L2_FRAME_BUF_SIZE (4096 * 4096) #define V4L2_IGNORE_FIRST_FRAME_ERRORS 3 #define V4L2_DEFAULT_FPS 30 @@ -88,6 +87,8 @@ struct v4l2_dev_info { int first_frame; struct v4lconvert_data *convert; unsigned char *convert_mmap_buf; + size_t convert_mmap_buf_size; + size_t convert_mmap_frame_size; /* Frame bookkeeping is only done when in read or mmap-conversion mode */ unsigned char *frame_pointers[V4L2_MAX_NO_FRAMES]; int frame_sizes[V4L2_MAX_NO_FRAMES]; diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c index 8291ebe..afac406 100644 --- a/lib/libv4l2/libv4l2.c +++ b/lib/libv4l2/libv4l2.c @@ -94,6 +94,48 @@ static struct v4l2_dev_info devices[V4L2_MAX_DEVICES] = { }; static int devices_used; +static int v4l2_ensure_convert_mmap_buf(int index) +{ + long page_size; + + if (devices[index].convert_mmap_buf != MAP_FAILED) { + return 0; + } + + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) { + int saved_err = errno; + V4L2_LOG_ERR("unable to retrieve page size\n"); + errno = saved_err; + return -1; + } + + /* round up to full page size */ + devices[index].convert_mmap_frame_size = + (((devices[index].dest_fmt.fmt.pix.sizeimage + page_size - 1) / + page_size) * page_size); + + devices[index].convert_mmap_buf_size = + devices[index].convert_mmap_frame_size * devices[index].no_frames; + + devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL, + devices[index].convert_mmap_buf_size, + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + + if (devices[index].convert_mmap_buf == MAP_FAILED) { + devices[index].convert_mmap_frame_size = 0; + devices[index].convert_mmap_buf_size = 0; + + int saved_err = errno; + V4L2_LOG_ERR("allocating conversion buffer\n"); + errno = saved_err; + return -1; + } + + return 0; +} static int v4l2_request_read_buffers(int index) { @@ -317,7 +359,8 @@ static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, &devices[index].src_fmt, &devices[index].dest_fmt, devices[index].frame_pointers[buf->index], buf->bytesused, dest ? dest : (devices[index].convert_mmap_buf + - buf->index * V4L2_FRAME_BUF_SIZE), dest_size); + buf->index * devices[index].convert_mmap_frame_size), + dest_size); if (devices[index].first_frame) { /* Always treat convert errors as EAGAIN during the first few frames, as @@ -526,7 +569,7 @@ static void v4l2_set_conversion_buf_params(int index, struct v4l2_buffer *buf) buf->index = 0; buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index; - buf->length = V4L2_FRAME_BUF_SIZE; + buf->length = devices[index].convert_mmap_frame_size; if (devices[index].frame_map_count[buf->index]) buf->flags |= V4L2_BUF_FLAG_MAPPED; else @@ -735,6 +778,8 @@ no_capture: devices[index].nreadbuffers = V4L2_DEFAULT_NREADBUFFERS; devices[index].convert = convert; devices[index].convert_mmap_buf = MAP_FAILED; + devices[index].convert_mmap_buf_size = 0; + devices[index].convert_mmap_frame_size = 0; for (i = 0; i < V4L2_MAX_NO_FRAMES; i++) { devices[index].frame_pointers[i] = MAP_FAILED; devices[index].frame_map_count[i] = 0; @@ -808,9 +853,11 @@ int v4l2_close(int fd) V4L2_LOG_WARN("v4l2 mmap buffers still mapped on close()\n"); } else { SYS_MUNMAP(devices[index].convert_mmap_buf, - devices[index].no_frames * V4L2_FRAME_BUF_SIZE); + devices[index].convert_mmap_buf_size); } devices[index].convert_mmap_buf = MAP_FAILED; + devices[index].convert_mmap_buf_size = 0; + devices[index].convert_mmap_frame_size = 0; } v4lconvert_destroy(devices[index].convert); free(devices[index].readbuf); @@ -864,8 +911,10 @@ static int v4l2_check_buffer_change_ok(int index) v4l2_unrequest_read_buffers may change the no_frames, so free the convert mmap buffer */ SYS_MUNMAP(devices[index].convert_mmap_buf, - devices[index].no_frames * V4L2_FRAME_BUF_SIZE); + devices[index].convert_mmap_buf_size); devices[index].convert_mmap_buf = MAP_FAILED; + devices[index].convert_mmap_buf_size = 0; + devices[index].convert_mmap_frame_size = 0; if (devices[index].flags & V4L2_STREAM_CONTROLLED_BY_READ) { V4L2_LOG("deactivating read-stream for settings change\n"); @@ -1334,23 +1383,12 @@ no_capture_request: /* An application can do a DQBUF before mmap-ing in the buffer, but we need the buffer _now_ to write our converted data to it! */ - if (devices[index].convert_mmap_buf == MAP_FAILED) { - devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL, - (size_t)(devices[index].no_frames * V4L2_FRAME_BUF_SIZE), - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, - -1, 0); - if (devices[index].convert_mmap_buf == MAP_FAILED) { - saved_err = errno; - V4L2_LOG_ERR("allocating conversion buffer\n"); - errno = saved_err; - result = -1; - break; - } - } + result = v4l2_ensure_convert_mmap_buf(index); + if (result) + break; result = v4l2_dequeue_and_convert(index, buf, 0, - V4L2_FRAME_BUF_SIZE); + devices[index].convert_mmap_frame_size); if (result >= 0) { buf->bytesused = result; result = 0; @@ -1575,7 +1613,7 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, if (index == -1 || /* Check if the mmap data matches our answer to QUERY_BUF. If it doesn't, let the kernel handle it (to allow for mmap-based non capture use) */ - start || length != V4L2_FRAME_BUF_SIZE || + start || length != devices[index].convert_mmap_frame_size || ((unsigned int)offset & ~0xFFu) != V4L2_MMAP_OFFSET_MAGIC) { if (index != -1) V4L2_LOG("Passing mmap(%p, %d, ..., %x, through to the driver\n", @@ -1600,26 +1638,16 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, goto leave; } - if (devices[index].convert_mmap_buf == MAP_FAILED) { - devices[index].convert_mmap_buf = (void *)SYS_MMAP(NULL, - (size_t)(devices[index].no_frames * V4L2_FRAME_BUF_SIZE), - PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, - -1, 0); - if (devices[index].convert_mmap_buf == MAP_FAILED) { - int saved_err = errno; - - V4L2_LOG_ERR("allocating conversion buffer\n"); - errno = saved_err; - result = MAP_FAILED; - goto leave; - } + if (v4l2_ensure_convert_mmap_buf(index)) { + errno = EINVAL; + result = MAP_FAILED; + goto leave; } devices[index].frame_map_count[buffer_index]++; result = devices[index].convert_mmap_buf + - buffer_index * V4L2_FRAME_BUF_SIZE; + buffer_index * devices[index].convert_mmap_frame_size; V4L2_LOG("Fake (conversion) mmap buf %u, seen by app at: %p\n", buffer_index, result); @@ -1637,10 +1665,11 @@ int v4l2_munmap(void *_start, size_t length) unsigned char *start = _start; /* Is this memory ours? */ - if (start != MAP_FAILED && length == V4L2_FRAME_BUF_SIZE) { + if (start != MAP_FAILED) { for (index = 0; index < devices_used; index++) if (devices[index].fd != -1 && devices[index].convert_mmap_buf != MAP_FAILED && + length == devices[index].convert_mmap_frame_size && start >= devices[index].convert_mmap_buf && (start - devices[index].convert_mmap_buf) % length == 0) break; @@ -1654,6 +1683,7 @@ int v4l2_munmap(void *_start, size_t length) /* Re-do our checks now that we have the lock, things may have changed */ if (devices[index].convert_mmap_buf != MAP_FAILED && + length == devices[index].convert_mmap_frame_size && start >= devices[index].convert_mmap_buf && (start - devices[index].convert_mmap_buf) % length == 0 && buffer_index < devices[index].no_frames) { _______________________________________________ linuxtv-commits mailing list [email protected] http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits
