mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
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:
parent
b9ebc71cc8
commit
a512a91598
6 changed files with 243 additions and 34 deletions
|
@ -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;
|
||||
|
|
|
@ -65,6 +65,10 @@ struct _GstGtkGLSink
|
|||
GstGLUpload *upload;
|
||||
GstBuffer *uploaded_buffer;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
GBinding *bind_aspect_ratio;
|
||||
|
||||
GstGtkGLSinkPrivate *priv;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -56,6 +56,10 @@ struct _GstGtkSink
|
|||
|
||||
GtkGstWidget *widget;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
GBinding *bind_aspect_ratio;
|
||||
|
||||
GstGtkSinkPrivate *priv;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue