Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v4l2src: added dmabuf support #2

Open
wants to merge 2 commits into
base: xlnx-rebase-v1.20.5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 96 additions & 4 deletions subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ gst_v4l2_allocator_release (GstV4l2Allocator * allocator, GstV4l2Memory * mem)

switch (allocator->memory) {
case V4L2_MEMORY_DMABUF:
close (mem->dmafd);
if (V4L2_TYPE_IS_CAPTURE(allocator->obj->type) && (allocator->obj->mode == GST_V4L2_IO_DMABUF_IMPORT))
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, consider backporting the upstream patch fixing this instead of deviating. This type of change would make future GStreamer upgrade difficult.

https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5101

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified as per the suggestion

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By backporting, I meant to port the patch "v4l2: allocator: Don't close foreign dmabuf", and apply it as its own patch. This way we know where the change is from as it has cross-reference and original authorship.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified as per your suggestion. Please review and comment.

mem->dmafd = -1;
break;
case V4L2_MEMORY_USERPTR:
Expand Down Expand Up @@ -396,9 +397,10 @@ 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);
GST_LOG_OBJECT (allocator, "close fd: %d", mem->dmafd);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't add debugging in your fork, it will simply make GStreamer update difficult later. This code is changed with https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5101, it is now limited to V4L2_MEMORY_MMAP (when the driver is exporter).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have added this change, But the above merge is done on 1.22 while we are using the 1.20 repo of gstreamer.
Will there be any issue in it?

}
}

g_slice_free (GstV4l2Memory, mem);
Expand Down Expand Up @@ -1023,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)
Expand Down Expand Up @@ -1455,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;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An else clause would be nicer.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified.

else {
gst_v4l2_allocator_clear_dmabufin (allocator, group);
}
break;
case V4L2_MEMORY_MMAP:
break;
Expand Down
3 changes: 3 additions & 0 deletions subprojects/gst-plugins-good/sys/v4l2/gstv4l2allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
53 changes: 40 additions & 13 deletions subprojects/gst-plugins-good/sys/v4l2/gstv4l2bufferpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 5 additions & 1 deletion subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down