mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 00:06:36 +00:00
9f5b2c4e25
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>
222 lines
6.3 KiB
C
222 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;
|
|
}
|