mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
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:
parent
a2920411d3
commit
afe8723196
5 changed files with 1754 additions and 9 deletions
1510
subprojects/gst-plugins-bad/sys/va/gstvacompositor.c
Normal file
1510
subprojects/gst-plugins-bad/sys/va/gstvacompositor.c
Normal file
File diff suppressed because it is too large
Load diff
36
subprojects/gst-plugins-bad/sys/va/gstvacompositor.h
Normal file
36
subprojects/gst-plugins-bad/sys/va/gstvacompositor.h
Normal 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
|
|
@ -1518,24 +1518,35 @@ gst_va_filter_drop_filter_buffers (GstVaFilter * self)
|
||||||
return ret;
|
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
|
static gboolean
|
||||||
_fill_va_sample (GstVaFilter * self, GstVaSample * sample,
|
_fill_va_sample (GstVaFilter * self, GstVaSample * sample,
|
||||||
GstPadDirection direction)
|
GstPadDirection direction)
|
||||||
{
|
{
|
||||||
GstVideoCropMeta *crop = NULL;
|
GstVideoCropMeta *crop = NULL;
|
||||||
|
|
||||||
if (sample->buffer)
|
sample->surface = _get_surface_from_buffer (self, sample->buffer);
|
||||||
sample->surface = gst_va_buffer_get_surface (sample->buffer);
|
|
||||||
if (sample->surface == VA_INVALID_ID)
|
if (sample->surface == VA_INVALID_ID)
|
||||||
return FALSE;
|
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 */
|
/* XXX: cropping occurs only in input frames */
|
||||||
if (direction == GST_PAD_SRC) {
|
if (direction == GST_PAD_SRC) {
|
||||||
GST_OBJECT_LOCK (self);
|
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, ¶ms,
|
||||||
|
&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:
|
* gst_va_buffer_get_surface_flags:
|
||||||
* @buffer: the #GstBuffer to check.
|
* @buffer: the #GstBuffer to check.
|
||||||
|
@ -1782,3 +1927,21 @@ gst_va_filter_has_video_format (GstVaFilter * self, GstVideoFormat format,
|
||||||
|
|
||||||
return FALSE;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ enum {
|
||||||
GST_VA_FILTER_PROP_LAST
|
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;
|
typedef struct _GstVaSample GstVaSample;
|
||||||
struct _GstVaSample
|
struct _GstVaSample
|
||||||
{
|
{
|
||||||
|
@ -78,6 +81,34 @@ struct _GstVaSample
|
||||||
VARectangle rect;
|
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);
|
GstVaFilter * gst_va_filter_new (GstVaDisplay * display);
|
||||||
gboolean gst_va_filter_open (GstVaFilter * self);
|
gboolean gst_va_filter_open (GstVaFilter * self);
|
||||||
gboolean gst_va_filter_close (GstVaFilter * self);
|
gboolean gst_va_filter_close (GstVaFilter * self);
|
||||||
|
@ -123,4 +154,8 @@ gboolean gst_va_filter_has_video_format (GstVaFilter * self,
|
||||||
GstVideoFormat format,
|
GstVideoFormat format,
|
||||||
GstCapsFeatures * feature);
|
GstCapsFeatures * feature);
|
||||||
|
|
||||||
|
gboolean gst_va_filter_has_compose (GstVaFilter * self);
|
||||||
|
gboolean gst_va_filter_compose (GstVaFilter * self,
|
||||||
|
GstVaComposeTransaction * tx);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -4,6 +4,7 @@ va_sources = [
|
||||||
'gstvabasetransform.c',
|
'gstvabasetransform.c',
|
||||||
'gstvabaseenc.c',
|
'gstvabaseenc.c',
|
||||||
'gstvacaps.c',
|
'gstvacaps.c',
|
||||||
|
'gstvacompositor.c',
|
||||||
'gstvadecoder.c',
|
'gstvadecoder.c',
|
||||||
'gstvadeinterlace.c',
|
'gstvadeinterlace.c',
|
||||||
'gstvaencoder.c',
|
'gstvaencoder.c',
|
||||||
|
|
Loading…
Reference in a new issue