d3d12videosink: Add support for 3D transformation

Add x, y, and z axis rotation with scaling support

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5891>
This commit is contained in:
Seungha Yang 2024-01-06 19:05:33 +09:00 committed by GStreamer Marge Bot
parent 72237d2563
commit 368d8b9252
7 changed files with 302 additions and 9 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -23,6 +23,13 @@
#include "gstd3d12pluginutils.h"
#define _XM_NO_INTRINSICS_
#include <DirectXMath.h>
/* *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;
}

View file

@ -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

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);