d3d11videosink: Add support for rotation

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>
This commit is contained in:
Seungha Yang 2022-07-03 01:22:10 +09:00 committed by GStreamer Marge Bot
parent 4e75ca0351
commit 5f39388ae5
5 changed files with 134 additions and 8 deletions

View 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,
@ -269,6 +278,19 @@ gst_d3d11_video_sink_class_init (GstD3D11VideoSinkClass * klass)
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
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)

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

View 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,

View 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;

View 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