va: allocator: add _set_format() and _get_format()

Since allocators keep an available memory queue to reuse, video format and usage
hint are now persistant while allocator's memories are around.

This patch adds _set_format() and _get_format() for both VA allocators.

_set_format() validates if given format can be used or reused. If no allocated
surface previously it creates a dummy one to fetch its offsets and
strides. Updated info is returned to callee.

GstVaPool uses _set_format() at config to verify the allocator capacity and to
get the surfaces offsets and strides, which are going to be used by the video
meta.

Allocator extracted caps are compared with caps from config and if they have
different strides or offsets, force_videometa is set.

A new bufferpool method gst_va_pool_requires_video_meta() is added return the
value of force_videometa. This value is checked in order to know if decoders
need to copy the surface if downstream doesn't announce video meta support.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1667>
This commit is contained in:
Víctor Manuel Jáquez Leal 2020-10-07 18:03:20 +02:00
parent 482e93b4d8
commit fbbf9c629a
7 changed files with 287 additions and 250 deletions

View file

@ -400,6 +400,9 @@ struct _GstVaDmabufAllocator
GstMemoryMapFunction parent_map;
GCond buffer_cond;
GstVideoInfo info;
guint usage_hint;
};
#define gst_va_dmabuf_allocator_parent_class dmabuf_parent_class
@ -514,11 +517,15 @@ gst_va_dmabuf_memory_release (GstMiniObject * mini_object)
return FALSE;
}
/* creates an exported VASurface and adds it as @buffer's memories
* qdata */
gboolean
gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
GstBuffer * buffer, GstVaAllocationParams * params)
/* Creates an exported VASurface and adds it as @buffer's memories
* qdata
*
* If @info is not NULL, a dummy (non-pooled) buffer is created to
* update offsets and strides, and it has to be unrefed immediately.
*/
static gboolean
gst_va_dmabuf_allocator_setup_buffer_full (GstAllocator * allocator,
GstBuffer * buffer, GstVideoInfo * info)
{
GstVaBufferSurface *buf;
GstVaDmabufAllocator *self = GST_VA_DMABUF_ALLOCATOR (allocator);
@ -528,20 +535,19 @@ gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
guint32 i, fourcc, rt_format, export_flags;
g_return_val_if_fail (GST_IS_VA_DMABUF_ALLOCATOR (allocator), FALSE);
g_return_val_if_fail (params, FALSE);
format = GST_VIDEO_INFO_FORMAT (&params->info);
format = GST_VIDEO_INFO_FORMAT (&self->info);
fourcc = gst_va_fourcc_from_video_format (format);
rt_format = gst_va_chroma_from_video_format (format);
if (fourcc == 0 || rt_format == 0) {
GST_ERROR_OBJECT (allocator, "Unsupported format: %s",
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&params->info)));
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&self->info)));
return FALSE;
}
if (!_create_surfaces (self->display, rt_format, fourcc,
GST_VIDEO_INFO_WIDTH (&params->info),
GST_VIDEO_INFO_HEIGHT (&params->info), params->usage_hint, NULL,
GST_VIDEO_INFO_WIDTH (&self->info),
GST_VIDEO_INFO_HEIGHT (&self->info), self->usage_hint, NULL,
&surface, 1))
return FALSE;
@ -561,7 +567,7 @@ gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
if (!_export_surface_to_dmabuf (self->display, surface, export_flags, &desc))
goto failed;
g_assert (GST_VIDEO_INFO_N_PLANES (&params->info) == desc.num_layers);
g_assert (GST_VIDEO_INFO_N_PLANES (&self->info) == desc.num_layers);
if (fourcc != desc.fourcc) {
GST_ERROR ("Unsupported fourcc: %" GST_FOURCC_FORMAT,
@ -570,7 +576,10 @@ gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
}
buf = gst_va_buffer_surface_new (surface, format, desc.width, desc.height);
GST_VIDEO_INFO_SIZE (&params->info) = 0;
if (G_UNLIKELY (info)) {
*info = self->info;
GST_VIDEO_INFO_SIZE (info) = 0;
}
for (i = 0; i < desc.num_objects; i++) {
gint fd = desc.objects[i].fd;
@ -581,7 +590,8 @@ gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
gst_buffer_append_memory (buffer, mem);
GST_MINI_OBJECT (mem)->dispose = gst_va_dmabuf_memory_release;
if (G_LIKELY (!info))
GST_MINI_OBJECT (mem)->dispose = gst_va_dmabuf_memory_release;
g_atomic_int_add (&buf->ref_count, 1);
gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
@ -591,21 +601,23 @@ gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), gst_va_drm_mod_quark (),
drm_mod, g_free);
GST_VIDEO_INFO_SIZE (&params->info) += size;
if (G_UNLIKELY (info))
GST_VIDEO_INFO_SIZE (info) += size;
}
for (i = 0; i < desc.num_layers; i++) {
g_assert (desc.layers[i].num_planes == 1);
GST_VIDEO_INFO_PLANE_OFFSET (&params->info, i) = desc.layers[i].offset[0];
GST_VIDEO_INFO_PLANE_STRIDE (&params->info, i) = desc.layers[i].pitch[0];
if (G_UNLIKELY (info)) {
for (i = 0; i < desc.num_layers; i++) {
g_assert (desc.layers[i].num_planes == 1);
GST_VIDEO_INFO_PLANE_OFFSET (info, i) = desc.layers[i].offset[0];
GST_VIDEO_INFO_PLANE_STRIDE (info, i) = desc.layers[i].pitch[0];
}
} else {
g_atomic_int_inc (&self->surface_count);
}
g_atomic_int_inc (&self->surface_count);
GST_LOG_OBJECT (self, "Created surface %#x [%dx%d] size %" G_GSIZE_FORMAT,
buf->surface, GST_VIDEO_INFO_WIDTH (&params->info),
GST_VIDEO_INFO_HEIGHT (&params->info),
GST_VIDEO_INFO_SIZE (&params->info));
buf->surface, GST_VIDEO_INFO_WIDTH (&self->info),
GST_VIDEO_INFO_HEIGHT (&self->info), GST_VIDEO_INFO_SIZE (&self->info));
return TRUE;
@ -616,6 +628,13 @@ failed:
}
}
gboolean
gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
GstBuffer * buffer)
{
return gst_va_dmabuf_allocator_setup_buffer_full (allocator, buffer, NULL);
}
gboolean
gst_va_dmabuf_allocator_prepare_buffer (GstAllocator * allocator,
GstBuffer * buffer)
@ -669,27 +688,75 @@ gst_va_dmabuf_allocator_flush (GstAllocator * allocator)
GST_OBJECT_UNLOCK (self);
}
gboolean
gst_va_dmabuf_try (GstAllocator * allocator, GstVaAllocationParams * params)
static gboolean
gst_va_dmabuf_allocator_try (GstAllocator * allocator)
{
GstBuffer *buffer = gst_buffer_new ();
GstMapInfo map_info;
GstBuffer *buffer;
GstVaDmabufAllocator *self = GST_VA_DMABUF_ALLOCATOR (allocator);
GstVideoInfo info = self->info;
gboolean ret;
ret = gst_va_dmabuf_allocator_setup_buffer (allocator, buffer, params);
if (ret) {
/* XXX: radeonsi for kadaveri cannot map dmabufs to user space */
if (!gst_buffer_map (buffer, &map_info, GST_MAP_READWRITE)) {
GST_WARNING_OBJECT (allocator,
"DMABuf backend cannot map frames to user space.");
}
gst_buffer_unmap (buffer, &map_info);
}
buffer = gst_buffer_new ();
ret = gst_va_dmabuf_allocator_setup_buffer_full (allocator, buffer, &info);
gst_buffer_unref (buffer);
if (ret)
self->info = info;
return ret;
}
gboolean
gst_va_dmabuf_allocator_set_format (GstAllocator * allocator,
GstVideoInfo * info, guint usage_hint)
{
GstVaDmabufAllocator *self;
gboolean ret;
g_return_val_if_fail (GST_IS_VA_DMABUF_ALLOCATOR (allocator), FALSE);
g_return_val_if_fail (info, FALSE);
self = GST_VA_DMABUF_ALLOCATOR (allocator);
if (self->surface_count != 0) {
if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_INFO_FORMAT (&self->info)
&& GST_VIDEO_INFO_WIDTH (info) == GST_VIDEO_INFO_WIDTH (&self->info)
&& GST_VIDEO_INFO_HEIGHT (info) == GST_VIDEO_INFO_HEIGHT (&self->info)
&& usage_hint == self->usage_hint) {
*info = self->info; /* update callee info (offset & stride) */
return TRUE;
}
return FALSE;
}
self->usage_hint = usage_hint;
self->info = *info;
ret = gst_va_dmabuf_allocator_try (allocator);
if (ret)
*info = self->info;
return ret;
}
gboolean
gst_va_dmabuf_allocator_get_format (GstAllocator * allocator,
GstVideoInfo * info, guint * usage_hint)
{
GstVaDmabufAllocator *self = GST_VA_DMABUF_ALLOCATOR (allocator);
if (GST_VIDEO_INFO_FORMAT (&self->info) == GST_VIDEO_FORMAT_UNKNOWN)
return FALSE;
if (info)
*info = self->info;
if (usage_hint)
*usage_hint = self->usage_hint;
return TRUE;
}
/* XXX: use a surface pool to control the created surfaces */
gboolean
gst_va_dmabuf_memories_setup (GstVaDisplay * display, GstVideoInfo * info,
@ -773,6 +840,9 @@ struct _GstVaAllocator
GArray *surface_formats;
GCond buffer_cond;
GstVideoInfo info;
guint usage_hint;
};
typedef struct _GstVaMemory GstVaMemory;
@ -780,7 +850,6 @@ struct _GstVaMemory
{
GstMemory mem;
GstVideoInfo info;
VASurfaceID surface;
GstVideoFormat surface_format;
VAImage image;
@ -886,7 +955,7 @@ _reset_mem (GstVaMemory * mem, GstAllocator * allocator, gsize size)
static inline gboolean
_ensure_image (GstVaDisplay * display, VASurfaceID surface, GstVideoInfo * info,
VAImage * image, gboolean * derived)
VAImage * image, gboolean * derived, gboolean update_info)
{
gint i;
gboolean try_derived;
@ -909,12 +978,14 @@ _ensure_image (GstVaDisplay * display, VASurfaceID surface, GstVideoInfo * info,
*derived = FALSE;
bail:
for (i = 0; i < image->num_planes; i++) {
GST_VIDEO_INFO_PLANE_OFFSET (info, i) = image->offsets[i];
GST_VIDEO_INFO_PLANE_STRIDE (info, i) = image->pitches[i];
}
if (G_UNLIKELY (update_info)) {
for (i = 0; i < image->num_planes; i++) {
GST_VIDEO_INFO_PLANE_OFFSET (info, i) = image->offsets[i];
GST_VIDEO_INFO_PLANE_STRIDE (info, i) = image->pitches[i];
}
GST_VIDEO_INFO_SIZE (info) = image->data_size;
GST_VIDEO_INFO_SIZE (info) = image->data_size;
}
return TRUE;
}
@ -945,7 +1016,7 @@ _va_map_unlocked (GstVaMemory * mem, GstMapFlags flags)
} else { /* GST_MAP_READ only */
mem->is_dirty = FALSE;
mem->is_derived = va_allocator->use_derived &&
(GST_VIDEO_INFO_FORMAT (&mem->info) == mem->surface_format);
(GST_VIDEO_INFO_FORMAT (&va_allocator->info) == mem->surface_format);
}
if (flags & GST_MAP_VA) {
@ -953,8 +1024,8 @@ _va_map_unlocked (GstVaMemory * mem, GstMapFlags flags)
goto success;
}
if (!_ensure_image (display, mem->surface, &mem->info, &mem->image,
&mem->is_derived))
if (!_ensure_image (display, mem->surface, &va_allocator->info, &mem->image,
&mem->is_derived, FALSE))
return NULL;
va_allocator->use_derived = mem->is_derived;
@ -1063,7 +1134,6 @@ _va_share (GstMemory * mem, gssize offset, gssize size)
sub->surface = vamem->surface;
sub->surface_format = vamem->surface_format;
sub->info = vamem->info;
_clean_mem (sub);
@ -1110,14 +1180,16 @@ gst_va_memory_release (GstMiniObject * mini_object)
return FALSE;
}
GstMemory *
gst_va_allocator_alloc (GstAllocator * allocator,
GstVaAllocationParams * params)
/* If @info is not NULL, a dummy (non-pooled) memory and its VAImage
* are created, to update offsets and strides. The memory has to be
* unrefed immediately.
*/
static GstMemory *
gst_va_allocator_alloc_full (GstAllocator * allocator, GstVideoInfo * info)
{
GstVaAllocator *self;
GstVaMemory *mem;
GstVideoFormat format, img_format;
VAImage image = { 0, };
VASurfaceID surface;
guint32 fourcc, rt_format;
@ -1125,7 +1197,7 @@ gst_va_allocator_alloc (GstAllocator * allocator,
self = GST_VA_ALLOCATOR (allocator);
img_format = GST_VIDEO_INFO_FORMAT (&params->info);
img_format = GST_VIDEO_INFO_FORMAT (&self->info);
format = gst_va_video_surface_format_from_image_format (img_format,
self->surface_formats);
@ -1145,35 +1217,43 @@ gst_va_allocator_alloc (GstAllocator * allocator,
}
if (!_create_surfaces (self->display, rt_format, fourcc,
GST_VIDEO_INFO_WIDTH (&params->info),
GST_VIDEO_INFO_HEIGHT (&params->info), params->usage_hint, NULL,
GST_VIDEO_INFO_WIDTH (&self->info),
GST_VIDEO_INFO_HEIGHT (&self->info), self->usage_hint, NULL,
&surface, 1))
return NULL;
image.image_id = VA_INVALID_ID;
if (!_ensure_image (self->display, surface, &params->info, &image, NULL))
return NULL;
_destroy_image (self->display, image.image_id);
if (G_UNLIKELY (info)) {
VAImage image = {.image_id = VA_INVALID_ID, };
if (!_ensure_image (self->display, surface, info, &image, NULL, TRUE))
return NULL;
_destroy_image (self->display, image.image_id);
}
mem = g_slice_new (GstVaMemory);
mem->surface = surface;
mem->surface_format = format;
mem->info = params->info;
_reset_mem (mem, allocator, GST_VIDEO_INFO_SIZE (&params->info));
_reset_mem (mem, allocator, GST_VIDEO_INFO_SIZE (&self->info));
GST_MINI_OBJECT (mem)->dispose = gst_va_memory_release;
g_atomic_int_inc (&self->surface_count);
if (G_LIKELY (!info)) {
GST_MINI_OBJECT (mem)->dispose = gst_va_memory_release;
g_atomic_int_inc (&self->surface_count);
}
GST_LOG_OBJECT (self, "Created surface %#x [%dx%d]", mem->surface,
GST_VIDEO_INFO_WIDTH (&params->info),
GST_VIDEO_INFO_HEIGHT (&params->info));
GST_VIDEO_INFO_WIDTH (&self->info), GST_VIDEO_INFO_HEIGHT (&self->info));
return GST_MEMORY_CAST (mem);
}
GstMemory *
gst_va_allocator_alloc (GstAllocator * allocator)
{
return gst_va_allocator_alloc_full (allocator, NULL);
}
GstAllocator *
gst_va_allocator_new (GstVaDisplay * display, GArray * surface_formats)
{
@ -1224,15 +1304,69 @@ gst_va_allocator_flush (GstAllocator * allocator)
GST_OBJECT_UNLOCK (self);
}
gboolean
gst_va_allocator_try (GstAllocator * allocator, GstVaAllocationParams * params)
static gboolean
gst_va_allocator_try (GstAllocator * allocator)
{
GstMemory *mem;
GstVaAllocator *self = GST_VA_ALLOCATOR (allocator);
GstVideoInfo info = self->info;
mem = gst_va_allocator_alloc (allocator, params);
mem = gst_va_allocator_alloc_full (allocator, &info);
if (!mem)
return FALSE;
gst_memory_unref (mem);
self->info = info;
return TRUE;
}
gboolean
gst_va_allocator_set_format (GstAllocator * allocator, GstVideoInfo * info,
guint usage_hint)
{
GstVaAllocator *self;
gboolean ret;
g_return_val_if_fail (GST_IS_VA_ALLOCATOR (allocator), FALSE);
g_return_val_if_fail (info, FALSE);
self = GST_VA_ALLOCATOR (allocator);
if (self->surface_count != 0) {
if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_INFO_FORMAT (&self->info)
&& GST_VIDEO_INFO_WIDTH (info) == GST_VIDEO_INFO_WIDTH (&self->info)
&& GST_VIDEO_INFO_HEIGHT (info) == GST_VIDEO_INFO_HEIGHT (&self->info)
&& usage_hint == self->usage_hint) {
*info = self->info; /* update callee info (offset & stride) */
return TRUE;
}
return FALSE;
}
self->usage_hint = usage_hint;
self->info = *info;
ret = gst_va_allocator_try (allocator);
if (ret)
*info = self->info;
return ret;
}
gboolean
gst_va_allocator_get_format (GstAllocator * allocator, GstVideoInfo * info,
guint * usage_hint)
{
GstVaAllocator *self = GST_VA_ALLOCATOR (allocator);
if (GST_VIDEO_INFO_FORMAT (&self->info) == GST_VIDEO_FORMAT_UNKNOWN)
return FALSE;
if (info)
*info = self->info;
if (usage_hint)
*usage_hint = self->usage_hint;
return TRUE;
}

View file

@ -27,26 +27,22 @@
G_BEGIN_DECLS
typedef struct _GstVaAllocationParams GstVaAllocationParams;
struct _GstVaAllocationParams
{
GstVideoInfo info;
guint32 usage_hint;
};
#define GST_TYPE_VA_DMABUF_ALLOCATOR (gst_va_dmabuf_allocator_get_type())
G_DECLARE_FINAL_TYPE (GstVaDmabufAllocator, gst_va_dmabuf_allocator, GST,
VA_DMABUF_ALLOCATOR, GstDmaBufAllocator);
GstAllocator * gst_va_dmabuf_allocator_new (GstVaDisplay * display);
gboolean gst_va_dmabuf_allocator_setup_buffer (GstAllocator * allocator,
GstBuffer * buffer,
GstVaAllocationParams * params);
GstBuffer * buffer);
gboolean gst_va_dmabuf_allocator_prepare_buffer (GstAllocator * allocator,
GstBuffer * buffer);
void gst_va_dmabuf_allocator_flush (GstAllocator * allocator);
gboolean gst_va_dmabuf_try (GstAllocator * allocator,
GstVaAllocationParams * params);
gboolean gst_va_dmabuf_allocator_set_format (GstAllocator * allocator,
GstVideoInfo * info,
guint usage_hint);
gboolean gst_va_dmabuf_allocator_get_format (GstAllocator * allocator,
GstVideoInfo * info,
guint * usage_hint);
gboolean gst_va_dmabuf_memories_setup (GstVaDisplay * display,
GstVideoInfo * info,
@ -65,13 +61,16 @@ G_DECLARE_FINAL_TYPE (GstVaAllocator, gst_va_allocator, GST, VA_ALLOCATOR, GstAl
GstAllocator * gst_va_allocator_new (GstVaDisplay * display,
GArray * surface_formats);
GstMemory * gst_va_allocator_alloc (GstAllocator * allocator,
GstVaAllocationParams * params);
GstMemory * gst_va_allocator_alloc (GstAllocator * allocator);
gboolean gst_va_allocator_prepare_buffer (GstAllocator * allocator,
GstBuffer * buffer);
void gst_va_allocator_flush (GstAllocator * allocator);
gboolean gst_va_allocator_try (GstAllocator * allocator,
GstVaAllocationParams * params);
gboolean gst_va_allocator_set_format (GstAllocator * allocator,
GstVideoInfo * info,
guint usage_hint);
gboolean gst_va_allocator_get_format (GstAllocator * allocator,
GstVideoInfo * info,
guint * usage_hint);
VASurfaceID gst_va_memory_get_surface (GstMemory * mem);
VASurfaceID gst_va_buffer_get_surface (GstBuffer * buffer);

View file

@ -745,6 +745,17 @@ gst_va_h264_dec_new_sequence (GstH264Decoder * decoder, const GstH264SPS * sps,
}
}
if (!self->has_videometa) {
GstBufferPool *pool;
pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
self->copy_frames = gst_va_pool_requires_video_meta (pool);
gst_object_unref (pool);
if (self->copy_frames)
GST_INFO_OBJECT (self, "Raw frame copy enabled.");
}
return TRUE;
}
@ -1048,81 +1059,19 @@ gst_va_h264_dec_negotiate (GstVideoDecoder * decoder)
return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
}
static inline void
_shall_copy_frames (GstVaH264Dec * self, GstVideoInfo * info)
{
GstVideoInfo ref_info;
guint i;
self->copy_frames = FALSE;
if (self->has_videometa)
return;
gst_video_info_set_format (&ref_info, GST_VIDEO_INFO_FORMAT (info),
self->display_width, self->display_height);
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
if (info->stride[i] != ref_info.stride[i] ||
info->offset[i] != ref_info.offset[i]) {
GST_WARNING_OBJECT (self,
"GstVideoMeta support required, copying frames.");
self->copy_frames = TRUE;
break;
}
}
}
static gboolean
_try_allocator (GstVaH264Dec * self, GstAllocator * allocator, GstCaps * caps)
{
GstVaAllocationParams params = {
.usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_DECODER,
};
if (!gst_video_info_from_caps (&params.info, caps))
return FALSE;
if (self->need_cropping) {
GST_VIDEO_INFO_WIDTH (&params.info) = self->coded_width;
GST_VIDEO_INFO_HEIGHT (&params.info) = self->coded_height;
}
if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
if (!gst_va_dmabuf_try (allocator, &params))
return FALSE;
} else if (GST_IS_VA_ALLOCATOR (allocator)) {
if (!gst_va_allocator_try (allocator, &params))
return FALSE;
if (!gst_caps_is_vamemory (caps))
_shall_copy_frames (self, &params.info);
} else {
return FALSE;
}
return TRUE;
}
static GstAllocator *
_create_allocator (GstVaH264Dec * self, GstCaps * caps)
{
GstAllocator *allocator = NULL;
GstVaDisplay *display = NULL;
g_object_get (self->decoder, "display", &display, NULL);
if (gst_caps_is_dmabuf (caps))
allocator = gst_va_dmabuf_allocator_new (display);
allocator = gst_va_dmabuf_allocator_new (self->display);
else {
GArray *surface_formats =
gst_va_decoder_get_surface_formats (self->decoder);
allocator = gst_va_allocator_new (display, surface_formats);
allocator = gst_va_allocator_new (self->display, surface_formats);
}
gst_object_unref (display);
if (!_try_allocator (self, allocator, caps))
gst_clear_object (&allocator);
return allocator;
}

View file

@ -25,6 +25,7 @@
#include "gstvapool.h"
#include "gstvaallocator.h"
#include "gstvacaps.h"
GST_DEBUG_CATEGORY_STATIC (gst_va_pool_debug);
#define GST_CAT_DEFAULT gst_va_pool_debug
@ -36,7 +37,7 @@ struct _GstVaPool
GstVideoInfo alloc_info;
GstVideoInfo caps_info;
GstAllocator *allocator;
guint32 usage_hint;
gboolean force_videometa;
gboolean add_videometa;
gboolean need_alignment;
GstVideoAlignment video_align;
@ -74,9 +75,9 @@ gst_va_pool_set_config (GstBufferPool * pool, GstStructure * config)
GstCaps *caps;
GstVaPool *vpool = GST_VA_POOL (pool);
GstVideoAlignment video_align = { 0, };
GstVideoInfo caps_info, alloc_info;
GstVideoInfo caps_info, alloc_info, orig_info;
gint width, height;
guint min_buffers, max_buffers;
guint i, min_buffers, max_buffers;
guint32 usage_hint;
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
@ -99,14 +100,12 @@ gst_va_pool_set_config (GstBufferPool * pool, GstStructure * config)
if (!gst_buffer_pool_config_get_va_allocation_params (config, &usage_hint))
goto wrong_config;
orig_info = caps_info;
width = GST_VIDEO_INFO_WIDTH (&caps_info);
height = GST_VIDEO_INFO_HEIGHT (&caps_info);
GST_LOG_OBJECT (vpool, "%dx%d | %" GST_PTR_FORMAT, width, height, caps);
gst_object_replace ((GstObject **) & vpool->allocator,
GST_OBJECT (allocator));
/* enable metadata based on config of the pool */
vpool->add_videometa = gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
@ -128,15 +127,40 @@ gst_va_pool_set_config (GstBufferPool * pool, GstStructure * config)
gst_buffer_pool_config_set_video_alignment (config, &video_align);
}
/* update allocation info with aligned size */
alloc_info = caps_info;
GST_VIDEO_INFO_WIDTH (&alloc_info) = width;
GST_VIDEO_INFO_HEIGHT (&alloc_info) = height;
if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
if (!gst_va_dmabuf_allocator_set_format (allocator, &alloc_info,
usage_hint))
goto failed_allocator;
} else if (GST_IS_VA_ALLOCATOR (allocator)) {
if (!gst_va_allocator_set_format (allocator, &alloc_info, usage_hint))
goto failed_allocator;
}
gst_object_replace ((GstObject **) & vpool->allocator,
GST_OBJECT (allocator));
vpool->caps_info = caps_info;
vpool->alloc_info = alloc_info;
vpool->usage_hint = usage_hint;
vpool->video_align = video_align;
if (gst_caps_is_raw (caps)) {
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&caps_info); i++) {
if (GST_VIDEO_INFO_PLANE_STRIDE (&orig_info, i) !=
GST_VIDEO_INFO_PLANE_STRIDE (&alloc_info, i) ||
GST_VIDEO_INFO_PLANE_OFFSET (&orig_info, i) !=
GST_VIDEO_INFO_PLANE_OFFSET (&alloc_info, i)) {
GST_INFO_OBJECT (vpool, "Video meta is required in buffer.");
vpool->force_videometa = TRUE;
break;
}
}
}
/* with pooled allocators bufferpool->release_buffer() is cheated
* because the memories are removed from the buffer at
* reset_buffer(), then buffer is an empty holder with size 0 while
@ -167,6 +191,11 @@ failed_to_align:
GST_WARNING_OBJECT (vpool, "Failed to align");
return FALSE;
}
failed_allocator:
{
GST_WARNING_OBJECT (vpool, "Failed to set format to allocator");
return FALSE;
}
}
static GstFlowReturn
@ -176,19 +205,14 @@ gst_va_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
GstBuffer *buf;
GstVideoMeta *vmeta;
GstVaPool *vpool = GST_VA_POOL (pool);
GstVaAllocationParams alloc_params = {
.info = vpool->alloc_info,
.usage_hint = vpool->usage_hint,
};
buf = gst_buffer_new ();
if (GST_IS_VA_DMABUF_ALLOCATOR (vpool->allocator)) {
if (!gst_va_dmabuf_allocator_setup_buffer (vpool->allocator, buf,
&alloc_params))
if (!gst_va_dmabuf_allocator_setup_buffer (vpool->allocator, buf))
goto no_memory;
} else if (GST_IS_VA_ALLOCATOR (vpool->allocator)) {
GstMemory *mem = gst_va_allocator_alloc (vpool->allocator, &alloc_params);
GstMemory *mem = gst_va_allocator_alloc (vpool->allocator);
if (!mem)
goto no_memory;
gst_buffer_append_memory (buf, mem);
@ -203,7 +227,7 @@ gst_va_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
GST_VIDEO_INFO_WIDTH (&vpool->caps_info),
GST_VIDEO_INFO_HEIGHT (&vpool->caps_info),
GST_VIDEO_INFO_N_PLANES (&vpool->caps_info),
alloc_params.info.offset, alloc_params.info.stride);
vpool->alloc_info.offset, vpool->alloc_info.stride);
if (vpool->need_alignment)
gst_video_meta_set_alignment (vmeta, vpool->video_align);
@ -342,3 +366,9 @@ gst_buffer_pool_config_set_va_allocation_params (GstStructure * config,
{
gst_structure_set (config, "usage-hint", G_TYPE_UINT, usage_hint, NULL);
}
gboolean
gst_va_pool_requires_video_meta (GstBufferPool * pool)
{
return GST_VA_POOL (pool)->force_videometa;
}

View file

@ -28,6 +28,7 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GstVaPool, gst_va_pool, GST, VA_POOL, GstBufferPool)
GstBufferPool * gst_va_pool_new (void);
gboolean gst_va_pool_requires_video_meta (GstBufferPool * pool);
void gst_buffer_pool_config_set_va_allocation_params (GstStructure * config,
guint usage_hint);
G_END_DECLS

View file

@ -367,77 +367,19 @@ gst_va_vp8_dec_negotiate (GstVideoDecoder * decoder)
return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
}
static inline void
_shall_copy_frames (GstVaVp8Dec * self, GstVideoInfo * info)
{
GstVideoInfo ref_info;
guint i;
self->copy_frames = FALSE;
if (self->has_videometa)
return;
gst_video_info_set_format (&ref_info, GST_VIDEO_INFO_FORMAT (info),
self->width, self->height);
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
if (info->stride[i] != ref_info.stride[i] ||
info->offset[i] != ref_info.offset[i]) {
GST_WARNING_OBJECT (self,
"GstVideoMeta support required, copying frames.");
self->copy_frames = TRUE;
break;
}
}
}
static gboolean
_try_allocator (GstVaVp8Dec * self, GstAllocator * allocator, GstCaps * caps)
{
GstVaAllocationParams params = {
.usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_DECODER,
};
if (!gst_video_info_from_caps (&params.info, caps))
return FALSE;
if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
if (!gst_va_dmabuf_try (allocator, &params))
return FALSE;
} else if (GST_IS_VA_ALLOCATOR (allocator)) {
if (!gst_va_allocator_try (allocator, &params))
return FALSE;
if (!gst_caps_is_vamemory (caps))
_shall_copy_frames (self, &params.info);
} else {
return FALSE;
}
return TRUE;
}
static GstAllocator *
_create_allocator (GstVaVp8Dec * self, GstCaps * caps)
{
GstAllocator *allocator = NULL;
GstVaDisplay *display = NULL;
g_object_get (self->decoder, "display", &display, NULL);
if (gst_caps_is_dmabuf (caps))
allocator = gst_va_dmabuf_allocator_new (display);
else {
if (gst_caps_is_dmabuf (caps)) {
allocator = gst_va_dmabuf_allocator_new (self->display);
} else {
GArray *surface_formats =
gst_va_decoder_get_surface_formats (self->decoder);
allocator = gst_va_allocator_new (display, surface_formats);
allocator = gst_va_allocator_new (self->display, surface_formats);
}
gst_object_unref (display);
if (!_try_allocator (self, allocator, caps))
gst_clear_object (&allocator);
return allocator;
}
@ -657,6 +599,14 @@ gst_va_vp8_dec_new_sequence (GstVp8Decoder * decoder,
}
}
if (!self->has_videometa) {
GstBufferPool *pool;
pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
self->copy_frames = gst_va_pool_requires_video_meta (pool);
gst_object_unref (pool);
}
return TRUE;
}

View file

@ -395,29 +395,6 @@ gst_va_vpp_set_context (GstElement * element, GstContext * context)
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static gboolean
_try_allocator (GstVaVpp * self, GstAllocator * allocator, GstCaps * caps,
guint usage_hint)
{
GstVaAllocationParams params = {
.usage_hint = usage_hint,
};
if (!gst_video_info_from_caps (&params.info, caps))
return FALSE;
if (GST_IS_VA_DMABUF_ALLOCATOR (allocator)) {
if (!gst_va_dmabuf_try (allocator, &params))
return FALSE;
} else if (GST_IS_VA_ALLOCATOR (allocator)) {
if (!gst_va_allocator_try (allocator, &params))
return FALSE;
} else {
return FALSE;
}
return TRUE;
}
static GstAllocator *
_create_allocator (GstVaVpp * self, GstCaps * caps, guint usage_hint)
{
@ -430,9 +407,6 @@ _create_allocator (GstVaVpp * self, GstCaps * caps, guint usage_hint)
allocator = gst_va_allocator_new (self->display, surface_formats);
}
if (!_try_allocator (self, allocator, caps, usage_hint))
gst_clear_object (&allocator);
return allocator;
}