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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5257>
This commit is contained in:
Víctor Manuel Jáquez Leal 2023-08-29 12:21:36 +02:00 committed by GStreamer Marge Bot
parent 94593735d3
commit 89b0a6fa23
7 changed files with 297 additions and 480 deletions

View file

@ -0,0 +1,190 @@
/* 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/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;
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;
}
}

View file

@ -0,0 +1,48 @@
/* GStreamer
* Copyright (C) 2021 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.
*/
#pragma once
#include <gst/gst.h>
#include <gst/va/gstva.h>
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);

View file

@ -25,6 +25,7 @@
#include <gst/va/gstvavideoformat.h>
#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 *

View file

@ -28,6 +28,7 @@
#include <gst/va/gstvavideoformat.h>
#include <gst/va/vasurfaceimage.h>
#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 *

View file

@ -51,6 +51,7 @@
#include <gst/video/video.h>
#include <va/va_drmcommon.h>
#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;

View file

@ -1,6 +1,7 @@
va_sources = [
'plugin.c',
'gstjpegdecoder.c',
'gstvabase.c',
'gstvabasedec.c',
'gstvabasetransform.c',
'gstvabaseenc.c',

View file

@ -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