1From 3241f7b42c92410f9d667ed26e5f65dbcb8b2c92 Mon Sep 17 00:00:00 2001 2From: Jeffy Chen <jeffy.chen@rock-chips.com> 3Date: Tue, 30 Mar 2021 07:08:06 +0800 4Subject: [PATCH 20/33] waylandsink: Support window fill-mode property 5 6Tested with: 7gst-launch-1.0 videotestsrc ! waylandsink fullscreen=1 fill-mode=crop 8 9Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 10--- 11 ext/wayland/gstwaylandsink.c | 55 ++++++++++++++++++++++++++++++++++++ 12 ext/wayland/gstwaylandsink.h | 1 + 13 ext/wayland/wlwindow.c | 28 +++++++++++++++++- 14 ext/wayland/wlwindow.h | 9 ++++++ 15 4 files changed, 92 insertions(+), 1 deletion(-) 16 17diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c 18index ff79ddf..24fd7bd 100644 19--- a/ext/wayland/gstwaylandsink.c 20+++ b/ext/wayland/gstwaylandsink.c 21@@ -66,9 +66,12 @@ enum 22 PROP_FULLSCREEN, 23 PROP_LAYER, 24 PROP_ALPHA, 25+ PROP_FILL_MODE, 26 PROP_LAST 27 }; 28 29+static GstWlWindowFillMode DEFAULT_FILL_MODE = GST_WL_WINDOW_FIT; 30+ 31 GST_DEBUG_CATEGORY (gstwayland_debug); 32 #define GST_CAT_DEFAULT gstwayland_debug 33 34@@ -185,6 +188,24 @@ gst_wl_window_layer_get_type (void) 35 return layer; 36 } 37 38+#define GST_TYPE_WL_WINDOW_FILL_MODE (gst_wl_window_fill_mode_get_type ()) 39+static GType 40+gst_wl_window_fill_mode_get_type (void) 41+{ 42+ static GType mode = 0; 43+ 44+ if (!mode) { 45+ static const GEnumValue modes[] = { 46+ {GST_WL_WINDOW_STRETCH, "Ignore aspect ratio", "stretch"}, 47+ {GST_WL_WINDOW_FIT, "Keep aspect ratio", "fit"}, 48+ {GST_WL_WINDOW_CROP, "Keep aspect ratio by expanding", "crop"}, 49+ {0, NULL, NULL} 50+ }; 51+ mode = g_enum_register_static ("GstWlWindowFillMode", modes); 52+ } 53+ return mode; 54+} 55+ 56 static void 57 gst_wayland_sink_class_init (GstWaylandSinkClass * klass) 58 { 59@@ -244,6 +265,15 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) 60 "Wayland window alpha", 0.0, 1.0, 1.0, 61 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); 62 63+ if (g_getenv ("WAYLANDSINK_STRETCH")) 64+ DEFAULT_FILL_MODE = GST_WL_WINDOW_STRETCH; 65+ 66+ g_object_class_install_property (gobject_class, PROP_FILL_MODE, 67+ g_param_spec_enum ("fill-mode", "Window fill mode", 68+ "Wayland window fill mode", 69+ GST_TYPE_WL_WINDOW_FILL_MODE, DEFAULT_FILL_MODE, 70+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 71+ 72 gst_video_overlay_install_properties (gobject_class, PROP_LAST); 73 74 gst_type_mark_as_plugin_api (GST_TYPE_WAYLAND_VIDEO, 0); 75@@ -258,6 +288,7 @@ gst_wayland_sink_init (GstWaylandSink * sink) 76 sink->window_handle = 1; 77 sink->layer = GST_WL_WINDOW_LAYER_NORMAL; 78 sink->alpha = 1.0; 79+ sink->fill_mode = DEFAULT_FILL_MODE; 80 } 81 82 static void 83@@ -296,6 +327,19 @@ gst_wayland_sink_set_alpha (GstWaylandSink * sink, gdouble alpha) 84 g_mutex_unlock (&sink->render_lock); 85 } 86 87+static void 88+gst_wayland_sink_set_fill_mode (GstWaylandSink * sink, 89+ GstWlWindowFillMode fill_mode) 90+{ 91+ if (fill_mode == sink->fill_mode) 92+ return; 93+ 94+ g_mutex_lock (&sink->render_lock); 95+ sink->fill_mode = fill_mode; 96+ sink->resend_info = FALSE; 97+ g_mutex_unlock (&sink->render_lock); 98+} 99+ 100 static void 101 gst_wayland_sink_get_property (GObject * object, 102 guint prop_id, GValue * value, GParamSpec * pspec) 103@@ -323,6 +367,11 @@ gst_wayland_sink_get_property (GObject * object, 104 g_value_set_double (value, sink->alpha); 105 GST_OBJECT_UNLOCK (sink); 106 break; 107+ case PROP_FILL_MODE: 108+ GST_OBJECT_LOCK (sink); 109+ g_value_set_enum (value, sink->fill_mode); 110+ GST_OBJECT_UNLOCK (sink); 111+ break; 112 default: 113 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 114 break; 115@@ -356,6 +405,11 @@ gst_wayland_sink_set_property (GObject * object, 116 gst_wayland_sink_set_alpha (sink, g_value_get_double (value)); 117 GST_OBJECT_UNLOCK (sink); 118 break; 119+ case PROP_FILL_MODE: 120+ GST_OBJECT_LOCK (sink); 121+ gst_wayland_sink_set_fill_mode (sink, g_value_get_enum (value)); 122+ GST_OBJECT_UNLOCK (sink); 123+ break; 124 default: 125 if (!gst_video_overlay_set_property (object, PROP_LAST, prop_id, value)) 126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 127@@ -763,6 +817,7 @@ render_last_buffer (GstWaylandSink * sink, gboolean redraw) 128 sink->video_info_changed = FALSE; 129 sink->resend_info = FALSE; 130 } 131+ sink->window->fill_mode = sink->fill_mode; 132 gst_wl_window_render (sink->window, wlbuffer, info); 133 } 134 135diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h 136index f798969..6fd77e8 100644 137--- a/ext/wayland/gstwaylandsink.h 138+++ b/ext/wayland/gstwaylandsink.h 139@@ -64,6 +64,7 @@ struct _GstWaylandSink 140 gboolean fullscreen; 141 GstWlWindowLayer layer; 142 gdouble alpha; 143+ GstWlWindowFillMode fill_mode; 144 145 gchar *display_name; 146 147diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c 148index 58e65dd..f4e7ca9 100644 149--- a/ext/wayland/wlwindow.c 150+++ b/ext/wayland/wlwindow.c 151@@ -467,7 +467,33 @@ gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit) 152 dst.h = window->render_rectangle.h; 153 154 if (window->video_viewport) { 155- gst_video_sink_center_rect (src, dst, &res, TRUE); 156+ if (window->fill_mode == GST_WL_WINDOW_STRETCH) { 157+ res = dst; 158+ } else if (window->fill_mode == GST_WL_WINDOW_FIT) { 159+ gst_video_sink_center_rect (src, dst, &res, TRUE); 160+ } else if (window->fill_mode == GST_WL_WINDOW_CROP) { 161+ gdouble src_ratio, dst_ratio; 162+ 163+ src_ratio = (gdouble) src.w / src.h; 164+ dst_ratio = (gdouble) dst.w / dst.h; 165+ 166+ if (src_ratio < dst_ratio) { 167+ int h = src.w / dst_ratio; 168+ src.y = (src.h - h) / 2; 169+ src.h = h; 170+ } else if (src_ratio > dst_ratio) { 171+ int w = src.h * dst_ratio; 172+ src.x = (src.w - w) / 2; 173+ src.w = w; 174+ } 175+ 176+ wp_viewport_set_source (window->video_viewport, 177+ wl_fixed_from_int (src.x), wl_fixed_from_int (src.y), 178+ wl_fixed_from_int (src.w), wl_fixed_from_int (src.h)); 179+ 180+ res = dst; 181+ } 182+ 183 wp_viewport_set_destination (window->video_viewport, res.w, res.h); 184 } else { 185 gst_video_sink_center_rect (src, dst, &res, FALSE); 186diff --git a/ext/wayland/wlwindow.h b/ext/wayland/wlwindow.h 187index 6fb8285..35d9d3c 100644 188--- a/ext/wayland/wlwindow.h 189+++ b/ext/wayland/wlwindow.h 190@@ -37,6 +37,13 @@ G_BEGIN_DECLS 191 typedef struct _GstWlWindow GstWlWindow; 192 typedef struct _GstWlWindowClass GstWlWindowClass; 193 194+typedef enum 195+{ 196+ GST_WL_WINDOW_STRETCH = 0, 197+ GST_WL_WINDOW_FIT = 1, 198+ GST_WL_WINDOW_CROP = 2, 199+} GstWlWindowFillMode; 200+ 201 struct _GstWlWindow 202 { 203 GObject parent_instance; 204@@ -71,6 +78,8 @@ struct _GstWlWindow 205 /* when this is not set both the area_surface and the video_surface are not 206 * visible and certain steps should be skipped */ 207 gboolean is_area_surface_mapped; 208+ 209+ GstWlWindowFillMode fill_mode; 210 }; 211 212 struct _GstWlWindowClass 213-- 2142.20.1 215 216