summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorU. Artie Eoff <ullysses.a.eoff@intel.com>2019-11-14 12:03:57 -0800
committerVíctor Manuel Jáquez Leal <vjaquez@igalia.com>2020-01-06 19:56:10 +0000
commitd28ffd73c305a505a0a3621dc3f7befc42be036b (patch)
tree3fac12c9344db2119d483a8b47ee730d0bb35732
parentb76c0a0caf46f69f14316f7cfbad326e4a36cebe (diff)
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.
-rw-r--r--gst/vaapi/gstvaapi.c3
-rw-r--r--gst/vaapi/gstvaapioverlay.c651
-rw-r--r--gst/vaapi/gstvaapioverlay.h103
-rw-r--r--gst/vaapi/meson.build1
4 files changed, 758 insertions, 0 deletions
diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c
index 43571f08..8bcf81d2 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 00000000..f3baf75e
--- /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 <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);
+}
diff --git a/gst/vaapi/gstvaapioverlay.h b/gst/vaapi/gstvaapioverlay.h
new file mode 100644
index 00000000..0357cd0f
--- /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 <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
diff --git a/gst/vaapi/meson.build b/gst/vaapi/meson.build
index 76b122cc..c363b00b 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',