diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp index b517e66bb0..b7374b7c7f 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.cpp @@ -982,7 +982,6 @@ gst_d3d12_converter_apply_orientation (GstD3D12Converter * self) switch (priv->video_direction) { case GST_VIDEO_ORIENTATION_IDENTITY: case GST_VIDEO_ORIENTATION_AUTO: - case GST_VIDEO_ORIENTATION_CUSTOM: default: priv->transform = g_matrix_identity; break; @@ -1007,6 +1006,8 @@ gst_d3d12_converter_apply_orientation (GstD3D12Converter * self) case GST_VIDEO_ORIENTATION_UR_LL: priv->transform = g_matrix_ur_ll; break; + case GST_VIDEO_ORIENTATION_CUSTOM: + priv->transform = priv->custom_transform; } return TRUE; @@ -2277,3 +2278,84 @@ gst_d3d12_converter_update_blend_state (GstD3D12Converter * converter, return TRUE; } + +gboolean +gst_d3d12_converter_apply_transform (GstD3D12Converter * converter, + GstVideoOrientationMethod orientation, gfloat viewport_width, + gfloat viewport_height, gfloat fov, gboolean ortho, gfloat rotation_x, + gfloat rotation_y, gfloat rotation_z, gfloat scale_x, gfloat scale_y) +{ + g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE); + + auto priv = converter->priv; + std::lock_guard < std::mutex > lk (priv->prop_lock); + + gfloat aspect_ratio; + gboolean rotated = FALSE; + XMMATRIX rotate_matrix = XMMatrixIdentity (); + + switch (orientation) { + case GST_VIDEO_ORIENTATION_IDENTITY: + case GST_VIDEO_ORIENTATION_AUTO: + case GST_VIDEO_ORIENTATION_CUSTOM: + default: + break; + case GST_VIDEO_ORIENTATION_90R: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_90r); + rotated = TRUE; + break; + case GST_VIDEO_ORIENTATION_180: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_180); + break; + case GST_VIDEO_ORIENTATION_90L: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_90l); + rotated = TRUE; + break; + case GST_VIDEO_ORIENTATION_HORIZ: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_horiz); + break; + case GST_VIDEO_ORIENTATION_VERT: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_vert); + break; + case GST_VIDEO_ORIENTATION_UL_LR: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_ul_lr); + rotated = TRUE; + break; + case GST_VIDEO_ORIENTATION_UR_LL: + rotate_matrix = XMLoadFloat4x4A (&g_matrix_ur_ll); + rotated = TRUE; + break; + } + + if (rotated) + aspect_ratio = viewport_height / viewport_width; + else + aspect_ratio = viewport_width / viewport_height; + + /* Apply user specified transform matrix first, then rotate-method */ + XMMATRIX scale = XMMatrixScaling (scale_x * aspect_ratio, scale_y, 1.0); + + XMMATRIX rotate = + XMMatrixRotationX (XMConvertToRadians (rotation_x)) * + XMMatrixRotationY (XMConvertToRadians (-rotation_y)) * + XMMatrixRotationZ (XMConvertToRadians (-rotation_z)); + + XMMATRIX view = XMMatrixLookAtLH (XMVectorSet (0.0, 0.0, -1.0, 0.0), + XMVectorSet (0.0, 0.0, 0.0, 0.0), XMVectorSet (0.0, 1.0, 0.0, 0.0)); + + XMMATRIX proj; + if (ortho) { + proj = XMMatrixOrthographicOffCenterLH (-aspect_ratio, + aspect_ratio, -1.0, 1.0, 0.1, 100.0); + } else { + proj = XMMatrixPerspectiveFovLH (XMConvertToRadians (fov), + aspect_ratio, 0.1, 100.0); + } + + XMMATRIX mvp = scale * rotate * view * proj * rotate_matrix; + XMStoreFloat4x4A (&priv->custom_transform, mvp); + priv->update_transform = TRUE; + priv->video_direction = GST_VIDEO_ORIENTATION_CUSTOM; + + return TRUE; +} diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.h index 309c6b6dcc..cf2d850c0d 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12converter.h @@ -150,4 +150,16 @@ gboolean gst_d3d12_converter_update_blend_state (GstD3D12Converter * const D3D12_BLEND_DESC * blend_desc, const gfloat blend_factor[4]); +gboolean gst_d3d12_converter_apply_transform (GstD3D12Converter * converter, + GstVideoOrientationMethod orientation, + gfloat viewport_width, + gfloat viewport_height, + gfloat fov, + gboolean ortho, + gfloat rotation_x, + gfloat rotation_y, + gfloat rotation_z, + gfloat scale_x, + gfloat scale_y); + G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp index be306edd1f..41987af508 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.cpp @@ -23,6 +23,13 @@ #include "gstd3d12pluginutils.h" +#define _XM_NO_INTRINSICS_ +#include + +/* *INDENT-OFF* */ +using namespace DirectX; +/* *INDENT-ON* */ + GType gst_d3d12_sampling_method_get_type (void) { @@ -102,3 +109,20 @@ gst_d3d12_buffer_after_write (GstBuffer * buffer, guint64 fence_value) GST_MINI_OBJECT_FLAG_UNSET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD); } } + +gboolean +gst_d3d12_need_transform (gfloat rotation_x, gfloat rotation_y, + gfloat rotation_z, gfloat scale_x, gfloat scale_y) +{ + const gfloat min_diff = 0.00001f; + + if (!XMScalarNearEqual (rotation_x, 0.0f, min_diff) || + !XMScalarNearEqual (rotation_y, 0.0f, min_diff) || + !XMScalarNearEqual (rotation_z, 0.0f, min_diff) || + !XMScalarNearEqual (scale_x, 1.0f, min_diff) || + !XMScalarNearEqual (scale_y, 1.0f, min_diff)) { + return TRUE; + } + + return FALSE; +} diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h index b719f50e27..6b51ce6d96 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12pluginutils.h @@ -52,4 +52,10 @@ GType gst_d3d12_msaa_mode_get_type (void); void gst_d3d12_buffer_after_write (GstBuffer * buffer, guint64 fence_value); +gboolean gst_d3d12_need_transform (gfloat rotation_x, + gfloat rotation_y, + gfloat rotation_z, + gfloat scale_x, + gfloat scale_y); + G_END_DECLS diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp index 2f137340a0..4d65ee9096 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12videosink.cpp @@ -38,6 +38,14 @@ enum PROP_FULLSCREEN_ON_ALT_ENTER, PROP_FULLSCREEN, PROP_MSAA, + PROP_REDRAW_ON_UPDATE, + PROP_FOV, + PROP_ORTHO, + PROP_ROTATION_X, + PROP_ROTATION_Y, + PROP_ROTATION_Z, + PROP_SCALE_X, + PROP_SCALE_Y, }; #define DEFAULT_ADAPTER -1 @@ -47,6 +55,11 @@ enum #define DEFAULT_FULLSCREEN_ON_ALT_ENTER FALSE #define DEFAULT_FULLSCREEN FALSE #define DEFAULT_MSAA GST_D3D12_MSAA_DISABLED +#define DEFAULT_REDROW_ON_UPDATE TRUE +#define DEFAULT_ROTATION 0.0f +#define DEFAULT_SCALE 1.0f +#define DEFAULT_FOV 90.0f +#define DEFAULT_ORTHO FALSE static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -105,6 +118,14 @@ struct GstD3D12VideoSinkPrivate gboolean fullscreen_on_alt_enter = DEFAULT_FULLSCREEN_ON_ALT_ENTER; gboolean fullscreen = DEFAULT_FULLSCREEN; GstD3D12MSAAMode msaa = DEFAULT_MSAA; + gboolean redraw_on_update = DEFAULT_REDROW_ON_UPDATE; + gfloat fov = DEFAULT_FOV; + gboolean ortho = DEFAULT_ORTHO; + gfloat rotation_x = DEFAULT_ROTATION; + gfloat rotation_y = DEFAULT_ROTATION; + gfloat rotation_z = DEFAULT_ROTATION; + gfloat scale_x = DEFAULT_SCALE; + gfloat scale_y = DEFAULT_SCALE; }; /* *INDENT-ON* */ @@ -223,6 +244,55 @@ gst_d3d12_video_sink_class_init (GstD3D12VideoSinkClass * klass) GST_TYPE_D3D12_MSAA_MODE, DEFAULT_MSAA, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property (object_class, PROP_REDRAW_ON_UPDATE, + g_param_spec_boolean ("redraw-on-update", + "redraw-on-update", + "Immediately apply updated geometry related properties and redraw. " + "If disabled, properties will be applied on the next frame or " + "window resize", DEFAULT_REDROW_ON_UPDATE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_FOV, + g_param_spec_float ("fov", "Fov", + "Field of view angle in degrees", + 0, G_MAXFLOAT, DEFAULT_FOV, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_ORTHO, + g_param_spec_boolean ("ortho", "Orthographic", + "Use orthographic projection", DEFAULT_ORTHO, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_ROTATION_X, + g_param_spec_float ("rotation-x", "Rotation X", + "x-axis rotation angle in degrees", + -G_MAXFLOAT, G_MAXFLOAT, DEFAULT_ROTATION, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_ROTATION_Y, + g_param_spec_float ("rotation-y", "Rotation Y", + "y-axis rotation angle in degrees", + -G_MAXFLOAT, G_MAXFLOAT, DEFAULT_ROTATION, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_ROTATION_Z, + g_param_spec_float ("rotation-z", "Rotation Z", + "z-axis rotation angle in degrees", + -G_MAXFLOAT, G_MAXFLOAT, DEFAULT_ROTATION, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_SCALE_X, + g_param_spec_float ("scale-x", "Scale X", + "Scale multiplier for x-axis", + -G_MAXFLOAT, G_MAXFLOAT, DEFAULT_SCALE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + g_object_class_install_property (object_class, PROP_SCALE_Y, + g_param_spec_float ("scale-y", "Scale Y", + "Scale multiplier for y-axis", + -G_MAXFLOAT, G_MAXFLOAT, DEFAULT_SCALE, + (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + element_class->set_context = GST_DEBUG_FUNCPTR (gst_d3d12_video_sink_set_context); @@ -314,6 +384,38 @@ gst_d3d12_videosink_set_property (GObject * object, guint prop_id, priv->msaa = (GstD3D12MSAAMode) g_value_get_enum (value); gst_d3d12_window_set_msaa (priv->window, priv->msaa); break; + case PROP_REDRAW_ON_UPDATE: + priv->redraw_on_update = g_value_get_boolean (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_FOV: + priv->fov = g_value_get_float (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_ORTHO: + priv->ortho = g_value_get_boolean (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_ROTATION_X: + priv->rotation_x = g_value_get_float (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_ROTATION_Y: + priv->rotation_y = g_value_get_float (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_ROTATION_Z: + priv->rotation_z = g_value_get_float (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_SCALE_X: + priv->scale_x = g_value_get_float (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; + case PROP_SCALE_Y: + priv->scale_y = g_value_get_float (value); + gst_d3d12_video_sink_set_orientation (self, priv->orientation, FALSE); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -350,6 +452,30 @@ gst_d3d12_videosink_get_property (GObject * object, guint prop_id, case PROP_MSAA: g_value_set_enum (value, priv->msaa); break; + case PROP_REDRAW_ON_UPDATE: + g_value_set_boolean (value, priv->redraw_on_update); + break; + case PROP_FOV: + g_value_set_float (value, priv->fov); + break; + case PROP_ORTHO: + g_value_set_boolean (value, priv->ortho); + break; + case PROP_ROTATION_X: + g_value_set_float (value, priv->rotation_x); + break; + case PROP_ROTATION_Y: + g_value_set_float (value, priv->rotation_x); + break; + case PROP_ROTATION_Z: + g_value_set_float (value, priv->rotation_z); + break; + case PROP_SCALE_X: + g_value_set_float (value, priv->scale_x); + break; + case PROP_SCALE_Y: + g_value_set_float (value, priv->scale_y); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -377,7 +503,10 @@ gst_d3d12_video_sink_set_orientation (GstD3D12VideoSink * self, else priv->orientation_selected = priv->orientation; - gst_d3d12_window_set_orientation (priv->window, priv->orientation_selected); + gst_d3d12_window_set_orientation (priv->window, + priv->redraw_on_update, priv->orientation_selected, priv->fov, + priv->ortho, priv->rotation_x, priv->rotation_y, priv->rotation_z, + priv->scale_x, priv->scale_y); } static void diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp index 28b12d3590..99bafda108 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.cpp @@ -172,6 +172,13 @@ struct GstD3D12WindowPrivate DXGI_FORMAT display_format = DXGI_FORMAT_R8G8B8A8_UNORM; GstVideoOrientationMethod orientation = GST_VIDEO_ORIENTATION_IDENTITY; + gfloat fov = 90.0f; + gboolean ortho = FALSE; + gfloat rotation_x = 0; + gfloat rotation_y = 0; + gfloat rotation_z = 0; + gfloat scale_x = 1.0f; + gfloat scale_y = 1.0f; /* fullscreen related variables */ gboolean fullscreen_on_alt_enter = TRUE; @@ -1407,8 +1414,19 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer) g_object_set (priv->ctx->conv, "dest-x", priv->output_rect.x, "dest-y", priv->output_rect.y, "dest-width", priv->output_rect.w, - "dest-height", priv->output_rect.h, - "video-direction", priv->orientation, nullptr); + "dest-height", priv->output_rect.h, nullptr); + + if (gst_d3d12_need_transform (priv->rotation_x, priv->rotation_y, + priv->rotation_z, priv->scale_x, priv->scale_y)) { + gst_d3d12_converter_apply_transform (priv->ctx->conv, priv->orientation, + priv->output_rect.w, priv->output_rect.h, priv->fov, priv->ortho, + priv->rotation_x, priv->rotation_y, priv->rotation_z, + priv->scale_x, priv->scale_y); + } else { + g_object_set (priv->ctx->conv, + "video-direction", priv->orientation, nullptr); + } + gst_d3d12_overlay_compositor_update_viewport (priv->ctx->comp, &priv->output_rect); } @@ -1648,16 +1666,30 @@ gst_d3d12_window_set_enable_navigation_events (GstD3D12Window * window, } void -gst_d3d12_window_set_orientation (GstD3D12Window * window, - GstVideoOrientationMethod orientation) +gst_d3d12_window_set_orientation (GstD3D12Window * window, gboolean immediate, + GstVideoOrientationMethod orientation, gfloat fov, gboolean ortho, + gfloat rotation_x, gfloat rotation_y, gfloat rotation_z, + gfloat scale_x, gfloat scale_y) { auto priv = window->priv; std::lock_guard < std::recursive_mutex > lk (priv->lock); - if (priv->orientation != orientation) { + if (priv->orientation != orientation || priv->fov != fov + || priv->ortho != ortho + || priv->rotation_x != rotation_x || priv->rotation_y != rotation_y + || priv->rotation_z != rotation_z || priv->scale_x != scale_x + || priv->scale_y != scale_y) { priv->orientation = orientation; + priv->fov = fov; + priv->ortho = ortho; + priv->rotation_x = rotation_x; + priv->rotation_y = rotation_y; + priv->rotation_z = rotation_z; + priv->scale_x = scale_x; + priv->scale_y = scale_y; priv->first_present = TRUE; - gst_d3d12_window_set_buffer (window, nullptr); + if (immediate) + gst_d3d12_window_set_buffer (window, nullptr); } } diff --git a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h index 1850ec5ab7..2d63d1f155 100644 --- a/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h +++ b/subprojects/gst-plugins-bad/sys/d3d12/gstd3d12window.h @@ -73,7 +73,15 @@ void gst_d3d12_window_set_enable_navigation_events (GstD3D12Window * gboolean enable); void gst_d3d12_window_set_orientation (GstD3D12Window * window, - GstVideoOrientationMethod orientation); + gboolean immediate, + GstVideoOrientationMethod orientation, + gfloat fov, + gboolean ortho, + gfloat rotation_x, + gfloat rotation_y, + gfloat rotation_z, + gfloat scale_x, + gfloat scale_y); void gst_d3d12_window_set_title (GstD3D12Window * window, const gchar * title);