v4l2: bufferpool: Drop writable check on output pool process

Output buffers don't have to be writable. Accepting read-only buffers
from the V4L2 buffer pool allows upstream elements to write directly
into the V4L2 buffers without triggering a CPU copy into a new buffer
from the same V4L2 buffer pool every time.

Tested with the vivid output device:

  GST_DEBUG=GST_PERFORMANCE:7 gst-launch-1.0 videotestsrc ! v4l2sink device=/dev/video5

With this change, gst_v4l2_buffer_pool_dqbuf() must be allowed to not
resize read-only memories of output buffers.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6572>
This commit is contained in:
Philipp Zabel 2024-04-05 14:09:18 +02:00 committed by GStreamer Marge Bot
parent a7fe79c4de
commit e1f5bacf8d

View file

@ -84,7 +84,8 @@ static void gst_v4l2_buffer_pool_complete_release_buffer (GstBufferPool * bpool,
GstBuffer * buffer, gboolean queued);
static gboolean
gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** out_group)
gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** out_group,
gboolean check_writable)
{
GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
gboolean valid = FALSE;
@ -108,7 +109,7 @@ gst_v4l2_is_buffer_valid (GstBuffer * buffer, GstV4l2MemoryGroup ** out_group)
if (group->mem[i] != gst_buffer_peek_memory (buffer, i))
goto done;
if (!gst_memory_is_writable (group->mem[i]))
if (check_writable && !gst_memory_is_writable (group->mem[i]))
goto done;
}
@ -127,7 +128,7 @@ gst_v4l2_buffer_pool_resize_buffer (GstBufferPool * bpool, GstBuffer * buffer)
GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
GstV4l2MemoryGroup *group;
if (gst_v4l2_is_buffer_valid (buffer, &group)) {
if (gst_v4l2_is_buffer_valid (buffer, &group, TRUE)) {
gst_v4l2_allocator_reset_group (pool->vallocator, group);
} else {
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
@ -238,7 +239,7 @@ gst_v4l2_buffer_pool_import_userptr (GstV4l2BufferPool * pool,
GST_LOG_OBJECT (pool, "importing userptr");
/* get the group */
if (!gst_v4l2_is_buffer_valid (dest, &group))
if (!gst_v4l2_is_buffer_valid (dest, &group, TRUE))
goto not_our_buffer;
if (V4L2_TYPE_IS_OUTPUT (pool->obj->type))
@ -355,7 +356,7 @@ gst_v4l2_buffer_pool_import_dmabuf (GstV4l2BufferPool * pool,
GST_LOG_OBJECT (pool, "importing dmabuf");
if (!gst_v4l2_is_buffer_valid (dest, &group))
if (!gst_v4l2_is_buffer_valid (dest, &group, TRUE))
goto not_our_buffer;
if (n_mem > GST_VIDEO_MAX_PLANES)
@ -1312,15 +1313,18 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer,
if (GST_VIDEO_INFO_FORMAT (&pool->caps_info) == GST_VIDEO_FORMAT_ENCODED)
break;
/* Ensure our offset matches the expected plane size, or image size if
* there is only one memory */
if (group->n_mem == 1) {
gst_memory_resize (group->mem[0], 0, info->size + info->offset[0]);
break;
}
if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
/* Ensure our offset matches the expected plane size, or image size if
* there is only one memory */
if (group->n_mem == 1) {
gst_memory_resize (group->mem[0], 0, info->size + info->offset[0]);
break;
}
if (!GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
gst_memory_resize (group->mem[i], 0, obj->plane_size[i]);
if (!GST_VIDEO_FORMAT_INFO_IS_TILED (finfo))
gst_memory_resize (group->mem[i], 0, obj->plane_size[i]);
}
}
/* Ignore timestamp and field for OUTPUT device */
@ -1520,7 +1524,7 @@ done:
/* Mark buffer as outstanding */
if (ret == GST_FLOW_OK) {
GstV4l2MemoryGroup *group;
if (gst_v4l2_is_buffer_valid (*buffer, &group)) {
if (gst_v4l2_is_buffer_valid (*buffer, &group, TRUE)) {
GST_LOG_OBJECT (pool, "mark buffer %u outstanding", group->buffer.index);
g_atomic_int_or (&pool->buffer_state[group->buffer.index],
BUFFER_STATE_OUTSTANDING);
@ -1571,7 +1575,7 @@ gst_v4l2_buffer_pool_complete_release_buffer (GstBufferPool * bpool,
case GST_V4L2_IO_DMABUF_IMPORT:
{
GstV4l2MemoryGroup *group;
if (gst_v4l2_is_buffer_valid (buffer, &group)) {
if (gst_v4l2_is_buffer_valid (buffer, &group, TRUE)) {
GstFlowReturn ret = GST_FLOW_OK;
gst_v4l2_allocator_reset_group (pool->vallocator, group);
@ -1612,7 +1616,7 @@ gst_v4l2_buffer_pool_complete_release_buffer (GstBufferPool * bpool,
GstV4l2MemoryGroup *group;
guint index;
if (!gst_v4l2_is_buffer_valid (buffer, &group)) {
if (!gst_v4l2_is_buffer_valid (buffer, &group, TRUE)) {
/* Simply release invalid/modified buffer, the allocator will
* give it back later */
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
@ -1663,7 +1667,7 @@ gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
GstV4l2MemoryGroup *group;
gboolean queued = FALSE;
if (gst_v4l2_is_buffer_valid (buffer, &group)) {
if (gst_v4l2_is_buffer_valid (buffer, &group, TRUE)) {
gint old_buffer_state =
g_atomic_int_and (&pool->buffer_state[group->buffer.index],
~BUFFER_STATE_OUTSTANDING);
@ -2065,7 +2069,8 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf,
if ((*buf)->pool != bpool)
goto copying;
if (!gst_v4l2_is_buffer_valid (*buf, &group))
/* Output buffers don't have to be writable */
if (!gst_v4l2_is_buffer_valid (*buf, &group, FALSE))
goto copying;
index = group->buffer.index;
@ -2102,7 +2107,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf,
}
/* retrieve the group */
gst_v4l2_is_buffer_valid (to_queue, &group);
gst_v4l2_is_buffer_valid (to_queue, &group, TRUE);
}
if ((ret =
@ -2115,7 +2120,7 @@ gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer ** buf,
* streaming now */
if (!gst_v4l2_buffer_pool_streamon (pool)) {
/* don't check return value because qbuf would have failed */
gst_v4l2_is_buffer_valid (to_queue, &group);
gst_v4l2_is_buffer_valid (to_queue, &group, TRUE);
/* qbuf has stored to_queue buffer but we are not in
* streaming state, so the flush logic won't be performed.