mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 00:36:51 +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;
|
||||
}
|
||||
|
||||
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, ¶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:
|
||||
* @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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,6 +4,7 @@ va_sources = [
|
|||
'gstvabasetransform.c',
|
||||
'gstvabaseenc.c',
|
||||
'gstvacaps.c',
|
||||
'gstvacompositor.c',
|
||||
'gstvadecoder.c',
|
||||
'gstvadeinterlace.c',
|
||||
'gstvaencoder.c',
|
||||
|
|
Loading…
Reference in a new issue