d3d11converter: Add support for GstVideoOrientationMethod

Shader can handle rotation/flip with other conversions
at once in a single pipeline, and depending on device
capability, videoprocessor may support it too.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2708>
This commit is contained in:
Seungha Yang 2022-07-02 02:15:00 +09:00 committed by GStreamer Marge Bot
parent 90090dc13b
commit f549575ce8

View file

@ -39,9 +39,13 @@ using namespace Microsoft::WRL;
#define CONVERTER_MAX_QUADS 2
#define GAMMA_LUT_SIZE 4096
/* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10
* missing in mingw header */
/* undefined symbols in ancient MinGW headers */
/* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10 */
#define FEATURE_CAPS_METADATA_HDR10 (0x800)
/* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION */
#define FEATURE_CAPS_ROTATION (0x40)
/* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_MIRROR */
#define PROCESSOR_FEATURE_CAPS_MIRROR (0x200)
/* *INDENT-OFF* */
typedef struct
@ -511,6 +515,7 @@ enum
PROP_SRC_CONTENT_LIGHT_LEVEL,
PROP_DEST_MASTERING_DISPLAY_INFO,
PROP_DEST_CONTENT_LIGHT_LEVEL,
PROP_VIDEO_DIRECTION,
};
struct _GstD3D11ConverterPrivate
@ -571,6 +576,12 @@ struct _GstD3D11ConverterPrivate
RECT dest_rect;
RECT dest_full_rect;
gboolean processor_in_use;
gboolean processor_direction_not_supported;
gboolean enable_mirror;
gboolean flip_h;
gboolean flip_v;
gboolean enable_rotation;
D3D11_VIDEO_PROCESSOR_ROTATION rotation;
/* HDR10 */
gboolean have_in_hdr10;
@ -587,6 +598,8 @@ struct _GstD3D11ConverterPrivate
GstVideoInfo fallback_info;
GstBuffer *fallback_inbuf;
GstVideoOrientationMethod video_direction;
GMutex prop_lock;
/* properties */
@ -709,6 +722,10 @@ gst_d3d11_converter_class_init (GstD3D11ConverterClass * klass)
"Src Content Light Level",
"String representation of GstVideoContentLightLevel for dest",
nullptr, param_flags));
g_object_class_install_property (object_class, PROP_VIDEO_DIRECTION,
g_param_spec_enum ("video-direction", "Video Direction",
"Video direction", GST_TYPE_VIDEO_ORIENTATION_METHOD,
GST_VIDEO_ORIENTATION_IDENTITY, param_flags));
GST_DEBUG_CATEGORY_INIT (gst_d3d11_converter_debug,
"d3d11converter", 0, "d3d11converter");
@ -918,6 +935,15 @@ gst_d3d11_converter_set_property (GObject * object, guint prop_id,
priv->out_cll_str = g_value_dup_string (value);
priv->out_hdr10_updated = TRUE;
break;
case PROP_VIDEO_DIRECTION:{
GstVideoOrientationMethod video_direction =
(GstVideoOrientationMethod) g_value_get_enum (value);
if (video_direction != priv->video_direction) {
priv->video_direction = video_direction;
priv->update_src_rect = TRUE;
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -997,6 +1023,9 @@ gst_d3d11_converter_get_property (GObject * object, guint prop_id,
case PROP_DEST_CONTENT_LIGHT_LEVEL:
g_value_set_string (value, priv->out_cll_str);
break;
case PROP_VIDEO_DIRECTION:
g_value_set_enum (value, priv->video_direction);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1339,6 +1368,154 @@ gst_d3d11_color_convert_setup_shader (GstD3D11Converter * self,
return TRUE;
}
static void
gst_d3d11_converter_apply_orientation (GstD3D11Converter * self,
VertexData * vertex_data, gfloat l, gfloat r, gfloat t, gfloat b)
{
GstD3D11ConverterPrivate *priv = self->priv;
gfloat u[4], v[4];
/*
* 1 (l, t) -- 2 (r, t)
* | |
* 0 (l, b) -- 3 (r, b)
*/
u[0] = l;
u[1] = l;
u[2] = r;
u[3] = r;
v[0] = b;
v[1] = t;
v[2] = t;
v[3] = b;
switch (priv->video_direction) {
case GST_VIDEO_ORIENTATION_IDENTITY:
case GST_VIDEO_ORIENTATION_AUTO:
case GST_VIDEO_ORIENTATION_CUSTOM:
default:
break;
case GST_VIDEO_ORIENTATION_90R:
/*
* 1 (l, t) -- 2 (r, t) 1 (l, b) -- 2 (l, t)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (r, b) -- 3 (r, t)
*/
u[0] = r;
u[1] = l;
u[2] = l;
u[3] = r;
v[0] = b;
v[1] = b;
v[2] = t;
v[3] = t;
break;
case GST_VIDEO_ORIENTATION_180:
/*
* 1 (l, t) -- 2 (r, t) 1 (r, b) -- 2 (l, b)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (r, t) -- 3 (l, t)
*/
u[0] = r;
u[1] = r;
u[2] = l;
u[3] = l;
v[0] = t;
v[1] = b;
v[2] = b;
v[3] = t;
break;
case GST_VIDEO_ORIENTATION_90L:
/*
* 1 (l, t) -- 2 (r, t) 1 (r, t) -- 2 (r, b)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (l, t) -- 3 (l, b)
*/
u[0] = l;
u[1] = r;
u[2] = r;
u[3] = l;
v[0] = t;
v[1] = t;
v[2] = b;
v[3] = b;
break;
case GST_VIDEO_ORIENTATION_HORIZ:
/*
* 1 (l, t) -- 2 (r, t) 1 (r, t) -- 2 (l, t)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (r, b) -- 3 (l, b)
*/
u[0] = r;
u[1] = r;
u[2] = l;
u[3] = l;
v[0] = b;
v[1] = t;
v[2] = t;
v[3] = b;
break;
case GST_VIDEO_ORIENTATION_VERT:
/*
* 1 (l, t) -- 2 (r, t) 1 (l, b) -- 2 (r, b)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (l, t) -- 3 (r, t)
*/
u[0] = l;
u[1] = l;
u[2] = r;
u[3] = r;
v[0] = t;
v[1] = b;
v[2] = b;
v[3] = t;
break;
case GST_VIDEO_ORIENTATION_UL_LR:
/*
* 1 (l, t) -- 2 (r, t) 1 (l, t) -- 2 (l, b)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (r, t) -- 3 (r, b)
*/
u[0] = r;
u[1] = l;
u[2] = l;
u[3] = r;
v[0] = t;
v[1] = t;
v[2] = b;
v[3] = b;
break;
case GST_VIDEO_ORIENTATION_UR_LL:
/*
* 1 (l, t) -- 2 (r, t) 1 (r, b) -- 2 (r, t)
* | | -> | |
* 0 (l, b) -- 3 (r, b) 0 (l, b) -- 3 (l, t)
*/
u[0] = l;
u[1] = r;
u[2] = r;
u[3] = l;
v[0] = b;
v[1] = b;
v[2] = t;
v[3] = t;
break;
}
for (guint i = 0; i < 4; i++) {
vertex_data[i].texture.u = u[i];
vertex_data[i].texture.v = v[i];
}
}
static gboolean
gst_d3d11_converter_update_src_rect (GstD3D11Converter * self)
{
@ -1358,6 +1535,69 @@ gst_d3d11_converter_update_src_rect (GstD3D11Converter * self)
priv->src_rect.right = priv->src_x + priv->src_width;
priv->src_rect.bottom = priv->src_y + priv->src_height;
if ((priv->supported_methods & GST_D3D11_CONVERTER_METHOD_VIDEO_PROCESSOR)) {
priv->processor_direction_not_supported = FALSE;
priv->enable_mirror = FALSE;
priv->flip_h = FALSE;
priv->flip_v = FALSE;
priv->enable_rotation = FALSE;
priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY;
/* filtering order is rotation -> mirror */
switch (priv->video_direction) {
case GST_VIDEO_ORIENTATION_IDENTITY:
case GST_VIDEO_ORIENTATION_AUTO:
case GST_VIDEO_ORIENTATION_CUSTOM:
default:
break;
case GST_VIDEO_ORIENTATION_90R:
priv->enable_rotation = TRUE;
priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_90;
break;
case GST_VIDEO_ORIENTATION_180:
priv->enable_rotation = TRUE;
priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_180;
break;
case GST_VIDEO_ORIENTATION_90L:
priv->enable_rotation = TRUE;
priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_270;
break;
case GST_VIDEO_ORIENTATION_HORIZ:
priv->enable_mirror = TRUE;
priv->flip_h = TRUE;
break;
case GST_VIDEO_ORIENTATION_VERT:
priv->enable_mirror = TRUE;
priv->flip_v = TRUE;
break;
case GST_VIDEO_ORIENTATION_UL_LR:
priv->enable_rotation = TRUE;
priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_270;
priv->enable_mirror = TRUE;
priv->flip_v = TRUE;
break;
case GST_VIDEO_ORIENTATION_UR_LL:
priv->enable_rotation = TRUE;
priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_90;
priv->enable_mirror = TRUE;
priv->flip_v = TRUE;
break;
}
if (priv->enable_rotation &&
(priv->processor_caps.FeatureCaps & FEATURE_CAPS_ROTATION) == 0) {
GST_WARNING_OBJECT (self, "Device does not support rotation");
priv->processor_direction_not_supported = TRUE;
}
if (priv->enable_mirror &&
(priv->processor_caps.FeatureCaps & PROCESSOR_FEATURE_CAPS_MIRROR) ==
0) {
GST_WARNING_OBJECT (self, "Device does not support mirror");
priv->processor_direction_not_supported = TRUE;
}
}
if ((priv->supported_methods & GST_D3D11_CONVERTER_METHOD_SHADER) == 0)
return TRUE;
@ -1406,29 +1646,23 @@ gst_d3d11_converter_update_src_rect (GstD3D11Converter * self)
vertex_data[0].position.x = -1.0f;
vertex_data[0].position.y = -1.0f;
vertex_data[0].position.z = 0.0f;
vertex_data[0].texture.u = u0;
vertex_data[0].texture.v = v1;
/* top left */
vertex_data[1].position.x = -1.0f;
vertex_data[1].position.y = 1.0f;
vertex_data[1].position.z = 0.0f;
vertex_data[1].texture.u = u0;
vertex_data[1].texture.v = v0;
/* top right */
vertex_data[2].position.x = 1.0f;
vertex_data[2].position.y = 1.0f;
vertex_data[2].position.z = 0.0f;
vertex_data[2].texture.u = u1;
vertex_data[2].texture.v = v0;
/* bottom right */
vertex_data[3].position.x = 1.0f;
vertex_data[3].position.y = -1.0f;
vertex_data[3].position.z = 0.0f;
vertex_data[3].texture.u = u1;
vertex_data[3].texture.v = v1;
gst_d3d11_converter_apply_orientation (self, vertex_data, u0, u1, v0, v1);
context_handle->Unmap (priv->vertex_buffer, 0);
@ -3461,8 +3695,8 @@ gst_d3d11_converter_convert_buffer_internal (GstD3D11Converter * self,
}
priv->processor_in_use = use_processor;
if (use_processor) {
ID3D11VideoContext *video_ctx = priv->video_context;
if (use_processor && !priv->processor_direction_not_supported) {
ID3D11VideoContext1 *video_ctx = priv->video_context;
ID3D11VideoProcessor *proc = priv->processor;
D3D11_VIDEO_PROCESSOR_STREAM stream = { 0, };
HRESULT hr;
@ -3512,6 +3746,16 @@ gst_d3d11_converter_convert_buffer_internal (GstD3D11Converter * self,
}
}
if ((priv->processor_caps.FeatureCaps & FEATURE_CAPS_ROTATION) != 0) {
video_ctx->VideoProcessorSetStreamRotation (proc, 0,
priv->enable_rotation, priv->rotation);
}
if ((priv->processor_caps.FeatureCaps & PROCESSOR_FEATURE_CAPS_MIRROR) != 0) {
video_ctx->VideoProcessorSetStreamMirror (proc, 0, priv->enable_mirror,
priv->flip_h, priv->flip_v);
}
stream.Enable = TRUE;
stream.pInputSurface = piv;
@ -3526,6 +3770,11 @@ gst_d3d11_converter_convert_buffer_internal (GstD3D11Converter * self,
g_mutex_unlock (&priv->prop_lock);
if ((priv->supported_methods & GST_D3D11_CONVERTER_METHOD_SHADER) == 0) {
GST_ERROR_OBJECT (self, "Conversion is not supported");
goto out;
}
num_rtv = gst_d3d11_converter_get_rtv (self, out_buf, rtv);
if (!num_rtv) {
GST_ERROR_OBJECT (self, "RTV is unavailable");