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.
This commit is contained in:
Matthew Waters 2015-06-12 15:17:30 +10:00
parent b9ebc71cc8
commit a512a91598
6 changed files with 243 additions and 34 deletions

View file

@ -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;

View file

@ -65,6 +65,10 @@ struct _GstGtkGLSink
GstGLUpload *upload;
GstBuffer *uploaded_buffer;
/* properties */
gboolean force_aspect_ratio;
GBinding *bind_aspect_ratio;
GstGtkGLSinkPrivate *priv;
};

View file

@ -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));
@ -119,17 +129,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)
{
@ -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;

View file

@ -56,6 +56,10 @@ struct _GstGtkSink
GtkGstWidget *widget;
/* properties */
gboolean force_aspect_ratio;
GBinding *bind_aspect_ratio;
GstGtkSinkPrivate *priv;
};

View file

@ -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)
@ -390,19 +425,62 @@ gtk_gst_gl_widget_finalize (GObject * object)
G_OBJECT_CLASS (gtk_gst_gl_widget_parent_class)->finalize (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 ();

View file

@ -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);
@ -143,18 +179,60 @@ gtk_gst_widget_finalize (GObject * object)
G_OBJECT_CLASS (gtk_gst_widget_parent_class)->finalize (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);
}