From d28ffd73c305a505a0a3621dc3f7befc42be036b Mon Sep 17 00:00:00 2001 From: "U. Artie Eoff" Date: Thu, 14 Nov 2019 12:03:57 -0800 Subject: [PATCH] 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. --- gst/vaapi/gstvaapi.c | 3 + gst/vaapi/gstvaapioverlay.c | 651 ++++++++++++++++++++++++++++++++++++ gst/vaapi/gstvaapioverlay.h | 103 ++++++ gst/vaapi/meson.build | 1 + 4 files changed, 758 insertions(+) create mode 100644 gst/vaapi/gstvaapioverlay.c create mode 100644 gst/vaapi/gstvaapioverlay.h diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c index 43571f084c..8bcf81d2a7 100644 --- a/gst/vaapi/gstvaapi.c +++ b/gst/vaapi/gstvaapi.c @@ -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); diff --git a/gst/vaapi/gstvaapioverlay.c b/gst/vaapi/gstvaapioverlay.c new file mode 100644 index 0000000000..f3baf75e24 --- /dev/null +++ b/gst/vaapi/gstvaapioverlay.c @@ -0,0 +1,651 @@ +/* + * gstvaapioverlay.c - VA-API vpp overlay + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * 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 "); +} + +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); +} diff --git a/gst/vaapi/gstvaapioverlay.h b/gst/vaapi/gstvaapioverlay.h new file mode 100644 index 0000000000..0357cd0fcf --- /dev/null +++ b/gst/vaapi/gstvaapioverlay.h @@ -0,0 +1,103 @@ +/* + * gstvaapioverlay.h - VA-API vpp overlay + * + * Copyright (C) 2019 Intel Corporation + * Author: U. Artie Eoff + * + * 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 +#include + +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 diff --git a/gst/vaapi/meson.build b/gst/vaapi/meson.build index 76b122cc32..c363b00b7e 100644 --- a/gst/vaapi/meson.build +++ b/gst/vaapi/meson.build @@ -2,6 +2,7 @@ vaapi_sources = [ 'gstvaapi.c', 'gstvaapidecode.c', 'gstvaapidecodedoc.c', + 'gstvaapioverlay.c', 'gstvaapipluginbase.c', 'gstvaapipluginutil.c', 'gstvaapipostproc.c',