gstreamer/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c
Bastien Nocera e1271c0d9c gtkglsink: Avoid assertion when applying "auto" rotation method
Guard against the orientation not coming from an inexistant tag, nor
from the application (rotation set to "auto") which caused an assertion.

When the application requests the auto rotation method, make sure it is
resolved to a rotation that's applicable.

ERROR:gstreamer/subprojects/gst-plugins-good/ext/gtk/gtkgstglwidget.c:745:gtk_gst_gl_widget_set_rotate_method: code should not be reached

Fixes: 103ceb853a
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1134>
2021-10-13 09:16:32 +00:00

768 lines
21 KiB
C

/*
* GStreamer
* Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include "gtkgstglwidget.h"
#include "gstgtkutils.h"
#include <gst/gl/gstglfuncs.h>
#include <gst/video/video.h>
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
#include <gdk/gdkx.h>
#include <gst/gl/x11/gstgldisplay_x11.h>
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
#include <gdk/gdkwayland.h>
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#endif
/**
* SECTION:gtkgstglwidget
* @title: GtkGstGlWidget
* @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers
* @see_also: #GtkGLArea, #GstBuffer
*
* #GtkGstGLWidget is an #GtkWidget that renders GStreamer video buffers.
*/
#define GST_CAT_DEFAULT gtk_gst_gl_widget_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
struct _GtkGstGLWidgetPrivate
{
gboolean initted;
GstGLDisplay *display;
GdkGLContext *gdk_context;
GstGLContext *other_context;
GstGLContext *context;
GstGLUpload *upload;
GstGLShader *shader;
GLuint vao;
GLuint vertex_buffer;
GLint attr_position;
GLint attr_texture;
GLuint current_tex;
GstGLOverlayCompositor *overlay_compositor;
GstVideoOrientationMethod rotate_method;
GstVideoOrientationMethod current_rotate_method;
const gfloat *transform_matrix;
};
static const GLfloat vertices[] = {
1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f
};
G_DEFINE_TYPE_WITH_CODE (GtkGstGLWidget, gtk_gst_gl_widget, GTK_TYPE_GL_AREA,
G_ADD_PRIVATE (GtkGstGLWidget)
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "gtkgstglwidget", 0,
"Gtk Gst GL Widget");
);
static void
gtk_gst_gl_widget_bind_buffer (GtkGstGLWidget * gst_widget)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
const GstGLFuncs *gl = priv->context->gl_vtable;
gl->BindBuffer (GL_ARRAY_BUFFER, priv->vertex_buffer);
/* Load the vertex position */
gl->VertexAttribPointer (priv->attr_position, 3, GL_FLOAT, GL_FALSE,
5 * sizeof (GLfloat), (void *) 0);
/* Load the texture coordinate */
gl->VertexAttribPointer (priv->attr_texture, 2, GL_FLOAT, GL_FALSE,
5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
gl->EnableVertexAttribArray (priv->attr_position);
gl->EnableVertexAttribArray (priv->attr_texture);
}
static void
gtk_gst_gl_widget_unbind_buffer (GtkGstGLWidget * gst_widget)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
const GstGLFuncs *gl = priv->context->gl_vtable;
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
gl->DisableVertexAttribArray (priv->attr_position);
gl->DisableVertexAttribArray (priv->attr_texture);
}
static void
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_link_with_stages (priv->context, &error, vert_stage,
frag_stage, NULL))) {
GST_ERROR ("Failed to initialize shader: %s", error->message);
return;
}
priv->attr_position =
gst_gl_shader_get_attribute_location (priv->shader, "a_position");
priv->attr_texture =
gst_gl_shader_get_attribute_location (priv->shader, "a_texcoord");
if (gl->GenVertexArrays) {
gl->GenVertexArrays (1, &priv->vao);
gl->BindVertexArray (priv->vao);
}
gl->GenBuffers (1, &priv->vertex_buffer);
gl->BindBuffer (GL_ARRAY_BUFFER, priv->vertex_buffer);
gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices,
GL_STATIC_DRAW);
if (gl->GenVertexArrays) {
gtk_gst_gl_widget_bind_buffer (gst_widget);
gl->BindVertexArray (0);
}
gl->BindBuffer (GL_ARRAY_BUFFER, 0);
priv->overlay_compositor =
gst_gl_overlay_compositor_new (priv->other_context);
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 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 (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 = video_width;
src.h = video_height;
dst.x = 0;
dst.y = 0;
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);
}
gst_gl_shader_use (priv->shader);
if (gl->BindVertexArray)
gl->BindVertexArray (priv->vao);
gtk_gst_gl_widget_bind_buffer (gst_widget);
gl->ActiveTexture (GL_TEXTURE0);
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)
gl->BindVertexArray (0);
else
gtk_gst_gl_widget_unbind_buffer (gst_widget);
gl->BindTexture (GL_TEXTURE_2D, 0);
}
static inline void
_draw_black (GstGLContext * context)
{
const GstGLFuncs *gl = context->gl_vtable;
gst_gl_insert_debug_marker (context, "no buffer. rendering black");
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT);
}
static gboolean
gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
{
GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (widget)->priv;
GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (widget);
GTK_GST_BASE_WIDGET_LOCK (widget);
if (!priv->context || !priv->other_context)
goto done;
gst_gl_context_activate (priv->other_context, TRUE);
if (!priv->initted)
gtk_gst_gl_widget_init_redisplay (GTK_GST_GL_WIDGET (widget));
if (!priv->initted || !base_widget->negotiated) {
_draw_black (priv->other_context);
goto done;
}
/* Upload latest buffer */
if (base_widget->pending_buffer) {
GstBuffer *buffer = base_widget->pending_buffer;
GstVideoFrame gl_frame;
GstGLSyncMeta *sync_meta;
if (!gst_video_frame_map (&gl_frame, &base_widget->v_info, buffer,
GST_MAP_READ | GST_MAP_GL)) {
_draw_black (priv->other_context);
goto done;
}
priv->current_tex = *(guint *) gl_frame.data[0];
gst_gl_insert_debug_marker (priv->other_context, "redrawing texture %u",
priv->current_tex);
gst_gl_overlay_compositor_upload_overlays (priv->overlay_compositor,
buffer);
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
if (sync_meta) {
/* XXX: the set_sync() seems to be needed for resizing */
gst_gl_sync_meta_set_sync_point (sync_meta, priv->context);
gst_gl_sync_meta_wait (sync_meta, priv->other_context);
}
gst_video_frame_unmap (&gl_frame);
if (base_widget->buffer)
gst_buffer_unref (base_widget->buffer);
/* Keep the buffer to ensure current_tex stay valid */
base_widget->buffer = buffer;
base_widget->pending_buffer = NULL;
}
GST_DEBUG ("rendering buffer %p with gdk context %p",
base_widget->buffer, context);
_redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex);
gst_gl_overlay_compositor_draw_overlays (priv->overlay_compositor);
gst_gl_insert_debug_marker (priv->other_context, "texture %u redrawn",
priv->current_tex);
done:
if (priv->other_context)
gst_gl_context_activate (priv->other_context, FALSE);
GTK_GST_BASE_WIDGET_UNLOCK (widget);
return FALSE;
}
static void
_reset_gl (GtkGstGLWidget * gst_widget)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
const GstGLFuncs *gl = priv->other_context->gl_vtable;
if (!priv->gdk_context)
priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (gst_widget));
if (priv->gdk_context == NULL)
return;
gdk_gl_context_make_current (priv->gdk_context);
gst_gl_context_activate (priv->other_context, TRUE);
if (priv->vao) {
gl->DeleteVertexArrays (1, &priv->vao);
priv->vao = 0;
}
if (priv->vertex_buffer) {
gl->DeleteBuffers (1, &priv->vertex_buffer);
priv->vertex_buffer = 0;
}
if (priv->upload) {
gst_object_unref (priv->upload);
priv->upload = NULL;
}
if (priv->shader) {
gst_object_unref (priv->shader);
priv->shader = NULL;
}
if (priv->overlay_compositor)
gst_object_unref (priv->overlay_compositor);
gst_gl_context_activate (priv->other_context, FALSE);
gst_object_unref (priv->other_context);
priv->other_context = NULL;
gdk_gl_context_clear_current ();
g_object_unref (priv->gdk_context);
priv->gdk_context = NULL;
}
static void
gtk_gst_gl_widget_finalize (GObject * object)
{
GtkGstGLWidgetPrivate *priv = GTK_GST_GL_WIDGET (object)->priv;
GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (object);
if (priv->other_context)
gst_gtk_invoke_on_main ((GThreadFunc) _reset_gl, base_widget);
if (priv->context)
gst_object_unref (priv->context);
if (priv->display)
gst_object_unref (priv->display);
gtk_gst_base_widget_finalize (object);
G_OBJECT_CLASS (gtk_gst_gl_widget_parent_class)->finalize (object);
}
static void
gtk_gst_gl_widget_class_init (GtkGstGLWidgetClass * klass)
{
GObjectClass *gobject_klass = (GObjectClass *) klass;
GtkGLAreaClass *gl_widget_klass = (GtkGLAreaClass *) klass;
gtk_gst_base_widget_class_init (GTK_GST_BASE_WIDGET_CLASS (klass));
gobject_klass->finalize = gtk_gst_gl_widget_finalize;
gl_widget_klass->render = gtk_gst_gl_widget_render;
}
static void
gtk_gst_gl_widget_init (GtkGstGLWidget * gst_widget)
{
GtkGstBaseWidget *base_widget = GTK_GST_BASE_WIDGET (gst_widget);
GdkDisplay *display;
GtkGstGLWidgetPrivate *priv;
gtk_gst_base_widget_init (base_widget);
gst_widget->priv = priv = gtk_gst_gl_widget_get_instance_private (gst_widget);
display = gdk_display_get_default ();
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
if (GDK_IS_X11_DISPLAY (display)) {
priv->display = (GstGLDisplay *)
gst_gl_display_x11_new_with_display (gdk_x11_display_get_xdisplay
(display));
}
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (GDK_WINDOWING_WAYLAND)
if (GDK_IS_WAYLAND_DISPLAY (display)) {
struct wl_display *wayland_display =
gdk_wayland_display_get_wl_display (display);
priv->display = (GstGLDisplay *)
gst_gl_display_wayland_new_with_display (wayland_display);
}
#endif
(void) display;
if (!priv->display)
priv->display = gst_gl_display_new ();
GST_INFO ("Created %" GST_PTR_FORMAT, priv->display);
gtk_gl_area_set_has_alpha (GTK_GL_AREA (gst_widget),
!base_widget->ignore_alpha);
}
static void
_get_gl_context (GtkGstGLWidget * gst_widget)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
GstGLAPI gl_api = GST_GL_API_NONE;
guintptr gl_handle = 0;
gtk_widget_realize (GTK_WIDGET (gst_widget));
if (priv->other_context)
gst_object_unref (priv->other_context);
priv->other_context = NULL;
if (priv->gdk_context)
g_object_unref (priv->gdk_context);
priv->gdk_context = gtk_gl_area_get_context (GTK_GL_AREA (gst_widget));
if (priv->gdk_context == NULL) {
GError *error = gtk_gl_area_get_error (GTK_GL_AREA (gst_widget));
GST_ERROR_OBJECT (gst_widget, "Error creating GdkGLContext : %s",
error ? error->message : "No error set by Gdk");
g_clear_error (&error);
return;
}
g_object_ref (priv->gdk_context);
gdk_gl_context_make_current (priv->gdk_context);
#if GST_GL_HAVE_WINDOW_X11 && defined (GDK_WINDOWING_X11)
if (GST_IS_GL_DISPLAY_X11 (priv->display)) {
#if GST_GL_HAVE_PLATFORM_GLX
if (!gl_handle) {
platform = GST_GL_PLATFORM_GLX;
gl_handle = gst_gl_context_get_current_gl_context (platform);
}
#endif
#if GST_GL_HAVE_PLATFORM_EGL
if (!gl_handle) {
platform = GST_GL_PLATFORM_EGL;
gl_handle = gst_gl_context_get_current_gl_context (platform);
}
#endif
if (gl_handle) {
gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
priv->other_context =
gst_gl_context_new_wrapped (priv->display, gl_handle,
platform, gl_api);
}
}
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (GDK_WINDOWING_WAYLAND)
if (GST_IS_GL_DISPLAY_WAYLAND (priv->display)) {
platform = GST_GL_PLATFORM_EGL;
gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
gl_handle = gst_gl_context_get_current_gl_context (platform);
if (gl_handle)
priv->other_context =
gst_gl_context_new_wrapped (priv->display, gl_handle,
platform, gl_api);
}
#endif
(void) platform;
(void) gl_api;
(void) gl_handle;
if (priv->other_context) {
GError *error = NULL;
GST_INFO ("Retrieved Gdk OpenGL context %" GST_PTR_FORMAT,
priv->other_context);
gst_gl_context_activate (priv->other_context, TRUE);
if (!gst_gl_context_fill_info (priv->other_context, &error)) {
GST_ERROR ("failed to retrieve gdk context info: %s", error->message);
g_clear_error (&error);
g_object_unref (priv->other_context);
priv->other_context = NULL;
} else {
gst_gl_context_activate (priv->other_context, FALSE);
}
} else {
GST_WARNING ("Could not retrieve Gdk OpenGL context");
}
}
GtkWidget *
gtk_gst_gl_widget_new (void)
{
return (GtkWidget *) g_object_new (GTK_TYPE_GST_GL_WIDGET, NULL);
}
gboolean
gtk_gst_gl_widget_init_winsys (GtkGstGLWidget * gst_widget)
{
GtkGstGLWidgetPrivate *priv = gst_widget->priv;
GError *error = NULL;
g_return_val_if_fail (GTK_IS_GST_GL_WIDGET (gst_widget), FALSE);
g_return_val_if_fail (priv->display != NULL, FALSE);
GTK_GST_BASE_WIDGET_LOCK (gst_widget);
if (priv->display && priv->gdk_context && priv->other_context) {
GST_TRACE ("have already initialized contexts");
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
return TRUE;
}
if (!priv->other_context) {
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
gst_gtk_invoke_on_main ((GThreadFunc) _get_gl_context, gst_widget);
GTK_GST_BASE_WIDGET_LOCK (gst_widget);
}
if (!GST_IS_GL_CONTEXT (priv->other_context)) {
GST_FIXME ("Could not retrieve Gdk OpenGL context");
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
return FALSE;
}
GST_OBJECT_LOCK (priv->display);
if (!gst_gl_display_create_context (priv->display, priv->other_context,
&priv->context, &error)) {
GST_WARNING ("Could not create OpenGL context: %s",
error ? error->message : "Unknown");
g_clear_error (&error);
GST_OBJECT_UNLOCK (priv->display);
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
return FALSE;
}
gst_gl_display_add_context (priv->display, priv->context);
GST_OBJECT_UNLOCK (priv->display);
GTK_GST_BASE_WIDGET_UNLOCK (gst_widget);
return TRUE;
}
GstGLContext *
gtk_gst_gl_widget_get_gtk_context (GtkGstGLWidget * gst_widget)
{
if (!gst_widget->priv->other_context)
return NULL;
return gst_object_ref (gst_widget->priv->other_context);
}
GstGLContext *
gtk_gst_gl_widget_get_context (GtkGstGLWidget * gst_widget)
{
if (!gst_widget->priv->context)
return NULL;
return gst_object_ref (gst_widget->priv->context);
}
GstGLDisplay *
gtk_gst_gl_widget_get_display (GtkGstGLWidget * gst_widget)
{
if (!gst_widget->priv->display)
return NULL;
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;
} else if (method == GST_VIDEO_ORIENTATION_AUTO && from_tag) {
GST_WARNING_OBJECT (gst_widget, "auto orientation cannot come from a tag");
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;
/* We can't apply an AUTO orientation if we don't have an
* orientation coming from a tag, so reset to identity */
if (method != priv->current_rotate_method &&
method == GST_VIDEO_ORIENTATION_AUTO)
method = GST_VIDEO_ORIENTATION_IDENTITY;
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;
}