gstreamer/subprojects/gst-plugins-bad/sys/va/gstvabase.c
Robert Mader f392e9b369 vabase: Stop aligning VideoInfo during DMABUF import
Doing so resets the stride from the VideoMeta and it wasn't done before
the commit below. While on it, drop the plane size check as we can't
reliably predict the correct size when using DRM modifiers.

Fixes: 89b0a6fa23 ("va: refactor buffer import")
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7187>
2024-07-18 09:10:23 +00:00

216 lines
6.1 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;
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];
/* 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 (&drm_info.vinfo);
meta = gst_buffer_get_video_meta (inbuf);
/* Update video info importerd on video meta */
if (meta) {
GST_VIDEO_INFO_WIDTH (&drm_info.vinfo) = meta->width;
GST_VIDEO_INFO_HEIGHT (&drm_info.vinfo) = meta->height;
g_assert (n_planes == meta->n_planes);
for (i = 0; i < n_planes; i++) {
GST_VIDEO_INFO_PLANE_OFFSET (&drm_info.vinfo, i) = meta->offset[i];
GST_VIDEO_INFO_PLANE_STRIDE (&drm_info.vinfo, i) = meta->stride[i];
}
}
/* 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 (&drm_info.vinfo, i), 1, &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;
}