gstreamer/subprojects/gst-plugins-bad/sys/va/gstvabase.c
Víctor Manuel Jáquez Leal 9f5b2c4e25 va: use GstVideoInfoDmaDrm when importing buffers
In the case of encoders and filters when importing a DMABuf, use
GstVideoInfoDmaDrm to get the drm fourcc and modifier.

In both cases, instead of keeping the original GstVideoInfoDmaDrm from caps, the
GstVideoInfo part of the structure is converted as canonical one, given the
format from the fourcc. It's kept in the way to handle V4L2 linear DMABufs and
to avoid too many changes in the current code.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5264>
2023-11-09 17:36:06 +00:00

223 lines
6.3 KiB
C

/* GStreamer
* Copyright (C) 2023 Igalia, S.L.
* Author: Víctor Jáquez <vjaquez@igalia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstvabase.h"
#include <gst/video/video.h>
#include <gst/va/gstvavideoformat.h>
#include <gst/va/vasurfaceimage.h>
#define GST_CAT_DEFAULT (importer->debug_category)
/* big bad mutex to exclusive access to shared stream buffers, such as
* DMABuf after a tee */
static GRecMutex GST_VA_SHARED_LOCK = { 0, };
static gboolean
_try_import_dmabuf_unlocked (GstVaBufferImporter * importer, GstBuffer * inbuf)
{
GstVideoMeta *meta;
GstVideoInfo in_info = *importer->in_info;
GstVideoInfoDmaDrm drm_info = *importer->in_drm_info;
GstMemory *mems[GST_VIDEO_MAX_PLANES];
guint i, n_planes, usage_hint;
gsize offset[GST_VIDEO_MAX_PLANES];
uintptr_t fd[GST_VIDEO_MAX_PLANES];
gsize plane_size[GST_VIDEO_MAX_PLANES];
GstVideoAlignment align = { 0, };
/* This will eliminate most non-dmabuf out there */
if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0)))
return FALSE;
n_planes = GST_VIDEO_INFO_N_PLANES (&in_info);
meta = gst_buffer_get_video_meta (inbuf);
/* Update video info importerd on video meta */
if (meta) {
GST_VIDEO_INFO_WIDTH (&in_info) = meta->width;
GST_VIDEO_INFO_HEIGHT (&in_info) = meta->height;
g_assert (n_planes == meta->n_planes);
for (i = 0; i < n_planes; i++) {
GST_VIDEO_INFO_PLANE_OFFSET (&in_info, i) = meta->offset[i];
GST_VIDEO_INFO_PLANE_STRIDE (&in_info, i) = meta->stride[i];
}
}
if (!gst_video_info_align_full (&in_info, &align, plane_size))
return FALSE;
/* Find and validate all memories */
for (i = 0; i < n_planes; i++) {
guint length;
guint mem_idx;
gsize mem_skip;
if (!gst_buffer_find_memory (inbuf,
GST_VIDEO_INFO_PLANE_OFFSET (&in_info, i), plane_size[i], &mem_idx,
&length, &mem_skip))
return FALSE;
/* We can't have more then one dmabuf per plane */
if (length != 1)
return FALSE;
mems[i] = gst_buffer_peek_memory (inbuf, mem_idx);
/* And all memory found must be dmabuf */
if (!gst_is_dmabuf_memory (mems[i]))
return FALSE;
offset[i] = mems[i]->offset + mem_skip;
fd[i] = gst_dmabuf_memory_get_fd (mems[i]);
}
usage_hint = va_get_surface_usage_hint (importer->display,
importer->entrypoint, GST_PAD_SINK, TRUE);
/* Now create a VASurfaceID for the buffer */
return gst_va_dmabuf_memories_setup (importer->display, &drm_info, mems, fd,
offset, usage_hint);
}
static gboolean
_try_import_buffer (GstVaBufferImporter * importer, GstBuffer * inbuf)
{
VASurfaceID surface;
gboolean ret;
surface = gst_va_buffer_get_surface (inbuf);
if (surface != VA_INVALID_ID &&
(gst_va_buffer_peek_display (inbuf) == importer->display))
return TRUE;
g_rec_mutex_lock (&GST_VA_SHARED_LOCK);
ret = _try_import_dmabuf_unlocked (importer, inbuf);
g_rec_mutex_unlock (&GST_VA_SHARED_LOCK);
return ret;
}
GstFlowReturn
gst_va_buffer_importer_import (GstVaBufferImporter * importer,
GstBuffer * inbuf, GstBuffer ** outbuf)
{
GstBuffer *buffer = NULL;
GstBufferPool *pool;
GstFlowReturn ret;
GstVideoFrame in_frame, out_frame;
gboolean imported, copied;
imported = _try_import_buffer (importer, inbuf);
if (imported) {
*outbuf = gst_buffer_ref (inbuf);
return GST_FLOW_OK;
}
/* input buffer doesn't come from a vapool, thus it is required to
* have a pool, grab from it a new buffer and copy the input
* buffer to the new one */
if (!(pool = importer->get_sinkpad_pool (importer->element,
importer->pool_data)))
return GST_FLOW_ERROR;
ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
if (ret != GST_FLOW_OK)
return ret;
GST_LOG_OBJECT (importer->element, "copying input frame");
if (!gst_video_frame_map (&in_frame, importer->in_info, inbuf, GST_MAP_READ))
goto invalid_buffer;
if (!gst_video_frame_map (&out_frame, importer->sinkpad_info, buffer,
GST_MAP_WRITE)) {
gst_video_frame_unmap (&in_frame);
goto invalid_buffer;
}
copied = gst_video_frame_copy (&out_frame, &in_frame);
gst_video_frame_unmap (&out_frame);
gst_video_frame_unmap (&in_frame);
if (!copied)
goto invalid_buffer;
if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS |
GST_BUFFER_COPY_TIMESTAMPS, 0, -1)) {
GST_WARNING_OBJECT (importer->element,
"Couldn't import buffer flags and timestamps");
}
*outbuf = buffer;
return GST_FLOW_OK;
invalid_buffer:
{
GST_ELEMENT_WARNING (importer->element, STREAM, FORMAT, (NULL),
("invalid video buffer received"));
if (buffer)
gst_buffer_unref (buffer);
return GST_FLOW_ERROR;
}
}
gboolean
gst_va_base_convert_caps_to_va (GstCaps * caps)
{
g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
/* For DMA buffer, we can only import linear buffers. Replace the drm-format
* into format field. */
if (gst_video_is_dma_drm_caps (caps)) {
GstVideoInfoDmaDrm dma_info;
GstVideoInfo info;
if (!gst_video_info_dma_drm_from_caps (&dma_info, caps))
return FALSE;
if (dma_info.drm_modifier != DRM_FORMAT_MOD_LINEAR)
return FALSE;
if (!gst_va_dma_drm_info_to_video_info (&dma_info, &info))
return FALSE;
gst_caps_set_simple (caps, "format", G_TYPE_STRING,
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&info)), NULL);
gst_structure_remove_field (gst_caps_get_structure (caps, 0), "drm-format");
}
gst_caps_set_features_simple (caps,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
return TRUE;
}