gtkglsink: Add rotate-method property

This mostly just takes code out of glimagesink and applies it here.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1088>
This commit is contained in:
Olivier Crête 2020-09-03 18:27:19 -04:00 committed by GStreamer Marge Bot
parent fdd7f9be23
commit 103ceb853a
6 changed files with 328 additions and 23 deletions

View file

@ -7114,7 +7114,20 @@
"presence": "always"
}
},
"properties": {},
"properties": {
"rotate-method": {
"blurb": "rotate method",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "identity (0)",
"mutable": "null",
"readable": true,
"type": "GstVideoOrientationMethod",
"writable": true
}
},
"rank": "none"
},
"gtksink": {

View file

@ -214,6 +214,24 @@ gst_gtk_base_sink_get_widget (GstGtkBaseSink * gtk_sink)
return gtk_sink->widget;
}
GtkWidget *
gst_gtk_base_sink_acquire_widget (GstGtkBaseSink * gtk_sink)
{
gpointer widget = NULL;
GST_OBJECT_LOCK (gtk_sink);
if (gtk_sink->widget != NULL)
widget = gtk_sink->widget;
GST_OBJECT_UNLOCK (gtk_sink);
if (!widget)
widget =
gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget,
gtk_sink);
return widget;
}
static void
gst_gtk_base_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
@ -223,19 +241,7 @@ gst_gtk_base_sink_get_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_WIDGET:
{
GObject *widget = NULL;
GST_OBJECT_LOCK (gtk_sink);
if (gtk_sink->widget != NULL)
widget = G_OBJECT (gtk_sink->widget);
GST_OBJECT_UNLOCK (gtk_sink);
if (!widget)
widget =
gst_gtk_invoke_on_main ((GThreadFunc) gst_gtk_base_sink_get_widget,
gtk_sink);
g_value_set_object (value, widget);
g_value_set_object (value, gst_gtk_base_sink_acquire_widget (gtk_sink));
break;
}
case PROP_FORCE_ASPECT_RATIO:

View file

@ -91,6 +91,9 @@ struct _GstGtkBaseSinkClass
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GstGtkBaseSink, gst_object_unref)
GtkWidget *
gst_gtk_base_sink_acquire_widget (GstGtkBaseSink * gtk_sink);
G_END_DECLS
#endif /* __GST_GTK_BASE_SINK_H__ */

View file

@ -28,6 +28,7 @@
#endif
#include <gst/gl/gstglfuncs.h>
#include <gst/video/gstvideoaffinetransformationmeta.h>
#include "gstgtkglsink.h"
#include "gtkgstglwidget.h"
@ -35,6 +36,11 @@
GST_DEBUG_CATEGORY (gst_debug_gtk_gl_sink);
#define GST_CAT_DEFAULT gst_debug_gtk_gl_sink
static void gst_gtk_gl_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gtk_gl_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gtk_gl_sink_start (GstBaseSink * bsink);
static gboolean gst_gtk_gl_sink_stop (GstBaseSink * bsink);
static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query);
@ -42,6 +48,7 @@ static gboolean gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink,
GstQuery * query);
static GstCaps *gst_gtk_gl_sink_get_caps (GstBaseSink * bsink,
GstCaps * filter);
static gboolean gst_gtk_gl_sink_event (GstBaseSink * sink, GstEvent * event);
static void gst_gtk_gl_sink_finalize (GObject * object);
@ -63,6 +70,12 @@ GST_ELEMENT_REGISTER_DEFINE (gtkglsink, "gtkglsink", GST_RANK_NONE,
GST_TYPE_GTK_GL_SINK);
enum
{
PROP_0,
PROP_ROTATE_METHOD,
};
static void
gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass)
{
@ -76,6 +89,8 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass)
gstbasesink_class = (GstBaseSinkClass *) klass;
gstgtkbasesink_class = (GstGtkBaseSinkClass *) klass;
gobject_class->set_property = gst_gtk_gl_sink_set_property;
gobject_class->get_property = gst_gtk_gl_sink_get_property;
gobject_class->finalize = gst_gtk_gl_sink_finalize;
gstbasesink_class->query = gst_gtk_gl_sink_query;
@ -83,10 +98,25 @@ gst_gtk_gl_sink_class_init (GstGtkGLSinkClass * klass)
gstbasesink_class->start = gst_gtk_gl_sink_start;
gstbasesink_class->stop = gst_gtk_gl_sink_stop;
gstbasesink_class->get_caps = gst_gtk_gl_sink_get_caps;
gstbasesink_class->event = gst_gtk_gl_sink_event;
gstgtkbasesink_class->create_widget = gtk_gst_gl_widget_new;
gstgtkbasesink_class->window_title = "Gtk+ GL renderer";
/**
* gtkglsink:rotate-method:
*
* Rotation method #GstVideoOrientationMethod used to render the media
*
* Since: 1.20
*/
g_object_class_install_property (gobject_class, PROP_ROTATE_METHOD,
g_param_spec_enum ("rotate-method",
"rotate method",
"rotate method",
GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (gstelement_class, "Gtk GL Video Sink",
"Sink/Video", "A video sink that renders to a GtkWidget using OpenGL",
"Matthew Waters <matthew@centricular.com>");
@ -100,6 +130,41 @@ 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) {
case PROP_ROTATE_METHOD:
gtk_gst_gl_widget_set_rotate_method (GTK_GST_GL_WIDGET
(gst_gtk_base_sink_acquire_widget (GST_GTK_BASE_SINK (object))),
g_value_get_enum (value), FALSE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gtk_gl_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
case PROP_ROTATE_METHOD:
g_value_set_enum (value,
gtk_gst_gl_widget_get_rotate_method (GTK_GST_GL_WIDGET
(gst_gtk_base_sink_acquire_widget (GST_GTK_BASE_SINK (object)))));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query)
{
@ -296,6 +361,8 @@ gst_gtk_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
/* we also support various metadata */
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
gst_query_add_allocation_meta (query,
GST_VIDEO_AFFINE_TRANSFORMATION_META_API_TYPE, 0);
if (gtk_sink->context->gl_vtable->FenceSync)
gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
@ -365,3 +432,35 @@ gst_gtk_gl_sink_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_gtk_gl_sink_event (GstBaseSink * sink, GstEvent * event)
{
GstTagList *taglist;
GstVideoOrientationMethod orientation;
gboolean ret;
GtkGstGLWidget *widget;
GST_DEBUG_OBJECT (sink, "handling %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG:
gst_event_parse_tag (event, &taglist);
if (gst_video_orientation_from_tag (taglist, &orientation)) {
widget = GTK_GST_GL_WIDGET
(gst_gtk_base_sink_acquire_widget (GST_GTK_BASE_SINK (sink)));
gtk_gst_gl_widget_set_rotate_method (widget, orientation, TRUE);
}
break;
default:
break;
}
ret = GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
return ret;
}

View file

@ -66,6 +66,9 @@ struct _GtkGstGLWidgetPrivate
GLint attr_texture;
GLuint current_tex;
GstGLOverlayCompositor *overlay_compositor;
GstVideoOrientationMethod rotate_method;
GstVideoOrientationMethod current_rotate_method;
const gfloat *transform_matrix;
};
static const GLfloat vertices[] = {
@ -119,9 +122,18 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget)
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
const GstGLFuncs *gl = priv->context->gl_vtable;
GError *error = NULL;
GstGLSLStage *frag_stage, *vert_stage;
vert_stage = gst_glsl_stage_new_with_string (priv->context,
GL_VERTEX_SHADER, GST_GLSL_VERSION_NONE,
GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY,
gst_gl_shader_string_vertex_mat4_vertex_transform);
frag_stage = gst_glsl_stage_new_default_fragment (priv->context);
gst_gl_insert_debug_marker (priv->other_context, "initializing redisplay");
if (!(priv->shader = gst_gl_shader_new_default (priv->context, &error))) {
if (!(priv->shader =
gst_gl_shader_new_link_with_stages (priv->context, &error, vert_stage,
frag_stage, NULL))) {
GST_ERROR ("Failed to initialize shader: %s", error->message);
return;
}
@ -154,36 +166,107 @@ gtk_gst_gl_widget_init_redisplay (GtkGstGLWidget * gst_widget)
priv->initted = TRUE;
}
/* rotate 90 */
static const gfloat clockwise_matrix[] = {
0.0f, -1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
/* rotate 180 */
static const gfloat clockwise_180_matrix[] = {
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
/* rotate 270 */
static const gfloat counterclockwise_matrix[] = {
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
/* horizontal-flip */
static const gfloat horizontal_flip_matrix[] = {
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
/* vertical-flip */
static const gfloat vertical_flip_matrix[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
/* upper-left-diagonal */
static const gfloat upper_left_matrix[] = {
0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
/* upper-right-diagonal */
static const gfloat upper_right_matrix[] = {
0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
static void
_redraw_texture (GtkGstGLWidget * gst_widget, guint tex)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
const GstGLFuncs *gl = priv->context->gl_vtable;
const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (gst_widget);
GtkWidget *widget = GTK_WIDGET (gst_widget);
if (gst_widget->base.force_aspect_ratio) {
GstVideoRectangle src, dst, result;
gint widget_width, widget_height, widget_scale;
gint video_width, video_height, widget_scale;
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT);
widget_scale = gtk_widget_get_scale_factor ((GtkWidget *) gst_widget);
widget_width = gtk_widget_get_allocated_width ((GtkWidget *) gst_widget);
widget_height = gtk_widget_get_allocated_height ((GtkWidget *) gst_widget);
widget_scale = gtk_widget_get_scale_factor (widget);
if (priv->current_rotate_method == GST_VIDEO_ORIENTATION_90R
|| priv->current_rotate_method == GST_VIDEO_ORIENTATION_90L
|| priv->current_rotate_method == GST_VIDEO_ORIENTATION_UL_LR
|| priv->current_rotate_method == GST_VIDEO_ORIENTATION_UR_LL) {
video_width = base_widget->display_height;
video_height = base_widget->display_width;
} else {
video_width = base_widget->display_width;
video_height = base_widget->display_height;
}
src.x = 0;
src.y = 0;
src.w = gst_widget->base.display_width;
src.h = gst_widget->base.display_height;
src.w = video_width;
src.h = video_height;
dst.x = 0;
dst.y = 0;
dst.w = widget_width * widget_scale;
dst.h = widget_height * widget_scale;
dst.w = gtk_widget_get_allocated_width (widget) * widget_scale;
dst.h = gtk_widget_get_allocated_height (widget) * widget_scale;
gst_video_sink_center_rect (src, dst, &result, TRUE);
GST_LOG ("Center src %dx%d into dst %dx%d result -> %dx%d",
src.w, src.h, dst.w, dst.h, result.w, result.h);
gl->Viewport (result.x, result.y, result.w, result.h);
}
@ -197,6 +280,26 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex)
gl->BindTexture (GL_TEXTURE_2D, tex);
gst_gl_shader_set_uniform_1i (priv->shader, "tex", 0);
{
GstVideoAffineTransformationMeta *af_meta;
gfloat matrix[16];
af_meta =
gst_buffer_get_video_affine_transformation_meta (base_widget->buffer);
if (priv->transform_matrix) {
gfloat tmp[16];
gst_gl_get_affine_transformation_meta_as_ndc (af_meta, tmp);
gst_gl_multiply_matrix4 (tmp, priv->transform_matrix, matrix);
} else {
gst_gl_get_affine_transformation_meta_as_ndc (af_meta, matrix);
}
gst_gl_shader_set_uniform_matrix_4fv (priv->shader,
"u_transformation", 1, FALSE, matrix);
}
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
if (gl->BindVertexArray)
@ -579,3 +682,78 @@ gtk_gst_gl_widget_get_display (GtkGstGLWidget * gst_widget)
return gst_object_ref (gst_widget->priv->display);
}
void
gtk_gst_gl_widget_set_rotate_method (GtkGstGLWidget * gst_widget,
GstVideoOrientationMethod method, gboolean from_tag)
{
GstVideoOrientationMethod tag_method = GST_VIDEO_ORIENTATION_AUTO;
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
if (method == GST_VIDEO_ORIENTATION_CUSTOM) {
GST_WARNING_OBJECT (gst_widget, "unsupported custom orientation");
return;
}
GTK_GST_BASE_WIDGET_LOCK (gst_widget);
if (from_tag)
tag_method = method;
else
priv->rotate_method = method;
if (priv->rotate_method == GST_VIDEO_ORIENTATION_AUTO)
method = tag_method;
else
method = priv->rotate_method;
if (method != priv->current_rotate_method) {
GST_DEBUG ("Changing method from %d to %d",
priv->current_rotate_method, method);
switch (method) {
case GST_VIDEO_ORIENTATION_IDENTITY:
priv->transform_matrix = NULL;
break;
case GST_VIDEO_ORIENTATION_90R:
priv->transform_matrix = clockwise_matrix;
break;
case GST_VIDEO_ORIENTATION_180:
priv->transform_matrix = clockwise_180_matrix;
break;
case GST_VIDEO_ORIENTATION_90L:
priv->transform_matrix = counterclockwise_matrix;
break;
case GST_VIDEO_ORIENTATION_HORIZ:
priv->transform_matrix = horizontal_flip_matrix;
break;
case GST_VIDEO_ORIENTATION_VERT:
priv->transform_matrix = vertical_flip_matrix;
break;
case GST_VIDEO_ORIENTATION_UL_LR:
priv->transform_matrix = upper_left_matrix;
break;
case GST_VIDEO_ORIENTATION_UR_LL:
priv->transform_matrix = upper_right_matrix;
break;
default:
g_assert_not_reached ();
break;
}
priv->current_rotate_method = method;
}
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
}
GstVideoOrientationMethod
gtk_gst_gl_widget_get_rotate_method (GtkGstGLWidget * gst_widget)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
GstVideoOrientationMethod method;
GTK_GST_BASE_WIDGET_LOCK (gst_widget);
method = priv->current_rotate_method;
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
return method;
}

View file

@ -72,6 +72,12 @@ GstGLDisplay * gtk_gst_gl_widget_get_display (GtkGstGLWidget * widget)
GstGLContext * gtk_gst_gl_widget_get_context (GtkGstGLWidget * widget);
GstGLContext * gtk_gst_gl_widget_get_gtk_context (GtkGstGLWidget * widget);
void gtk_gst_gl_widget_set_rotate_method (GtkGstGLWidget * gst_widget,
GstVideoOrientationMethod method, gboolean from_tag);
GstVideoOrientationMethod gtk_gst_gl_widget_get_rotate_method (
GtkGstGLWidget * gst_widget);
G_END_DECLS
#endif /* __GTK_GST_GL_WIDGET_H__ */