mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 14:56:36 +00:00
plugins: add vaapioverlay plugin
A plugin similar to the base compositor element but uses VA-API VPP blend functions to accelerate the overlay/compositing. Simple example: gst-launch-1.0 -vf videotestsrc ! vaapipostproc \ ! tee name=testsrc ! queue \ ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 \ name=overlay ! vaapisink testsrc. ! queue ! overlay.
This commit is contained in:
parent
b76c0a0caf
commit
d28ffd73c3
4 changed files with 758 additions and 0 deletions
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "gstcompat.h"
|
||||
#include "gstvaapidecode.h"
|
||||
#include "gstvaapioverlay.h"
|
||||
#include "gstvaapipostproc.h"
|
||||
#include "gstvaapisink.h"
|
||||
#include "gstvaapidecodebin.h"
|
||||
|
@ -214,6 +215,8 @@ plugin_init (GstPlugin * plugin)
|
|||
g_array_unref (decoders);
|
||||
}
|
||||
|
||||
gst_vaapioverlay_register (plugin, display);
|
||||
|
||||
gst_element_register (plugin, "vaapipostproc",
|
||||
GST_RANK_PRIMARY, GST_TYPE_VAAPIPOSTPROC);
|
||||
|
||||
|
|
651
gst/vaapi/gstvaapioverlay.c
Normal file
651
gst/vaapi/gstvaapioverlay.c
Normal file
|
@ -0,0 +1,651 @@
|
|||
/*
|
||||
* gstvaapioverlay.c - VA-API vpp overlay
|
||||
*
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "gstvaapioverlay.h"
|
||||
#include "gstvaapipluginutil.h"
|
||||
#include "gstvaapivideobufferpool.h"
|
||||
|
||||
#define GST_PLUGIN_NAME "vaapioverlay"
|
||||
#define GST_PLUGIN_DESC "A VA-API overlay filter"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_overlay);
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
#define GST_CAT_DEFAULT gst_debug_vaapi_overlay
|
||||
#else
|
||||
#define GST_CAT_DEFAULT NULL
|
||||
#endif
|
||||
|
||||
/* Default templates */
|
||||
/* *INDENT-OFF* */
|
||||
static const char gst_vaapi_overlay_sink_caps_str[] =
|
||||
GST_VAAPI_MAKE_SURFACE_CAPS ";"
|
||||
GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL);
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static const char gst_vaapi_overlay_src_caps_str[] =
|
||||
GST_VAAPI_MAKE_SURFACE_CAPS ";"
|
||||
GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL);
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static GstStaticPadTemplate gst_vaapi_overlay_sink_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink_%u",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_REQUEST,
|
||||
GST_STATIC_CAPS (gst_vaapi_overlay_sink_caps_str));
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
static GstStaticPadTemplate gst_vaapi_overlay_src_factory =
|
||||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (gst_vaapi_overlay_src_caps_str));
|
||||
/* *INDENT-ON* */
|
||||
|
||||
G_DEFINE_TYPE (GstVaapiOverlaySinkPad, gst_vaapi_overlay_sink_pad,
|
||||
GST_TYPE_VIDEO_AGGREGATOR_PAD);
|
||||
|
||||
#define DEFAULT_PAD_XPOS 0
|
||||
#define DEFAULT_PAD_YPOS 0
|
||||
#define DEFAULT_PAD_ALPHA 1.0
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_PAD_0,
|
||||
PROP_PAD_XPOS,
|
||||
PROP_PAD_YPOS,
|
||||
PROP_PAD_ALPHA,
|
||||
};
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_sink_pad_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PAD_XPOS:
|
||||
g_value_set_int (value, pad->xpos);
|
||||
break;
|
||||
case PROP_PAD_YPOS:
|
||||
g_value_set_int (value, pad->ypos);
|
||||
break;
|
||||
case PROP_PAD_ALPHA:
|
||||
g_value_set_double (value, pad->alpha);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_sink_pad_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PAD_XPOS:
|
||||
pad->xpos = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_PAD_YPOS:
|
||||
pad->ypos = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_PAD_ALPHA:
|
||||
pad->alpha = g_value_get_double (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_sink_pad_finalize (GObject * object)
|
||||
{
|
||||
gst_vaapi_pad_private_finalize (GST_VAAPI_OVERLAY_SINK_PAD (object)->priv);
|
||||
|
||||
G_OBJECT_CLASS (gst_vaapi_overlay_sink_pad_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_sink_pad_class_init (GstVaapiOverlaySinkPadClass * klass)
|
||||
{
|
||||
GObjectClass *const gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = gst_vaapi_overlay_sink_pad_finalize;
|
||||
gobject_class->set_property = gst_vaapi_overlay_sink_pad_set_property;
|
||||
gobject_class->get_property = gst_vaapi_overlay_sink_pad_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_PAD_XPOS,
|
||||
g_param_spec_int ("xpos", "X Position", "X Position of the picture",
|
||||
G_MININT, G_MAXINT, DEFAULT_PAD_XPOS,
|
||||
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_PAD_YPOS,
|
||||
g_param_spec_int ("ypos", "Y Position", "Y Position of the picture",
|
||||
G_MININT, G_MAXINT, DEFAULT_PAD_YPOS,
|
||||
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_PAD_ALPHA,
|
||||
g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
|
||||
DEFAULT_PAD_ALPHA,
|
||||
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_sink_pad_init (GstVaapiOverlaySinkPad * pad)
|
||||
{
|
||||
pad->xpos = DEFAULT_PAD_XPOS;
|
||||
pad->ypos = DEFAULT_PAD_YPOS;
|
||||
pad->alpha = DEFAULT_PAD_ALPHA;
|
||||
pad->priv = gst_vaapi_pad_private_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_child_proxy_init (gpointer g_iface, gpointer iface_data);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GstVaapiOverlay, gst_vaapi_overlay,
|
||||
GST_TYPE_VIDEO_AGGREGATOR, GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
|
||||
gst_vaapi_overlay_child_proxy_init));
|
||||
|
||||
GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapi_overlay_parent_class);
|
||||
|
||||
static GstPad *
|
||||
gst_vaapi_overlay_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||
const gchar * req_name, const GstCaps * caps)
|
||||
{
|
||||
GstPad *newpad = GST_PAD (GST_ELEMENT_CLASS
|
||||
(gst_vaapi_overlay_parent_class)->request_new_pad (element, templ,
|
||||
req_name, caps));
|
||||
|
||||
if (!newpad)
|
||||
GST_DEBUG_OBJECT (element, "could not create/add pad");
|
||||
else
|
||||
gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
|
||||
GST_OBJECT_NAME (newpad));
|
||||
|
||||
return newpad;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_release_pad (GstElement * element, GstPad * pad)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (element);
|
||||
|
||||
gst_child_proxy_child_removed (GST_CHILD_PROXY (overlay), G_OBJECT (pad),
|
||||
GST_OBJECT_NAME (pad));
|
||||
|
||||
GST_ELEMENT_CLASS (gst_vaapi_overlay_parent_class)->release_pad (element,
|
||||
pad);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
gst_vaapi_overlay_ensure_display (GstVaapiOverlay * overlay)
|
||||
{
|
||||
return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (overlay));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
|
||||
GstQuery * query)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
|
||||
|
||||
if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) {
|
||||
if (gst_vaapi_handle_context_query (GST_ELEMENT (overlay), query)) {
|
||||
GST_DEBUG_OBJECT (overlay, "sharing display %" GST_PTR_FORMAT,
|
||||
GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay));
|
||||
return TRUE;
|
||||
}
|
||||
} else if (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION) {
|
||||
GstCaps *caps;
|
||||
|
||||
gst_query_parse_allocation (query, &caps, NULL);
|
||||
|
||||
if (caps == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!gst_vaapi_plugin_base_pad_set_caps
|
||||
(GST_VAAPI_PLUGIN_BASE (overlay), GST_PAD (bpad), caps, NULL, NULL))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->sink_query
|
||||
(agg, bpad, query);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_src_query (GstAggregator * agg, GstQuery * query)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
|
||||
|
||||
if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) {
|
||||
if (gst_vaapi_handle_context_query (GST_ELEMENT (overlay), query)) {
|
||||
GST_DEBUG_OBJECT (overlay, "sharing display %" GST_PTR_FORMAT,
|
||||
GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->src_query
|
||||
(agg, query);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_start (GstAggregator * agg)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
|
||||
|
||||
if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (overlay)))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_vaapi_overlay_ensure_display (overlay))
|
||||
return FALSE;
|
||||
|
||||
overlay->blend =
|
||||
gst_vaapi_blend_new (GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay));
|
||||
if (!overlay->blend)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_reset_sinkpad_private (GstElement * element, GstPad * pad, gpointer user_data)
|
||||
{
|
||||
gst_vaapi_pad_private_reset (GST_VAAPI_OVERLAY_SINK_PAD (pad)->priv);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_stop (GstAggregator * agg)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
|
||||
|
||||
gst_vaapi_video_pool_replace (&overlay->blend_pool, NULL);
|
||||
gst_vaapi_blend_replace (&overlay->blend, NULL);
|
||||
|
||||
gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (overlay));
|
||||
|
||||
gst_element_foreach_sink_pad (GST_ELEMENT (overlay), _reset_sinkpad_private,
|
||||
NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_destroy (GstVaapiOverlay * const overlay)
|
||||
{
|
||||
gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (overlay));
|
||||
gst_element_foreach_sink_pad (GST_ELEMENT (overlay), _reset_sinkpad_private,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_finalize (GObject * object)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (object);
|
||||
|
||||
gst_vaapi_overlay_destroy (overlay);
|
||||
gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (overlay));
|
||||
|
||||
G_OBJECT_CLASS (gst_vaapi_overlay_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_propose_allocation (GstAggregator * agg,
|
||||
GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query)
|
||||
{
|
||||
return gst_vaapi_plugin_base_pad_propose_allocation
|
||||
(GST_VAAPI_PLUGIN_BASE (agg), GST_PAD (pad), query);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_decide_allocation (GstAggregator * agg, GstQuery * query)
|
||||
{
|
||||
return gst_vaapi_plugin_base_decide_allocation
|
||||
(GST_VAAPI_PLUGIN_BASE (agg), query);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_process_frames (GstVaapiOverlay * overlay)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = GST_ELEMENT (overlay)->sinkpads; l; l = l->next) {
|
||||
GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (l->data);
|
||||
GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (vagg_pad);
|
||||
GstVideoFrame *inframe =
|
||||
gst_video_aggregator_pad_get_prepared_frame (vagg_pad);
|
||||
GstBuffer *inbuf = NULL;
|
||||
GstBuffer *buf = gst_video_aggregator_pad_get_current_buffer (vagg_pad);
|
||||
GstVaapiVideoMeta *inbuf_meta;
|
||||
GstVaapiRectangle target_rect;
|
||||
|
||||
if (gst_vaapi_plugin_base_pad_get_input_buffer (GST_VAAPI_PLUGIN_BASE
|
||||
(overlay), GST_PAD (pad), buf, &inbuf) != GST_FLOW_OK)
|
||||
return FALSE;
|
||||
|
||||
/* Current sinkpad may have reached EOS */
|
||||
if (!inframe || !inbuf)
|
||||
continue;
|
||||
|
||||
target_rect.x = pad->xpos;
|
||||
target_rect.y = pad->ypos;
|
||||
target_rect.width = GST_VIDEO_FRAME_WIDTH (inframe);
|
||||
target_rect.height = GST_VIDEO_FRAME_HEIGHT (inframe);
|
||||
|
||||
inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf);
|
||||
|
||||
if (!inbuf_meta) {
|
||||
gst_buffer_unref (inbuf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_vaapi_blend_process_render (overlay->blend,
|
||||
gst_vaapi_video_meta_get_surface (inbuf_meta),
|
||||
gst_vaapi_video_meta_get_render_rect (inbuf_meta),
|
||||
&target_rect, pad->alpha)) {
|
||||
gst_buffer_unref (inbuf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_buffer_unref (inbuf);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vaapi_overlay_aggregate_frames (GstVideoAggregator * vagg,
|
||||
GstBuffer * outbuf)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (vagg);
|
||||
GstVaapiVideoMeta *outbuf_meta;
|
||||
GstVaapiSurface *outbuf_surface;
|
||||
GstVaapiSurfaceProxy *proxy;
|
||||
|
||||
if (!overlay->blend_pool) {
|
||||
GstVaapiVideoPool *pool =
|
||||
gst_vaapi_surface_pool_new_full (GST_VAAPI_PLUGIN_BASE_DISPLAY
|
||||
(overlay),
|
||||
GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (overlay), 0);
|
||||
if (!pool)
|
||||
return GST_FLOW_ERROR;
|
||||
gst_vaapi_video_pool_replace (&overlay->blend_pool, pool);
|
||||
gst_vaapi_video_pool_unref (pool);
|
||||
}
|
||||
|
||||
outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf);
|
||||
if (!outbuf_meta)
|
||||
return GST_FLOW_ERROR;
|
||||
|
||||
if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) {
|
||||
proxy = gst_vaapi_surface_proxy_new_from_pool
|
||||
(GST_VAAPI_SURFACE_POOL (overlay->blend_pool));
|
||||
if (!proxy)
|
||||
return GST_FLOW_ERROR;
|
||||
gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy);
|
||||
gst_vaapi_surface_proxy_unref (proxy);
|
||||
}
|
||||
|
||||
outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta);
|
||||
|
||||
if (!gst_vaapi_blend_process_begin (overlay->blend, outbuf_surface))
|
||||
return GST_FLOW_ERROR;
|
||||
|
||||
if (!gst_vaapi_overlay_process_frames (overlay)) {
|
||||
gst_vaapi_blend_process_end (overlay->blend);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
if (!gst_vaapi_blend_process_end (overlay->blend))
|
||||
return GST_FLOW_ERROR;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vaapi_overlay_create_output_buffer (GstVideoAggregator * vagg,
|
||||
GstBuffer ** outbuf)
|
||||
{
|
||||
GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (vagg);
|
||||
GstBufferPool *const pool =
|
||||
GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL (overlay);
|
||||
|
||||
g_return_val_if_fail (pool != NULL, GST_FLOW_ERROR);
|
||||
|
||||
if (!gst_buffer_pool_is_active (pool) &&
|
||||
!gst_buffer_pool_set_active (pool, TRUE)) {
|
||||
GST_ERROR_OBJECT (overlay, "failed to activate output video buffer pool");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
*outbuf = NULL;
|
||||
if ((gst_buffer_pool_acquire_buffer (pool, outbuf, NULL) != GST_FLOW_OK)
|
||||
|| !outbuf) {
|
||||
GST_ERROR_OBJECT (overlay, "failed to create output video buffer");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_overlay_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
|
||||
{
|
||||
if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (agg), NULL, caps))
|
||||
return FALSE;
|
||||
|
||||
return
|
||||
GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->negotiated_src_caps
|
||||
(agg, caps);
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_vaapi_overlay_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
|
||||
{
|
||||
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
|
||||
GList *l;
|
||||
gint best_width = -1, best_height = -1;
|
||||
gint best_fps_n = -1, best_fps_d = -1;
|
||||
gdouble best_fps = 0.;
|
||||
GstCaps *ret = NULL;
|
||||
GstStructure *s;
|
||||
|
||||
ret = gst_caps_make_writable (caps);
|
||||
|
||||
GST_OBJECT_LOCK (vagg);
|
||||
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
|
||||
GstVideoAggregatorPad *vaggpad = l->data;
|
||||
GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (vaggpad);
|
||||
gint this_width, this_height;
|
||||
gint fps_n, fps_d;
|
||||
gdouble cur_fps;
|
||||
|
||||
fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
|
||||
fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
|
||||
|
||||
this_width = GST_VIDEO_INFO_WIDTH (&vaggpad->info) + MAX (pad->xpos, 0);
|
||||
this_height = GST_VIDEO_INFO_HEIGHT (&vaggpad->info) + MAX (pad->ypos, 0);
|
||||
|
||||
if (best_width < this_width)
|
||||
best_width = this_width;
|
||||
if (best_height < this_height)
|
||||
best_height = this_height;
|
||||
|
||||
if (fps_d == 0)
|
||||
cur_fps = 0.0;
|
||||
else
|
||||
gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
|
||||
|
||||
if (best_fps < cur_fps) {
|
||||
best_fps = cur_fps;
|
||||
best_fps_n = fps_n;
|
||||
best_fps_d = fps_d;
|
||||
}
|
||||
}
|
||||
GST_OBJECT_UNLOCK (vagg);
|
||||
|
||||
if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
|
||||
best_fps_n = 25;
|
||||
best_fps_d = 1;
|
||||
best_fps = 25.0;
|
||||
}
|
||||
|
||||
s = gst_caps_get_structure (ret, 0);
|
||||
gst_structure_fixate_field_nearest_int (s, "width", best_width);
|
||||
gst_structure_fixate_field_nearest_int (s, "height", best_height);
|
||||
gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
|
||||
best_fps_d);
|
||||
|
||||
return gst_caps_fixate (ret);
|
||||
}
|
||||
|
||||
static GstVaapiPadPrivate *
|
||||
gst_vaapi_overlay_get_vaapi_pad_private (GstVaapiPluginBase * plugin,
|
||||
GstPad * pad)
|
||||
{
|
||||
if (GST_IS_VAAPI_OVERLAY_SINK_PAD (pad))
|
||||
return GST_VAAPI_OVERLAY_SINK_PAD (pad)->priv;
|
||||
|
||||
g_assert (GST_VAAPI_PLUGIN_BASE_SRC_PAD (plugin) == pad);
|
||||
return GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE (plugin);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_class_init (GstVaapiOverlayClass * klass)
|
||||
{
|
||||
GObjectClass *const object_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
|
||||
GstAggregatorClass *const agg_class = GST_AGGREGATOR_CLASS (klass);
|
||||
GstVideoAggregatorClass *const vagg_class =
|
||||
GST_VIDEO_AGGREGATOR_CLASS (klass);
|
||||
GstVaapiPluginBaseClass *plugin_class = GST_VAAPI_PLUGIN_BASE_CLASS (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_overlay,
|
||||
GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
|
||||
|
||||
gst_vaapi_plugin_base_class_init (plugin_class);
|
||||
plugin_class->get_vaapi_pad_private =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_get_vaapi_pad_private);
|
||||
|
||||
object_class->finalize = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_finalize);
|
||||
|
||||
agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_sink_query);
|
||||
agg_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_src_query);
|
||||
agg_class->start = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_start);
|
||||
agg_class->propose_allocation =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_propose_allocation);
|
||||
agg_class->fixate_src_caps =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_fixate_src_caps);
|
||||
agg_class->negotiated_src_caps =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_negotiated_src_caps);
|
||||
agg_class->decide_allocation =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_decide_allocation);
|
||||
agg_class->stop = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_stop);
|
||||
|
||||
vagg_class->aggregate_frames =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_aggregate_frames);
|
||||
vagg_class->create_output_buffer =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_create_output_buffer);
|
||||
|
||||
element_class->request_new_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_request_new_pad);
|
||||
element_class->release_pad =
|
||||
GST_DEBUG_FUNCPTR (gst_vaapi_overlay_release_pad);
|
||||
element_class->set_context = GST_DEBUG_FUNCPTR (gst_vaapi_base_set_context);
|
||||
|
||||
gst_element_class_add_static_pad_template_with_gtype (element_class,
|
||||
&gst_vaapi_overlay_sink_factory, GST_TYPE_VAAPI_OVERLAY_SINK_PAD);
|
||||
|
||||
gst_element_class_add_static_pad_template_with_gtype (element_class,
|
||||
&gst_vaapi_overlay_src_factory, GST_TYPE_AGGREGATOR_PAD);
|
||||
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
"VA-API overlay",
|
||||
"Filter/Editor/Video/Compositor/Hardware",
|
||||
GST_PLUGIN_DESC, "U. Artie Eoff <ullysses.a.eoff@intel.com>");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_init (GstVaapiOverlay * overlay)
|
||||
{
|
||||
gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (overlay), GST_CAT_DEFAULT);
|
||||
}
|
||||
|
||||
/* GstChildProxy implementation */
|
||||
static GObject *
|
||||
gst_vaapi_overlay_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
|
||||
guint index)
|
||||
{
|
||||
GstVaapiOverlay *overlay = GST_VAAPI_OVERLAY (child_proxy);
|
||||
GObject *obj = NULL;
|
||||
|
||||
GST_OBJECT_LOCK (overlay);
|
||||
obj = g_list_nth_data (GST_ELEMENT_CAST (overlay)->sinkpads, index);
|
||||
if (obj)
|
||||
gst_object_ref (obj);
|
||||
GST_OBJECT_UNLOCK (overlay);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static guint
|
||||
gst_vaapi_overlay_child_proxy_get_children_count (GstChildProxy * child_proxy)
|
||||
{
|
||||
guint count = 0;
|
||||
GstVaapiOverlay *overlay = GST_VAAPI_OVERLAY (child_proxy);
|
||||
|
||||
GST_OBJECT_LOCK (overlay);
|
||||
count = GST_ELEMENT_CAST (overlay)->numsinkpads;
|
||||
GST_OBJECT_UNLOCK (overlay);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vaapi_overlay_child_proxy_init (gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GstChildProxyInterface *iface = g_iface;
|
||||
|
||||
iface->get_child_by_index = gst_vaapi_overlay_child_proxy_get_child_by_index;
|
||||
iface->get_children_count = gst_vaapi_overlay_child_proxy_get_children_count;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_vaapioverlay_register (GstPlugin * plugin, GstVaapiDisplay * display)
|
||||
{
|
||||
GstVaapiBlend *blend = NULL;
|
||||
|
||||
blend = gst_vaapi_blend_new (display);
|
||||
if (!blend)
|
||||
return FALSE;
|
||||
gst_vaapi_blend_replace (&blend, NULL);
|
||||
|
||||
return gst_element_register (plugin, "vaapioverlay",
|
||||
GST_RANK_PRIMARY, GST_TYPE_VAAPI_OVERLAY);
|
||||
}
|
103
gst/vaapi/gstvaapioverlay.h
Normal file
103
gst/vaapi/gstvaapioverlay.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* gstvaapioverlay.h - VA-API vpp overlay
|
||||
*
|
||||
* Copyright (C) 2019 Intel Corporation
|
||||
* Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef GST_VAAPI_OVERLAY_H
|
||||
#define GST_VAAPI_OVERLAY_H
|
||||
|
||||
#include "gstvaapipluginbase.h"
|
||||
#include <gst/vaapi/gstvaapisurfacepool.h>
|
||||
#include <gst/vaapi/gstvaapiblend.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_VAAPI_OVERLAY (gst_vaapi_overlay_get_type ())
|
||||
#define GST_VAAPI_OVERLAY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_OVERLAY, GstVaapiOverlay))
|
||||
#define GST_VAAPI_OVERLAY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_OVERLAY, \
|
||||
GstVaapiOverlayClass))
|
||||
#define GST_IS_VAAPI_OVERLAY(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_OVERLAY))
|
||||
#define GST_IS_VAAPI_OVERLAY_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_OVERLAY))
|
||||
#define GST_VAAPI_OVERLAY_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_OVERLAY, \
|
||||
GstVaapiOverlayClass))
|
||||
|
||||
#define GST_TYPE_VAAPI_OVERLAY_SINK_PAD (gst_vaapi_overlay_sink_pad_get_type())
|
||||
#define GST_VAAPI_OVERLAY_SINK_PAD(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_OVERLAY_SINK_PAD, \
|
||||
GstVaapiOverlaySinkPad))
|
||||
#define GST_VAAPI_OVERLAY_SINK_PAD_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_OVERLAY_SINK_PAD, \
|
||||
GstVaapiOverlaySinkPadClass))
|
||||
#define GST_IS_VAAPI_OVERLAY_SINK_PAD(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_OVERLAY_SINK_PAD))
|
||||
#define GST_IS_VAAPI_OVERLAY_SINK_PAD_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_OVERLAY_SINK_PAD))
|
||||
|
||||
typedef struct _GstVaapiOverlay GstVaapiOverlay;
|
||||
typedef struct _GstVaapiOverlayClass GstVaapiOverlayClass;
|
||||
|
||||
typedef struct _GstVaapiOverlaySinkPad GstVaapiOverlaySinkPad;
|
||||
typedef struct _GstVaapiOverlaySinkPadClass GstVaapiOverlaySinkPadClass;
|
||||
|
||||
struct _GstVaapiOverlay
|
||||
{
|
||||
GstVaapiPluginBase parent_instance;
|
||||
|
||||
GstVaapiBlend *blend;
|
||||
GstVaapiVideoPool *blend_pool;
|
||||
};
|
||||
|
||||
struct _GstVaapiOverlayClass
|
||||
{
|
||||
GstVaapiPluginBaseClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstVaapiOverlaySinkPad
|
||||
{
|
||||
GstVideoAggregatorPad parent_instance;
|
||||
|
||||
gint xpos, ypos;
|
||||
gdouble alpha;
|
||||
|
||||
GstVaapiPadPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstVaapiOverlaySinkPadClass
|
||||
{
|
||||
GstVideoAggregatorPadClass parent_class;
|
||||
};
|
||||
|
||||
GType
|
||||
gst_vaapi_overlay_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GType
|
||||
gst_vaapi_overlay_sink_pad_get_type (void) G_GNUC_CONST;
|
||||
|
||||
gboolean
|
||||
gst_vaapioverlay_register (GstPlugin * plugin, GstVaapiDisplay * display);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
|
@ -2,6 +2,7 @@ vaapi_sources = [
|
|||
'gstvaapi.c',
|
||||
'gstvaapidecode.c',
|
||||
'gstvaapidecodedoc.c',
|
||||
'gstvaapioverlay.c',
|
||||
'gstvaapipluginbase.c',
|
||||
'gstvaapipluginutil.c',
|
||||
'gstvaapipostproc.c',
|
||||
|
|
Loading…
Reference in a new issue