From 38c8faa689802240f49587cf066f056ae142a4dc Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 8 Mar 2021 10:07:39 +0800 Subject: [PATCH 29/40] waylandsink: Support window fill-mode property Tested with: gst-launch-1.0 videotestsrc ! waylandsink fullscreen=1 fill-mode=crop Signed-off-by: Jeffy Chen --- ext/wayland/gstwaylandsink.c | 55 ++++++++++++++++++++++++++++++++++++ ext/wayland/gstwaylandsink.h | 1 + ext/wayland/wlwindow.c | 31 ++++++++++++++++++-- ext/wayland/wlwindow.h | 8 ++++++ 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index cec28f2..4c69a80 100644 --- a/ext/wayland/gstwaylandsink.c +++ b/ext/wayland/gstwaylandsink.c @@ -66,9 +66,12 @@ enum PROP_FULLSCREEN, PROP_LAYER, PROP_ALPHA, + PROP_FILL_MODE, PROP_LAST }; +static GstWlWindowFillMode DEFAULT_FILL_MODE = GST_WL_WINDOW_FIT; + GST_DEBUG_CATEGORY (gstwayland_debug); #define GST_CAT_DEFAULT gstwayland_debug @@ -183,6 +186,24 @@ gst_wl_window_layer_get_type (void) return layer; } +#define GST_TYPE_WL_WINDOW_FILL_MODE (gst_wl_window_fill_mode_get_type ()) +static GType +gst_wl_window_fill_mode_get_type (void) +{ + static GType mode = 0; + + if (!mode) { + static const GEnumValue modes[] = { + {GST_WL_WINDOW_STRETCH, "Ignore aspect ratio", "stretch"}, + {GST_WL_WINDOW_FIT, "Keep aspect ratio", "fit"}, + {GST_WL_WINDOW_CROP, "Keep aspect ratio by expanding", "crop"}, + {0, NULL, NULL} + }; + mode = g_enum_register_static ("GstWlWindowFillMode", modes); + } + return mode; +} + static void gst_wayland_sink_class_init (GstWaylandSinkClass * klass) { @@ -242,6 +263,15 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) "Wayland window alpha", 0.0, 1.0, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); + if (g_getenv ("WAYLANDSINK_STRETCH")) + DEFAULT_FILL_MODE = GST_WL_WINDOW_STRETCH; + + g_object_class_install_property (gobject_class, PROP_FILL_MODE, + g_param_spec_enum ("fill-mode", "Window fill mode", + "Wayland window fill mode", + GST_TYPE_WL_WINDOW_FILL_MODE, DEFAULT_FILL_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_video_overlay_install_properties (gobject_class, PROP_LAST); gst_type_mark_as_plugin_api (GST_TYPE_WAYLAND_VIDEO, 0); @@ -256,6 +286,7 @@ gst_wayland_sink_init (GstWaylandSink * sink) sink->window_handle = 1; sink->layer = GST_WL_WINDOW_LAYER_NORMAL; sink->alpha = 1.0; + sink->fill_mode = DEFAULT_FILL_MODE; } static void @@ -294,6 +325,19 @@ gst_wayland_sink_set_alpha (GstWaylandSink * sink, gdouble alpha) g_mutex_unlock (&sink->render_lock); } +static void +gst_wayland_sink_set_fill_mode (GstWaylandSink * sink, + GstWlWindowFillMode fill_mode) +{ + if (fill_mode == sink->fill_mode) + return; + + g_mutex_lock (&sink->render_lock); + sink->fill_mode = fill_mode; + sink->resend_info = FALSE; + g_mutex_unlock (&sink->render_lock); +} + static void gst_wayland_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -321,6 +365,11 @@ gst_wayland_sink_get_property (GObject * object, g_value_set_double (value, sink->alpha); GST_OBJECT_UNLOCK (sink); break; + case PROP_FILL_MODE: + GST_OBJECT_LOCK (sink); + g_value_set_enum (value, sink->fill_mode); + GST_OBJECT_UNLOCK (sink); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -354,6 +403,11 @@ gst_wayland_sink_set_property (GObject * object, gst_wayland_sink_set_alpha (sink, g_value_get_double (value)); GST_OBJECT_UNLOCK (sink); break; + case PROP_FILL_MODE: + GST_OBJECT_LOCK (sink); + gst_wayland_sink_set_fill_mode (sink, g_value_get_enum (value)); + GST_OBJECT_UNLOCK (sink); + break; default: if (!gst_video_overlay_set_property (object, PROP_LAST, prop_id, value)) G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -761,6 +815,7 @@ render_last_buffer (GstWaylandSink * sink, gboolean redraw) sink->video_info_changed = FALSE; sink->resend_info = FALSE; } + sink->window->fill_mode = sink->fill_mode; gst_wl_window_render (sink->window, wlbuffer, info); } diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h index 6fa4de3..dc3a1d1 100644 --- a/ext/wayland/gstwaylandsink.h +++ b/ext/wayland/gstwaylandsink.h @@ -64,6 +64,7 @@ struct _GstWaylandSink gboolean fullscreen; GstWlWindowLayer layer; gdouble alpha; + GstWlWindowFillMode fill_mode; gchar *display_name; diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c index 7771def..9388f75 100644 --- a/ext/wayland/wlwindow.c +++ b/ext/wayland/wlwindow.c @@ -463,8 +463,35 @@ gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit) dst.h = window->render_rectangle.h; if (window->video_viewport) { - gst_video_sink_center_rect (src, dst, &res, TRUE); - wp_viewport_set_destination (window->video_viewport, res.w, res.h); + if (window->fill_mode == GST_WL_WINDOW_STRETCH) { + res = dst; + } else if (window->fill_mode == GST_WL_WINDOW_FIT) { + gst_video_sink_center_rect (src, dst, &res, TRUE); + } else if (window->fill_mode == GST_WL_WINDOW_CROP) { + gdouble src_ratio, dst_ratio; + + src_ratio = (gdouble) src.w / src.h; + dst_ratio = (gdouble) dst.w / dst.h; + + if (src_ratio < dst_ratio) { + int h = src.w / dst_ratio; + src.y = (src.h - h) / 2; + src.h = h; + } else if (src_ratio > dst_ratio) { + int w = src.h * dst_ratio; + src.x = (src.w - w) / 2; + src.w = w; + } + + wp_viewport_set_source (window->video_viewport, + wl_fixed_from_int (src.x), wl_fixed_from_int (src.y), + wl_fixed_from_int (src.w), wl_fixed_from_int (src.h)); + + res = dst; + } + + if (res.w > 0 && res.h > 0) + wp_viewport_set_destination (window->video_viewport, res.w, res.h); } else { gst_video_sink_center_rect (src, dst, &res, FALSE); } diff --git a/ext/wayland/wlwindow.h b/ext/wayland/wlwindow.h index 2fcaa98..4932cdd 100644 --- a/ext/wayland/wlwindow.h +++ b/ext/wayland/wlwindow.h @@ -37,6 +37,13 @@ G_BEGIN_DECLS typedef struct _GstWlWindow GstWlWindow; typedef struct _GstWlWindowClass GstWlWindowClass; +typedef enum +{ + GST_WL_WINDOW_STRETCH = 0, + GST_WL_WINDOW_FIT = 1, + GST_WL_WINDOW_CROP = 2, +} GstWlWindowFillMode; + struct _GstWlWindow { GObject parent_instance; @@ -72,6 +79,7 @@ struct _GstWlWindow * already been set on the area_subsurface */ gboolean no_border_update; + GstWlWindowFillMode fill_mode; }; struct _GstWlWindowClass -- 2.17.1