2023-08-29 10:21:36 +00:00
|
|
|
/* 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>
|
|
|
|
|
2023-08-29 18:33:33 +00:00
|
|
|
#include <gst/va/gstvavideoformat.h>
|
2023-08-29 10:21:36 +00:00
|
|
|
#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;
|
2023-11-08 12:59:44 +00:00
|
|
|
GstVideoInfoDmaDrm drm_info = *importer->in_drm_info;
|
2023-08-29 10:21:36 +00:00
|
|
|
GstMemory *mems[GST_VIDEO_MAX_PLANES];
|
2023-11-08 12:59:44 +00:00
|
|
|
guint i, n_planes, usage_hint;
|
2023-08-29 10:21:36 +00:00
|
|
|
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;
|
|
|
|
|
2024-07-17 10:45:31 +00:00
|
|
|
n_planes = GST_VIDEO_INFO_N_PLANES (&drm_info.vinfo);
|
2023-08-30 19:49:22 +00:00
|
|
|
|
|
|
|
meta = gst_buffer_get_video_meta (inbuf);
|
|
|
|
|
2023-08-29 10:21:36 +00:00
|
|
|
/* Update video info importerd on video meta */
|
|
|
|
if (meta) {
|
2024-07-17 10:45:31 +00:00
|
|
|
GST_VIDEO_INFO_WIDTH (&drm_info.vinfo) = meta->width;
|
|
|
|
GST_VIDEO_INFO_HEIGHT (&drm_info.vinfo) = meta->height;
|
2023-08-29 10:21:36 +00:00
|
|
|
|
2023-11-08 12:59:44 +00:00
|
|
|
g_assert (n_planes == meta->n_planes);
|
|
|
|
|
|
|
|
for (i = 0; i < n_planes; i++) {
|
2024-07-17 10:45:31 +00:00
|
|
|
GST_VIDEO_INFO_PLANE_OFFSET (&drm_info.vinfo, i) = meta->offset[i];
|
|
|
|
GST_VIDEO_INFO_PLANE_STRIDE (&drm_info.vinfo, i) = meta->stride[i];
|
2023-08-29 10:21:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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,
|
2024-07-16 21:08:39 +00:00
|
|
|
GST_VIDEO_INFO_PLANE_OFFSET (&drm_info.vinfo, i), 1, &mem_idx,
|
|
|
|
&length, &mem_skip))
|
2023-08-29 10:21:36 +00:00
|
|
|
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 */
|
2023-08-30 19:49:22 +00:00
|
|
|
return gst_va_dmabuf_memories_setup (importer->display, &drm_info, mems, fd,
|
2023-08-30 19:25:41 +00:00
|
|
|
offset, usage_hint);
|
2023-08-29 10:21:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2023-08-29 18:33:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|