summaryrefslogtreecommitdiff
path: root/sys/d3d11/gstd3d11videosinkbin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sys/d3d11/gstd3d11videosinkbin.cpp')
-rw-r--r--sys/d3d11/gstd3d11videosinkbin.cpp517
1 files changed, 517 insertions, 0 deletions
diff --git a/sys/d3d11/gstd3d11videosinkbin.cpp b/sys/d3d11/gstd3d11videosinkbin.cpp
new file mode 100644
index 000000000..aed231386
--- /dev/null
+++ b/sys/d3d11/gstd3d11videosinkbin.cpp
@@ -0,0 +1,517 @@
+/* GStreamer
+ * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
+ * Copyright (C) 2020 Seungha Yang <seungha@centricular.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 the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:element-d3d11videosink
+ * @title: d3d11videosink
+ *
+ * Direct3D11 based video render element
+ *
+ * ## Example launch line
+ * ```
+ * gst-launch-1.0 videotestsrc ! d3d11videosink
+ * ```
+ * This pipeline will display test video stream on screen via #d3d11videosink
+ *
+ * Since: 1.18
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideosink.h>
+#include <gst/video/videooverlay.h>
+#include <gst/video/navigation.h>
+#include <gst/d3d11/gstd3d11.h>
+#include "gstd3d11videosink.h"
+#include "gstd3d11videosinkbin.h"
+#include "gstd3d11pluginutils.h"
+
+enum
+{
+ PROP_0,
+ /* basesink */
+ PROP_SYNC,
+ PROP_MAX_LATENESS,
+ PROP_QOS,
+ PROP_ASYNC,
+ PROP_TS_OFFSET,
+ PROP_ENABLE_LAST_SAMPLE,
+ PROP_LAST_SAMPLE,
+ PROP_BLOCKSIZE,
+ PROP_RENDER_DELAY,
+ PROP_THROTTLE_TIME,
+ PROP_MAX_BITRATE,
+ PROP_PROCESSING_DEADLINE,
+ PROP_STATS,
+ /* videosink */
+ PROP_SHOW_PREROLL_FRAME,
+ /* d3d11videosink */
+ PROP_ADAPTER,
+ PROP_FORCE_ASPECT_RATIO,
+ PROP_ENABLE_NAVIGATION_EVENTS,
+ PROP_FULLSCREEN_TOGGLE_MODE,
+ PROP_FULLSCREEN,
+ PROP_RENDER_STATS,
+ PROP_DRAW_ON_SHARED_TEXTURE,
+};
+
+/* basesink */
+#define DEFAULT_SYNC TRUE
+#define DEFAULT_MAX_LATENESS -1
+#define DEFAULT_QOS FALSE
+#define DEFAULT_ASYNC TRUE
+#define DEFAULT_TS_OFFSET 0
+#define DEFAULT_BLOCKSIZE 4096
+#define DEFAULT_RENDER_DELAY 0
+#define DEFAULT_ENABLE_LAST_SAMPLE TRUE
+#define DEFAULT_THROTTLE_TIME 0
+#define DEFAULT_MAX_BITRATE 0
+#define DEFAULT_DROP_OUT_OF_SEGMENT TRUE
+#define DEFAULT_PROCESSING_DEADLINE (20 * GST_MSECOND)
+
+/* videosink */
+#define DEFAULT_SHOW_PREROLL_FRAME TRUE
+
+/* d3d11videosink */
+#define DEFAULT_ADAPTER -1
+#define DEFAULT_FORCE_ASPECT_RATIO TRUE
+#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
+#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
+#define DEFAULT_FULLSCREEN FALSE
+#define DEFAULT_RENDER_STATS FALSE
+#define DEFAULT_DRAW_ON_SHARED_TEXTURE FALSE
+
+enum
+{
+ /* signals */
+ SIGNAL_BEGIN_DRAW,
+
+ /* actions */
+ SIGNAL_DRAW,
+
+ LAST_SIGNAL
+};
+
+static guint gst_d3d11_video_sink_bin_signals[LAST_SIGNAL] = { 0, };
+
+static GstStaticCaps pad_template_caps =
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
+ (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, GST_D3D11_SINK_FORMATS) "; "
+ GST_VIDEO_CAPS_MAKE_WITH_FEATURES
+ (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY ","
+ GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
+ GST_D3D11_SINK_FORMATS) ";"
+ GST_VIDEO_CAPS_MAKE (GST_D3D11_SINK_FORMATS) "; "
+ GST_VIDEO_CAPS_MAKE_WITH_FEATURES
+ (GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY ","
+ GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
+ GST_D3D11_SINK_FORMATS));
+
+GST_DEBUG_CATEGORY (d3d11_video_sink_bin_debug);
+#define GST_CAT_DEFAULT d3d11_video_sink_bin_debug
+
+struct _GstD3D11VideoSinkBin
+{
+ GstBin parent;
+
+ GstPad *sinkpad;
+
+ GstElement *upload;
+ GstElement *sink;
+};
+
+static void gst_d3d11_video_sink_bin_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_d3d11_video_sink_bin_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static void
+gst_d3d11_video_sink_bin_video_overlay_init (GstVideoOverlayInterface * iface);
+static void
+gst_d3d11_video_sink_bin_navigation_init (GstNavigationInterface * iface);
+static void gst_d311_video_sink_bin_on_begin_draw (GstD3D11VideoSink * sink,
+ gpointer self);
+static gboolean
+gst_d3d11_video_sink_bin_draw_action (GstD3D11VideoSinkBin * self,
+ gpointer shared_handle, guint texture_misc_flags, guint64 acquire_key,
+ guint64 release_key);
+
+#define gst_d3d11_video_sink_bin_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstD3D11VideoSinkBin, gst_d3d11_video_sink_bin,
+ GST_TYPE_BIN,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
+ gst_d3d11_video_sink_bin_video_overlay_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
+ gst_d3d11_video_sink_bin_navigation_init);
+ GST_DEBUG_CATEGORY_INIT (d3d11_video_sink_bin_debug,
+ "d3d11videosink", 0, "Direct3D11 Video Sink"));
+
+static void
+gst_d3d11_video_sink_bin_class_init (GstD3D11VideoSinkBinClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstCaps *caps;
+
+ gobject_class->set_property = gst_d3d11_video_sink_bin_set_property;
+ gobject_class->get_property = gst_d3d11_video_sink_bin_get_property;
+
+ /* basesink */
+ g_object_class_install_property (gobject_class, PROP_SYNC,
+ g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
+ g_param_spec_int64 ("max-lateness", "Max Lateness",
+ "Maximum number of nanoseconds that a buffer can be late before it "
+ "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_QOS,
+ g_param_spec_boolean ("qos", "Qos",
+ "Generate Quality-of-Service events upstream", DEFAULT_QOS,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_ASYNC,
+ g_param_spec_boolean ("async", "Async",
+ "Go asynchronously to PAUSED", DEFAULT_ASYNC,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
+ g_param_spec_int64 ("ts-offset", "TS Offset",
+ "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
+ DEFAULT_TS_OFFSET,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_SAMPLE,
+ g_param_spec_boolean ("enable-last-sample", "Enable Last Buffer",
+ "Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_LAST_SAMPLE,
+ g_param_spec_boxed ("last-sample", "Last Sample",
+ "The last sample received in the sink", GST_TYPE_SAMPLE,
+ (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
+ g_param_spec_uint ("blocksize", "Block size",
+ "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
+ DEFAULT_BLOCKSIZE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
+ g_param_spec_uint64 ("render-delay", "Render Delay",
+ "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
+ DEFAULT_RENDER_DELAY,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_THROTTLE_TIME,
+ g_param_spec_uint64 ("throttle-time", "Throttle time",
+ "The time to keep between rendered buffers (0 = disabled)", 0,
+ G_MAXUINT64, DEFAULT_THROTTLE_TIME,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
+ g_param_spec_uint64 ("max-bitrate", "Max Bitrate",
+ "The maximum bits per second to render (0 = disabled)", 0,
+ G_MAXUINT64, DEFAULT_MAX_BITRATE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_PROCESSING_DEADLINE,
+ g_param_spec_uint64 ("processing-deadline", "Processing deadline",
+ "Maximum processing deadline in nanoseconds", 0, G_MAXUINT64,
+ DEFAULT_PROCESSING_DEADLINE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_STATS,
+ g_param_spec_boxed ("stats", "Statistics",
+ "Sink Statistics", GST_TYPE_STRUCTURE,
+ (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+ /* videosink */
+ g_object_class_install_property (gobject_class, PROP_SHOW_PREROLL_FRAME,
+ g_param_spec_boolean ("show-preroll-frame", "Show preroll frame",
+ "Whether to render video frames during preroll",
+ DEFAULT_SHOW_PREROLL_FRAME,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS)));
+
+ /* d3d11videosink */
+ g_object_class_install_property (gobject_class, PROP_ADAPTER,
+ g_param_spec_int ("adapter", "Adapter",
+ "Adapter index for creating device (-1 for default)",
+ -1, G_MAXINT32, DEFAULT_ADAPTER,
+ (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
+ G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
+ g_param_spec_boolean ("force-aspect-ratio",
+ "Force aspect ratio",
+ "When enabled, scaling will respect original aspect ratio",
+ DEFAULT_FORCE_ASPECT_RATIO,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_ENABLE_NAVIGATION_EVENTS,
+ g_param_spec_boolean ("enable-navigation-events",
+ "Enable navigation events",
+ "When enabled, navigation events are sent upstream",
+ DEFAULT_ENABLE_NAVIGATION_EVENTS,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_FULLSCREEN_TOGGLE_MODE,
+ g_param_spec_flags ("fullscreen-toggle-mode",
+ "Full screen toggle mode",
+ "Full screen toggle mode used to trigger fullscreen mode change",
+ GST_D3D11_WINDOW_TOGGLE_MODE_GET_TYPE, DEFAULT_FULLSCREEN_TOGGLE_MODE,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+ g_object_class_install_property (gobject_class, PROP_FULLSCREEN,
+ g_param_spec_boolean ("fullscreen",
+ "fullscreen",
+ "Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
+ DEFAULT_FULLSCREEN,
+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+#ifdef HAVE_DIRECT_WRITE
+ g_object_class_install_property (gobject_class, PROP_RENDER_STATS,
+ g_param_spec_boolean ("render-stats",
+ "Render Stats",
+ "Render statistics data (e.g., average framerate) on window",
+ DEFAULT_RENDER_STATS,
+ (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
+ GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS)));
+#endif
+
+ /**
+ * GstD3D11VideoSinkBin:draw-on-shared-texture:
+ *
+ * Instruct the sink to draw on a shared texture provided by user.
+ * User must watch #d3d11videosink::begin-draw signal and should call
+ * #d3d11videosink::draw method on the #d3d11videosink::begin-draw
+ * signal handler.
+ *
+ * Currently supported formats for user texture are:
+ * - DXGI_FORMAT_R8G8B8A8_UNORM
+ * - DXGI_FORMAT_B8G8R8A8_UNORM
+ * - DXGI_FORMAT_R10G10B10A2_UNORM
+ *
+ * Since: 1.20
+ */
+ g_object_class_install_property (gobject_class, PROP_DRAW_ON_SHARED_TEXTURE,
+ g_param_spec_boolean ("draw-on-shared-texture",
+ "Draw on shared texture",
+ "Draw on user provided shared texture instead of window. "
+ "When enabled, user can pass application's own texture to sink "
+ "by using \"draw\" action signal on \"begin-draw\" signal handler, "
+ "so that sink can draw video data on application's texture. "
+ "Supported texture formats for user texture are "
+ "DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, and "
+ "DXGI_FORMAT_R10G10B10A2_UNORM.",
+ DEFAULT_DRAW_ON_SHARED_TEXTURE,
+ (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
+ G_PARAM_STATIC_STRINGS)));
+
+ /**
+ * GstD3D11VideoSinkBin::begin-draw:
+ * @videosink: the #d3d11videosink
+ *
+ * Emitted when sink has a texture to draw. Application needs to invoke
+ * #d3d11videosink::draw action signal before returning from
+ * #d3d11videosink::begin-draw signal handler.
+ *
+ * Since: 1.20
+ */
+ gst_d3d11_video_sink_bin_signals[SIGNAL_BEGIN_DRAW] =
+ g_signal_new ("begin-draw", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstD3D11VideoSinkBinClass, begin_draw),
+ NULL, NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+ /**
+ * GstD3D11VideoSinkBin::draw:
+ * @videosink: the #d3d11videosink
+ * @shard_handle: a pointer to HANDLE
+ * @texture_misc_flags: a D3D11_RESOURCE_MISC_FLAG value
+ * @acquire_key: a key value used for IDXGIKeyedMutex::AcquireSync
+ * @release_key: a key value used for IDXGIKeyedMutex::ReleaseSync
+ *
+ * Draws on a shared texture. @shard_handle must be a valid pointer to
+ * a HANDLE which was obtained via IDXGIResource::GetSharedHandle or
+ * IDXGIResource1::CreateSharedHandle.
+ *
+ * If the texture was created with D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX flag,
+ * caller must specify valid @acquire_key and @release_key.
+ * Otherwise (i.e., created with D3D11_RESOURCE_MISC_SHARED flag),
+ * @acquire_key and @release_key will be ignored.
+ *
+ * Since: 1.20
+ */
+ gst_d3d11_video_sink_bin_signals[SIGNAL_DRAW] =
+ g_signal_new ("draw", G_TYPE_FROM_CLASS (klass),
+ (GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
+ G_STRUCT_OFFSET (GstD3D11VideoSinkBinClass, draw), NULL, NULL, NULL,
+ G_TYPE_BOOLEAN, 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT64,
+ G_TYPE_UINT64);
+
+ klass->draw = gst_d3d11_video_sink_bin_draw_action;
+
+ gst_element_class_set_static_metadata (element_class,
+ "Direct3D11 video sink bin", "Sink/Video",
+ "A Direct3D11 based videosink bin",
+ "Seungha Yang <seungha.yang@navercorp.com>");
+
+ caps = gst_d3d11_get_updated_template_caps (&pad_template_caps);
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps));
+ gst_caps_unref (caps);
+}
+
+static void
+gst_d3d11_video_sink_bin_init (GstD3D11VideoSinkBin * self)
+{
+ GstPad *pad;
+ GstD3D11VideoSinkCallbacks callbacks;
+
+ self->upload = gst_element_factory_make ("d3d11upload", NULL);
+ if (!self->upload) {
+ GST_ERROR_OBJECT (self, "d3d11upload unavailable");
+ return;
+ }
+
+ self->sink = gst_element_factory_make ("d3d11videosinkelement", NULL);
+ if (!self->sink) {
+ gst_clear_object (&self->upload);
+ GST_ERROR_OBJECT (self, "d3d11videosinkelement unavailable");
+ return;
+ }
+
+ callbacks.begin_draw = gst_d311_video_sink_bin_on_begin_draw;
+ gst_d3d11_video_sink_set_callbacks (GST_D3D11_VIDEO_SINK (self->sink),
+ &callbacks, self);
+
+ gst_bin_add_many (GST_BIN (self), self->upload, self->sink, NULL);
+
+ gst_element_link_many (self->upload, self->sink, NULL);
+
+ pad = gst_element_get_static_pad (self->upload, "sink");
+
+ self->sinkpad = gst_ghost_pad_new ("sink", pad);
+ gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
+ gst_object_unref (pad);
+}
+
+static void
+gst_d3d11_video_sink_bin_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (object);
+ GParamSpec *sink_pspec;
+
+ sink_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (self->sink),
+ pspec->name);
+
+ if (sink_pspec && G_PARAM_SPEC_TYPE (sink_pspec) == G_PARAM_SPEC_TYPE (pspec)) {
+ g_object_set_property (G_OBJECT (self->sink), pspec->name, value);
+ } else {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gst_d3d11_video_sink_bin_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (object);
+
+ g_object_get_property (G_OBJECT (self->sink), pspec->name, value);
+}
+
+static void
+gst_d311_video_sink_bin_on_begin_draw (GstD3D11VideoSink * sink, gpointer self)
+{
+ g_signal_emit (self, gst_d3d11_video_sink_bin_signals[SIGNAL_BEGIN_DRAW], 0,
+ NULL);
+}
+
+static gboolean
+gst_d3d11_video_sink_bin_draw_action (GstD3D11VideoSinkBin * self,
+ gpointer shared_handle, guint texture_misc_flags, guint64 acquire_key,
+ guint64 release_key)
+{
+ if (!self->sink) {
+ GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
+ ("D3D11VideoSink element wasn't configured"), (NULL));
+ return FALSE;
+ }
+
+ return gst_d3d11_video_sink_draw (GST_D3D11_VIDEO_SINK (self->sink),
+ shared_handle, texture_misc_flags, acquire_key, release_key);
+}
+
+/* VideoOverlay interface */
+static void
+gst_d3d11_video_sink_bin_set_window_handle (GstVideoOverlay * overlay,
+ guintptr window_id)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (overlay);
+
+ gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (self->sink),
+ window_id);
+}
+
+static void
+gst_d3d11_video_sink_bin_set_render_rectangle (GstVideoOverlay * overlay,
+ gint x, gint y, gint width, gint height)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (overlay);
+
+ gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (self->sink),
+ x, y, width, height);
+}
+
+static void
+gst_d3d11_video_sink_bin_expose (GstVideoOverlay * overlay)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (overlay);
+
+ gst_video_overlay_expose (GST_VIDEO_OVERLAY (self->sink));
+}
+
+static void
+gst_d3d11_video_sink_bin_handle_events (GstVideoOverlay * overlay,
+ gboolean handle_events)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (overlay);
+
+ gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (self->sink),
+ handle_events);
+}
+
+static void
+gst_d3d11_video_sink_bin_video_overlay_init (GstVideoOverlayInterface * iface)
+{
+ iface->set_window_handle = gst_d3d11_video_sink_bin_set_window_handle;
+ iface->set_render_rectangle = gst_d3d11_video_sink_bin_set_render_rectangle;
+ iface->expose = gst_d3d11_video_sink_bin_expose;
+ iface->handle_events = gst_d3d11_video_sink_bin_handle_events;
+}
+
+/* Navigation interface */
+static void
+gst_d3d11_video_sink_bin_navigation_send_event (GstNavigation * navigation,
+ GstStructure * structure)
+{
+ GstD3D11VideoSinkBin *self = GST_D3D11_VIDEO_SINK_BIN (navigation);
+
+ gst_navigation_send_event (GST_NAVIGATION (self->sink), structure);
+}
+
+static void
+gst_d3d11_video_sink_bin_navigation_init (GstNavigationInterface * iface)
+{
+ iface->send_event = gst_d3d11_video_sink_bin_navigation_send_event;
+}