va: vpp: add compositor

New implementation of a VA-API compositor with blend feature.

Various chunks of code was taken from vavpp.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2332>
This commit is contained in:
U. Artie Eoff 2022-04-26 12:06:17 -04:00 committed by Víctor Manuel Jáquez Leal
parent a2920411d3
commit afe8723196
5 changed files with 1754 additions and 9 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/* GStreamer
* Copyright (C) 2022 Intel Corporation
* Author: U. Artie Eoff <ullysses.a.eoff@intel.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 the0
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "gstvadevice.h"
#include <gst/video/gstvideoaggregator.h>
G_BEGIN_DECLS
#define GST_TYPE_VA_COMPOSITOR_PAD (gst_va_compositor_pad_get_type())
G_DECLARE_FINAL_TYPE (GstVaCompositorPad, gst_va_compositor_pad,
GST, VA_COMPOSITOR_PAD, GstVideoAggregatorPad)
gboolean gst_va_compositor_register (GstPlugin * plugin,
GstVaDevice * device,
guint rank);
G_END_DECLS

View file

@ -1518,24 +1518,35 @@ gst_va_filter_drop_filter_buffers (GstVaFilter * self)
return ret;
}
static VASurfaceID
_get_surface_from_buffer (GstVaFilter * self, GstBuffer * buffer)
{
VASurfaceID surface = VA_INVALID_ID;
if (buffer)
surface = gst_va_buffer_get_surface (buffer);
if (surface != VA_INVALID_ID) {
/* @FIXME: in gallium vaQuerySurfaceStatus only seems to work with
* encoder's surfaces */
if (!GST_VA_DISPLAY_IS_IMPLEMENTATION (self->display, MESA_GALLIUM))
if (!va_check_surface (self->display, surface))
surface = VA_INVALID_ID;
}
return surface;
}
static gboolean
_fill_va_sample (GstVaFilter * self, GstVaSample * sample,
GstPadDirection direction)
{
GstVideoCropMeta *crop = NULL;
if (sample->buffer)
sample->surface = gst_va_buffer_get_surface (sample->buffer);
sample->surface = _get_surface_from_buffer (self, sample->buffer);
if (sample->surface == VA_INVALID_ID)
return FALSE;
/* @FIXME: in gallium vaQuerySurfaceStatus only seems to work with
* encoder's surfaces */
if (!GST_VA_DISPLAY_IS_IMPLEMENTATION (self->display, MESA_GALLIUM)) {
if (!va_check_surface (self->display, sample->surface))
return FALSE;
}
/* XXX: cropping occurs only in input frames */
if (direction == GST_PAD_SRC) {
GST_OBJECT_LOCK (self);
@ -1703,6 +1714,140 @@ fail_end_pic:
}
}
gboolean
gst_va_filter_has_compose (GstVaFilter * self)
{
g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
if (!gst_va_filter_is_open (self))
return FALSE;
/* HACK(uartie): i965 can't do composition */
if (gst_va_display_is_implementation (self->display,
GST_VA_IMPLEMENTATION_INTEL_I965))
return FALSE;
/* some drivers can compose, but may not support blending (e.g. GALLIUM) */
#ifndef GST_DISABLE_GST_DEBUG
if (self->pipeline_caps.blend_flags & VA_BLEND_GLOBAL_ALPHA)
GST_WARNING_OBJECT (self, "VPP does not support alpha blending");
#endif
return TRUE;
}
/**
* gst_va_filter_compose:
* @tx: the #GstVaComposeTransaction for input samples and output.
*
* Iterates over all inputs via #GstVaComposeTransaction:next and composes
* them onto the #GstVaComposeTransaction:output.
*
* Only csc, scaling and blending filters are applied during composition.
* All other filters are ignored here. Use #gst_va_filter_process to apply
* other filters.
*
* Returns: TRUE on successful compose, FALSE otherwise.
*
* Since: 1.22
*/
gboolean
gst_va_filter_compose (GstVaFilter * self, GstVaComposeTransaction * tx)
{
VADisplay dpy;
VAStatus status;
VASurfaceID out_surface;
GstVaComposeSample *sample;
g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
g_return_val_if_fail (tx, FALSE);
g_return_val_if_fail (tx->next, FALSE);
g_return_val_if_fail (tx->output, FALSE);
if (!gst_va_filter_is_open (self))
return FALSE;
out_surface = _get_surface_from_buffer (self, tx->output);
if (out_surface == VA_INVALID_ID)
return FALSE;
dpy = gst_va_display_get_va_dpy (self->display);
status = vaBeginPicture (dpy, self->context, out_surface);
if (status != VA_STATUS_SUCCESS) {
GST_ERROR_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
return FALSE;
}
sample = tx->next (tx->user_data);
for (; sample; sample = tx->next (tx->user_data)) {
VAProcPipelineParameterBuffer params = { 0, };
VABufferID buffer;
VASurfaceID in_surface;
VABlendState blend = { 0, };
in_surface = _get_surface_from_buffer (self, sample->buffer);
if (in_surface == VA_INVALID_ID)
return FALSE;
/* (transfer full), unref it */
gst_buffer_unref (sample->buffer);
/* *INDENT-OFF* */
params = (VAProcPipelineParameterBuffer) {
.surface = in_surface,
.surface_region = &sample->input_region,
.output_region = &sample->output_region,
.output_background_color = 0xff000000,
.filter_flags = sample->flags,
};
/* *INDENT-ON* */
/* only send blend state when sample is not fully opaque */
if ((self->pipeline_caps.blend_flags & VA_BLEND_GLOBAL_ALPHA)
&& sample->alpha < 1.0) {
/* *INDENT-OFF* */
blend = (VABlendState) {
.flags = VA_BLEND_GLOBAL_ALPHA,
.global_alpha = sample->alpha,
};
/* *INDENT-ON* */
params.blend_state = &blend;
}
status = vaCreateBuffer (dpy, self->context,
VAProcPipelineParameterBufferType, sizeof (params), 1, &params,
&buffer);
if (status != VA_STATUS_SUCCESS) {
GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
goto fail_end_pic;
}
status = vaRenderPicture (dpy, self->context, &buffer, 1);
vaDestroyBuffer (dpy, buffer);
if (status != VA_STATUS_SUCCESS) {
GST_ERROR_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
goto fail_end_pic;
}
}
status = vaEndPicture (dpy, self->context);
if (status != VA_STATUS_SUCCESS) {
GST_ERROR_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
return FALSE;
}
return TRUE;
fail_end_pic:
{
status = vaEndPicture (dpy, self->context);
if (status != VA_STATUS_SUCCESS)
GST_ERROR_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
return FALSE;
}
}
/**
* gst_va_buffer_get_surface_flags:
* @buffer: the #GstBuffer to check.
@ -1782,3 +1927,21 @@ gst_va_filter_has_video_format (GstVaFilter * self, GstVideoFormat format,
return FALSE;
}
GType
gst_va_scale_method_get_type (void)
{
static gsize type = 0;
static const GEnumValue values[] = {
{VA_FILTER_SCALING_DEFAULT, "Default scaling method", "default"},
{VA_FILTER_SCALING_FAST, "Fast scaling method", "fast"},
{VA_FILTER_SCALING_HQ, "High quality scaling method", "hq"},
{0, NULL, NULL},
};
if (g_once_init_enter (&type)) {
const GType _type = g_enum_register_static ("GstVaScaleMethod", values);
g_once_init_leave (&type, _type);
}
return type;
}

View file

@ -57,6 +57,9 @@ enum {
GST_VA_FILTER_PROP_LAST
};
#define GST_TYPE_VA_SCALE_METHOD gst_va_scale_method_get_type()
GType gst_va_scale_method_get_type (void) G_GNUC_CONST;
typedef struct _GstVaSample GstVaSample;
struct _GstVaSample
{
@ -78,6 +81,34 @@ struct _GstVaSample
VARectangle rect;
};
typedef struct _GstVaComposeSample GstVaComposeSample;
struct _GstVaComposeSample
{
/* input buffer (transfer full) */
GstBuffer *buffer;
/* scale method flags */
guint32 flags;
VARectangle input_region;
VARectangle output_region;
gdouble alpha;
};
typedef struct _GstVaComposeTransaction GstVaComposeTransaction;
struct _GstVaComposeTransaction
{
/* input sample iterator function */
GstVaComposeSample* (*next) (gpointer user_data);
/* the output buffer to compose onto */
GstBuffer *output;
/* user data parameter for "next" function */
gpointer user_data;
};
GstVaFilter * gst_va_filter_new (GstVaDisplay * display);
gboolean gst_va_filter_open (GstVaFilter * self);
gboolean gst_va_filter_close (GstVaFilter * self);
@ -123,4 +154,8 @@ gboolean gst_va_filter_has_video_format (GstVaFilter * self,
GstVideoFormat format,
GstCapsFeatures * feature);
gboolean gst_va_filter_has_compose (GstVaFilter * self);
gboolean gst_va_filter_compose (GstVaFilter * self,
GstVaComposeTransaction * tx);
G_END_DECLS

View file

@ -4,6 +4,7 @@ va_sources = [
'gstvabasetransform.c',
'gstvabaseenc.c',
'gstvacaps.c',
'gstvacompositor.c',
'gstvadecoder.c',
'gstvadeinterlace.c',
'gstvaencoder.c',