From 4b617a0f6787c7f90f5b977f01234ecc660b5306 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 30 Mar 2021 07:08:06 +0800 Subject: [PATCH 20/31] 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 | 28 +++++++++++++++++- ext/wayland/wlwindow.h | 9 ++++++ 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index ff79ddf..24fd7bd 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 @@ -185,6 +188,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) { @@ -244,6 +265,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); @@ -258,6 +288,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 @@ -296,6 +327,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) @@ -323,6 +367,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; @@ -356,6 +405,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); @@ -763,6 +817,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 f798969..6fd77e8 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 58e65dd..f4e7ca9 100644 --- a/ext/wayland/wlwindow.c +++ b/ext/wayland/wlwindow.c @@ -467,7 +467,33 @@ 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); + 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; + } + 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 6fb8285..35d9d3c 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; @@ -71,6 +78,8 @@ struct _GstWlWindow /* 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; + + GstWlWindowFillMode fill_mode; }; struct _GstWlWindowClass -- 2.20.1