mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-03 06:56:46 +00:00
4a22cc8fb3
VA drivers allocate surfaces given their properties, so there's no need to provide a buffer size to the VA pool. Though, the buffer size is provided by the driver, or the canonical size is used for single planed surfaces. This patch removes the need to provide a size for the function gst_va_pool_new_with_config() and adds a helper method to retrieve the surface size, gst_va_pool_get_buffer_size(). Also change the callers accordingly. Changes for custom VA pool creation will be addressed in the following commits. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5805>
537 lines
15 KiB
C
537 lines
15 KiB
C
/* GStreamer
|
|
* Copyright (C) 2020 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.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:gstvapool
|
|
* @title: GstVaPool
|
|
* @short_description: VA Buffer pool
|
|
* @sources:
|
|
* - gstvapool.h
|
|
*
|
|
* @GstVaPool is a buffer pool for VA allocators.
|
|
*
|
|
* Since: 1.22
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstvapool.h"
|
|
#include "gstvavideoformat.h"
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (gst_va_pool_debug);
|
|
#define GST_CAT_DEFAULT gst_va_pool_debug
|
|
|
|
/**
|
|
* GstVaPool:
|
|
*
|
|
* A buffer pool that uses either #GstVaAllocator or
|
|
* #GstVaDmabufAllocator to pre-allocate and recycle #GstBuffers.
|
|
*
|
|
* Since: 1.22
|
|
*/
|
|
typedef struct _GstVaPool GstVaPool;
|
|
typedef struct _GstVaPoolClass GstVaPoolClass;
|
|
|
|
struct _GstVaPool
|
|
{
|
|
GstBufferPool parent;
|
|
|
|
GstVideoInfo alloc_info;
|
|
union
|
|
{
|
|
GstVideoInfo caps_info;
|
|
/* GstVideoInfoDmaDrm contains GstVideoInfo. */
|
|
GstVideoInfoDmaDrm caps_info_drm;
|
|
};
|
|
GstAllocator *allocator;
|
|
gboolean force_videometa;
|
|
gboolean add_videometa;
|
|
gint crop_left;
|
|
gint crop_top;
|
|
|
|
gboolean starting;
|
|
};
|
|
|
|
struct _GstVaPoolClass
|
|
{
|
|
GstBufferPoolClass parent_class;
|
|
};
|
|
|
|
#define gst_va_pool_parent_class parent_class
|
|
G_DEFINE_TYPE_WITH_CODE (GstVaPool, gst_va_pool, GST_TYPE_BUFFER_POOL,
|
|
GST_DEBUG_CATEGORY_INIT (gst_va_pool_debug, "vapool", 0, "VA Pool"));
|
|
|
|
static const gchar **
|
|
gst_va_pool_get_options (GstBufferPool * pool)
|
|
{
|
|
static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL };
|
|
return options;
|
|
}
|
|
|
|
static inline gboolean
|
|
gst_buffer_pool_config_get_va_allocation_params (GstStructure * config,
|
|
guint32 * usage_hint, GstVaFeature * use_derived)
|
|
{
|
|
if (!gst_structure_get (config, "usage-hint", G_TYPE_UINT, usage_hint, NULL)) {
|
|
*usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
|
|
}
|
|
|
|
if (!gst_structure_get (config, "use-derived", GST_TYPE_VA_FEATURE,
|
|
use_derived, NULL)) {
|
|
*use_derived = GST_VA_FEATURE_AUTO;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static inline gboolean
|
|
gst_buffer_pool_config_get_va_alignment (GstStructure * config,
|
|
GstVideoAlignment * align)
|
|
{
|
|
return gst_structure_get (config,
|
|
"va-padding-top", G_TYPE_UINT, &align->padding_top,
|
|
"va-padding-bottom", G_TYPE_UINT, &align->padding_bottom,
|
|
"va-padding-left", G_TYPE_UINT, &align->padding_left,
|
|
"va-padding-right", G_TYPE_UINT, &align->padding_right, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
gst_va_pool_set_config (GstBufferPool * pool, GstStructure * config)
|
|
{
|
|
GstAllocator *allocator;
|
|
GstCaps *caps;
|
|
GstVaPool *vpool = GST_VA_POOL (pool);
|
|
GstVideoAlignment video_align = { 0, };
|
|
GstVideoInfo orginal_alloc_info;
|
|
GstVideoInfoDmaDrm alloc_info_drm;
|
|
gint width, height;
|
|
guint i, min_buffers, max_buffers;
|
|
guint32 usage_hint;
|
|
GstVaFeature use_derived;
|
|
gboolean has_alignment;
|
|
|
|
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
|
|
&max_buffers))
|
|
goto wrong_config;
|
|
|
|
if (!caps)
|
|
goto no_caps;
|
|
|
|
if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
|
|
goto wrong_config;
|
|
|
|
if (!allocator)
|
|
goto wrong_config;
|
|
|
|
gst_video_info_dma_drm_init (&vpool->caps_info_drm);
|
|
if (gst_video_is_dma_drm_caps (caps)) {
|
|
GstVideoInfo info;
|
|
|
|
if (!GST_IS_VA_DMABUF_ALLOCATOR (allocator))
|
|
goto wrong_caps;
|
|
|
|
if (!gst_video_info_dma_drm_from_caps (&vpool->caps_info_drm, caps))
|
|
goto wrong_caps;
|
|
|
|
if (!gst_va_dma_drm_info_to_video_info (&vpool->caps_info_drm, &info))
|
|
goto wrong_caps;
|
|
|
|
vpool->caps_info_drm.vinfo = info;
|
|
} else {
|
|
if (!GST_IS_VA_ALLOCATOR (allocator))
|
|
goto wrong_caps;
|
|
|
|
if (!gst_video_info_from_caps (&vpool->caps_info, caps))
|
|
goto wrong_caps;
|
|
}
|
|
|
|
if (!gst_buffer_pool_config_get_va_allocation_params (config, &usage_hint,
|
|
&use_derived))
|
|
goto wrong_config;
|
|
|
|
width = GST_VIDEO_INFO_WIDTH (&vpool->caps_info);
|
|
height = GST_VIDEO_INFO_HEIGHT (&vpool->caps_info);
|
|
|
|
GST_LOG_OBJECT (vpool, "%dx%d | %" GST_PTR_FORMAT, width, height, caps);
|
|
|
|
/* enable metadata based on config of the pool */
|
|
vpool->add_videometa = gst_buffer_pool_config_has_option (config,
|
|
GST_BUFFER_POOL_OPTION_VIDEO_META);
|
|
|
|
/* parse extra alignment info */
|
|
has_alignment = gst_buffer_pool_config_get_va_alignment (config,
|
|
&video_align);
|
|
|
|
if (has_alignment) {
|
|
width += video_align.padding_left + video_align.padding_right;
|
|
height += video_align.padding_bottom + video_align.padding_top;
|
|
|
|
if (video_align.padding_left > 0)
|
|
vpool->crop_left = video_align.padding_left;
|
|
if (video_align.padding_top > 0)
|
|
vpool->crop_top = video_align.padding_top;
|
|
}
|
|
|
|
/* update allocation info with aligned size */
|
|
alloc_info_drm = vpool->caps_info_drm;
|
|
g_assert (GST_VIDEO_INFO_FORMAT (&alloc_info_drm.vinfo) !=
|
|
GST_VIDEO_FORMAT_UNKNOWN
|
|
&& GST_VIDEO_INFO_FORMAT (&alloc_info_drm.vinfo) !=
|
|
GST_VIDEO_FORMAT_DMA_DRM);
|
|
GST_VIDEO_INFO_WIDTH (&alloc_info_drm.vinfo) = width;
|
|
GST_VIDEO_INFO_HEIGHT (&alloc_info_drm.vinfo) = height;
|
|
|
|
orginal_alloc_info = alloc_info_drm.vinfo;
|
|
|
|
if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
|
|
if (!gst_va_dmabuf_allocator_set_format (allocator, &alloc_info_drm,
|
|
usage_hint))
|
|
goto failed_allocator;
|
|
} else if (GST_IS_VA_ALLOCATOR (allocator)) {
|
|
if (!gst_va_allocator_set_format (allocator, &alloc_info_drm.vinfo,
|
|
usage_hint, use_derived))
|
|
goto failed_allocator;
|
|
}
|
|
|
|
gst_object_replace ((GstObject **) & vpool->allocator,
|
|
GST_OBJECT (allocator));
|
|
|
|
vpool->alloc_info = alloc_info_drm.vinfo;
|
|
|
|
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&orginal_alloc_info); i++) {
|
|
if (GST_VIDEO_INFO_PLANE_STRIDE (&orginal_alloc_info, i) !=
|
|
GST_VIDEO_INFO_PLANE_STRIDE (&alloc_info_drm.vinfo, i) ||
|
|
GST_VIDEO_INFO_PLANE_OFFSET (&orginal_alloc_info, i) !=
|
|
GST_VIDEO_INFO_PLANE_OFFSET (&alloc_info_drm.vinfo, i)) {
|
|
GST_INFO_OBJECT (vpool, "Video meta is required in buffer.");
|
|
vpool->force_videometa = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
gst_buffer_pool_config_set_params (config, caps,
|
|
GST_VIDEO_INFO_SIZE (&alloc_info_drm.vinfo), min_buffers, max_buffers);
|
|
|
|
return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
|
|
|
|
/* ERRORS */
|
|
wrong_config:
|
|
{
|
|
GST_WARNING_OBJECT (vpool, "invalid config");
|
|
return FALSE;
|
|
}
|
|
no_caps:
|
|
{
|
|
GST_WARNING_OBJECT (vpool, "no caps in config");
|
|
return FALSE;
|
|
}
|
|
wrong_caps:
|
|
{
|
|
GST_WARNING_OBJECT (vpool,
|
|
"failed getting geometry from caps %" GST_PTR_FORMAT, caps);
|
|
return FALSE;
|
|
}
|
|
failed_allocator:
|
|
{
|
|
GST_WARNING_OBJECT (vpool, "Failed to set format to allocator");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_va_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
|
|
GstBufferPoolAcquireParams * params)
|
|
{
|
|
GstBuffer *buf;
|
|
GstVaPool *vpool = GST_VA_POOL (pool);
|
|
|
|
buf = gst_buffer_new ();
|
|
|
|
if (GST_IS_VA_DMABUF_ALLOCATOR (vpool->allocator)) {
|
|
if (vpool->starting) {
|
|
if (!gst_va_dmabuf_allocator_setup_buffer (vpool->allocator, buf))
|
|
goto no_memory;
|
|
} else if (!gst_va_dmabuf_allocator_prepare_buffer (vpool->allocator, buf)) {
|
|
if (!gst_va_dmabuf_allocator_setup_buffer (vpool->allocator, buf))
|
|
goto no_memory;
|
|
}
|
|
} else if (GST_IS_VA_ALLOCATOR (vpool->allocator)) {
|
|
if (vpool->starting) {
|
|
if (!gst_va_allocator_setup_buffer (vpool->allocator, buf))
|
|
goto no_memory;
|
|
} else if (!gst_va_allocator_prepare_buffer (vpool->allocator, buf)) {
|
|
if (!gst_va_allocator_setup_buffer (vpool->allocator, buf))
|
|
goto no_memory;
|
|
}
|
|
} else
|
|
goto no_memory;
|
|
|
|
if (vpool->add_videometa) {
|
|
if (vpool->crop_left > 0 || vpool->crop_top > 0) {
|
|
GstVideoCropMeta *crop_meta;
|
|
|
|
/* For video crop, its video meta's width and height should be
|
|
the full size of uncropped resolution. */
|
|
gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
|
|
GST_VIDEO_INFO_FORMAT (&vpool->alloc_info),
|
|
GST_VIDEO_INFO_WIDTH (&vpool->alloc_info),
|
|
GST_VIDEO_INFO_HEIGHT (&vpool->alloc_info),
|
|
GST_VIDEO_INFO_N_PLANES (&vpool->alloc_info),
|
|
vpool->alloc_info.offset, vpool->alloc_info.stride);
|
|
|
|
crop_meta = gst_buffer_add_video_crop_meta (buf);
|
|
crop_meta->x = vpool->crop_left;
|
|
crop_meta->y = vpool->crop_top;
|
|
crop_meta->width = GST_VIDEO_INFO_WIDTH (&vpool->caps_info);
|
|
crop_meta->height = GST_VIDEO_INFO_HEIGHT (&vpool->caps_info);
|
|
} else {
|
|
/* GstVaAllocator may update offset/stride given the physical
|
|
* memory */
|
|
gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
|
|
GST_VIDEO_INFO_FORMAT (&vpool->caps_info),
|
|
GST_VIDEO_INFO_WIDTH (&vpool->caps_info),
|
|
GST_VIDEO_INFO_HEIGHT (&vpool->caps_info),
|
|
GST_VIDEO_INFO_N_PLANES (&vpool->caps_info),
|
|
vpool->alloc_info.offset, vpool->alloc_info.stride);
|
|
}
|
|
}
|
|
|
|
*buffer = buf;
|
|
|
|
return GST_FLOW_OK;
|
|
|
|
/* ERROR */
|
|
no_memory:
|
|
{
|
|
gst_buffer_unref (buf);
|
|
GST_WARNING_OBJECT (vpool, "can't create memory");
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gst_va_pool_start (GstBufferPool * pool)
|
|
{
|
|
GstVaPool *vpool = GST_VA_POOL (pool);
|
|
gboolean ret;
|
|
|
|
vpool->starting = TRUE;
|
|
ret = GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
|
|
vpool->starting = FALSE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
gst_va_pool_stop (GstBufferPool * pool)
|
|
{
|
|
GstVaPool *vpool = GST_VA_POOL (pool);
|
|
gboolean ret;
|
|
|
|
ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
|
|
|
|
if (GST_IS_VA_DMABUF_ALLOCATOR (vpool->allocator))
|
|
gst_va_dmabuf_allocator_flush (vpool->allocator);
|
|
else if (GST_IS_VA_ALLOCATOR (vpool->allocator))
|
|
gst_va_allocator_flush (vpool->allocator);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
gst_va_pool_dispose (GObject * object)
|
|
{
|
|
GstVaPool *pool = GST_VA_POOL (object);
|
|
|
|
GST_LOG_OBJECT (pool, "finalize video buffer pool %p", pool);
|
|
|
|
gst_clear_object (&pool->allocator);
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gst_va_pool_class_init (GstVaPoolClass * klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
GstBufferPoolClass *gstbufferpool_class = GST_BUFFER_POOL_CLASS (klass);
|
|
|
|
gobject_class->dispose = gst_va_pool_dispose;
|
|
|
|
gstbufferpool_class->get_options = gst_va_pool_get_options;
|
|
gstbufferpool_class->set_config = gst_va_pool_set_config;
|
|
gstbufferpool_class->alloc_buffer = gst_va_pool_alloc;
|
|
gstbufferpool_class->start = gst_va_pool_start;
|
|
gstbufferpool_class->stop = gst_va_pool_stop;
|
|
}
|
|
|
|
static void
|
|
gst_va_pool_init (GstVaPool * self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* gst_va_pool_new:
|
|
*
|
|
* Returns: A new #GstBufferPool for VA allocators.
|
|
*
|
|
* Since: 1.22
|
|
*/
|
|
GstBufferPool *
|
|
gst_va_pool_new (void)
|
|
{
|
|
GstVaPool *pool;
|
|
|
|
pool = g_object_new (GST_TYPE_VA_POOL, NULL);
|
|
gst_object_ref_sink (pool);
|
|
|
|
GST_LOG_OBJECT (pool, "new va video buffer pool %p", pool);
|
|
|
|
return GST_BUFFER_POOL_CAST (pool);
|
|
}
|
|
|
|
/**
|
|
* gst_buffer_pool_config_set_va_allocation_params:
|
|
* @config: the #GstStructure with the pool's configuration.
|
|
* @usage_hint: the VA usage hint for new VASurfaceID.
|
|
* @use_derived: a #GstVaFeature for derived mapping (only used when
|
|
* VA allocator).
|
|
*
|
|
* Sets the usage hint for the buffers handled by the buffer pool.
|
|
*
|
|
* Since: 1.22
|
|
*/
|
|
void
|
|
gst_buffer_pool_config_set_va_allocation_params (GstStructure * config,
|
|
guint usage_hint, GstVaFeature use_derived)
|
|
{
|
|
gst_structure_set (config, "usage-hint", G_TYPE_UINT, usage_hint,
|
|
"use-derived", GST_TYPE_VA_FEATURE, use_derived, NULL);
|
|
}
|
|
|
|
/**
|
|
* gst_buffer_pool_config_set_va_alignment:
|
|
* @config: the #GstStructure with the pool's configuration.
|
|
* @align: a #GstVideoAlignment
|
|
*
|
|
* Video alignment is not handled as expected by VA since it uses
|
|
* opaque surfaces, not directly mappable memory. Still, decoders
|
|
* might need to request bigger surfaces for coded size rather than
|
|
* display sizes. This method will set the coded size to bufferpool's
|
|
* configuration, out of the typical video aligment.
|
|
*
|
|
* Since: 1.20.2
|
|
*/
|
|
void
|
|
gst_buffer_pool_config_set_va_alignment (GstStructure * config,
|
|
const GstVideoAlignment * align)
|
|
{
|
|
gst_structure_set (config,
|
|
"va-padding-top", G_TYPE_UINT, align->padding_top,
|
|
"va-padding-bottom", G_TYPE_UINT, align->padding_bottom,
|
|
"va-padding-left", G_TYPE_UINT, align->padding_left,
|
|
"va-padding-right", G_TYPE_UINT, align->padding_right, NULL);
|
|
}
|
|
|
|
/**
|
|
* gst_va_pool_requires_video_meta:
|
|
* @pool: the #GstBufferPool
|
|
*
|
|
* Retuns: %TRUE if @pool always add #GstVideoMeta to its
|
|
* buffers. Otherwise, %FALSE.
|
|
*
|
|
* Since: 1.22
|
|
*/
|
|
gboolean
|
|
gst_va_pool_requires_video_meta (GstBufferPool * pool)
|
|
{
|
|
g_return_val_if_fail (GST_IS_VA_POOL (pool), FALSE);
|
|
|
|
return GST_VA_POOL (pool)->force_videometa;
|
|
}
|
|
|
|
/**
|
|
* gst_va_pool_new_with_config:
|
|
* @caps: the #GstCaps of the buffers handled by the new pool.
|
|
* @min_buffers: minimum number of frames to create.
|
|
* @max_buffers: maximum number of frames to create.
|
|
* @usage_hint: VA usage hint
|
|
* @use_derived: a #GstVaFeature for derived mapping (only used when
|
|
* VA allocator).
|
|
* @allocator: the VA allocator to use.
|
|
* @alloc_params: #GstAllocationParams to use.
|
|
*
|
|
* Returns: a new #GstBufferPool that handles VASurfacesID-backed
|
|
* buffers. If the pool cannot be configured correctly, %NULL is
|
|
* returned.
|
|
*
|
|
* Since: 1.22
|
|
*/
|
|
GstBufferPool *
|
|
gst_va_pool_new_with_config (GstCaps * caps, guint min_buffers,
|
|
guint max_buffers, guint usage_hint, GstVaFeature use_derived,
|
|
GstAllocator * allocator, GstAllocationParams * alloc_params)
|
|
{
|
|
GstBufferPool *pool;
|
|
GstStructure *config;
|
|
|
|
pool = gst_va_pool_new ();
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
/* ignore the size since it's calculated by the driver */
|
|
gst_buffer_pool_config_set_params (config, caps, 0, min_buffers, max_buffers);
|
|
gst_buffer_pool_config_set_va_allocation_params (config, usage_hint,
|
|
use_derived);
|
|
gst_buffer_pool_config_set_allocator (config, allocator, alloc_params);
|
|
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
|
|
|
|
if (!gst_buffer_pool_set_config (pool, config))
|
|
gst_clear_object (&pool);
|
|
|
|
return pool;
|
|
}
|
|
|
|
/**
|
|
* gst_va_pool_get_buffer_size:
|
|
* @pool: a #GstBufferPool
|
|
* @size: (out) (allow-null-none): the declared surface size
|
|
*
|
|
* Helper function to retrieve the VA surface size provided by @pool.
|
|
*
|
|
* Returns: whether the surface size was retrieved.
|
|
*
|
|
* Since: 1.24
|
|
*/
|
|
gboolean
|
|
gst_va_pool_get_buffer_size (GstBufferPool * pool, guint * size)
|
|
{
|
|
gboolean ret;
|
|
GstStructure *config;
|
|
|
|
g_return_val_if_fail (GST_IS_VA_POOL (pool), FALSE);
|
|
|
|
config = gst_buffer_pool_get_config (pool);
|
|
ret = gst_buffer_pool_config_get_params (config, NULL, size, NULL, NULL);
|
|
gst_structure_free (config);
|
|
return ret && *size > 0;
|
|
}
|