From 89b0a6fa231b598f30ce7025aab579784b14fc56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Tue, 29 Aug 2023 12:21:36 +0200 Subject: [PATCH] va: refactor buffer import This patch removes the code duplication of input buffer importation, in all the va elements that import video frames. It defines a synthetic object whose members are required to create a new input buffer and do the importation of the upstream buffer. Part-of: --- .../gst-plugins-bad/sys/va/gstvabase.c | 190 ++++++++++++++++++ .../gst-plugins-bad/sys/va/gstvabase.h | 48 +++++ .../gst-plugins-bad/sys/va/gstvabaseenc.c | 175 ++-------------- .../sys/va/gstvabasetransform.c | 188 +++-------------- .../gst-plugins-bad/sys/va/gstvacompositor.c | 171 ++-------------- .../gst-plugins-bad/sys/va/meson.build | 1 + subprojects/gst-plugins-bad/sys/va/plugin.c | 4 - 7 files changed, 297 insertions(+), 480 deletions(-) create mode 100644 subprojects/gst-plugins-bad/sys/va/gstvabase.c create mode 100644 subprojects/gst-plugins-bad/sys/va/gstvabase.h diff --git a/subprojects/gst-plugins-bad/sys/va/gstvabase.c b/subprojects/gst-plugins-bad/sys/va/gstvabase.c new file mode 100644 index 0000000000..d8f0975166 --- /dev/null +++ b/subprojects/gst-plugins-bad/sys/va/gstvabase.c @@ -0,0 +1,190 @@ +/* GStreamer + * Copyright (C) 2023 Igalia, S.L. + * Author: Víctor Jáquez + * + * 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 + +#include + +#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; + GstMemory *mems[GST_VIDEO_MAX_PLANES]; + guint i, n_mem, 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, }; + + n_planes = GST_VIDEO_INFO_N_PLANES (&in_info); + n_mem = gst_buffer_n_memory (inbuf); + meta = gst_buffer_get_video_meta (inbuf); + + /* This will eliminate most non-dmabuf out there */ + if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0))) + return FALSE; + + /* We cannot have multiple dmabuf per plane */ + if (n_mem > n_planes) + return FALSE; + + /* 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; + + for (i = 0; i < meta->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, &in_info, n_planes, + 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; + } +} diff --git a/subprojects/gst-plugins-bad/sys/va/gstvabase.h b/subprojects/gst-plugins-bad/sys/va/gstvabase.h new file mode 100644 index 0000000000..229d6c3c22 --- /dev/null +++ b/subprojects/gst-plugins-bad/sys/va/gstvabase.h @@ -0,0 +1,48 @@ +/* GStreamer + * Copyright (C) 2021 Igalia, S.L. + * Author: Víctor Jáquez + * + * 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. + */ + +#pragma once + +#include + +#include + +typedef struct _GstVaBufferImporter GstVaBufferImporter; + +typedef GstBufferPool *(*GstVaBufferImporterGetSinkPool) (GstElement * element, gpointer data); + +struct _GstVaBufferImporter +{ + GstElement *element; + GstDebugCategory *debug_category; + + GstVaDisplay *display; + VAEntrypoint entrypoint; + + GstVideoInfo *in_info; + GstVideoInfo *sinkpad_info; + + gpointer pool_data; + GstVaBufferImporterGetSinkPool get_sinkpad_pool; +}; + +GstFlowReturn gst_va_buffer_importer_import (GstVaBufferImporter * base, + GstBuffer * inbuf, + GstBuffer ** outbuf); diff --git a/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c b/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c index dcf9d5a37d..1111850bc0 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c @@ -25,6 +25,7 @@ #include #include "vacompat.h" +#include "gstvabase.h" #include "gstvacaps.h" #include "gstvapluginutils.h" @@ -195,8 +196,9 @@ gst_va_base_enc_get_caps (GstVideoEncoder * venc, GstCaps * filter) } static GstBufferPool * -_get_sinkpad_pool (GstVaBaseEnc * base) +_get_sinkpad_pool (GstElement * element, gpointer data) { + GstVaBaseEnc *base = GST_VA_BASE_ENC (element); GstAllocator *allocator; GstAllocationParams params = { 0, }; guint size, usage_hint; @@ -273,170 +275,25 @@ _get_sinkpad_pool (GstVaBaseEnc * base) return base->priv->raw_pool; } -static inline gsize -_get_plane_data_size (GstVideoInfo * info, guint plane) -{ - gint comp[GST_VIDEO_MAX_COMPONENTS]; - gint height, padded_height; - - gst_video_format_info_component (info->finfo, plane, comp); - - height = GST_VIDEO_INFO_HEIGHT (info); - padded_height = - GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0], height); - - return GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height; -} - -static gboolean -_try_import_dmabuf_unlocked (GstVaBaseEnc * base, GstBuffer * inbuf) -{ - GstVideoMeta *meta; - GstVideoInfo in_info = base->in_info; - GstMemory *mems[GST_VIDEO_MAX_PLANES]; - guint i, n_mem, n_planes, usage_hint; - gsize offset[GST_VIDEO_MAX_PLANES]; - uintptr_t fd[GST_VIDEO_MAX_PLANES]; - - n_planes = GST_VIDEO_INFO_N_PLANES (&in_info); - n_mem = gst_buffer_n_memory (inbuf); - meta = gst_buffer_get_video_meta (inbuf); - - /* This will eliminate most non-dmabuf out there */ - if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0))) - return FALSE; - - /* We cannot have multiple dmabuf per plane */ - if (n_mem > n_planes) - return FALSE; - - /* Update video info based on video meta */ - if (meta) { - GST_VIDEO_INFO_WIDTH (&in_info) = meta->width; - GST_VIDEO_INFO_HEIGHT (&in_info) = meta->height; - - for (i = 0; i < meta->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]; - } - } - - /* Find and validate all memories */ - for (i = 0; i < n_planes; i++) { - guint plane_size; - guint length; - guint mem_idx; - gsize mem_skip; - - plane_size = _get_plane_data_size (&in_info, i); - - if (!gst_buffer_find_memory (inbuf, in_info.offset[i], plane_size, - &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 (base->display, - VAEntrypointEncSlice, GST_PAD_SINK, TRUE); - - /* Now create a VASurfaceID for the buffer */ - return gst_va_dmabuf_memories_setup (base->display, &in_info, n_planes, - mems, fd, offset, usage_hint); -} - -static gboolean -_try_import_buffer (GstVaBaseEnc * base, GstBuffer * inbuf) -{ - VASurfaceID surface; - gboolean ret; - - /* The VA buffer. */ - surface = gst_va_buffer_get_surface (inbuf); - if (surface != VA_INVALID_ID && - (gst_va_buffer_peek_display (inbuf) == base->display)) - return TRUE; - - g_rec_mutex_lock (&GST_VA_SHARED_LOCK); - ret = _try_import_dmabuf_unlocked (base, inbuf); - g_rec_mutex_unlock (&GST_VA_SHARED_LOCK); - - return ret; -} - static GstFlowReturn gst_va_base_enc_import_input_buffer (GstVaBaseEnc * base, GstBuffer * inbuf, GstBuffer ** buf) { - GstBuffer *buffer = NULL; - GstBufferPool *pool; - GstFlowReturn ret; - GstVideoFrame in_frame, out_frame; - gboolean imported, copied; + GstVaBufferImporter importer = { + .element = GST_ELEMENT_CAST (base), +#ifndef GST_DISABLE_GST_DEBUG + .debug_category = GST_CAT_DEFAULT, +#endif + .display = base->display, + .entrypoint = GST_VA_BASE_ENC_ENTRYPOINT (base), + .in_info = &base->input_state->info, + .sinkpad_info = &base->priv->sinkpad_info, + .get_sinkpad_pool = _get_sinkpad_pool, + }; - imported = _try_import_buffer (base, inbuf); - if (imported) { - *buf = gst_buffer_ref (inbuf); - return GST_FLOW_OK; - } + g_return_val_if_fail (GST_IS_VA_BASE_ENC (base), GST_FLOW_ERROR); - /* 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 = _get_sinkpad_pool (base))) - return GST_FLOW_ERROR; - - ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL); - if (ret != GST_FLOW_OK) - return ret; - - GST_LOG_OBJECT (base, "copying input frame"); - - if (!gst_video_frame_map (&in_frame, &base->input_state->info, - inbuf, GST_MAP_READ)) - goto invalid_buffer; - if (!gst_video_frame_map (&out_frame, &base->priv->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; - - /* strictly speaking this is not needed but let's play safe */ - if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS | - GST_BUFFER_COPY_TIMESTAMPS, 0, -1)) - return GST_FLOW_ERROR; - - *buf = buffer; - - return GST_FLOW_OK; - -invalid_buffer: - { - GST_ELEMENT_WARNING (base, CORE, NOT_IMPLEMENTED, (NULL), - ("invalid video buffer received")); - if (buffer) - gst_buffer_unref (buffer); - return GST_FLOW_ERROR; - } + return gst_va_buffer_importer_import (&importer, inbuf, buf); } static GstBuffer * diff --git a/subprojects/gst-plugins-bad/sys/va/gstvabasetransform.c b/subprojects/gst-plugins-bad/sys/va/gstvabasetransform.c index 90b9007ff5..f5d145d353 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvabasetransform.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvabasetransform.c @@ -28,6 +28,7 @@ #include #include +#include "gstvabase.h" #include "gstvacaps.h" #include "gstvapluginutils.h" @@ -80,8 +81,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaBaseTransform, gst_va_base_transform, "vabasetransform", 0, "vabasetransform element"); ); -extern GRecMutex GST_VA_SHARED_LOCK; - static void gst_va_base_transform_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -700,90 +699,6 @@ gst_va_base_transform_allocator_from_caps (GstVaBaseTransform * self, return allocator; } -static inline gsize -_get_plane_data_size (GstVideoInfo * info, guint plane) -{ - gint comp[GST_VIDEO_MAX_COMPONENTS]; - gint height, padded_height; - - gst_video_format_info_component (info->finfo, plane, comp); - - height = GST_VIDEO_INFO_HEIGHT (info); - padded_height = - GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0], height); - - return GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height; -} - -static gboolean -_try_import_dmabuf_unlocked (GstVaBaseTransform * self, GstBuffer * inbuf) -{ - GstVaBaseTransform *btrans = GST_VA_BASE_TRANSFORM (self); - GstVideoMeta *meta; - GstVideoInfo in_info = btrans->in_info; - GstMemory *mems[GST_VIDEO_MAX_PLANES]; - guint i, n_mem, n_planes, usage_hint; - gsize offset[GST_VIDEO_MAX_PLANES]; - uintptr_t fd[GST_VIDEO_MAX_PLANES]; - - n_planes = GST_VIDEO_INFO_N_PLANES (&in_info); - n_mem = gst_buffer_n_memory (inbuf); - meta = gst_buffer_get_video_meta (inbuf); - - /* This will eliminate most non-dmabuf out there */ - if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0))) - return FALSE; - - /* We cannot have multiple dmabuf per plane */ - if (n_mem > n_planes) - return FALSE; - - /* Update video info based on video meta */ - if (meta) { - GST_VIDEO_INFO_WIDTH (&in_info) = meta->width; - GST_VIDEO_INFO_HEIGHT (&in_info) = meta->height; - - for (i = 0; i < meta->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]; - } - } - - /* Find and validate all memories */ - for (i = 0; i < n_planes; i++) { - guint plane_size; - guint length; - guint mem_idx; - gsize mem_skip; - - plane_size = _get_plane_data_size (&in_info, i); - - if (!gst_buffer_find_memory (inbuf, in_info.offset[i], plane_size, - &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 (self->display, - VAEntrypointVideoProc, GST_PAD_SINK, TRUE); - - /* Now create a VASurfaceID for the buffer */ - return gst_va_dmabuf_memories_setup (btrans->display, &in_info, n_planes, - mems, fd, offset, usage_hint); -} - static gboolean _check_uncropped_size (GstVaBaseTransform * self, GstBuffer * inbuf) { @@ -831,21 +746,15 @@ _check_uncropped_size (GstVaBaseTransform * self, GstBuffer * inbuf) } static GstBufferPool * -_get_sinkpad_pool (GstVaBaseTransform * self, GstBuffer * inbuf) +_get_sinkpad_pool (GstElement * element, gpointer data) { + GstVaBaseTransform *self = GST_VA_BASE_TRANSFORM (element); GstAllocator *allocator; GstAllocationParams params = { 0, }; GstCaps *caps; GstVideoInfo in_info; guint size, usage_hint; - if (_check_uncropped_size (self, inbuf)) { - if (self->priv->sinkpad_pool) - gst_buffer_pool_set_active (self->priv->sinkpad_pool, FALSE); - - gst_clear_object (&self->priv->sinkpad_pool); - } - if (self->priv->sinkpad_pool) return self->priv->sinkpad_pool; @@ -933,24 +842,6 @@ _get_sinkpad_pool (GstVaBaseTransform * self, GstBuffer * inbuf) return self->priv->sinkpad_pool; } -static gboolean -_try_import_buffer (GstVaBaseTransform * self, GstBuffer * inbuf) -{ - VASurfaceID surface; - gboolean ret; - - surface = gst_va_buffer_get_surface (inbuf); - if (surface != VA_INVALID_ID && - (gst_va_buffer_peek_display (inbuf) == self->display)) - return TRUE; - - g_rec_mutex_lock (&GST_VA_SHARED_LOCK); - ret = _try_import_dmabuf_unlocked (self, inbuf); - g_rec_mutex_unlock (&GST_VA_SHARED_LOCK); - - return ret; -} - typedef struct { GstVaBaseTransform *self; @@ -992,70 +883,43 @@ GstFlowReturn gst_va_base_transform_import_buffer (GstVaBaseTransform * self, GstBuffer * inbuf, GstBuffer ** buf) { - GstBuffer *buffer = NULL; - GstBufferPool *pool; + GstVaBufferImporter importer = { + .element = GST_ELEMENT_CAST (self), +#ifndef GST_DISABLE_GST_DEBUG + .debug_category = GST_CAT_DEFAULT, +#endif + .display = self->display, + .entrypoint = VAEntrypointVideoProc, + .in_info = &self->in_info, + .sinkpad_info = &self->priv->sinkpad_info, + .get_sinkpad_pool = _get_sinkpad_pool, + }; GstFlowReturn ret; - GstVideoFrame in_frame, out_frame; - gboolean imported, copied; CopyMetaData data; g_return_val_if_fail (GST_IS_VA_BASE_TRANSFORM (self), GST_FLOW_ERROR); - imported = _try_import_buffer (self, inbuf); - if (imported) { - *buf = gst_buffer_ref (inbuf); - return GST_FLOW_OK; + if (_check_uncropped_size (self, inbuf)) { + if (self->priv->sinkpad_pool) + gst_buffer_pool_set_active (self->priv->sinkpad_pool, FALSE); + + gst_clear_object (&self->priv->sinkpad_pool); } - /* 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 = _get_sinkpad_pool (self, inbuf))) - return GST_FLOW_ERROR; - - ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL); + ret = gst_va_buffer_importer_import (&importer, inbuf, buf); if (ret != GST_FLOW_OK) - return ret; + goto bail; - GST_LOG_OBJECT (self, "copying input frame"); - - if (!gst_video_frame_map (&in_frame, &self->in_info, inbuf, GST_MAP_READ)) - goto invalid_buffer; - - if (!gst_video_frame_map (&out_frame, &self->priv->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; - - gst_buffer_copy_into (buffer, inbuf, - GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); + if (*buf == inbuf) + goto bail; data.self = self; - data.outbuf = buffer; + data.outbuf = *buf; gst_buffer_foreach_meta (inbuf, foreach_metadata, &data); - *buf = buffer; - - return GST_FLOW_OK; - -invalid_buffer: - { - GST_ELEMENT_WARNING (self, STREAM, FORMAT, (NULL), - ("invalid video buffer received")); - if (buffer) - gst_buffer_unref (buffer); - return GST_FLOW_ERROR; - } +bail: + return ret; } GstCaps * diff --git a/subprojects/gst-plugins-bad/sys/va/gstvacompositor.c b/subprojects/gst-plugins-bad/sys/va/gstvacompositor.c index ab60fa3319..2131dc263b 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvacompositor.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvacompositor.c @@ -51,6 +51,7 @@ #include #include +#include "gstvabase.h" #include "gstvacaps.h" #include "gstvadisplay_priv.h" #include "gstvafilter.h" @@ -794,8 +795,10 @@ gst_va_compositor_decide_allocation (GstAggregator * agg, GstQuery * query) } static GstBufferPool * -_get_sinkpad_pool (GstVaCompositor * self, GstVaCompositorPad * pad) +_get_sinkpad_pool (GstElement * element, gpointer data) { + GstVaCompositor *self = GST_VA_COMPOSITOR (element); + GstVaCompositorPad *pad = GST_VA_COMPOSITOR_PAD (data); GstAllocator *allocator; GstAllocationParams params = { 0, }; GstCaps *caps; @@ -851,121 +854,22 @@ _get_sinkpad_pool (GstVaCompositor * self, GstVaCompositorPad * pad) return pad->pool; } -static inline gsize -_get_plane_data_size (GstVideoInfo * info, guint plane) -{ - gint comp[GST_VIDEO_MAX_COMPONENTS]; - gint height, padded_height; - - gst_video_format_info_component (info->finfo, plane, comp); - - height = GST_VIDEO_INFO_HEIGHT (info); - padded_height = - GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, comp[0], height); - - return GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height; -} - -static gboolean -_try_import_dmabuf_unlocked (GstVaCompositor * self, GstVideoInfo * info, - GstBuffer * inbuf) -{ - GstVideoMeta *meta; - GstMemory *mems[GST_VIDEO_MAX_PLANES]; - guint i, n_mem, n_planes, usage_hint; - gsize offset[GST_VIDEO_MAX_PLANES]; - uintptr_t fd[GST_VIDEO_MAX_PLANES]; - - n_planes = GST_VIDEO_INFO_N_PLANES (info); - n_mem = gst_buffer_n_memory (inbuf); - meta = gst_buffer_get_video_meta (inbuf); - - /* This will eliminate most non-dmabuf out there */ - if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0))) - return FALSE; - - /* We cannot have multiple dmabuf per plane */ - if (n_mem > n_planes) - return FALSE; - - /* Update video info based on video meta */ - if (meta) { - GST_VIDEO_INFO_WIDTH (info) = meta->width; - GST_VIDEO_INFO_HEIGHT (info) = meta->height; - - for (i = 0; i < meta->n_planes; i++) { - GST_VIDEO_INFO_PLANE_OFFSET (info, i) = meta->offset[i]; - GST_VIDEO_INFO_PLANE_STRIDE (info, i) = meta->stride[i]; - } - } - - /* Find and validate all memories */ - for (i = 0; i < n_planes; i++) { - guint plane_size; - guint length; - guint mem_idx; - gsize mem_skip; - - plane_size = _get_plane_data_size (info, i); - - if (!gst_buffer_find_memory (inbuf, info->offset[i], plane_size, - &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 (self->display, - VAEntrypointVideoProc, GST_PAD_SINK, TRUE); - - /* Now create a VASurfaceID for the buffer */ - return gst_va_dmabuf_memories_setup (self->display, info, n_planes, - mems, fd, offset, usage_hint); -} - -extern GRecMutex GST_VA_SHARED_LOCK; - -static gboolean -_try_import_buffer (GstVaCompositor * self, GstVideoInfo * info, - GstBuffer * inbuf) -{ - VASurfaceID surface; - gboolean ret; - - surface = gst_va_buffer_get_surface (inbuf); - if (surface != VA_INVALID_ID && - (gst_va_buffer_peek_display (inbuf) == self->display)) - return TRUE; - - g_rec_mutex_lock (&GST_VA_SHARED_LOCK); - ret = _try_import_dmabuf_unlocked (self, info, inbuf); - g_rec_mutex_unlock (&GST_VA_SHARED_LOCK); - - return ret; -} - static GstFlowReturn gst_va_compositor_import_buffer (GstVaCompositor * self, GstVaCompositorPad * pad, GstBuffer * inbuf, GstBuffer ** buf) { - GstBuffer *buffer = NULL; - GstBufferPool *pool; - GstFlowReturn ret; + GstVaBufferImporter importer = { + .element = GST_ELEMENT_CAST (self), +#ifndef GST_DISABLE_GST_DEBUG + .debug_category = GST_CAT_DEFAULT, +#endif + .display = self->display, + .entrypoint = VAEntrypointVideoProc, + .get_sinkpad_pool = _get_sinkpad_pool, + .pool_data = pad, + }; GstCaps *caps; GstVideoInfo info; - GstVideoFrame in_frame, out_frame; - gboolean imported, copied; caps = gst_pad_get_current_caps (GST_PAD (pad)); if (!caps) @@ -977,52 +881,9 @@ gst_va_compositor_import_buffer (GstVaCompositor * self, } gst_caps_unref (caps); - imported = _try_import_buffer (self, &info, inbuf); - if (imported) { - *buf = gst_buffer_ref (inbuf); - return GST_FLOW_OK; - } + importer.in_info = importer.sinkpad_info = &info; - GST_LOG_OBJECT (self, "copying input frame"); - - /* 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 = _get_sinkpad_pool (self, pad))) - return GST_FLOW_ERROR; - - ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL); - if (ret != GST_FLOW_OK) - return ret; - - if (!gst_video_frame_map (&in_frame, &info, inbuf, GST_MAP_READ)) - goto invalid_buffer; - - if (!gst_video_frame_map (&out_frame, &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; - - *buf = buffer; - - return GST_FLOW_OK; - -invalid_buffer: - { - GST_ELEMENT_WARNING (self, CORE, NOT_IMPLEMENTED, (NULL), - ("invalid video buffer received")); - if (buffer) - gst_buffer_unref (buffer); - return GST_FLOW_OK; - } + return gst_va_buffer_importer_import (&importer, inbuf, buf); } typedef struct _GstVaCompositorSampleGenerator GstVaCompositorSampleGenerator; diff --git a/subprojects/gst-plugins-bad/sys/va/meson.build b/subprojects/gst-plugins-bad/sys/va/meson.build index 3e0a3f7060..3dbcfa60d1 100644 --- a/subprojects/gst-plugins-bad/sys/va/meson.build +++ b/subprojects/gst-plugins-bad/sys/va/meson.build @@ -1,6 +1,7 @@ va_sources = [ 'plugin.c', 'gstjpegdecoder.c', + 'gstvabase.c', 'gstvabasedec.c', 'gstvabasetransform.c', 'gstvabaseenc.c', diff --git a/subprojects/gst-plugins-bad/sys/va/plugin.c b/subprojects/gst-plugins-bad/sys/va/plugin.c index 85c4cc64bd..52924dcaa5 100644 --- a/subprojects/gst-plugins-bad/sys/va/plugin.c +++ b/subprojects/gst-plugins-bad/sys/va/plugin.c @@ -47,10 +47,6 @@ #define GST_CAT_DEFAULT gstva_debug GST_DEBUG_CATEGORY (gstva_debug); -/* big bad mutex to exclusive access to shared stream buffers, such as - * DMABuf after a tee */ -GRecMutex GST_VA_SHARED_LOCK = { 0, }; - #ifdef G_OS_WIN32 /* Windows support is still experimental */ #define GST_VA_RANK_PRIMARY GST_RANK_NONE