From b97f2e6e6a7868e8ded4fd197445b257256a8c9c Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Fri, 12 Jun 2015 15:17:30 +1000 Subject: [PATCH] gtk: implement video aspect-ratio handling For both the software and the GL sink's. Doesn't deal with the pixel-aspect-ratio field at all yet. --- ext/gtk/gstgtkglsink.c | 48 +++++++++++++++++++-------- ext/gtk/gstgtkglsink.h | 4 +++ ext/gtk/gstgtksink.c | 51 +++++++++++++++++++--------- ext/gtk/gstgtksink.h | 4 +++ ext/gtk/gtkgstglwidget.c | 84 ++++++++++++++++++++++++++++++++++++++++++++-- ext/gtk/gtkgstwidget.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 243 insertions(+), 34 deletions(-) diff --git a/ext/gtk/gstgtkglsink.c b/ext/gtk/gstgtkglsink.c index c89c940..372846f 100644 --- a/ext/gtk/gstgtkglsink.c +++ b/ext/gtk/gstgtkglsink.c @@ -32,6 +32,8 @@ GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink); #define GST_CAT_DEFAULT gst_debug_gtk_gl_sink +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + static void gst_gtk_gl_sink_finalize (GObject * object); static void gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * param_spec); @@ -62,8 +64,9 @@ GST_STATIC_PAD_TEMPLATE ("sink", enum { - ARG_0, - PROP_WIDGET + PROP_0, + PROP_WIDGET, + PROP_FORCE_ASPECT_RATIO, }; enum @@ -102,6 +105,13 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) "The GtkWidget to place in the widget heirachy", GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + DEFAULT_FORCE_ASPECT_RATIO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_gl_sink_template)); @@ -120,17 +130,7 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass) static void gst_gtk_gl_sink_init (GstGtkGLSink * gtk_sink) { -} - -static void -gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + gtk_sink->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; } static void @@ -157,6 +157,9 @@ gst_gtk_gl_sink_get_widget (GstGtkGLSink * gtk_sink) } gtk_sink->widget = (GtkGstGLWidget *) gtk_gst_gl_widget_new (); + gtk_sink->bind_aspect_ratio = + g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, + "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); /* Take the floating ref, otherwise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -177,6 +180,25 @@ gst_gtk_gl_sink_get_property (GObject * object, guint prop_id, case PROP_WIDGET: g_value_set_object (value, gst_gtk_gl_sink_get_widget (gtk_sink)); break; + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_sink->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gtk_gl_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_sink->force_aspect_ratio = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/gtk/gstgtkglsink.h b/ext/gtk/gstgtkglsink.h index 1457260..4c13059 100644 --- a/ext/gtk/gstgtkglsink.h +++ b/ext/gtk/gstgtkglsink.h @@ -65,6 +65,10 @@ struct _GstGtkGLSink GstGLUpload *upload; GstBuffer *uploaded_buffer; + /* properties */ + gboolean force_aspect_ratio; + GBinding *bind_aspect_ratio; + GstGtkGLSinkPrivate *priv; }; diff --git a/ext/gtk/gstgtksink.c b/ext/gtk/gstgtksink.c index 94b7047..1b34956 100644 --- a/ext/gtk/gstgtksink.c +++ b/ext/gtk/gstgtksink.c @@ -58,10 +58,13 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRA")) ); +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + enum { - ARG_0, - PROP_WIDGET + PROP_0, + PROP_WIDGET, + PROP_FORCE_ASPECT_RATIO, }; enum @@ -100,6 +103,13 @@ gst_gtk_sink_class_init (GstGtkSinkClass * klass) "The GtkWidget to place in the widget heirachy", GTK_TYPE_WIDGET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + DEFAULT_FORCE_ASPECT_RATIO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&gst_gtk_sink_template)); @@ -120,17 +130,6 @@ gst_gtk_sink_init (GstGtkSink * gtk_sink) } static void -gst_gtk_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void gst_gtk_sink_finalize (GObject * object) { GstGtkSink *gtk_sink = GST_GTK_SINK (object);; @@ -154,6 +153,9 @@ gst_gtk_sink_get_widget (GstGtkSink * gtk_sink) } gtk_sink->widget = (GtkGstWidget *) gtk_gst_widget_new (); + gtk_sink->bind_aspect_ratio = + g_object_bind_property (gtk_sink, "force-aspect-ratio", gtk_sink->widget, + "force-aspect-ratio", G_BINDING_BIDIRECTIONAL); /* Take the floating ref, other wise the destruction of the container will * make this widget disapear possibly before we are done. */ @@ -166,14 +168,31 @@ static void gst_gtk_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstGtkSink *gtk_sink; - - gtk_sink = GST_GTK_SINK (object); + GstGtkSink *gtk_sink = GST_GTK_SINK (object); switch (prop_id) { case PROP_WIDGET: g_value_set_object (value, gst_gtk_sink_get_widget (gtk_sink)); break; + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_sink->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gtk_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstGtkSink *gtk_sink = GST_GTK_SINK (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_sink->force_aspect_ratio = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/gtk/gstgtksink.h b/ext/gtk/gstgtksink.h index e8cdf48..444c4b1 100644 --- a/ext/gtk/gstgtksink.h +++ b/ext/gtk/gstgtksink.h @@ -56,6 +56,10 @@ struct _GstGtkSink GtkGstWidget *widget; + /* properties */ + gboolean force_aspect_ratio; + GBinding *bind_aspect_ratio; + GstGtkSinkPrivate *priv; }; diff --git a/ext/gtk/gtkgstglwidget.c b/ext/gtk/gtkgstglwidget.c index 11c5b6f..100fa1d 100644 --- a/ext/gtk/gtkgstglwidget.c +++ b/ext/gtk/gtkgstglwidget.c @@ -51,10 +51,21 @@ G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA, #define GTK_GST_GL_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_GL_WIDGET, GtkGstGLWidgetPrivate)) +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + +enum +{ + PROP_0, + PROP_FORCE_ASPECT_RATIO, +}; + struct _GtkGstGLWidgetPrivate { GMutex lock; + /* properties */ + gboolean force_aspect_ratio; + gboolean negotiated; GstBuffer *buffer; GstCaps *gl_caps; @@ -182,6 +193,30 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex) const GstGLFuncs *gl = gst_widget->priv->context->gl_vtable; GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + if (gst_widget->priv->force_aspect_ratio) { + GstVideoRectangle src, dst, result; + gint gtk_viewport[4]; + + gl->ClearColor (0.0, 0.0, 0.0, 0.0); + gl->Clear (GL_COLOR_BUFFER_BIT); + + gl->GetIntegerv (GL_VIEWPORT, gtk_viewport); + + src.x = 0; + src.y = 0; + src.w = GST_VIDEO_INFO_WIDTH (&gst_widget->priv->v_info); + src.h = GST_VIDEO_INFO_HEIGHT (&gst_widget->priv->v_info); + + dst.x = gtk_viewport[0]; + dst.y = gtk_viewport[1]; + dst.w = gtk_viewport[2]; + dst.h = gtk_viewport[3]; + + gst_video_sink_center_rect (src, dst, &result, TRUE); + + gl->Viewport (result.x, result.y, result.w, result.h); + } + gst_gl_shader_use (gst_widget->priv->shader); if (gl->BindVertexArray) @@ -391,18 +426,61 @@ gtk_gst_gl_widget_finalize (GObject * object) } static void +gtk_gst_gl_widget_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GtkGstGLWidget *gtk_widget = GTK_GST_GL_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_gst_gl_widget_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GtkGstGLWidget *gtk_widget = GTK_GST_GL_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass) { + GObjectClass *gobject_klass = (GObjectClass *) klass; GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) klass; g_type_class_add_private (klass, sizeof (GtkGstGLWidgetPrivate)); + gobject_klass->set_property = gtk_gst_gl_widget_set_property; + gobject_klass->get_property = gtk_gst_gl_widget_get_property; + gobject_klass->finalize = gtk_gst_gl_widget_finalize; + + g_object_class_install_property (gobject_klass, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + DEFAULT_FORCE_ASPECT_RATIO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gl_widget_klass->render = gtk_gst_gl_widget_render; + widget_klass->get_preferred_width = gtk_gst_gl_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_gl_widget_get_preferred_height; - - G_OBJECT_CLASS (klass)->finalize = gtk_gst_gl_widget_finalize; } static void @@ -412,6 +490,8 @@ gtk_gst_gl_widget_init (GtkGstGLWidget * widget) widget->priv = GTK_GST_GL_WIDGET_GET_PRIVATE (widget); + widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + g_mutex_init (&widget->priv->lock); display = gdk_display_get_default (); diff --git a/ext/gtk/gtkgstwidget.c b/ext/gtk/gtkgstwidget.c index c103df7..aa40f39 100644 --- a/ext/gtk/gtkgstwidget.c +++ b/ext/gtk/gtkgstwidget.c @@ -40,10 +40,21 @@ G_DEFINE_TYPE (GtkGstWidget, gtk_gst_widget, GTK_TYPE_DRAWING_AREA); #define GTK_GST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ GTK_TYPE_GST_WIDGET, GtkGstWidgetPrivate)) +#define DEFAULT_FORCE_ASPECT_RATIO TRUE + +enum +{ + PROP_0, + PROP_FORCE_ASPECT_RATIO, +}; + struct _GtkGstWidgetPrivate { GMutex lock; + /* properties */ + gboolean force_aspect_ratio; + gboolean negotiated; GstBuffer *buffer; GstCaps *caps; @@ -103,6 +114,7 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) (gdouble) widget_width / GST_VIDEO_INFO_WIDTH (&frame.info); gdouble scale_y = (gdouble) widget_height / GST_VIDEO_INFO_HEIGHT (&frame.info); + GstVideoRectangle result; gst_widget->priv->v_info = frame.info; @@ -110,8 +122,32 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr) CAIRO_FORMAT_ARGB32, frame.info.width, frame.info.height, frame.info.stride[0]); + if (gst_widget->priv->force_aspect_ratio) { + GstVideoRectangle src, dst; + + src.x = 0; + src.y = 0; + src.w = GST_VIDEO_INFO_WIDTH (&frame.info); + src.h = GST_VIDEO_INFO_HEIGHT (&frame.info); + + dst.x = 0; + dst.y = 0; + dst.w = widget_width; + dst.h = widget_height; + + gst_video_sink_center_rect (src, dst, &result, TRUE); + + scale_x = scale_y = MIN (scale_x, scale_y); + } else { + result.x = 0; + result.y = 0; + result.w = widget_width; + result.h = widget_height; + } + + cairo_translate (cr, result.x, result.y); cairo_scale (cr, scale_x, scale_y); - cairo_rectangle (cr, 0, 0, widget_width, widget_height); + cairo_rectangle (cr, 0, 0, result.w, result.h); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); @@ -144,17 +180,59 @@ gtk_gst_widget_finalize (GObject * object) } static void +gtk_gst_widget_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GtkGstWidget *gtk_widget = GTK_GST_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + gtk_widget->priv->force_aspect_ratio = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_gst_widget_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GtkGstWidget *gtk_widget = GTK_GST_WIDGET (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, gtk_widget->priv->force_aspect_ratio); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gtk_gst_widget_class_init (GtkGstWidgetClass * klass) { + GObjectClass *gobject_klass = (GObjectClass *) klass; GtkWidgetClass *widget_klass = (GtkWidgetClass *) klass; g_type_class_add_private (klass, sizeof (GtkGstWidgetPrivate)); + gobject_klass->set_property = gtk_gst_widget_set_property; + gobject_klass->get_property = gtk_gst_widget_get_property; + gobject_klass->finalize = gtk_gst_widget_finalize; + + g_object_class_install_property (gobject_klass, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", + "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", + DEFAULT_FORCE_ASPECT_RATIO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + widget_klass->draw = gtk_gst_widget_draw; widget_klass->get_preferred_width = gtk_gst_widget_get_preferred_width; widget_klass->get_preferred_height = gtk_gst_widget_get_preferred_height; - - G_OBJECT_CLASS (klass)->finalize = gtk_gst_widget_finalize; } static void @@ -162,6 +240,8 @@ gtk_gst_widget_init (GtkGstWidget * widget) { widget->priv = GTK_GST_WIDGET_GET_PRIVATE (widget); + widget->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; + g_mutex_init (&widget->priv->lock); } -- 2.7.4