From 5f39388ae50ad1bd4d2f7e2cdda1bb59775b37ad Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sun, 3 Jul 2022 01:22:10 +0900 Subject: [PATCH] d3d11videosink: Add support for rotation Adding "rotate-method" property Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1396 Part-of: --- .../sys/d3d11/gstd3d11videosink.cpp | 65 +++++++++++++++++++++- .../gst-plugins-bad/sys/d3d11/gstd3d11window.cpp | 43 ++++++++++++-- .../gst-plugins-bad/sys/d3d11/gstd3d11window.h | 5 ++ .../sys/d3d11/gstd3d11window_dummy.cpp | 14 +++++ .../sys/d3d11/gstd3d11window_win32.cpp | 15 ++++- 5 files changed, 134 insertions(+), 8 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp index 901c51b..fffd975 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp @@ -61,6 +61,7 @@ enum PROP_FULLSCREEN_TOGGLE_MODE, PROP_FULLSCREEN, PROP_DRAW_ON_SHARED_TEXTURE, + PROP_ROTATE_METHOD, }; #define DEFAULT_ADAPTER -1 @@ -131,6 +132,13 @@ struct _GstD3D11VideoSink GRecMutex lock; gchar *title; + + /* method configured via property */ + GstVideoOrientationMethod method; + /* method parsed from tag */ + GstVideoOrientationMethod tag_method; + /* method currently selected based on "method" and "tag_method" */ + GstVideoOrientationMethod selected_method; }; #define GST_D3D11_VIDEO_SINK_GET_LOCK(d) (&(GST_D3D11_VIDEO_SINK_CAST(d)->lock)) @@ -177,10 +185,11 @@ static gboolean gst_d3d11_video_sink_unlock (GstBaseSink * sink); static gboolean gst_d3d11_video_sink_unlock_stop (GstBaseSink * sink); static gboolean gst_d3d11_video_sink_event (GstBaseSink * sink, GstEvent * event); - static GstFlowReturn gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf); static gboolean gst_d3d11_video_sink_prepare_window (GstD3D11VideoSink * self); +static void gst_d3d11_video_sink_set_orientation (GstD3D11VideoSink * self, + GstVideoOrientationMethod method, gboolean from_tag); #define gst_d3d11_video_sink_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstD3D11VideoSink, gst_d3d11_video_sink, @@ -270,6 +279,19 @@ gst_d3d11_video_sink_class_init (GstD3D11VideoSinkClass * klass) G_PARAM_STATIC_STRINGS))); /** + * GstD3D11VideoSink:rotate-method: + * + * Video rotation/flip method to use + * + * Since: 1.22 + */ + g_object_class_install_property (gobject_class, PROP_ROTATE_METHOD, + g_param_spec_enum ("rotate-method", "Rotate Method", + "Rotate method to use", + GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + /** * GstD3D11VideoSink::begin-draw: * @videosink: the #d3d11videosink * @@ -398,6 +420,10 @@ gst_d3d11_videosink_set_property (GObject * object, guint prop_id, case PROP_DRAW_ON_SHARED_TEXTURE: self->draw_on_shared_texture = g_value_get_boolean (value); break; + case PROP_ROTATE_METHOD: + gst_d3d11_video_sink_set_orientation (self, + (GstVideoOrientationMethod) g_value_get_enum (value), FALSE); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -435,6 +461,9 @@ gst_d3d11_videosink_get_property (GObject * object, guint prop_id, case PROP_DRAW_ON_SHARED_TEXTURE: g_value_set_boolean (value, self->draw_on_shared_texture); break; + case PROP_ROTATE_METHOD: + g_value_set_enum (value, self->method); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -785,6 +814,8 @@ done: "fullscreen", self->fullscreen, "enable-navigation-events", self->enable_navigation_events, NULL); + gst_d3d11_window_set_orientation (self->window, self->selected_method); + g_signal_connect (self->window, "key-event", G_CALLBACK (gst_d3d11_video_sink_key_event), self); g_signal_connect (self->window, "mouse-event", @@ -981,6 +1012,7 @@ gst_d3d11_video_sink_event (GstBaseSink * sink, GstEvent * event) case GST_EVENT_TAG:{ GstTagList *taglist; gchar *title = nullptr; + GstVideoOrientationMethod method = GST_VIDEO_ORIENTATION_IDENTITY; gst_event_parse_tag (event, &taglist); gst_tag_list_get_string (taglist, GST_TAG_TITLE, &title); @@ -1006,6 +1038,12 @@ gst_d3d11_video_sink_event (GstBaseSink * sink, GstEvent * event) g_free (title); } + + if (gst_video_orientation_from_tag (taglist, &method)) { + GST_D3D11_VIDEO_SINK_LOCK (self); + gst_d3d11_video_sink_set_orientation (self, method, TRUE); + GST_D3D11_VIDEO_SINK_UNLOCK (self); + } break; } default: @@ -1015,6 +1053,31 @@ gst_d3d11_video_sink_event (GstBaseSink * sink, GstEvent * event) return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); } +/* called with lock */ +static void +gst_d3d11_video_sink_set_orientation (GstD3D11VideoSink * self, + GstVideoOrientationMethod method, gboolean from_tag) +{ + if (method == GST_VIDEO_ORIENTATION_CUSTOM) { + GST_WARNING_OBJECT (self, "Unsupported custom orientation"); + return; + } + + if (from_tag) + self->tag_method = method; + else + self->method = method; + + if (self->method == GST_VIDEO_ORIENTATION_AUTO) { + self->selected_method = self->tag_method; + } else { + self->selected_method = self->method; + } + + if (self->window) + gst_d3d11_window_set_orientation (self->window, self->selected_method); +} + static void gst_d3d11_video_sink_check_device_update (GstD3D11VideoSink * self, GstBuffer * buf) diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp index dc97281..484ff79 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp @@ -334,8 +334,20 @@ gst_d3d11_window_on_resize_default (GstD3D11Window * self, guint width, if (self->force_aspect_ratio) { src_rect.x = 0; src_rect.y = 0; - src_rect.w = GST_VIDEO_INFO_WIDTH (&self->render_info); - src_rect.h = GST_VIDEO_INFO_HEIGHT (&self->render_info); + + switch (self->method) { + case GST_VIDEO_ORIENTATION_90R: + case GST_VIDEO_ORIENTATION_90L: + case GST_VIDEO_ORIENTATION_UL_LR: + case GST_VIDEO_ORIENTATION_UR_LL: + src_rect.w = GST_VIDEO_INFO_HEIGHT (&self->render_info); + src_rect.h = GST_VIDEO_INFO_WIDTH (&self->render_info); + break; + default: + src_rect.w = GST_VIDEO_INFO_WIDTH (&self->render_info); + src_rect.h = GST_VIDEO_INFO_HEIGHT (&self->render_info); + break; + } gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE); } else { @@ -677,9 +689,8 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width, /* call resize to allocated resources */ klass->on_resize (window, display_width, display_height); - if (window->requested_fullscreen != window->fullscreen) { + if (window->requested_fullscreen != window->fullscreen) klass->change_fullscreen_mode (window); - } GST_DEBUG_OBJECT (window, "New swap chain 0x%p created", window->swap_chain); @@ -800,7 +811,8 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer, "dest-width", (gint) (self->render_rect.right - self->render_rect.left), "dest-height", - (gint) (self->render_rect.bottom - self->render_rect.top), nullptr); + (gint) (self->render_rect.bottom - self->render_rect.top), + "video-direction", self->method, nullptr); gst_d3d11_overlay_compositor_update_viewport (self->compositor, &viewport); } @@ -974,3 +986,24 @@ gst_d3d11_window_get_native_type_to_string (GstD3D11WindowNativeType type) return "none"; } + +void +gst_d3d11_window_set_orientation (GstD3D11Window * window, + GstVideoOrientationMethod method) +{ + if (method == GST_VIDEO_ORIENTATION_AUTO || + method == GST_VIDEO_ORIENTATION_CUSTOM) { + return; + } + + gst_d3d11_device_lock (window->device); + if (window->method != method) { + window->method = method; + if (window->swap_chain) { + GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (window); + + klass->on_resize (window, window->surface_width, window->surface_height); + } + } + gst_d3d11_device_unlock (window->device); +} diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h index 1324e00..82c32fb 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h @@ -116,6 +116,8 @@ struct _GstD3D11Window GstBuffer *cached_buffer; gboolean first_present; gboolean allow_tearing; + + GstVideoOrientationMethod method; }; struct _GstD3D11WindowClass @@ -177,6 +179,9 @@ void gst_d3d11_window_set_render_rectangle (GstD3D11Window * window, void gst_d3d11_window_set_title (GstD3D11Window * window, const gchar *title); +void gst_d3d11_window_set_orientation (GstD3D11Window * window, + GstVideoOrientationMethod method); + gboolean gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width, guint display_height, diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_dummy.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_dummy.cpp index 65498bb..cb1d696 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_dummy.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_dummy.cpp @@ -164,6 +164,20 @@ gst_d3d11_window_dummy_on_resize (GstD3D11Window * window, src_rect.w = GST_VIDEO_INFO_WIDTH (&window->render_info); src_rect.h = GST_VIDEO_INFO_HEIGHT (&window->render_info); + switch (window->method) { + case GST_VIDEO_ORIENTATION_90R: + case GST_VIDEO_ORIENTATION_90L: + case GST_VIDEO_ORIENTATION_UL_LR: + case GST_VIDEO_ORIENTATION_UR_LL: + src_rect.w = GST_VIDEO_INFO_HEIGHT (&window->render_info); + src_rect.h = GST_VIDEO_INFO_WIDTH (&window->render_info); + break; + default: + src_rect.w = GST_VIDEO_INFO_WIDTH (&window->render_info); + src_rect.h = GST_VIDEO_INFO_HEIGHT (&window->render_info); + break; + } + gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE); } else { rst_rect = dst_rect; diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp index 3e30847..8d98cb3 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp @@ -1036,8 +1036,19 @@ gst_d3d11_window_win32_show (GstD3D11Window * window) GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window); gint width, height; - width = GST_VIDEO_INFO_WIDTH (&window->render_info); - height = GST_VIDEO_INFO_HEIGHT (&window->render_info); + switch (window->method) { + case GST_VIDEO_ORIENTATION_90R: + case GST_VIDEO_ORIENTATION_90L: + case GST_VIDEO_ORIENTATION_UL_LR: + case GST_VIDEO_ORIENTATION_UR_LL: + width = GST_VIDEO_INFO_HEIGHT (&window->render_info); + height = GST_VIDEO_INFO_WIDTH (&window->render_info); + break; + default: + width = GST_VIDEO_INFO_WIDTH (&window->render_info); + height = GST_VIDEO_INFO_HEIGHT (&window->render_info); + break; + } if (!self->visible) { /* if no parent the real size has to be set now because this has not been done -- 2.7.4