From: Robert Mader Date: Thu, 2 Jun 2022 12:22:21 +0000 (+0200) Subject: gstwaylandsink: Add rotate-method property X-Git-Tag: 1.22.0~1417 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6aa0b0cae223c25208fa59fd4683e7b95aa43e4a;p=platform%2Fupstream%2Fgstreamer.git gstwaylandsink: Add rotate-method property Similar to and inspired by glimagesink and gtkglsink. Using the Wayland buffer transform API allows to offload rotate operations to the Wayland compositor. This can have several advantages: - The Wayland compositor may be able to use hardware plane capabilities to do the rotation. - In case of pre-rotated content on rotated outputs the rotations may equal out, potentially allowing the compositor to use hardware planes even if they don't support rotate operations. Part-of: --- diff --git a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json index 5855250..b0e7668 100644 --- a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json @@ -230601,6 +230601,18 @@ "readable": false, "type": "GstValueArray", "writable": true + }, + "rotate-method": { + "blurb": "rotate method", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "identity (0)", + "mutable": "null", + "readable": true, + "type": "GstVideoOrientationMethod", + "writable": true } }, "rank": "marginal" diff --git a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c index 1a2eed2..87ed2b8 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c +++ b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c @@ -60,6 +60,7 @@ enum PROP_0, PROP_DISPLAY, PROP_FULLSCREEN, + PROP_ROTATE_METHOD, PROP_LAST }; @@ -90,6 +91,7 @@ static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element, static void gst_wayland_sink_set_context (GstElement * element, GstContext * context); +static gboolean gst_wayland_sink_event (GstBaseSink * sink, GstEvent * event); static GstCaps *gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter); static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps); @@ -144,6 +146,7 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context); + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_wayland_sink_event); gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_caps); gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_set_caps); gstbasesink_class->propose_allocation = @@ -162,6 +165,18 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) "Whether the surface should be made fullscreen ", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * waylandsink:rotate-method: + * + * Since: 1.22 + */ + g_object_class_install_property (gobject_class, PROP_ROTATE_METHOD, + g_param_spec_enum ("rotate-method", + "rotate method", + "rotate method", + GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * waylandsink:render-rectangle: * @@ -193,6 +208,43 @@ gst_wayland_sink_set_fullscreen (GstWaylandSink * sink, gboolean fullscreen) } static void +gst_wayland_sink_set_rotate_method (GstWaylandSink * sink, + GstVideoOrientationMethod method, gboolean from_tag) +{ + GstVideoOrientationMethod new_method; + + if (method == GST_VIDEO_ORIENTATION_CUSTOM) { + GST_WARNING_OBJECT (sink, "unsupported custom orientation"); + return; + } + + GST_OBJECT_LOCK (sink); + if (from_tag) + sink->tag_rotate_method = method; + else + sink->sink_rotate_method = method; + + if (sink->sink_rotate_method == GST_VIDEO_ORIENTATION_AUTO) + new_method = sink->tag_rotate_method; + else + new_method = sink->sink_rotate_method; + + if (new_method != sink->current_rotate_method) { + GST_DEBUG_OBJECT (sink, "Changing method from %d to %d", + sink->current_rotate_method, new_method); + + if (sink->window) { + g_mutex_lock (&sink->render_lock); + gst_wl_window_set_rotate_method (sink->window, new_method); + g_mutex_unlock (&sink->render_lock); + } + + sink->current_rotate_method = new_method; + } + GST_OBJECT_UNLOCK (sink); +} + +static void gst_wayland_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { @@ -209,6 +261,11 @@ gst_wayland_sink_get_property (GObject * object, g_value_set_boolean (value, sink->fullscreen); GST_OBJECT_UNLOCK (sink); break; + case PROP_ROTATE_METHOD: + GST_OBJECT_LOCK (sink); + g_value_set_enum (value, sink->current_rotate_method); + GST_OBJECT_UNLOCK (sink); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -232,6 +289,10 @@ gst_wayland_sink_set_property (GObject * object, gst_wayland_sink_set_fullscreen (sink, g_value_get_boolean (value)); GST_OBJECT_UNLOCK (sink); break; + case PROP_ROTATE_METHOD: + gst_wayland_sink_set_rotate_method (sink, g_value_get_enum (value), + FALSE); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -420,6 +481,34 @@ gst_wayland_sink_set_context (GstElement * element, GstContext * context) GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } +static gboolean +gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstTagList *taglist; + GstVideoOrientationMethod method; + gboolean ret; + + GST_DEBUG_OBJECT (sink, "handling %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_TAG: + gst_event_parse_tag (event, &taglist); + + if (gst_video_orientation_from_tag (taglist, &method)) { + gst_wayland_sink_set_rotate_method (sink, method, TRUE); + } + + break; + default: + break; + } + + ret = GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); + + return ret; +} + static GstCaps * gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) { @@ -679,6 +768,8 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer) &sink->video_info, sink->fullscreen, &sink->render_lock); g_signal_connect_object (sink->window, "closed", G_CALLBACK (on_window_closed), sink, 0); + gst_wl_window_set_rotate_method (sink->window, + sink->current_rotate_method); } } @@ -922,6 +1013,8 @@ gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) } else { sink->window = gst_wl_window_new_in_surface (sink->display, surface, &sink->render_lock); + gst_wl_window_set_rotate_method (sink->window, + sink->current_rotate_method); } } else { GST_ERROR_OBJECT (sink, "Failed to find display handle, " diff --git a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h index f36c639..3243d8c 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h +++ b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.h @@ -63,6 +63,10 @@ struct _GstWaylandSink GMutex render_lock; GstBuffer *last_buffer; + GstVideoOrientationMethod sink_rotate_method; + GstVideoOrientationMethod tag_rotate_method; + GstVideoOrientationMethod current_rotate_method; + struct wl_callback *callback; }; diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c index d50dc6a..4aa53c3 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c @@ -63,6 +63,8 @@ typedef struct _GstWlWindowPrivate /* the size of the video in the buffers */ gint video_width, video_height; + enum wl_output_transform buffer_transform; + /* when this is not set both the area_surface and the video_surface are not * visible and certain steps should be skipped */ gboolean is_area_surface_mapped; @@ -420,12 +422,27 @@ gst_wl_window_resize_video_surface (GstWlWindow * self, gboolean commit) GstVideoRectangle dst = { 0, }; GstVideoRectangle res; - /* center the video_subsurface inside area_subsurface */ - src.w = priv->video_width; - src.h = priv->video_height; + switch (priv->buffer_transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + case WL_OUTPUT_TRANSFORM_180: + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + src.w = priv->video_width; + src.h = priv->video_height; + break; + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + src.w = priv->video_height; + src.h = priv->video_width; + break; + } + dst.w = priv->render_rectangle.w; dst.h = priv->render_rectangle.h; + /* center the video_subsurface inside area_subsurface */ if (priv->video_viewport) { gst_video_center_rect (&src, &dst, &res, TRUE); wp_viewport_set_destination (priv->video_viewport, res.w, res.h); @@ -434,6 +451,8 @@ gst_wl_window_resize_video_surface (GstWlWindow * self, gboolean commit) } wl_subsurface_set_position (priv->video_subsurface, res.x, res.y); + wl_surface_set_buffer_transform (priv->video_surface_wrapper, + priv->buffer_transform); if (commit) wl_surface_commit (priv->video_surface_wrapper); @@ -567,24 +586,16 @@ gst_wl_window_update_borders (GstWlWindow * self) g_object_unref (alloc); } -void -gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y, - gint w, gint h) +static void +gst_wl_window_update_geometry (GstWlWindow * self) { GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); - if (priv->render_rectangle.x == x && priv->render_rectangle.y == y && - priv->render_rectangle.w == w && priv->render_rectangle.h == h) - return; - - priv->render_rectangle.x = x; - priv->render_rectangle.y = y; - priv->render_rectangle.w = w; - priv->render_rectangle.h = h; - /* position the area inside the parent - needs a parent commit to apply */ - if (priv->area_subsurface) - wl_subsurface_set_position (priv->area_subsurface, x, y); + if (priv->area_subsurface) { + wl_subsurface_set_position (priv->area_subsurface, priv->render_rectangle.x, + priv->render_rectangle.y); + } if (priv->is_area_surface_mapped) gst_wl_window_update_borders (self); @@ -603,6 +614,24 @@ gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y, wl_subsurface_set_desync (priv->video_subsurface); } +void +gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y, + gint w, gint h) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + if (priv->render_rectangle.x == x && priv->render_rectangle.y == y && + priv->render_rectangle.w == w && priv->render_rectangle.h == h) + return; + + priv->render_rectangle.x = x; + priv->render_rectangle.y = y; + priv->render_rectangle.w = w; + priv->render_rectangle.h = h; + + gst_wl_window_update_geometry (self); +} + const GstVideoRectangle * gst_wl_window_get_render_rectangle (GstWlWindow * self) { @@ -610,3 +639,39 @@ gst_wl_window_get_render_rectangle (GstWlWindow * self) return &priv->render_rectangle; } + +static enum wl_output_transform +output_transform_from_orientation_method (GstVideoOrientationMethod method) +{ + switch (method) { + case GST_VIDEO_ORIENTATION_IDENTITY: + return WL_OUTPUT_TRANSFORM_NORMAL; + case GST_VIDEO_ORIENTATION_90R: + return WL_OUTPUT_TRANSFORM_90; + case GST_VIDEO_ORIENTATION_180: + return WL_OUTPUT_TRANSFORM_180; + case GST_VIDEO_ORIENTATION_90L: + return WL_OUTPUT_TRANSFORM_270; + case GST_VIDEO_ORIENTATION_HORIZ: + return WL_OUTPUT_TRANSFORM_FLIPPED; + case GST_VIDEO_ORIENTATION_VERT: + return WL_OUTPUT_TRANSFORM_FLIPPED_180; + case GST_VIDEO_ORIENTATION_UL_LR: + return WL_OUTPUT_TRANSFORM_FLIPPED_90; + case GST_VIDEO_ORIENTATION_UR_LL: + return WL_OUTPUT_TRANSFORM_FLIPPED_270; + default: + g_assert_not_reached (); + } +} + +void +gst_wl_window_set_rotate_method (GstWlWindow * self, + GstVideoOrientationMethod method) +{ + GstWlWindowPrivate *priv = gst_wl_window_get_instance_private (self); + + priv->buffer_transform = output_transform_from_orientation_method (method); + + gst_wl_window_update_geometry (self); +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h index 78871d7..06c4001 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.h @@ -68,4 +68,8 @@ void gst_wl_window_set_render_rectangle (GstWlWindow * self, gint x, gint y, GST_WL_API const GstVideoRectangle *gst_wl_window_get_render_rectangle (GstWlWindow * self); +GST_WL_API +void gst_wl_window_set_rotate_method (GstWlWindow *self, + GstVideoOrientationMethod rotate_method); + G_END_DECLS