From 143d24fcf64d491aa24d728899e67e1197aaee6f Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 25 Jul 2023 15:14:11 -0400 Subject: [PATCH 1/2] v4l2: allocator: Don't close foreign dmabuf Imported dmabuf are not being duped, so they should never be closed. Instead, we ensure their live time by having strong reference on their original buffer. This should fix potential flickering due to dmabuf being closed too early. Part-of: --- subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c index 48d1bb86e84..cfdeeee7945 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c @@ -357,7 +357,6 @@ gst_v4l2_allocator_release (GstV4l2Allocator * allocator, GstV4l2Memory * mem) switch (allocator->memory) { case V4L2_MEMORY_DMABUF: - close (mem->dmafd); mem->dmafd = -1; break; case V4L2_MEMORY_USERPTR: @@ -396,8 +395,7 @@ gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem) obj->munmap (mem->data, group->planes[mem->plane].length); } - /* This apply for both mmap with expbuf, and dmabuf imported memory */ - if (mem->dmafd >= 0) + if (allocator->memory == V4L2_MEMORY_MMAP && mem->dmafd >= 0) close (mem->dmafd); } From 54a5b520bd820fa7b6de41ff18b34a2cff4f8e67 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Tue, 31 Mar 2020 21:23:28 -0700 Subject: [PATCH 2/2] v4l2: Reuse right buffer index when dmabuf import mode --- .../sys/v4l2/gstv4l2allocator.c | 98 ++++++++++++++++++- .../sys/v4l2/gstv4l2allocator.h | 3 + .../sys/v4l2/gstv4l2bufferpool.c | 53 +++++++--- .../gst-plugins-good/sys/v4l2/gstv4l2object.c | 6 +- 4 files changed, 144 insertions(+), 16 deletions(-) diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c index cfdeeee7945..23d6b6cb354 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c @@ -357,6 +357,8 @@ gst_v4l2_allocator_release (GstV4l2Allocator * allocator, GstV4l2Memory * mem) switch (allocator->memory) { case V4L2_MEMORY_DMABUF: + if (V4L2_TYPE_IS_CAPTURE(allocator->obj->type) && (allocator->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)) + break; mem->dmafd = -1; break; case V4L2_MEMORY_USERPTR: @@ -395,8 +397,10 @@ gst_v4l2_allocator_free (GstAllocator * gallocator, GstMemory * gmem) obj->munmap (mem->data, group->planes[mem->plane].length); } - if (allocator->memory == V4L2_MEMORY_MMAP && mem->dmafd >= 0) + if (allocator->memory == V4L2_MEMORY_MMAP && mem->dmafd >= 0){ close (mem->dmafd); + GST_LOG_OBJECT (allocator, "close fd: %d", mem->dmafd); + } } g_slice_free (GstV4l2Memory, mem); @@ -1021,6 +1025,91 @@ gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator) return group; } +GstV4l2MemoryGroup * +gst_v4l2_allocator_alloc_dmabufin_capture (GstV4l2Allocator * allocator, + GstAllocator * dmabuf_allocator, GstBuffer* downstream_buffer) +{ + GstV4l2Object *obj = allocator->obj; + GstV4l2MemoryGroup *group; + gint i; + + g_return_val_if_fail (allocator->memory == V4L2_MEMORY_DMABUF, NULL); + + group = gst_v4l2_allocator_alloc (allocator); + + if (group == NULL) + return NULL; + + for (i = 0; i < group->n_mem; i++) { + GstV4l2Memory *mem; + GstMemory *dma_mem; + gsize size, offset, maxsize; + + + if (group->mem[i] == NULL) { + dma_mem = gst_buffer_peek_memory (downstream_buffer, i); + int downstream_fd = gst_dmabuf_memory_get_fd (dma_mem); + + GST_LOG_OBJECT (allocator, "import DMABUF fd %d into fd %i plane %d", + downstream_fd, downstream_fd, i); + + group->planes[i].m.fd = downstream_fd; + group->planes[i].length = dma_mem->size; + group->planes[i].data_offset = dma_mem->offset; + + group->mem[i] = (GstMemory *) _v4l2mem_new (0, GST_ALLOCATOR (allocator), + NULL, group->planes[i].length, 0, group->planes[i].data_offset, + group->planes[i].length - group->planes[i].data_offset, i, NULL, + downstream_fd, group); + } else { + /* Take back the allocator reference */ + gst_object_ref (allocator); + } + + group->mems_allocated++; + + g_assert (gst_is_v4l2_memory (group->mem[i])); + mem = (GstV4l2Memory *) group->mem[i]; + + dma_mem = gst_fd_allocator_alloc (dmabuf_allocator, mem->dmafd, + group->planes[i].length, GST_FD_MEMORY_FLAG_DONT_CLOSE); + gst_memory_resize (dma_mem, group->planes[i].data_offset, + group->planes[i].length - group->planes[i].data_offset); + + gst_mini_object_set_qdata (GST_MINI_OBJECT (dma_mem), + GST_V4L2_MEMORY_QUARK, mem, (GDestroyNotify) gst_memory_unref); + + group->mem[i] = dma_mem; + } + + if (!V4L2_TYPE_IS_MULTIPLANAR (obj->type)) { + group->buffer.bytesused = group->planes[0].bytesused; + group->buffer.length = group->planes[0].length; + group->buffer.m.fd = group->planes[0].m.fd; + + /* FIXME Check if data_offset > 0 and fail for non-multi-planar */ + g_assert (group->planes[0].data_offset == 0); + } else { + group->buffer.length = group->n_mem; + } + + gst_v4l2_allocator_reset_size (allocator, group); + + return group; + +expbuf_failed: + { + GST_ERROR_OBJECT (allocator, "Failed to export DMABUF: %s", + g_strerror (errno)); + goto cleanup; + } +cleanup: + { + _cleanup_failed_alloc (allocator, group); + return NULL; + } +} + static void gst_v4l2_allocator_clear_userptr (GstV4l2Allocator * allocator, GstV4l2MemoryGroup * group) @@ -1453,7 +1542,12 @@ gst_v4l2_allocator_reset_group (GstV4l2Allocator * allocator, gst_v4l2_allocator_clear_userptr (allocator, group); break; case V4L2_MEMORY_DMABUF: - gst_v4l2_allocator_clear_dmabufin (allocator, group); + if (V4L2_TYPE_IS_CAPTURE(allocator->obj->type) && (allocator->obj->mode == GST_V4L2_IO_DMABUF_IMPORT)) { + break; + } + else { + gst_v4l2_allocator_clear_dmabufin (allocator, group); + } break; case V4L2_MEMORY_MMAP: break; diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.h b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.h index eb515245a1a..6da9ae236c6 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.h +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.h @@ -137,6 +137,9 @@ GstV4l2MemoryGroup* gst_v4l2_allocator_alloc_dmabuf (GstV4l2Allocator * alloc GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_dmabufin (GstV4l2Allocator * allocator); +GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_dmabufin_capture (GstV4l2Allocator * allocator, + GstAllocator * dmabuf_allocator, GstBuffer* downstream_buffer); + GstV4l2MemoryGroup * gst_v4l2_allocator_alloc_userptr (GstV4l2Allocator * allocator); gboolean gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator, diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c index 8f1c8436761..b41df5a78c6 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c @@ -456,6 +456,7 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, GstBuffer *newbuf = NULL; GstV4l2Object *obj; GstVideoInfo *info; + GstBuffer *downstream_buffer = NULL; obj = pool->obj; info = &obj->info; @@ -476,7 +477,23 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, group = gst_v4l2_allocator_alloc_userptr (pool->vallocator); break; case GST_V4L2_IO_DMABUF_IMPORT: - group = gst_v4l2_allocator_alloc_dmabufin (pool->vallocator); + if (V4L2_TYPE_IS_OUTPUT(obj->type)) + group = gst_v4l2_allocator_alloc_dmabufin (pool->vallocator); + else { + GstFlowReturn ret = gst_buffer_pool_acquire_buffer (pool->other_pool, &downstream_buffer, NULL); + if (ret == GST_FLOW_OK) + { + group = gst_v4l2_allocator_alloc_dmabufin_capture (pool->vallocator, pool->allocator, downstream_buffer); + if (group == NULL) { + gst_buffer_unref (downstream_buffer); + GST_DEBUG_OBJECT (pool, "failed to create buffer while dmabuf importing"); + } + } + else + { + GST_DEBUG_OBJECT (pool->other_pool, "failed to acquire buffer"); + } + } break; default: newbuf = NULL; @@ -512,6 +529,11 @@ gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer, *buffer = newbuf; + if (downstream_buffer) { + gst_mini_object_set_qdata (GST_MINI_OBJECT (newbuf), GST_V4L2_IMPORT_QUARK, + downstream_buffer, (GDestroyNotify) gst_buffer_unref); + } + return GST_FLOW_OK; /* ERRORS */ @@ -566,6 +588,7 @@ gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config) GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, USERPTR); break; case GST_V4L2_IO_DMABUF_IMPORT: + pool->allocator = gst_dmabuf_allocator_new (); can_allocate = GST_V4L2_ALLOCATOR_CAN_ALLOCATE (pool->vallocator, DMABUF); break; case GST_V4L2_IO_RW: @@ -1741,7 +1764,6 @@ gst_v4l2_buffer_pool_complete_release_buffer (GstBufferPool * bpool, case GST_V4L2_IO_DMABUF: case GST_V4L2_IO_MMAP: case GST_V4L2_IO_USERPTR: - case GST_V4L2_IO_DMABUF_IMPORT: { GstV4l2MemoryGroup *group; if (gst_v4l2_is_buffer_valid (buffer, &group)) { @@ -1773,6 +1795,22 @@ gst_v4l2_buffer_pool_complete_release_buffer (GstBufferPool * bpool, } break; } + case GST_V4L2_IO_DMABUF_IMPORT: + { + GstV4l2MemoryGroup *group; + if (gst_v4l2_is_buffer_valid (buffer, &group)) { + GstFlowReturn ret = GST_FLOW_OK; + if (ret != GST_FLOW_OK || + gst_v4l2_buffer_pool_qbuf (pool, buffer, group, NULL) != GST_FLOW_OK) + pclass->release_buffer (bpool, buffer); + } else { + /* Simply release invalid/modified buffer, the allocator will + * give it back later */ + GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY); + pclass->release_buffer (bpool, buffer); + } + break; + } default: g_assert_not_reached (); break; @@ -2221,17 +2259,6 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf, case GST_V4L2_IO_DMABUF_IMPORT: { - GstBuffer *tmp; - - /* Replace our buffer with downstream allocated buffer */ - tmp = gst_mini_object_steal_qdata (GST_MINI_OBJECT (*buf), - GST_V4L2_IMPORT_QUARK); - - gst_buffer_copy_into (tmp, *buf, - GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); - - gst_buffer_replace (buf, tmp); - gst_buffer_unref (tmp); break; } diff --git a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c index bb7458223bf..b5eabfe64cb 100644 --- a/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c +++ b/subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c @@ -5214,7 +5214,11 @@ gst_v4l2_object_decide_allocation (GstV4l2Object * obj, GstQuery * query) gst_v4l2_buffer_pool_copy_at_threshold (GST_V4L2_BUFFER_POOL (pool), FALSE); } - + } else if (V4L2_TYPE_IS_CAPTURE(obj->type) && (obj->mode == GST_V4L2_IO_DMABUF_IMPORT)) { + // since we reuse right index, so let's keep buffer number of downstream pool same with v4l2buffer pool + GST_DEBUG_OBJECT (pool, "got min: %d own_min: %d max: %d min_buffers:%d", min, own_min, max, obj->min_buffers); + own_min = (obj->min_buffers) + min + 1; + min = own_min; } else { /* In this case we'll have to configure two buffer pool. For our buffer * pool, we'll need what the driver one, and one more, so we can dequeu */