d3d11videosink: Add support for rotation
authorSeungha Yang <seungha@centricular.com>
Sat, 2 Jul 2022 16:22:10 +0000 (01:22 +0900)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Sat, 2 Jul 2022 20:40:37 +0000 (20:40 +0000)
Adding "rotate-method" property

Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1396
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2708>

subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp
subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp
subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h
subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_dummy.cpp
subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp

index 901c51b..fffd975 100644 (file)
@@ -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)
index dc97281..484ff79 100644 (file)
@@ -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);
+}
index 1324e00..82c32fb 100644 (file)
@@ -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,
index 65498bb..cb1d696 100644 (file)
@@ -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;
index 3e30847..8d98cb3 100644 (file)
@@ -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