diff --git a/ext/eglgles/Makefile.am b/ext/eglgles/Makefile.am index 22f767c8e0..c20646d49a 100644 --- a/ext/eglgles/Makefile.am +++ b/ext/eglgles/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgsteglglessink.la -libgsteglglessink_la_SOURCES = gsteglglessink.c video_platform_wrapper.c +libgsteglglessink_la_SOURCES = gsteglglessink.c gstegladaptation.c video_platform_wrapper.c libgsteglglessink_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) \ @@ -17,4 +17,4 @@ libgsteglglessink_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \ libgsteglglessink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgsteglglessink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) -noinst_HEADERS = gsteglglessink.h video_platform_wrapper.h +noinst_HEADERS = gsteglglessink.h gstegladaptation.h video_platform_wrapper.h diff --git a/ext/eglgles/gstegladaptation.c b/ext/eglgles/gstegladaptation.c new file mode 100644 index 0000000000..28193d0a46 --- /dev/null +++ b/ext/eglgles/gstegladaptation.c @@ -0,0 +1,1011 @@ +/* + * GStreamer EGL/GLES Sink Adaptation + * Copyright (C) 2012-2013 Collabora Ltd. + * @author: Reynaldo H. Verdejo Pinochet + * @author: Sebastian Dröge + * @author: Thiago Santos + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gstegladaptation.h" + +/* Some EGL implementations are reporting wrong + * values for the display's EGL_PIXEL_ASPECT_RATIO. + * They are required by the khronos specs to report + * this value as w/h * EGL_DISPLAY_SCALING (Which is + * a constant with value 10000) but at least the + * Galaxy SIII (Android) is reporting just 1 when + * w = h. We use these two to bound returned values to + * sanity. + */ +#define EGL_SANE_DAR_MIN ((EGL_DISPLAY_SCALING)/10) +#define EGL_SANE_DAR_MAX ((EGL_DISPLAY_SCALING)*10) + +/* GLESv2 GLSL Shaders + * + * OpenGL ES Standard does not mandate YUV support. This is + * why most of these shaders deal with Packed/Planar YUV->RGB + * conversion. + */ + +static const EGLint eglglessink_RGBA8888_attribs[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE +}; + +/* *INDENT-OFF* */ +/* Direct vertex copy */ +static const char *vert_COPY_prog = { + "attribute vec3 position;" + "attribute vec2 texpos;" + "varying vec2 opos;" + "void main(void)" + "{" + " opos = texpos;" + " gl_Position = vec4(position, 1.0);" + "}" +}; + +static const char *vert_COPY_prog_no_tex = { + "attribute vec3 position;" + "void main(void)" + "{" + " gl_Position = vec4(position, 1.0);" + "}" +}; + +/* Paint all black */ +static const char *frag_BLACK_prog = { + "precision mediump float;" + "void main(void)" + "{" + " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);" + "}" +}; + +/* Direct fragments copy with stride-scaling */ +static const char *frag_COPY_prog = { + "precision mediump float;" + "varying vec2 opos;" + "uniform sampler2D tex;" + "uniform vec2 tex_scale0;" + "uniform vec2 tex_scale1;" + "uniform vec2 tex_scale2;" + "void main(void)" + "{" + " vec4 t = texture2D(tex, opos / tex_scale0);" + " gl_FragColor = vec4(t.rgb, 1.0);" + "}" +}; + +/* Direct fragments copy without stride-scaling */ +static const char *frag_COPY_DIRECT_prog = { + "precision mediump float;" + "varying vec2 opos;" + "uniform sampler2D tex;" + "void main(void)" + "{" + " vec4 t = texture2D(tex, opos);" + " gl_FragColor = vec4(t.rgb, 1.0);" + "}" +}; + +/* Channel reordering for XYZ <-> ZYX conversion */ +static const char *frag_REORDER_prog = { + "precision mediump float;" + "varying vec2 opos;" + "uniform sampler2D tex;" + "uniform vec2 tex_scale0;" + "uniform vec2 tex_scale1;" + "uniform vec2 tex_scale2;" + "void main(void)" + "{" + " vec4 t = texture2D(tex, opos / tex_scale0);" + " gl_FragColor = vec4(t.%c, t.%c, t.%c, 1.0);" + "}" +}; + +/* Packed YUV converters */ + +/** AYUV to RGB conversion */ +static const char *frag_AYUV_prog = { + "precision mediump float;" + "varying vec2 opos;" + "uniform sampler2D tex;" + "uniform vec2 tex_scale0;" + "uniform vec2 tex_scale1;" + "uniform vec2 tex_scale2;" + "const vec3 offset = vec3(-0.0625, -0.5, -0.5);" + "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);" + "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);" + "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);" + "void main(void) {" + " float r,g,b;" + " vec3 yuv;" + " yuv = texture2D(tex,opos / tex_scale0).gba;" + " yuv += offset;" + " r = dot(yuv, rcoeff);" + " g = dot(yuv, gcoeff);" + " b = dot(yuv, bcoeff);" + " gl_FragColor=vec4(r,g,b,1.0);" + "}" +}; + +/* Planar YUV converters */ + +/** YUV to RGB conversion */ +static const char *frag_PLANAR_YUV_prog = { + "precision mediump float;" + "varying vec2 opos;" + "uniform sampler2D Ytex,Utex,Vtex;" + "uniform vec2 tex_scale0;" + "uniform vec2 tex_scale1;" + "uniform vec2 tex_scale2;" + "const vec3 offset = vec3(-0.0625, -0.5, -0.5);" + "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);" + "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);" + "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);" + "void main(void) {" + " float r,g,b;" + " vec3 yuv;" + " yuv.x=texture2D(Ytex,opos / tex_scale0).r;" + " yuv.y=texture2D(Utex,opos / tex_scale1).r;" + " yuv.z=texture2D(Vtex,opos / tex_scale2).r;" + " yuv += offset;" + " r = dot(yuv, rcoeff);" + " g = dot(yuv, gcoeff);" + " b = dot(yuv, bcoeff);" + " gl_FragColor=vec4(r,g,b,1.0);" + "}" +}; + +/** NV12/NV21 to RGB conversion */ +static const char *frag_NV12_NV21_prog = { + "precision mediump float;" + "varying vec2 opos;" + "uniform sampler2D Ytex,UVtex;" + "uniform vec2 tex_scale0;" + "uniform vec2 tex_scale1;" + "uniform vec2 tex_scale2;" + "const vec3 offset = vec3(-0.0625, -0.5, -0.5);" + "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);" + "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);" + "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);" + "void main(void) {" + " float r,g,b;" + " vec3 yuv;" + " yuv.x=texture2D(Ytex,opos / tex_scale0).r;" + " yuv.yz=texture2D(UVtex,opos / tex_scale1).%c%c;" + " yuv += offset;" + " r = dot(yuv, rcoeff);" + " g = dot(yuv, gcoeff);" + " b = dot(yuv, bcoeff);" + " gl_FragColor=vec4(r,g,b,1.0);" + "}" +}; +/* *INDENT-ON* */ + +static GstCaps * +_gst_video_format_new_template_caps (GstVideoFormat format) +{ + return gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string (format), + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); +} + +GstCaps * +gst_egl_adaptation_fill_supported_fbuffer_configs (GstEglAdaptationContext * + ctx) +{ + EGLint cfg_number; + GstCaps *caps = NULL, *copy1, *copy2; + guint i, n; + + GST_DEBUG_OBJECT (ctx->element, + "Building initial list of wanted eglattribs per format"); + + /* Init supported format/caps list */ + if (eglChooseConfig (gst_egl_display_get (ctx->eglglesctx.display), + eglglessink_RGBA8888_attribs, NULL, 1, &cfg_number) != EGL_FALSE) { + + caps = gst_caps_new_empty (); + + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBA)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRA)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ARGB)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ABGR)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBx)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRx)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xRGB)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xBGR)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_AYUV)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y444)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGR)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_I420)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YV12)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV12)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV21)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y42B)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y41B)); + gst_caps_append (caps, + _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB16)); + + copy1 = gst_caps_copy (caps); + copy2 = gst_caps_copy (caps); + + n = gst_caps_get_size (caps); + for (i = 0; i < n; i++) { + GstCapsFeatures *features = + gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, NULL); + gst_caps_set_features (caps, i, features); + } + + n = gst_caps_get_size (copy1); + for (i = 0; i < n; i++) { + GstCapsFeatures *features = + gst_caps_features_new + (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL); + gst_caps_set_features (copy1, i, features); + } + + gst_caps_append (caps, copy1); + gst_caps_append (caps, copy2); + } else { + GST_INFO_OBJECT (ctx->element, + "EGL display doesn't support RGBA8888 config"); + } + + return caps; +} + +void +gst_egl_adaptation_wipe_eglglesctx (GstEglAdaptationContext * ctx) +{ + gint i; + + glUseProgram (0); + + if (ctx->have_vbo) { + glDeleteBuffers (1, &ctx->eglglesctx.position_buffer); + glDeleteBuffers (1, &ctx->eglglesctx.index_buffer); + ctx->have_vbo = FALSE; + } + + if (ctx->have_texture) { + glDeleteTextures (ctx->eglglesctx.n_textures + 1, ctx->eglglesctx.texture); + ctx->have_texture = FALSE; + ctx->eglglesctx.n_textures = 0; + } + + for (i = 0; i < 3; i++) { + if (ctx->eglglesctx.glslprogram[i]) { + glDetachShader (ctx->eglglesctx.glslprogram[i], + ctx->eglglesctx.fragshader[i]); + glDetachShader (ctx->eglglesctx.glslprogram[i], + ctx->eglglesctx.vertshader[i]); + glDeleteProgram (ctx->eglglesctx.glslprogram[i]); + glDeleteShader (ctx->eglglesctx.fragshader[i]); + glDeleteShader (ctx->eglglesctx.vertshader[i]); + ctx->eglglesctx.glslprogram[i] = 0; + ctx->eglglesctx.fragshader[i] = 0; + ctx->eglglesctx.vertshader[i] = 0; + } + } + + gst_egl_adaptation_context_make_current (ctx, FALSE); + + if (ctx->eglglesctx.surface) { + eglDestroySurface (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.surface); + ctx->eglglesctx.surface = NULL; + ctx->have_surface = FALSE; + } + + if (ctx->eglglesctx.eglcontext) { + eglDestroyContext (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.eglcontext); + ctx->eglglesctx.eglcontext = NULL; + } +} + +gboolean +got_gl_error (const char *wtf) +{ + GLuint error = GL_NO_ERROR; + + if ((error = glGetError ()) != GL_NO_ERROR) { + GST_CAT_ERROR (GST_CAT_DEFAULT, "GL ERROR: %s returned 0x%04x", wtf, error); + return TRUE; + } + return FALSE; +} + +gboolean +got_egl_error (const char *wtf) +{ + EGLint error; + + if ((error = eglGetError ()) != EGL_SUCCESS) { + GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned 0x%04x", wtf, + error); + return TRUE; + } + + return FALSE; +} + +/* Prints available EGL/GLES extensions + * If another rendering path is implemented this is the place + * where you want to check for the availability of its supporting + * EGL/GLES extensions. + */ +void +gst_egl_adaptation_init_egl_exts (GstEglAdaptationContext * ctx) +{ + const char *eglexts; + unsigned const char *glexts; + + eglexts = + eglQueryString (gst_egl_display_get (ctx->eglglesctx.display), + EGL_EXTENSIONS); + glexts = glGetString (GL_EXTENSIONS); + + GST_DEBUG_OBJECT (ctx->element, "Available EGL extensions: %s\n", + GST_STR_NULL (eglexts)); + GST_DEBUG_OBJECT (ctx->element, "Available GLES extensions: %s\n", + GST_STR_NULL ((const char *) glexts)); + + return; +} + +/* XXX: Lock eglgles context? */ +gboolean +gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext * ctx) +{ + gint width, height; + + /* Save surface dims */ + eglQuerySurface (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.surface, EGL_WIDTH, &width); + eglQuerySurface (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.surface, EGL_HEIGHT, &height); + + if (width != ctx->eglglesctx.surface_width || + height != ctx->eglglesctx.surface_height) { + ctx->eglglesctx.surface_width = width; + ctx->eglglesctx.surface_height = height; + GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels", width, + height); + return TRUE; + } + + return FALSE; +} + +gboolean +gst_egl_adaptation_context_make_current (GstEglAdaptationContext * ctx, + gboolean bind) +{ + g_assert (ctx->eglglesctx.display != NULL); + + if (bind && ctx->eglglesctx.surface && ctx->eglglesctx.eglcontext) { + EGLContext *cur_ctx = eglGetCurrentContext (); + + if (cur_ctx == ctx->eglglesctx.eglcontext) { + GST_DEBUG_OBJECT (ctx->element, + "Already attached the context to thread %p", g_thread_self ()); + return TRUE; + } + + GST_DEBUG_OBJECT (ctx->element, "Attaching context to thread %p", + g_thread_self ()); + if (!eglMakeCurrent (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.surface, ctx->eglglesctx.surface, + ctx->eglglesctx.eglcontext)) { + got_egl_error ("eglMakeCurrent"); + GST_ERROR_OBJECT (ctx->element, "Couldn't bind context"); + return FALSE; + } + } else { + GST_DEBUG_OBJECT (ctx->element, "Detaching context from thread %p", + g_thread_self ()); + if (!eglMakeCurrent (gst_egl_display_get (ctx->eglglesctx.display), + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { + got_egl_error ("eglMakeCurrent"); + GST_ERROR_OBJECT (ctx->element, "Couldn't unbind context"); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +create_shader_program (GstEglAdaptationContext * ctx, GLuint * prog, + GLuint * vert, GLuint * frag, const gchar * vert_text, + const gchar * frag_text) +{ + GLint test; + GLchar *info_log; + + /* Build shader program for video texture rendering */ + *vert = glCreateShader (GL_VERTEX_SHADER); + GST_DEBUG_OBJECT (ctx->element, "Sending %s to handle %d", vert_text, *vert); + glShaderSource (*vert, 1, &vert_text, NULL); + if (got_gl_error ("glShaderSource vertex")) + goto HANDLE_ERROR; + + glCompileShader (*vert); + if (got_gl_error ("glCompileShader vertex")) + goto HANDLE_ERROR; + + glGetShaderiv (*vert, GL_COMPILE_STATUS, &test); + if (test != GL_FALSE) + GST_DEBUG_OBJECT (ctx->element, "Successfully compiled vertex shader"); + else { + GST_ERROR_OBJECT (ctx->element, "Couldn't compile vertex shader"); + glGetShaderiv (*vert, GL_INFO_LOG_LENGTH, &test); + info_log = g_new0 (GLchar, test); + glGetShaderInfoLog (*vert, test, NULL, info_log); + GST_INFO_OBJECT (ctx->element, "Compilation info log:\n%s", info_log); + g_free (info_log); + goto HANDLE_ERROR; + } + + *frag = glCreateShader (GL_FRAGMENT_SHADER); + GST_DEBUG_OBJECT (ctx->element, "Sending %s to handle %d", frag_text, *frag); + glShaderSource (*frag, 1, &frag_text, NULL); + if (got_gl_error ("glShaderSource fragment")) + goto HANDLE_ERROR; + + glCompileShader (*frag); + if (got_gl_error ("glCompileShader fragment")) + goto HANDLE_ERROR; + + glGetShaderiv (*frag, GL_COMPILE_STATUS, &test); + if (test != GL_FALSE) + GST_DEBUG_OBJECT (ctx->element, "Successfully compiled fragment shader"); + else { + GST_ERROR_OBJECT (ctx->element, "Couldn't compile fragment shader"); + glGetShaderiv (*frag, GL_INFO_LOG_LENGTH, &test); + info_log = g_new0 (GLchar, test); + glGetShaderInfoLog (*frag, test, NULL, info_log); + GST_INFO_OBJECT (ctx->element, "Compilation info log:\n%s", info_log); + g_free (info_log); + goto HANDLE_ERROR; + } + + *prog = glCreateProgram (); + if (got_gl_error ("glCreateProgram")) + goto HANDLE_ERROR; + glAttachShader (*prog, *vert); + if (got_gl_error ("glAttachShader vertices")) + goto HANDLE_ERROR; + glAttachShader (*prog, *frag); + if (got_gl_error ("glAttachShader fragments")) + goto HANDLE_ERROR; + glLinkProgram (*prog); + glGetProgramiv (*prog, GL_LINK_STATUS, &test); + if (test != GL_FALSE) { + GST_DEBUG_OBJECT (ctx->element, "GLES: Successfully linked program"); + } else { + GST_ERROR_OBJECT (ctx->element, "Couldn't link program"); + goto HANDLE_ERROR; + } + + return TRUE; + +HANDLE_ERROR: + { + if (*frag && *prog) + glDetachShader (*prog, *frag); + if (*vert && *prog) + glDetachShader (*prog, *vert); + if (*prog) + glDeleteProgram (*prog); + if (*frag) + glDeleteShader (*frag); + if (*vert) + glDeleteShader (*vert); + *prog = 0; + *frag = 0; + *vert = 0; + + return FALSE; + } +} + +gboolean +gst_egl_adaptation_init_egl_surface (GstEglAdaptationContext * ctx, + GstVideoFormat format) +{ + GLboolean ret; + EGLint display_par; + const gchar *texnames[3] = { NULL, }; + gchar *frag_prog = NULL; + gboolean free_frag_prog = FALSE; + EGLint swap_behavior; + gint i; + + GST_DEBUG_OBJECT (ctx->element, "Enter EGL surface setup"); + + ctx->eglglesctx.surface = + eglCreateWindowSurface (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.config, ctx->eglglesctx.used_window, NULL); + + if (ctx->eglglesctx.surface == EGL_NO_SURFACE) { + got_egl_error ("eglCreateWindowSurface"); + GST_ERROR_OBJECT (ctx->element, "Can't create surface"); + goto HANDLE_EGL_ERROR_LOCKED; + } + + ctx->eglglesctx.buffer_preserved = FALSE; + if (eglQuerySurface (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.surface, EGL_SWAP_BEHAVIOR, &swap_behavior)) { + GST_DEBUG_OBJECT (ctx->element, "Buffer swap behavior %x", swap_behavior); + ctx->eglglesctx.buffer_preserved = swap_behavior == EGL_BUFFER_PRESERVED; + } else { + GST_DEBUG_OBJECT (ctx->element, "Can't query buffer swap behavior"); + } + + if (!gst_egl_adaptation_context_make_current (ctx, TRUE)) + goto HANDLE_EGL_ERROR_LOCKED; + + gst_egl_adaptation_init_egl_exts (ctx); + + /* Save display's pixel aspect ratio + * + * DAR is reported as w/h * EGL_DISPLAY_SCALING wich is + * a constant with value 10000. This attribute is only + * supported if the EGL version is >= 1.2 + * XXX: Setup this as a property. + * or some other one time check. Right now it's being called once + * per frame. + */ + if (ctx->eglglesctx.egl_major == 1 && ctx->eglglesctx.egl_minor < 2) { + GST_DEBUG_OBJECT (ctx->element, "Can't query PAR. Using default: %dx%d", + EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING); + ctx->eglglesctx.pixel_aspect_ratio = EGL_DISPLAY_SCALING; + } else { + eglQuerySurface (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.surface, EGL_PIXEL_ASPECT_RATIO, &display_par); + /* Fix for outbound DAR reporting on some implementations not + * honoring the 'should return w/h * EGL_DISPLAY_SCALING' spec + * requirement + */ + if (display_par == EGL_UNKNOWN || display_par < EGL_SANE_DAR_MIN || + display_par > EGL_SANE_DAR_MAX) { + GST_DEBUG_OBJECT (ctx->element, "Nonsensical PAR value returned: %d. " + "Bad EGL implementation? " + "Will use default: %d/%d", ctx->eglglesctx.pixel_aspect_ratio, + EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING); + ctx->eglglesctx.pixel_aspect_ratio = EGL_DISPLAY_SCALING; + } else { + ctx->eglglesctx.pixel_aspect_ratio = display_par; + } + } + + /* Save surface dims */ + gst_egl_adaptation_update_surface_dimensions (ctx); + + /* We have a surface! */ + ctx->have_surface = TRUE; + + /* Init vertex and fragment GLSL shaders. + * Note: Shader compiler support is optional but we currently rely on it. + */ + + glGetBooleanv (GL_SHADER_COMPILER, &ret); + if (ret == GL_FALSE) { + GST_ERROR_OBJECT (ctx->element, "Shader compiler support is unavailable!"); + goto HANDLE_ERROR; + } + + /* Build shader program for video texture rendering */ + + switch (format) { + case GST_VIDEO_FORMAT_AYUV: + frag_prog = (gchar *) frag_AYUV_prog; + free_frag_prog = FALSE; + ctx->eglglesctx.n_textures = 1; + texnames[0] = "tex"; + break; + case GST_VIDEO_FORMAT_Y444: + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + case GST_VIDEO_FORMAT_Y42B: + case GST_VIDEO_FORMAT_Y41B: + frag_prog = (gchar *) frag_PLANAR_YUV_prog; + free_frag_prog = FALSE; + ctx->eglglesctx.n_textures = 3; + texnames[0] = "Ytex"; + texnames[1] = "Utex"; + texnames[2] = "Vtex"; + break; + case GST_VIDEO_FORMAT_NV12: + frag_prog = g_strdup_printf (frag_NV12_NV21_prog, 'r', 'a'); + free_frag_prog = TRUE; + ctx->eglglesctx.n_textures = 2; + texnames[0] = "Ytex"; + texnames[1] = "UVtex"; + break; + case GST_VIDEO_FORMAT_NV21: + frag_prog = g_strdup_printf (frag_NV12_NV21_prog, 'a', 'r'); + free_frag_prog = TRUE; + ctx->eglglesctx.n_textures = 2; + texnames[0] = "Ytex"; + texnames[1] = "UVtex"; + break; + case GST_VIDEO_FORMAT_BGR: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_BGRA: + frag_prog = g_strdup_printf (frag_REORDER_prog, 'b', 'g', 'r'); + free_frag_prog = TRUE; + ctx->eglglesctx.n_textures = 1; + texnames[0] = "tex"; + break; + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_ARGB: + frag_prog = g_strdup_printf (frag_REORDER_prog, 'g', 'b', 'a'); + free_frag_prog = TRUE; + ctx->eglglesctx.n_textures = 1; + texnames[0] = "tex"; + break; + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_ABGR: + frag_prog = g_strdup_printf (frag_REORDER_prog, 'a', 'b', 'g'); + free_frag_prog = TRUE; + ctx->eglglesctx.n_textures = 1; + texnames[0] = "tex"; + break; + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_RGB16: + frag_prog = (gchar *) frag_COPY_prog; + free_frag_prog = FALSE; + ctx->eglglesctx.n_textures = 1; + texnames[0] = "tex"; + break; + default: + g_assert_not_reached (); + break; + } + + if (!create_shader_program (ctx, + &ctx->eglglesctx.glslprogram[0], + &ctx->eglglesctx.vertshader[0], + &ctx->eglglesctx.fragshader[0], vert_COPY_prog, frag_prog)) { + if (free_frag_prog) + g_free (frag_prog); + frag_prog = NULL; + goto HANDLE_ERROR; + } + if (free_frag_prog) + g_free (frag_prog); + frag_prog = NULL; + + ctx->eglglesctx.position_loc[0] = + glGetAttribLocation (ctx->eglglesctx.glslprogram[0], "position"); + ctx->eglglesctx.texpos_loc[0] = + glGetAttribLocation (ctx->eglglesctx.glslprogram[0], "texpos"); + ctx->eglglesctx.tex_scale_loc[0][0] = + glGetUniformLocation (ctx->eglglesctx.glslprogram[0], "tex_scale0"); + ctx->eglglesctx.tex_scale_loc[0][1] = + glGetUniformLocation (ctx->eglglesctx.glslprogram[0], "tex_scale1"); + ctx->eglglesctx.tex_scale_loc[0][2] = + glGetUniformLocation (ctx->eglglesctx.glslprogram[0], "tex_scale2"); + + glEnableVertexAttribArray (ctx->eglglesctx.position_loc[0]); + if (got_gl_error ("glEnableVertexAttribArray")) + goto HANDLE_ERROR; + + glEnableVertexAttribArray (ctx->eglglesctx.texpos_loc[0]); + if (got_gl_error ("glEnableVertexAttribArray")) + goto HANDLE_ERROR; + + for (i = 0; i < ctx->eglglesctx.n_textures; i++) { + ctx->eglglesctx.tex_loc[0][i] = + glGetUniformLocation (ctx->eglglesctx.glslprogram[0], texnames[i]); + } + + /* custom rendering shader */ + + if (!create_shader_program (ctx, + &ctx->eglglesctx.glslprogram[2], + &ctx->eglglesctx.vertshader[2], + &ctx->eglglesctx.fragshader[2], vert_COPY_prog, + frag_COPY_DIRECT_prog)) { + if (free_frag_prog) + g_free (frag_prog); + frag_prog = NULL; + goto HANDLE_ERROR; + } + if (free_frag_prog) + g_free (frag_prog); + frag_prog = NULL; + + ctx->eglglesctx.position_loc[2] = + glGetAttribLocation (ctx->eglglesctx.glslprogram[2], "position"); + ctx->eglglesctx.texpos_loc[1] = + glGetAttribLocation (ctx->eglglesctx.glslprogram[2], "texpos"); + + glEnableVertexAttribArray (ctx->eglglesctx.position_loc[2]); + if (got_gl_error ("glEnableVertexAttribArray")) + goto HANDLE_ERROR; + + ctx->eglglesctx.tex_loc[1][0] = + glGetUniformLocation (ctx->eglglesctx.glslprogram[2], "tex"); + + if (!ctx->eglglesctx.buffer_preserved) { + /* Build shader program for black borders */ + if (!create_shader_program (ctx, + &ctx->eglglesctx.glslprogram[1], + &ctx->eglglesctx.vertshader[1], + &ctx->eglglesctx.fragshader[1], vert_COPY_prog_no_tex, + frag_BLACK_prog)) + goto HANDLE_ERROR; + + ctx->eglglesctx.position_loc[1] = + glGetAttribLocation (ctx->eglglesctx.glslprogram[1], "position"); + + glEnableVertexAttribArray (ctx->eglglesctx.position_loc[1]); + if (got_gl_error ("glEnableVertexAttribArray")) + goto HANDLE_ERROR; + } + + /* Generate textures */ + if (!ctx->have_texture) { + GST_INFO_OBJECT (ctx->element, "Performing initial texture setup"); + + glGenTextures (ctx->eglglesctx.n_textures + 1, ctx->eglglesctx.texture); + if (got_gl_error ("glGenTextures")) + goto HANDLE_ERROR_LOCKED; + + for (i = 0; i < ctx->eglglesctx.n_textures + 1; i++) { + glBindTexture (GL_TEXTURE_2D, ctx->eglglesctx.texture[i]); + if (got_gl_error ("glBindTexture")) + goto HANDLE_ERROR; + + /* Set 2D resizing params */ + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + /* If these are not set the texture image unit will return + * (R, G, B, A) = black on glTexImage2D for non-POT width/height + * frames. For a deeper explanation take a look at the OpenGL ES + * documentation for glTexParameter */ + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (got_gl_error ("glTexParameteri")) + goto HANDLE_ERROR_LOCKED; + } + + ctx->have_texture = TRUE; + } + + glUseProgram (0); + + return TRUE; + + /* Errors */ +HANDLE_EGL_ERROR_LOCKED: + GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ()); +HANDLE_ERROR_LOCKED: +HANDLE_ERROR: + GST_ERROR_OBJECT (ctx->element, "Couldn't setup EGL surface"); + return FALSE; +} + +gboolean +gst_egl_adaptation_init_egl_display (GstEglAdaptationContext * ctx) +{ + GstMessage *msg; + EGLDisplay display; + GST_DEBUG_OBJECT (ctx->element, "Enter EGL initial configuration"); + +#ifdef USE_EGL_RPI + /* See https://github.com/raspberrypi/firmware/issues/99 */ + if (!eglMakeCurrent ((EGLDisplay) 1, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT)) { + got_egl_error ("eglMakeCurrent"); + GST_ERROR_OBJECT (ctx->element, "Couldn't unbind context"); + return FALSE; + } +#endif + + msg = gst_message_new_need_context (GST_OBJECT_CAST (ctx->element)); + gst_message_add_context_type (msg, GST_EGL_DISPLAY_CONTEXT_TYPE); + gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg); + + GST_OBJECT_LOCK (ctx->element); + if (ctx->eglglesctx.set_display) { + GstContext *context; + + ctx->eglglesctx.display = gst_egl_display_ref (ctx->eglglesctx.set_display); + GST_OBJECT_UNLOCK (ctx->element); + context = gst_element_get_context (GST_ELEMENT_CAST (ctx->element)); + if (!context) + context = gst_context_new (); + context = gst_context_make_writable (context); + gst_context_set_egl_display (context, ctx->eglglesctx.display); + gst_element_set_context (GST_ELEMENT_CAST (ctx->element), context); + } else { + GstContext *context; + + GST_OBJECT_UNLOCK (ctx->element); + + display = eglGetDisplay (EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + GST_ERROR_OBJECT (ctx->element, "Could not get EGL display connection"); + goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */ + } + ctx->eglglesctx.display = gst_egl_display_new (display); + + context = gst_context_new (); + gst_context_set_egl_display (context, ctx->eglglesctx.display); + + msg = gst_message_new_have_context (GST_OBJECT (ctx->element), context); + gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg); + + context = gst_element_get_context (GST_ELEMENT_CAST (ctx->element)); + if (!context) + context = gst_context_new (); + context = gst_context_make_writable (context); + gst_context_set_egl_display (context, ctx->eglglesctx.display); + gst_element_set_context (GST_ELEMENT_CAST (ctx->element), context); + } + + if (!eglInitialize (gst_egl_display_get (ctx->eglglesctx.display), + &ctx->eglglesctx.egl_major, &ctx->eglglesctx.egl_minor)) { + got_egl_error ("eglInitialize"); + GST_ERROR_OBJECT (ctx->element, "Could not init EGL display connection"); + goto HANDLE_EGL_ERROR; + } + + /* Check against required EGL version + * XXX: Need to review the version requirement in terms of the needed API + */ + if (ctx->eglglesctx.egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) { + GST_ERROR_OBJECT (ctx->element, "EGL v%d needed, but you only have v%d.%d", + GST_EGLGLESSINK_EGL_MIN_VERSION, ctx->eglglesctx.egl_major, + ctx->eglglesctx.egl_minor); + goto HANDLE_ERROR; + } + + GST_INFO_OBJECT (ctx->element, "System reports supported EGL version v%d.%d", + ctx->eglglesctx.egl_major, ctx->eglglesctx.egl_minor); + + eglBindAPI (EGL_OPENGL_ES_API); + + return TRUE; + + /* Errors */ +HANDLE_EGL_ERROR: + GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ()); +HANDLE_ERROR: + GST_ERROR_OBJECT (ctx->element, "Couldn't setup window/surface from handle"); + return FALSE; +} + +gboolean +gst_egl_adaptation_choose_config (GstEglAdaptationContext * ctx) +{ + EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + GLint egl_configs; + + if ((eglChooseConfig (gst_egl_display_get (ctx->eglglesctx.display), + eglglessink_RGBA8888_attribs, + &ctx->eglglesctx.config, 1, &egl_configs)) == EGL_FALSE) { + got_egl_error ("eglChooseConfig"); + GST_ERROR_OBJECT (ctx->element, "eglChooseConfig failed"); + goto HANDLE_EGL_ERROR; + } + + if (egl_configs < 1) { + GST_ERROR_OBJECT (ctx->element, + "Could not find matching framebuffer config"); + goto HANDLE_ERROR; + } + + ctx->eglglesctx.eglcontext = + eglCreateContext (gst_egl_display_get (ctx->eglglesctx.display), + ctx->eglglesctx.config, EGL_NO_CONTEXT, con_attribs); + + if (ctx->eglglesctx.eglcontext == EGL_NO_CONTEXT) { + GST_ERROR_OBJECT (ctx->element, "Error getting context, eglCreateContext"); + goto HANDLE_EGL_ERROR; + } + + GST_DEBUG_OBJECT (ctx->element, "EGL Context: %p", + ctx->eglglesctx.eglcontext); + + return TRUE; + + /* Errors */ +HANDLE_EGL_ERROR: + GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ()); +HANDLE_ERROR: + GST_ERROR_OBJECT (ctx->element, "Couldn't choose an usable config"); + return FALSE; +} + +GstEglAdaptationContext * +gst_egl_adaptation_context_new (GstElement * element) +{ + GstEglAdaptationContext *ctx = g_new0 (GstEglAdaptationContext, 1); + + ctx->element = gst_object_ref (element); + + return ctx; +} + +void +gst_egl_adaptation_context_free (GstEglAdaptationContext * ctx) +{ + gst_object_unref (ctx->element); + g_free (ctx); +} diff --git a/ext/eglgles/gstegladaptation.h b/ext/eglgles/gstegladaptation.h new file mode 100644 index 0000000000..697e800656 --- /dev/null +++ b/ext/eglgles/gstegladaptation.h @@ -0,0 +1,168 @@ +/* + * GStreamer EGL/GLES Sink Adaptation + * Copyright (C) 2012-2013 Collabora Ltd. + * @author: Reynaldo H. Verdejo Pinochet + * @author: Sebastian Dröge + * @author: Thiago Santos + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_EGL_ADAPTATION_H__ +#define __GST_EGL_ADAPTATION_H__ + +#include +#include +#include +#include +#include +#include + +#define GST_EGLGLESSINK_EGL_MIN_VERSION 1 + +G_BEGIN_DECLS + +typedef struct _GstEglAdaptationContext GstEglAdaptationContext; +typedef struct _GstEglGlesRenderContext GstEglGlesRenderContext; +typedef struct _GstEglGlesImageFmt GstEglGlesImageFmt; + +typedef struct _coord5 +{ + float x; + float y; + float z; + float a; /* texpos x */ + float b; /* texpos y */ +} coord5; + +/* + * GstEglGlesRenderContext: + * @config: Current EGL config + * @eglcontext: Current EGL context + * @display: Current EGL display connection + * @window: Current EGL window asociated with the display connection + * @used_window: Last seen EGL window asociated with the display connection + * @surface: EGL surface the sink is rendering into + * @fragshader: Fragment shader + * @vertshader: Vertex shader + * @glslprogram: Compiled and linked GLSL program in use for rendering + * @texture Texture units in use + * @surface_width: Pixel width of the surface the sink is rendering into + * @surface_height: Pixel height of the surface the sink is rendering into + * @pixel_aspect_ratio: EGL display aspect ratio + * @egl_minor: EGL version (minor) + * @egl_major: EGL version (major) + * @n_textures: Texture units count + * @position_loc: Index of the position vertex attribute array + * @texpos_loc: Index of the textpos vertex attribute array + * @position_array: VBO position array + * @texpos_array: VBO texpos array + * @index_array: VBO index array + * @position_buffer: Position buffer object name + * @texpos_buffer: Texpos buffer object name + * @index_buffer: Index buffer object name + * + * This struct holds the sink's EGL/GLES rendering context. + */ +struct _GstEglGlesRenderContext +{ + EGLConfig config; + EGLContext eglcontext; + GstEGLDisplay *display, *set_display; + EGLNativeWindowType window, used_window; + EGLSurface surface; + gboolean buffer_preserved; + GLuint fragshader[3]; /* frame, border, frame-custom */ + GLuint vertshader[3]; /* frame, border, frame-custom */ + GLuint glslprogram[3]; /* frame, border, frame-custom */ + GLuint texture[4]; /* RGB/Y, U/UV, V, custom */ + EGLint surface_width; + EGLint surface_height; + EGLint pixel_aspect_ratio; + EGLint egl_minor, egl_major; + gint n_textures; + + /* shader vars */ + GLuint position_loc[3]; /* frame, border, frame-custom */ + GLuint texpos_loc[2]; /* frame, frame-custom */ + GLuint tex_scale_loc[1][3]; /* [frame] RGB/Y, U/UV, V */ + GLuint tex_loc[2][3]; /* [frame,frame-custom] RGB/Y, U/UV, V */ + coord5 position_array[16]; /* 4 x Frame x-normal,y-normal, 4x Frame x-normal,y-flip, 4 x Border1, 4 x Border2 */ + unsigned short index_array[4]; + unsigned int position_buffer, index_buffer; +}; + +/* + * GstEglAdaptationContext: + * @have_vbo: Set if the GLES VBO setup has been performed + * @have_texture: Set if the GLES texture setup has been performed + * @have_surface: Set if the EGL surface setup has been performed + * + * The #GstEglAdaptationContext data structure. + */ +struct _GstEglAdaptationContext +{ + GstElement *element; + GstEglGlesRenderContext eglglesctx; + + gboolean have_vbo; + gboolean have_texture; + gboolean have_surface; +}; + +GstEglAdaptationContext * gst_egl_adaptation_context_new (GstElement * element); +void gst_egl_adaptation_context_free (GstEglAdaptationContext * ctx); + +GstCaps *gst_egl_adaptation_fill_supported_fbuffer_configs (GstEglAdaptationContext * ctx); +gboolean gst_egl_adaptation_init_egl_display (GstEglAdaptationContext * ctx); +gboolean gst_egl_adaptation_choose_config (GstEglAdaptationContext * ctx); +gboolean gst_egl_adaptation_init_egl_surface (GstEglAdaptationContext * ctx, GstVideoFormat format); +void gst_egl_adaptation_init_egl_exts (GstEglAdaptationContext * ctx); +gboolean gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext * ctx); + +gboolean got_gl_error (const char *wtf); +gboolean got_egl_error (const char *wtf); + +gboolean gst_egl_adaptation_context_make_current (GstEglAdaptationContext * + ctx, gboolean bind); +void gst_egl_adaptation_wipe_eglglesctx (GstEglAdaptationContext * ctx); + +G_END_DECLS + +#endif /* __GST_EGL_ADAPTATION_H__ */ diff --git a/ext/eglgles/gsteglglessink.c b/ext/eglgles/gsteglglessink.c index 961d8bc924..36c67255ec 100644 --- a/ext/eglgles/gsteglglessink.c +++ b/ext/eglgles/gsteglglessink.c @@ -136,216 +136,32 @@ #include "video_platform_wrapper.h" +#include "gstegladaptation.h" #include "gsteglglessink.h" -/* Some EGL implementations are reporting wrong - * values for the display's EGL_PIXEL_ASPECT_RATIO. - * They are required by the khronos specs to report - * this value as w/h * EGL_DISPLAY_SCALING (Which is - * a constant with value 10000) but at least the - * Galaxy SIII (Android) is reporting just 1 when - * w = h. We use these two to bound returned values to - * sanity. - */ -#define EGL_SANE_DAR_MIN ((EGL_DISPLAY_SCALING)/10) -#define EGL_SANE_DAR_MAX ((EGL_DISPLAY_SCALING)*10) - GST_DEBUG_CATEGORY_STATIC (gst_eglglessink_debug); #define GST_CAT_DEFAULT gst_eglglessink_debug GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE); -/* GLESv2 GLSL Shaders - * - * OpenGL ES Standard does not mandate YUV support. This is - * why most of these shaders deal with Packed/Planar YUV->RGB - * conversion. - */ - -/* *INDENT-OFF* */ -/* Direct vertex copy */ -static const char *vert_COPY_prog = { - "attribute vec3 position;" - "attribute vec2 texpos;" - "varying vec2 opos;" - "void main(void)" - "{" - " opos = texpos;" - " gl_Position = vec4(position, 1.0);" - "}" -}; - -static const char *vert_COPY_prog_no_tex = { - "attribute vec3 position;" - "void main(void)" - "{" - " gl_Position = vec4(position, 1.0);" - "}" -}; - -/* Paint all black */ -static const char *frag_BLACK_prog = { - "precision mediump float;" - "void main(void)" - "{" - " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);" - "}" -}; - -/* Direct fragments copy with stride-scaling */ -static const char *frag_COPY_prog = { - "precision mediump float;" - "varying vec2 opos;" - "uniform sampler2D tex;" - "uniform vec2 tex_scale0;" - "uniform vec2 tex_scale1;" - "uniform vec2 tex_scale2;" - "void main(void)" - "{" - " vec4 t = texture2D(tex, opos / tex_scale0);" - " gl_FragColor = vec4(t.rgb, 1.0);" - "}" -}; - -/* Direct fragments copy without stride-scaling */ -static const char *frag_COPY_DIRECT_prog = { - "precision mediump float;" - "varying vec2 opos;" - "uniform sampler2D tex;" - "void main(void)" - "{" - " vec4 t = texture2D(tex, opos);" - " gl_FragColor = vec4(t.rgb, 1.0);" - "}" -}; - -/* Channel reordering for XYZ <-> ZYX conversion */ -static const char *frag_REORDER_prog = { - "precision mediump float;" - "varying vec2 opos;" - "uniform sampler2D tex;" - "uniform vec2 tex_scale0;" - "uniform vec2 tex_scale1;" - "uniform vec2 tex_scale2;" - "void main(void)" - "{" - " vec4 t = texture2D(tex, opos / tex_scale0);" - " gl_FragColor = vec4(t.%c, t.%c, t.%c, 1.0);" - "}" -}; - -/* Packed YUV converters */ - -/** AYUV to RGB conversion */ -static const char *frag_AYUV_prog = { - "precision mediump float;" - "varying vec2 opos;" - "uniform sampler2D tex;" - "uniform vec2 tex_scale0;" - "uniform vec2 tex_scale1;" - "uniform vec2 tex_scale2;" - "const vec3 offset = vec3(-0.0625, -0.5, -0.5);" - "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);" - "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);" - "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);" - "void main(void) {" - " float r,g,b;" - " vec3 yuv;" - " yuv = texture2D(tex,opos / tex_scale0).gba;" - " yuv += offset;" - " r = dot(yuv, rcoeff);" - " g = dot(yuv, gcoeff);" - " b = dot(yuv, bcoeff);" - " gl_FragColor=vec4(r,g,b,1.0);" - "}" -}; - -/* Planar YUV converters */ - -/** YUV to RGB conversion */ -static const char *frag_PLANAR_YUV_prog = { - "precision mediump float;" - "varying vec2 opos;" - "uniform sampler2D Ytex,Utex,Vtex;" - "uniform vec2 tex_scale0;" - "uniform vec2 tex_scale1;" - "uniform vec2 tex_scale2;" - "const vec3 offset = vec3(-0.0625, -0.5, -0.5);" - "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);" - "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);" - "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);" - "void main(void) {" - " float r,g,b;" - " vec3 yuv;" - " yuv.x=texture2D(Ytex,opos / tex_scale0).r;" - " yuv.y=texture2D(Utex,opos / tex_scale1).r;" - " yuv.z=texture2D(Vtex,opos / tex_scale2).r;" - " yuv += offset;" - " r = dot(yuv, rcoeff);" - " g = dot(yuv, gcoeff);" - " b = dot(yuv, bcoeff);" - " gl_FragColor=vec4(r,g,b,1.0);" - "}" -}; - -/** NV12/NV21 to RGB conversion */ -static const char *frag_NV12_NV21_prog = { - "precision mediump float;" - "varying vec2 opos;" - "uniform sampler2D Ytex,UVtex;" - "uniform vec2 tex_scale0;" - "uniform vec2 tex_scale1;" - "uniform vec2 tex_scale2;" - "const vec3 offset = vec3(-0.0625, -0.5, -0.5);" - "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);" - "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);" - "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);" - "void main(void) {" - " float r,g,b;" - " vec3 yuv;" - " yuv.x=texture2D(Ytex,opos / tex_scale0).r;" - " yuv.yz=texture2D(UVtex,opos / tex_scale1).%c%c;" - " yuv += offset;" - " r = dot(yuv, rcoeff);" - " g = dot(yuv, gcoeff);" - " b = dot(yuv, bcoeff);" - " gl_FragColor=vec4(r,g,b,1.0);" - "}" -}; -/* *INDENT-ON* */ - -static const EGLint eglglessink_RGBA8888_attribs[] = { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE -}; - /* Input capabilities. */ static GstStaticPadTemplate gst_eglglessink_sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", + GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, - "{ " - "RGBA, BGRA, ARGB, ABGR, " - "RGBx, BGRx, xRGB, xBGR, " - "AYUV, Y444, I420, YV12, " - "NV12, NV21, Y42B, Y41B, " "RGB, BGR, RGB16 }") ";" - GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, - "{ " - "RGBA, BGRA, ARGB, ABGR, " - "RGBx, BGRx, xRGB, xBGR, " - "AYUV, Y444, I420, YV12, " - "NV12, NV21, Y42B, Y41B, " "RGB, BGR, RGB16 }") ";" - GST_VIDEO_CAPS_MAKE ("{ " - "RGBA, BGRA, ARGB, ABGR, " - "RGBx, BGRx, xRGB, xBGR, " - "AYUV, Y444, I420, YV12, " - "NV12, NV21, Y42B, Y41B, " "RGB, BGR, RGB16 }"))); + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, + "{ " "RGBA, BGRA, ARGB, ABGR, " "RGBx, BGRx, xRGB, xBGR, " + "AYUV, Y444, I420, YV12, " "NV12, NV21, Y42B, Y41B, " + "RGB, BGR, RGB16 }") ";" + GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, + "{ " "RGBA, BGRA, ARGB, ABGR, " "RGBx, BGRx, xRGB, xBGR, " + "AYUV, Y444, I420, YV12, " "NV12, NV21, Y42B, Y41B, " + "RGB, BGR, RGB16 }") ";" GST_VIDEO_CAPS_MAKE ("{ " + "RGBA, BGRA, ARGB, ABGR, " "RGBx, BGRx, xRGB, xBGR, " + "AYUV, Y444, I420, YV12, " "NV12, NV21, Y42B, Y41B, " + "RGB, BGR, RGB16 }"))); /* Filter signals and args */ enum @@ -395,12 +211,6 @@ static void gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay, /* Utility */ static EGLNativeWindowType gst_eglglessink_create_window (GstEglGlesSink * eglglessink, gint width, gint height); -static gboolean gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * - eglglessink); -static gboolean gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink); -static gboolean gst_eglglessink_choose_config (GstEglGlesSink * eglglessink); -static gboolean gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink); -static void gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink); static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset); static gboolean @@ -410,12 +220,7 @@ static GstFlowReturn gst_eglglessink_upload (GstEglGlesSink * sink, static GstFlowReturn gst_eglglessink_render (GstEglGlesSink * sink); static GstFlowReturn gst_eglglessink_queue_object (GstEglGlesSink * sink, GstMiniObject * obj); -static inline gboolean got_gl_error (const char *wtf); -static inline gboolean got_egl_error (const char *wtf); static inline gboolean egl_init (GstEglGlesSink * eglglessink); -static gboolean gst_eglglessink_context_make_current (GstEglGlesSink * - eglglessink, gboolean bind); -static void gst_eglglessink_wipe_eglglesctx (GstEglGlesSink * eglglessink); static GstBuffer *gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, GstVideoFormat format, gint width, gint height); static GstBufferPool *gst_egl_image_buffer_pool_new (GstEglGlesSink * @@ -427,118 +232,34 @@ G_DEFINE_TYPE_WITH_CODE (GstEglGlesSink, gst_eglglessink, GST_TYPE_VIDEO_SINK, gst_eglglessink_videooverlay_init)); -static GstCaps * -_gst_video_format_new_template_caps (GstVideoFormat format) -{ - return gst_caps_new_simple ("video/x-raw", - "format", G_TYPE_STRING, gst_video_format_to_string (format), - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); -} - -static gboolean -gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink) -{ - gboolean ret = FALSE; - EGLint cfg_number; - GstCaps *caps, *copy1, *copy2; - guint i, n; - - GST_DEBUG_OBJECT (eglglessink, - "Building initial list of wanted eglattribs per format"); - - /* Init supported format/caps list */ - caps = gst_caps_new_empty (); - - if (eglChooseConfig (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink_RGBA8888_attribs, NULL, 1, &cfg_number) != EGL_FALSE) { - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBA)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRA)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ARGB)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ABGR)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBx)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRx)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xRGB)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xBGR)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_AYUV)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y444)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGR)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_I420)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YV12)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV12)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV21)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y42B)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y41B)); - gst_caps_append (caps, - _gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB16)); - - copy1 = gst_caps_copy (caps); - copy2 = gst_caps_copy (caps); - - n = gst_caps_get_size (caps); - for (i = 0; i < n; i++) { - GstCapsFeatures *features = gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, NULL); - gst_caps_set_features (caps, i, features); - } - - n = gst_caps_get_size (copy1); - for (i = 0; i < n; i++) { - GstCapsFeatures *features = gst_caps_features_new (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL); - gst_caps_set_features (copy1, i, features); - } - - gst_caps_append (caps, copy1); - gst_caps_append (caps, copy2); - ret = TRUE; - } else { - GST_INFO_OBJECT (eglglessink, - "EGL display doesn't support RGBA8888 config"); - } - - GST_OBJECT_LOCK (eglglessink); - gst_caps_replace (&eglglessink->sinkcaps, caps); - GST_OBJECT_UNLOCK (eglglessink); - gst_caps_unref (caps); - - return ret; -} - static inline gboolean egl_init (GstEglGlesSink * eglglessink) { + GstCaps *caps; + if (!platform_wrapper_init ()) { GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL platform wrapper"); goto HANDLE_ERROR; } - if (!gst_eglglessink_init_egl_display (eglglessink)) { + if (!gst_egl_adaptation_init_egl_display (eglglessink->egl_context)) { GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL display"); goto HANDLE_ERROR; } - if (!gst_eglglessink_fill_supported_fbuffer_configs (eglglessink)) { + gst_egl_adaptation_init_egl_exts (eglglessink->egl_context); + + caps = + gst_egl_adaptation_fill_supported_fbuffer_configs + (eglglessink->egl_context); + if (!caps) { GST_ERROR_OBJECT (eglglessink, "Display support NONE of our configs"); goto HANDLE_ERROR; + } else { + GST_OBJECT_LOCK (eglglessink); + gst_caps_replace (&eglglessink->sinkcaps, caps); + GST_OBJECT_UNLOCK (eglglessink); + gst_caps_unref (caps); } eglglessink->egl_started = TRUE; @@ -655,7 +376,7 @@ render_thread_func (GstEglGlesSink * eglglessink) GST_DEBUG_OBJECT (eglglessink, "Shutting down thread"); /* EGL/GLES cleanup */ - gst_eglglessink_wipe_eglglesctx (eglglessink); + gst_egl_adaptation_wipe_eglglesctx (eglglessink->egl_context); if (eglglessink->configured_caps) { gst_caps_unref (eglglessink->configured_caps); @@ -674,57 +395,6 @@ render_thread_func (GstEglGlesSink * eglglessink) return NULL; } -static void -gst_eglglessink_wipe_eglglesctx (GstEglGlesSink * eglglessink) -{ - gint i; - - glUseProgram (0); - - if (eglglessink->have_vbo) { - glDeleteBuffers (1, &eglglessink->eglglesctx.position_buffer); - glDeleteBuffers (1, &eglglessink->eglglesctx.index_buffer); - eglglessink->have_vbo = FALSE; - } - - if (eglglessink->have_texture) { - glDeleteTextures (eglglessink->eglglesctx.n_textures + 1, - eglglessink->eglglesctx.texture); - eglglessink->have_texture = FALSE; - eglglessink->eglglesctx.n_textures = 0; - } - - for (i = 0; i < 3; i++) { - if (eglglessink->eglglesctx.glslprogram[i]) { - glDetachShader (eglglessink->eglglesctx.glslprogram[i], - eglglessink->eglglesctx.fragshader[i]); - glDetachShader (eglglessink->eglglesctx.glslprogram[i], - eglglessink->eglglesctx.vertshader[i]); - glDeleteProgram (eglglessink->eglglesctx.glslprogram[i]); - glDeleteShader (eglglessink->eglglesctx.fragshader[i]); - glDeleteShader (eglglessink->eglglesctx.vertshader[i]); - eglglessink->eglglesctx.glslprogram[i] = 0; - eglglessink->eglglesctx.fragshader[i] = 0; - eglglessink->eglglesctx.vertshader[i] = 0; - } - } - - gst_eglglessink_context_make_current (eglglessink, FALSE); - - if (eglglessink->eglglesctx.surface) { - eglDestroySurface (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface); - eglglessink->eglglesctx.surface = NULL; - eglglessink->have_surface = FALSE; - } - - if (eglglessink->eglglesctx.eglcontext) { - eglDestroyContext (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.eglcontext); - eglglessink->eglglesctx.eglcontext = NULL; - } -} - static gboolean gst_eglglessink_start (GstEglGlesSink * eglglessink) { @@ -795,12 +465,12 @@ gst_eglglessink_stop (GstEglGlesSink * eglglessink) if (eglglessink->using_own_window) { platform_destroy_native_window (gst_egl_display_get - (eglglessink->eglglesctx.display), eglglessink->eglglesctx.used_window, - &eglglessink->own_window_data); - eglglessink->eglglesctx.used_window = 0; + (eglglessink->eglglesctx->display), + eglglessink->eglglesctx->used_window, &eglglessink->own_window_data); + eglglessink->eglglesctx->used_window = 0; eglglessink->have_window = FALSE; } - eglglessink->eglglesctx.used_window = 0; + eglglessink->eglglesctx->used_window = 0; if (eglglessink->current_caps) { gst_caps_unref (eglglessink->current_caps); eglglessink->current_caps = NULL; @@ -819,32 +489,6 @@ gst_eglglessink_videooverlay_init (GstVideoOverlayInterface * iface) iface->set_render_rectangle = gst_eglglessink_set_render_rectangle; } -static inline gboolean -got_gl_error (const char *wtf) -{ - GLuint error = GL_NO_ERROR; - - if ((error = glGetError ()) != GL_NO_ERROR) { - GST_CAT_ERROR (GST_CAT_DEFAULT, "GL ERROR: %s returned 0x%04x", wtf, error); - return TRUE; - } - return FALSE; -} - -static inline gboolean -got_egl_error (const char *wtf) -{ - EGLint error; - - if ((error = eglGetError ()) != EGL_SUCCESS) { - GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned 0x%04x", wtf, - error); - return TRUE; - } - - return FALSE; -} - static EGLNativeWindowType gst_eglglessink_create_window (GstEglGlesSink * eglglessink, gint width, gint height) @@ -882,28 +526,6 @@ gst_eglglessink_expose (GstVideoOverlay * overlay) GST_ERROR_OBJECT (eglglessink, "Redisplay failed"); } -/* Prints available EGL/GLES extensions - * If another rendering path is implemented this is the place - * where you want to check for the availability of its supporting - * EGL/GLES extensions. - */ -static void -gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink) -{ - const char *eglexts; - unsigned const char *glexts; - - eglexts = - eglQueryString (gst_egl_display_get (eglglessink->eglglesctx.display), - EGL_EXTENSIONS); - glexts = glGetString (GL_EXTENSIONS); - - GST_DEBUG_OBJECT (eglglessink, "Available EGL extensions: %s\n", - GST_STR_NULL (eglexts)); - GST_DEBUG_OBJECT (eglglessink, "Available GLES extensions: %s\n", - GST_STR_NULL ((const char *) glexts)); -} - static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset) { @@ -913,12 +535,12 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset) gdouble tx1, tx2, ty1, ty2; GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d", - eglglessink->have_vbo, reset); + eglglessink->egl_context->have_vbo, reset); - if (eglglessink->have_vbo && reset) { - glDeleteBuffers (1, &eglglessink->eglglesctx.position_buffer); - glDeleteBuffers (1, &eglglessink->eglglesctx.index_buffer); - eglglessink->have_vbo = FALSE; + if (eglglessink->egl_context->have_vbo && reset) { + glDeleteBuffers (1, &eglglessink->eglglesctx->position_buffer); + glDeleteBuffers (1, &eglglessink->eglglesctx->index_buffer); + eglglessink->egl_context->have_vbo = FALSE; } render_width = eglglessink->render_region.w; @@ -942,157 +564,157 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset) ty2 = ((eglglessink->crop.y + eglglessink->crop.h) / texture_height); /* X-normal, Y-normal orientation */ - eglglessink->eglglesctx.position_array[0].x = x2; - eglglessink->eglglesctx.position_array[0].y = y2; - eglglessink->eglglesctx.position_array[0].z = 0; - eglglessink->eglglesctx.position_array[0].a = tx2; - eglglessink->eglglesctx.position_array[0].b = ty1; + eglglessink->eglglesctx->position_array[0].x = x2; + eglglessink->eglglesctx->position_array[0].y = y2; + eglglessink->eglglesctx->position_array[0].z = 0; + eglglessink->eglglesctx->position_array[0].a = tx2; + eglglessink->eglglesctx->position_array[0].b = ty1; - eglglessink->eglglesctx.position_array[1].x = x2; - eglglessink->eglglesctx.position_array[1].y = y1; - eglglessink->eglglesctx.position_array[1].z = 0; - eglglessink->eglglesctx.position_array[1].a = tx2; - eglglessink->eglglesctx.position_array[1].b = ty2; + eglglessink->eglglesctx->position_array[1].x = x2; + eglglessink->eglglesctx->position_array[1].y = y1; + eglglessink->eglglesctx->position_array[1].z = 0; + eglglessink->eglglesctx->position_array[1].a = tx2; + eglglessink->eglglesctx->position_array[1].b = ty2; - eglglessink->eglglesctx.position_array[2].x = x1; - eglglessink->eglglesctx.position_array[2].y = y2; - eglglessink->eglglesctx.position_array[2].z = 0; - eglglessink->eglglesctx.position_array[2].a = tx1; - eglglessink->eglglesctx.position_array[2].b = ty1; + eglglessink->eglglesctx->position_array[2].x = x1; + eglglessink->eglglesctx->position_array[2].y = y2; + eglglessink->eglglesctx->position_array[2].z = 0; + eglglessink->eglglesctx->position_array[2].a = tx1; + eglglessink->eglglesctx->position_array[2].b = ty1; - eglglessink->eglglesctx.position_array[3].x = x1; - eglglessink->eglglesctx.position_array[3].y = y1; - eglglessink->eglglesctx.position_array[3].z = 0; - eglglessink->eglglesctx.position_array[3].a = tx1; - eglglessink->eglglesctx.position_array[3].b = ty2; + eglglessink->eglglesctx->position_array[3].x = x1; + eglglessink->eglglesctx->position_array[3].y = y1; + eglglessink->eglglesctx->position_array[3].z = 0; + eglglessink->eglglesctx->position_array[3].a = tx1; + eglglessink->eglglesctx->position_array[3].b = ty2; /* X-normal, Y-flip orientation */ - eglglessink->eglglesctx.position_array[4 + 0].x = x2; - eglglessink->eglglesctx.position_array[4 + 0].y = y2; - eglglessink->eglglesctx.position_array[4 + 0].z = 0; - eglglessink->eglglesctx.position_array[4 + 0].a = tx2; - eglglessink->eglglesctx.position_array[4 + 0].b = ty2; + eglglessink->eglglesctx->position_array[4 + 0].x = x2; + eglglessink->eglglesctx->position_array[4 + 0].y = y2; + eglglessink->eglglesctx->position_array[4 + 0].z = 0; + eglglessink->eglglesctx->position_array[4 + 0].a = tx2; + eglglessink->eglglesctx->position_array[4 + 0].b = ty2; - eglglessink->eglglesctx.position_array[4 + 1].x = x2; - eglglessink->eglglesctx.position_array[4 + 1].y = y1; - eglglessink->eglglesctx.position_array[4 + 1].z = 0; - eglglessink->eglglesctx.position_array[4 + 1].a = tx2; - eglglessink->eglglesctx.position_array[4 + 1].b = ty1; + eglglessink->eglglesctx->position_array[4 + 1].x = x2; + eglglessink->eglglesctx->position_array[4 + 1].y = y1; + eglglessink->eglglesctx->position_array[4 + 1].z = 0; + eglglessink->eglglesctx->position_array[4 + 1].a = tx2; + eglglessink->eglglesctx->position_array[4 + 1].b = ty1; - eglglessink->eglglesctx.position_array[4 + 2].x = x1; - eglglessink->eglglesctx.position_array[4 + 2].y = y2; - eglglessink->eglglesctx.position_array[4 + 2].z = 0; - eglglessink->eglglesctx.position_array[4 + 2].a = tx1; - eglglessink->eglglesctx.position_array[4 + 2].b = ty2; + eglglessink->eglglesctx->position_array[4 + 2].x = x1; + eglglessink->eglglesctx->position_array[4 + 2].y = y2; + eglglessink->eglglesctx->position_array[4 + 2].z = 0; + eglglessink->eglglesctx->position_array[4 + 2].a = tx1; + eglglessink->eglglesctx->position_array[4 + 2].b = ty2; - eglglessink->eglglesctx.position_array[4 + 3].x = x1; - eglglessink->eglglesctx.position_array[4 + 3].y = y1; - eglglessink->eglglesctx.position_array[4 + 3].z = 0; - eglglessink->eglglesctx.position_array[4 + 3].a = tx1; - eglglessink->eglglesctx.position_array[4 + 3].b = ty1; + eglglessink->eglglesctx->position_array[4 + 3].x = x1; + eglglessink->eglglesctx->position_array[4 + 3].y = y1; + eglglessink->eglglesctx->position_array[4 + 3].z = 0; + eglglessink->eglglesctx->position_array[4 + 3].a = tx1; + eglglessink->eglglesctx->position_array[4 + 3].b = ty1; if (eglglessink->display_region.x == 0) { /* Borders top/bottom */ - eglglessink->eglglesctx.position_array[8 + 0].x = 1; - eglglessink->eglglesctx.position_array[8 + 0].y = 1; - eglglessink->eglglesctx.position_array[8 + 0].z = 0; + eglglessink->eglglesctx->position_array[8 + 0].x = 1; + eglglessink->eglglesctx->position_array[8 + 0].y = 1; + eglglessink->eglglesctx->position_array[8 + 0].z = 0; - eglglessink->eglglesctx.position_array[8 + 1].x = x2; - eglglessink->eglglesctx.position_array[8 + 1].y = y2; - eglglessink->eglglesctx.position_array[8 + 1].z = 0; + eglglessink->eglglesctx->position_array[8 + 1].x = x2; + eglglessink->eglglesctx->position_array[8 + 1].y = y2; + eglglessink->eglglesctx->position_array[8 + 1].z = 0; - eglglessink->eglglesctx.position_array[8 + 2].x = -1; - eglglessink->eglglesctx.position_array[8 + 2].y = 1; - eglglessink->eglglesctx.position_array[8 + 2].z = 0; + eglglessink->eglglesctx->position_array[8 + 2].x = -1; + eglglessink->eglglesctx->position_array[8 + 2].y = 1; + eglglessink->eglglesctx->position_array[8 + 2].z = 0; - eglglessink->eglglesctx.position_array[8 + 3].x = x1; - eglglessink->eglglesctx.position_array[8 + 3].y = y2; - eglglessink->eglglesctx.position_array[8 + 3].z = 0; + eglglessink->eglglesctx->position_array[8 + 3].x = x1; + eglglessink->eglglesctx->position_array[8 + 3].y = y2; + eglglessink->eglglesctx->position_array[8 + 3].z = 0; - eglglessink->eglglesctx.position_array[12 + 0].x = 1; - eglglessink->eglglesctx.position_array[12 + 0].y = y1; - eglglessink->eglglesctx.position_array[12 + 0].z = 0; + eglglessink->eglglesctx->position_array[12 + 0].x = 1; + eglglessink->eglglesctx->position_array[12 + 0].y = y1; + eglglessink->eglglesctx->position_array[12 + 0].z = 0; - eglglessink->eglglesctx.position_array[12 + 1].x = 1; - eglglessink->eglglesctx.position_array[12 + 1].y = -1; - eglglessink->eglglesctx.position_array[12 + 1].z = 0; + eglglessink->eglglesctx->position_array[12 + 1].x = 1; + eglglessink->eglglesctx->position_array[12 + 1].y = -1; + eglglessink->eglglesctx->position_array[12 + 1].z = 0; - eglglessink->eglglesctx.position_array[12 + 2].x = x1; - eglglessink->eglglesctx.position_array[12 + 2].y = y1; - eglglessink->eglglesctx.position_array[12 + 2].z = 0; + eglglessink->eglglesctx->position_array[12 + 2].x = x1; + eglglessink->eglglesctx->position_array[12 + 2].y = y1; + eglglessink->eglglesctx->position_array[12 + 2].z = 0; - eglglessink->eglglesctx.position_array[12 + 3].x = -1; - eglglessink->eglglesctx.position_array[12 + 3].y = -1; - eglglessink->eglglesctx.position_array[12 + 3].z = 0; + eglglessink->eglglesctx->position_array[12 + 3].x = -1; + eglglessink->eglglesctx->position_array[12 + 3].y = -1; + eglglessink->eglglesctx->position_array[12 + 3].z = 0; } else { /* Borders left/right */ - eglglessink->eglglesctx.position_array[8 + 0].x = x1; - eglglessink->eglglesctx.position_array[8 + 0].y = 1; - eglglessink->eglglesctx.position_array[8 + 0].z = 0; + eglglessink->eglglesctx->position_array[8 + 0].x = x1; + eglglessink->eglglesctx->position_array[8 + 0].y = 1; + eglglessink->eglglesctx->position_array[8 + 0].z = 0; - eglglessink->eglglesctx.position_array[8 + 1].x = x1; - eglglessink->eglglesctx.position_array[8 + 1].y = -1; - eglglessink->eglglesctx.position_array[8 + 1].z = 0; + eglglessink->eglglesctx->position_array[8 + 1].x = x1; + eglglessink->eglglesctx->position_array[8 + 1].y = -1; + eglglessink->eglglesctx->position_array[8 + 1].z = 0; - eglglessink->eglglesctx.position_array[8 + 2].x = -1; - eglglessink->eglglesctx.position_array[8 + 2].y = 1; - eglglessink->eglglesctx.position_array[8 + 2].z = 0; + eglglessink->eglglesctx->position_array[8 + 2].x = -1; + eglglessink->eglglesctx->position_array[8 + 2].y = 1; + eglglessink->eglglesctx->position_array[8 + 2].z = 0; - eglglessink->eglglesctx.position_array[8 + 3].x = -1; - eglglessink->eglglesctx.position_array[8 + 3].y = -1; - eglglessink->eglglesctx.position_array[8 + 3].z = 0; + eglglessink->eglglesctx->position_array[8 + 3].x = -1; + eglglessink->eglglesctx->position_array[8 + 3].y = -1; + eglglessink->eglglesctx->position_array[8 + 3].z = 0; - eglglessink->eglglesctx.position_array[12 + 0].x = 1; - eglglessink->eglglesctx.position_array[12 + 0].y = 1; - eglglessink->eglglesctx.position_array[12 + 0].z = 0; + eglglessink->eglglesctx->position_array[12 + 0].x = 1; + eglglessink->eglglesctx->position_array[12 + 0].y = 1; + eglglessink->eglglesctx->position_array[12 + 0].z = 0; - eglglessink->eglglesctx.position_array[12 + 1].x = 1; - eglglessink->eglglesctx.position_array[12 + 1].y = -1; - eglglessink->eglglesctx.position_array[12 + 1].z = 0; + eglglessink->eglglesctx->position_array[12 + 1].x = 1; + eglglessink->eglglesctx->position_array[12 + 1].y = -1; + eglglessink->eglglesctx->position_array[12 + 1].z = 0; - eglglessink->eglglesctx.position_array[12 + 2].x = x2; - eglglessink->eglglesctx.position_array[12 + 2].y = y2; - eglglessink->eglglesctx.position_array[12 + 2].z = 0; + eglglessink->eglglesctx->position_array[12 + 2].x = x2; + eglglessink->eglglesctx->position_array[12 + 2].y = y2; + eglglessink->eglglesctx->position_array[12 + 2].z = 0; - eglglessink->eglglesctx.position_array[12 + 3].x = x2; - eglglessink->eglglesctx.position_array[12 + 3].y = -1; - eglglessink->eglglesctx.position_array[12 + 3].z = 0; + eglglessink->eglglesctx->position_array[12 + 3].x = x2; + eglglessink->eglglesctx->position_array[12 + 3].y = -1; + eglglessink->eglglesctx->position_array[12 + 3].z = 0; } - eglglessink->eglglesctx.index_array[0] = 0; - eglglessink->eglglesctx.index_array[1] = 1; - eglglessink->eglglesctx.index_array[2] = 2; - eglglessink->eglglesctx.index_array[3] = 3; + eglglessink->eglglesctx->index_array[0] = 0; + eglglessink->eglglesctx->index_array[1] = 1; + eglglessink->eglglesctx->index_array[2] = 2; + eglglessink->eglglesctx->index_array[3] = 3; - glGenBuffers (1, &eglglessink->eglglesctx.position_buffer); - glGenBuffers (1, &eglglessink->eglglesctx.index_buffer); + glGenBuffers (1, &eglglessink->eglglesctx->position_buffer); + glGenBuffers (1, &eglglessink->eglglesctx->index_buffer); if (got_gl_error ("glGenBuffers")) goto HANDLE_ERROR_LOCKED; - glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx.position_buffer); + glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx->position_buffer); if (got_gl_error ("glBindBuffer position_buffer")) goto HANDLE_ERROR_LOCKED; glBufferData (GL_ARRAY_BUFFER, - sizeof (eglglessink->eglglesctx.position_array), - eglglessink->eglglesctx.position_array, GL_STATIC_DRAW); + sizeof (eglglessink->eglglesctx->position_array), + eglglessink->eglglesctx->position_array, GL_STATIC_DRAW); if (got_gl_error ("glBufferData position_buffer")) goto HANDLE_ERROR_LOCKED; - glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, eglglessink->eglglesctx.index_buffer); + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, eglglessink->eglglesctx->index_buffer); if (got_gl_error ("glBindBuffer index_buffer")) goto HANDLE_ERROR_LOCKED; glBufferData (GL_ELEMENT_ARRAY_BUFFER, - sizeof (eglglessink->eglglesctx.index_array), - eglglessink->eglglesctx.index_array, GL_STATIC_DRAW); + sizeof (eglglessink->eglglesctx->index_array), + eglglessink->eglglesctx->index_array, GL_STATIC_DRAW); if (got_gl_error ("glBufferData index_buffer")) goto HANDLE_ERROR_LOCKED; - eglglessink->have_vbo = TRUE; + eglglessink->egl_context->have_vbo = TRUE; GST_DEBUG_OBJECT (eglglessink, "VBO setup done"); return TRUE; @@ -1102,587 +724,6 @@ HANDLE_ERROR_LOCKED: return FALSE; } -/* XXX: Lock eglgles context? */ -static gboolean -gst_eglglessink_update_surface_dimensions (GstEglGlesSink * eglglessink) -{ - gint width, height; - - /* Save surface dims */ - eglQuerySurface (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface, EGL_WIDTH, &width); - eglQuerySurface (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface, EGL_HEIGHT, &height); - - if (width != eglglessink->eglglesctx.surface_width || - height != eglglessink->eglglesctx.surface_height) { - eglglessink->eglglesctx.surface_width = width; - eglglessink->eglglesctx.surface_height = height; - GST_INFO_OBJECT (eglglessink, "Got surface of %dx%d pixels", width, height); - return TRUE; - } - - return FALSE; -} - -static gboolean -gst_eglglessink_context_make_current (GstEglGlesSink * eglglessink, - gboolean bind) -{ - g_assert (eglglessink->eglglesctx.display != NULL); - - if (bind && eglglessink->eglglesctx.surface && - eglglessink->eglglesctx.eglcontext) { - EGLContext *ctx = eglGetCurrentContext (); - - if (ctx == eglglessink->eglglesctx.eglcontext) { - GST_DEBUG_OBJECT (eglglessink, - "Already attached the context to thread %p", g_thread_self ()); - return TRUE; - } - - GST_DEBUG_OBJECT (eglglessink, "Attaching context to thread %p", - g_thread_self ()); - if (!eglMakeCurrent (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface, eglglessink->eglglesctx.surface, - eglglessink->eglglesctx.eglcontext)) { - got_egl_error ("eglMakeCurrent"); - GST_ERROR_OBJECT (eglglessink, "Couldn't bind context"); - return FALSE; - } - } else { - GST_DEBUG_OBJECT (eglglessink, "Detaching context from thread %p", - g_thread_self ()); - if (!eglMakeCurrent (gst_egl_display_get (eglglessink->eglglesctx.display), - EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) { - got_egl_error ("eglMakeCurrent"); - GST_ERROR_OBJECT (eglglessink, "Couldn't unbind context"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -create_shader_program (GstEglGlesSink * eglglessink, GLuint * prog, - GLuint * vert, GLuint * frag, const gchar * vert_text, - const gchar * frag_text) -{ - GLint test; - GLchar *info_log; - - /* Build shader program for video texture rendering */ - *vert = glCreateShader (GL_VERTEX_SHADER); - GST_DEBUG_OBJECT (eglglessink, "Sending %s to handle %d", vert_text, *vert); - glShaderSource (*vert, 1, &vert_text, NULL); - if (got_gl_error ("glShaderSource vertex")) - goto HANDLE_ERROR; - - glCompileShader (*vert); - if (got_gl_error ("glCompileShader vertex")) - goto HANDLE_ERROR; - - glGetShaderiv (*vert, GL_COMPILE_STATUS, &test); - if (test != GL_FALSE) - GST_DEBUG_OBJECT (eglglessink, "Successfully compiled vertex shader"); - else { - GST_ERROR_OBJECT (eglglessink, "Couldn't compile vertex shader"); - glGetShaderiv (*vert, GL_INFO_LOG_LENGTH, &test); - info_log = g_new0 (GLchar, test); - glGetShaderInfoLog (*vert, test, NULL, info_log); - GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log); - g_free (info_log); - goto HANDLE_ERROR; - } - - *frag = glCreateShader (GL_FRAGMENT_SHADER); - GST_DEBUG_OBJECT (eglglessink, "Sending %s to handle %d", frag_text, *frag); - glShaderSource (*frag, 1, &frag_text, NULL); - if (got_gl_error ("glShaderSource fragment")) - goto HANDLE_ERROR; - - glCompileShader (*frag); - if (got_gl_error ("glCompileShader fragment")) - goto HANDLE_ERROR; - - glGetShaderiv (*frag, GL_COMPILE_STATUS, &test); - if (test != GL_FALSE) - GST_DEBUG_OBJECT (eglglessink, "Successfully compiled fragment shader"); - else { - GST_ERROR_OBJECT (eglglessink, "Couldn't compile fragment shader"); - glGetShaderiv (*frag, GL_INFO_LOG_LENGTH, &test); - info_log = g_new0 (GLchar, test); - glGetShaderInfoLog (*frag, test, NULL, info_log); - GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log); - g_free (info_log); - goto HANDLE_ERROR; - } - - *prog = glCreateProgram (); - if (got_gl_error ("glCreateProgram")) - goto HANDLE_ERROR; - glAttachShader (*prog, *vert); - if (got_gl_error ("glAttachShader vertices")) - goto HANDLE_ERROR; - glAttachShader (*prog, *frag); - if (got_gl_error ("glAttachShader fragments")) - goto HANDLE_ERROR; - glLinkProgram (*prog); - glGetProgramiv (*prog, GL_LINK_STATUS, &test); - if (test != GL_FALSE) { - GST_DEBUG_OBJECT (eglglessink, "GLES: Successfully linked program"); - } else { - GST_ERROR_OBJECT (eglglessink, "Couldn't link program"); - goto HANDLE_ERROR; - } - - return TRUE; - -HANDLE_ERROR: - { - if (*frag && *prog) - glDetachShader (*prog, *frag); - if (*vert && *prog) - glDetachShader (*prog, *vert); - if (*prog) - glDeleteProgram (*prog); - if (*frag) - glDeleteShader (*frag); - if (*vert) - glDeleteShader (*vert); - *prog = 0; - *frag = 0; - *vert = 0; - - return FALSE; - } -} - -static gboolean -gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink) -{ - GLboolean ret; - EGLint display_par; - const gchar *texnames[3] = { NULL, }; - gchar *frag_prog = NULL; - gboolean free_frag_prog = FALSE; - EGLint swap_behavior; - gint i; - - GST_DEBUG_OBJECT (eglglessink, "Enter EGL surface setup"); - - eglglessink->eglglesctx.surface = - eglCreateWindowSurface (gst_egl_display_get (eglglessink-> - eglglesctx.display), eglglessink->eglglesctx.config, - eglglessink->eglglesctx.used_window, NULL); - - if (eglglessink->eglglesctx.surface == EGL_NO_SURFACE) { - got_egl_error ("eglCreateWindowSurface"); - GST_ERROR_OBJECT (eglglessink, "Can't create surface"); - goto HANDLE_EGL_ERROR_LOCKED; - } - - eglglessink->eglglesctx.buffer_preserved = FALSE; - if (eglQuerySurface (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface, EGL_SWAP_BEHAVIOR, &swap_behavior)) { - GST_DEBUG_OBJECT (eglglessink, "Buffer swap behavior %x", swap_behavior); - eglglessink->eglglesctx.buffer_preserved = - swap_behavior == EGL_BUFFER_PRESERVED; - } else { - GST_DEBUG_OBJECT (eglglessink, "Can't query buffer swap behavior"); - } - - if (!gst_eglglessink_context_make_current (eglglessink, TRUE)) - goto HANDLE_EGL_ERROR_LOCKED; - - gst_eglglessink_init_egl_exts (eglglessink); - - /* Save display's pixel aspect ratio - * - * DAR is reported as w/h * EGL_DISPLAY_SCALING wich is - * a constant with value 10000. This attribute is only - * supported if the EGL version is >= 1.2 - * XXX: Setup this as a property. - * or some other one time check. Right now it's being called once - * per frame. - */ - if (eglglessink->eglglesctx.egl_major == 1 && - eglglessink->eglglesctx.egl_minor < 2) { - GST_DEBUG_OBJECT (eglglessink, "Can't query PAR. Using default: %dx%d", - EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING); - eglglessink->eglglesctx.pixel_aspect_ratio = EGL_DISPLAY_SCALING; - } else { - eglQuerySurface (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface, EGL_PIXEL_ASPECT_RATIO, &display_par); - /* Fix for outbound DAR reporting on some implementations not - * honoring the 'should return w/h * EGL_DISPLAY_SCALING' spec - * requirement - */ - if (display_par == EGL_UNKNOWN || display_par < EGL_SANE_DAR_MIN || - display_par > EGL_SANE_DAR_MAX) { - GST_DEBUG_OBJECT (eglglessink, "Nonsensical PAR value returned: %d. " - "Bad EGL implementation? " - "Will use default: %d/%d", eglglessink->eglglesctx.pixel_aspect_ratio, - EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING); - eglglessink->eglglesctx.pixel_aspect_ratio = EGL_DISPLAY_SCALING; - } else { - eglglessink->eglglesctx.pixel_aspect_ratio = display_par; - } - } - - /* Save surface dims */ - gst_eglglessink_update_surface_dimensions (eglglessink); - - /* We have a surface! */ - eglglessink->have_surface = TRUE; - - /* Init vertex and fragment GLSL shaders. - * Note: Shader compiler support is optional but we currently rely on it. - */ - - glGetBooleanv (GL_SHADER_COMPILER, &ret); - if (ret == GL_FALSE) { - GST_ERROR_OBJECT (eglglessink, "Shader compiler support is unavailable!"); - goto HANDLE_ERROR; - } - - /* Build shader program for video texture rendering */ - - switch (eglglessink->configured_info.finfo->format) { - case GST_VIDEO_FORMAT_AYUV: - frag_prog = (gchar *) frag_AYUV_prog; - free_frag_prog = FALSE; - eglglessink->eglglesctx.n_textures = 1; - texnames[0] = "tex"; - break; - case GST_VIDEO_FORMAT_Y444: - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - case GST_VIDEO_FORMAT_Y42B: - case GST_VIDEO_FORMAT_Y41B: - frag_prog = (gchar *) frag_PLANAR_YUV_prog; - free_frag_prog = FALSE; - eglglessink->eglglesctx.n_textures = 3; - texnames[0] = "Ytex"; - texnames[1] = "Utex"; - texnames[2] = "Vtex"; - break; - case GST_VIDEO_FORMAT_NV12: - frag_prog = g_strdup_printf (frag_NV12_NV21_prog, 'r', 'a'); - free_frag_prog = TRUE; - eglglessink->eglglesctx.n_textures = 2; - texnames[0] = "Ytex"; - texnames[1] = "UVtex"; - break; - case GST_VIDEO_FORMAT_NV21: - frag_prog = g_strdup_printf (frag_NV12_NV21_prog, 'a', 'r'); - free_frag_prog = TRUE; - eglglessink->eglglesctx.n_textures = 2; - texnames[0] = "Ytex"; - texnames[1] = "UVtex"; - break; - case GST_VIDEO_FORMAT_BGR: - case GST_VIDEO_FORMAT_BGRx: - case GST_VIDEO_FORMAT_BGRA: - frag_prog = g_strdup_printf (frag_REORDER_prog, 'b', 'g', 'r'); - free_frag_prog = TRUE; - eglglessink->eglglesctx.n_textures = 1; - texnames[0] = "tex"; - break; - case GST_VIDEO_FORMAT_xRGB: - case GST_VIDEO_FORMAT_ARGB: - frag_prog = g_strdup_printf (frag_REORDER_prog, 'g', 'b', 'a'); - free_frag_prog = TRUE; - eglglessink->eglglesctx.n_textures = 1; - texnames[0] = "tex"; - break; - case GST_VIDEO_FORMAT_xBGR: - case GST_VIDEO_FORMAT_ABGR: - frag_prog = g_strdup_printf (frag_REORDER_prog, 'a', 'b', 'g'); - free_frag_prog = TRUE; - eglglessink->eglglesctx.n_textures = 1; - texnames[0] = "tex"; - break; - case GST_VIDEO_FORMAT_RGB: - case GST_VIDEO_FORMAT_RGBx: - case GST_VIDEO_FORMAT_RGBA: - case GST_VIDEO_FORMAT_RGB16: - frag_prog = (gchar *) frag_COPY_prog; - free_frag_prog = FALSE; - eglglessink->eglglesctx.n_textures = 1; - texnames[0] = "tex"; - break; - default: - g_assert_not_reached (); - break; - } - - if (!create_shader_program (eglglessink, - &eglglessink->eglglesctx.glslprogram[0], - &eglglessink->eglglesctx.vertshader[0], - &eglglessink->eglglesctx.fragshader[0], vert_COPY_prog, frag_prog)) { - if (free_frag_prog) - g_free (frag_prog); - frag_prog = NULL; - goto HANDLE_ERROR; - } - if (free_frag_prog) - g_free (frag_prog); - frag_prog = NULL; - - eglglessink->eglglesctx.position_loc[0] = - glGetAttribLocation (eglglessink->eglglesctx.glslprogram[0], "position"); - eglglessink->eglglesctx.texpos_loc[0] = - glGetAttribLocation (eglglessink->eglglesctx.glslprogram[0], "texpos"); - eglglessink->eglglesctx.tex_scale_loc[0][0] = - glGetUniformLocation (eglglessink->eglglesctx.glslprogram[0], - "tex_scale0"); - eglglessink->eglglesctx.tex_scale_loc[0][1] = - glGetUniformLocation (eglglessink->eglglesctx.glslprogram[0], - "tex_scale1"); - eglglessink->eglglesctx.tex_scale_loc[0][2] = - glGetUniformLocation (eglglessink->eglglesctx.glslprogram[0], - "tex_scale2"); - - glEnableVertexAttribArray (eglglessink->eglglesctx.position_loc[0]); - if (got_gl_error ("glEnableVertexAttribArray")) - goto HANDLE_ERROR; - - glEnableVertexAttribArray (eglglessink->eglglesctx.texpos_loc[0]); - if (got_gl_error ("glEnableVertexAttribArray")) - goto HANDLE_ERROR; - - for (i = 0; i < eglglessink->eglglesctx.n_textures; i++) { - eglglessink->eglglesctx.tex_loc[0][i] = - glGetUniformLocation (eglglessink->eglglesctx.glslprogram[0], - texnames[i]); - } - - /* custom rendering shader */ - - if (!create_shader_program (eglglessink, - &eglglessink->eglglesctx.glslprogram[2], - &eglglessink->eglglesctx.vertshader[2], - &eglglessink->eglglesctx.fragshader[2], vert_COPY_prog, - frag_COPY_DIRECT_prog)) { - if (free_frag_prog) - g_free (frag_prog); - frag_prog = NULL; - goto HANDLE_ERROR; - } - if (free_frag_prog) - g_free (frag_prog); - frag_prog = NULL; - - eglglessink->eglglesctx.position_loc[2] = - glGetAttribLocation (eglglessink->eglglesctx.glslprogram[2], "position"); - eglglessink->eglglesctx.texpos_loc[1] = - glGetAttribLocation (eglglessink->eglglesctx.glslprogram[2], "texpos"); - - glEnableVertexAttribArray (eglglessink->eglglesctx.position_loc[2]); - if (got_gl_error ("glEnableVertexAttribArray")) - goto HANDLE_ERROR; - - eglglessink->eglglesctx.tex_loc[1][0] = - glGetUniformLocation (eglglessink->eglglesctx.glslprogram[2], "tex"); - - if (!eglglessink->eglglesctx.buffer_preserved) { - /* Build shader program for black borders */ - if (!create_shader_program (eglglessink, - &eglglessink->eglglesctx.glslprogram[1], - &eglglessink->eglglesctx.vertshader[1], - &eglglessink->eglglesctx.fragshader[1], vert_COPY_prog_no_tex, - frag_BLACK_prog)) - goto HANDLE_ERROR; - - eglglessink->eglglesctx.position_loc[1] = - glGetAttribLocation (eglglessink->eglglesctx.glslprogram[1], - "position"); - - glEnableVertexAttribArray (eglglessink->eglglesctx.position_loc[1]); - if (got_gl_error ("glEnableVertexAttribArray")) - goto HANDLE_ERROR; - } - - /* Generate textures */ - if (!eglglessink->have_texture) { - GST_INFO_OBJECT (eglglessink, "Performing initial texture setup"); - - glGenTextures (eglglessink->eglglesctx.n_textures+1, - eglglessink->eglglesctx.texture); - if (got_gl_error ("glGenTextures")) - goto HANDLE_ERROR_LOCKED; - - for (i = 0; i < eglglessink->eglglesctx.n_textures+1; i++) { - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[i]); - if (got_gl_error ("glBindTexture")) - goto HANDLE_ERROR; - - /* Set 2D resizing params */ - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - /* If these are not set the texture image unit will return - * (R, G, B, A) = black on glTexImage2D for non-POT width/height - * frames. For a deeper explanation take a look at the OpenGL ES - * documentation for glTexParameter */ - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (got_gl_error ("glTexParameteri")) - goto HANDLE_ERROR_LOCKED; - } - - eglglessink->have_texture = TRUE; - } - - glUseProgram (0); - - return TRUE; - - /* Errors */ -HANDLE_EGL_ERROR_LOCKED: - GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ()); -HANDLE_ERROR_LOCKED: -HANDLE_ERROR: - GST_ERROR_OBJECT (eglglessink, "Couldn't setup EGL surface"); - return FALSE; -} - -static gboolean -gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink) -{ - GstMessage *msg; - EGLDisplay display; - GST_DEBUG_OBJECT (eglglessink, "Enter EGL initial configuration"); - -#ifdef USE_EGL_RPI - /* See https://github.com/raspberrypi/firmware/issues/99 */ - if (!eglMakeCurrent ((EGLDisplay) 1, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT)) { - got_egl_error ("eglMakeCurrent"); - GST_ERROR_OBJECT (eglglessink, "Couldn't unbind context"); - return FALSE; - } -#endif - - msg = gst_message_new_need_context (GST_OBJECT_CAST (eglglessink)); - gst_message_add_context_type (msg, GST_EGL_DISPLAY_CONTEXT_TYPE); - gst_element_post_message (GST_ELEMENT_CAST (eglglessink), msg); - - GST_OBJECT_LOCK (eglglessink); - if (eglglessink->eglglesctx.set_display) { - GstContext * context; - - eglglessink->eglglesctx.display = - gst_egl_display_ref (eglglessink->eglglesctx.set_display); - GST_OBJECT_UNLOCK (eglglessink); - context = gst_element_get_context (GST_ELEMENT_CAST (eglglessink)); - if (!context) - context = gst_context_new (); - context = gst_context_make_writable (context); - gst_context_set_egl_display (context, eglglessink->eglglesctx.display); - gst_element_set_context (GST_ELEMENT_CAST (eglglessink), context); - } else { - GstContext *context; - - GST_OBJECT_UNLOCK (eglglessink); - - display = eglGetDisplay (EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) { - GST_ERROR_OBJECT (eglglessink, "Could not get EGL display connection"); - goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */ - } - eglglessink->eglglesctx.display = gst_egl_display_new (display); - - context = gst_context_new (); - gst_context_set_egl_display (context, eglglessink->eglglesctx.display); - - msg = gst_message_new_have_context (GST_OBJECT (eglglessink), context); - gst_element_post_message (GST_ELEMENT_CAST (eglglessink), msg); - - context = gst_element_get_context (GST_ELEMENT_CAST (eglglessink)); - if (!context) - context = gst_context_new (); - context = gst_context_make_writable (context); - gst_context_set_egl_display (context, eglglessink->eglglesctx.display); - gst_element_set_context (GST_ELEMENT_CAST (eglglessink), context); - } - - if (!eglInitialize (gst_egl_display_get (eglglessink->eglglesctx.display), - &eglglessink->eglglesctx.egl_major, - &eglglessink->eglglesctx.egl_minor)) { - got_egl_error ("eglInitialize"); - GST_ERROR_OBJECT (eglglessink, "Could not init EGL display connection"); - goto HANDLE_EGL_ERROR; - } - - /* Check against required EGL version - * XXX: Need to review the version requirement in terms of the needed API - */ - if (eglglessink->eglglesctx.egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) { - GST_ERROR_OBJECT (eglglessink, "EGL v%d needed, but you only have v%d.%d", - GST_EGLGLESSINK_EGL_MIN_VERSION, eglglessink->eglglesctx.egl_major, - eglglessink->eglglesctx.egl_minor); - goto HANDLE_ERROR; - } - - GST_INFO_OBJECT (eglglessink, "System reports supported EGL version v%d.%d", - eglglessink->eglglesctx.egl_major, eglglessink->eglglesctx.egl_minor); - - eglBindAPI (EGL_OPENGL_ES_API); - - return TRUE; - - /* Errors */ -HANDLE_EGL_ERROR: - GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ()); -HANDLE_ERROR: - GST_ERROR_OBJECT (eglglessink, "Couldn't setup window/surface from handle"); - return FALSE; -} - -static gboolean -gst_eglglessink_choose_config (GstEglGlesSink * eglglessink) -{ - EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - GLint egl_configs; - - if ((eglChooseConfig (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink_RGBA8888_attribs, - &eglglessink->eglglesctx.config, 1, &egl_configs)) == EGL_FALSE) { - got_egl_error ("eglChooseConfig"); - GST_ERROR_OBJECT (eglglessink, "eglChooseConfig failed"); - goto HANDLE_EGL_ERROR; - } - - if (egl_configs < 1) { - GST_ERROR_OBJECT (eglglessink, - "Could not find matching framebuffer config"); - goto HANDLE_ERROR; - } - - eglglessink->eglglesctx.eglcontext = - eglCreateContext (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.config, EGL_NO_CONTEXT, con_attribs); - - if (eglglessink->eglglesctx.eglcontext == EGL_NO_CONTEXT) { - GST_ERROR_OBJECT (eglglessink, "Error getting context, eglCreateContext"); - goto HANDLE_EGL_ERROR; - } - - GST_DEBUG_OBJECT (eglglessink, "EGL Context: %p", - eglglessink->eglglesctx.eglcontext); - - return TRUE; - - /* Errors */ -HANDLE_EGL_ERROR: - GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ()); -HANDLE_ERROR: - GST_ERROR_OBJECT (eglglessink, "Couldn't choose an usable config"); - return FALSE; -} - static void gst_eglglessink_set_window_handle (GstVideoOverlay * overlay, guintptr id) { @@ -1693,7 +734,7 @@ gst_eglglessink_set_window_handle (GstVideoOverlay * overlay, guintptr id) /* OK, we have a new window */ GST_OBJECT_LOCK (eglglessink); - eglglessink->eglglesctx.window = (EGLNativeWindowType) id; + eglglessink->eglglesctx->window = (EGLNativeWindowType) id; eglglessink->have_window = ((gpointer) id != NULL); GST_OBJECT_UNLOCK (eglglessink); @@ -1811,7 +852,8 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) h = GST_VIDEO_FRAME_HEIGHT (&vframe); GST_DEBUG_OBJECT (eglglessink, - "Got buffer %p: %dx%d size %" G_GSIZE_FORMAT, buf, w, h, gst_buffer_get_size (buf)); + "Got buffer %p: %dx%d size %" G_GSIZE_FORMAT, buf, w, h, + gst_buffer_get_size (buf)); switch (eglglessink->configured_info.finfo->format) { case GST_VIDEO_FORMAT_BGR: @@ -1854,7 +896,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, stride_width, h, 0, GL_RGB, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0)); break; @@ -1894,7 +936,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, stride_width, h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0)); break; @@ -1937,7 +979,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, stride_width, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0)); break; @@ -1973,7 +1015,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, stride_width, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0)); break; @@ -2021,7 +1063,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, stride_width, GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0), @@ -2063,7 +1105,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[1] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[1]); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, stride_width, GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 1), @@ -2105,7 +1147,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[2] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[2]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[2]); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, stride_width, GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 2), @@ -2153,7 +1195,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, stride_width, GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0), @@ -2191,7 +1233,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf) eglglessink->stride[1] = ((gdouble) stride_width) / ((gdouble) c_w); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[1]); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, stride_width, GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 1), @@ -2253,10 +1295,11 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf) if (upload_meta) { glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, - eglglessink->eglglesctx.texture[eglglessink->eglglesctx.n_textures]); + eglglessink->eglglesctx->texture[eglglessink->eglglesctx-> + n_textures]); if (!gst_video_gl_texture_upload_meta_upload (upload_meta, GL_RGBA, - eglglessink->eglglesctx.texture[eglglessink-> - eglglesctx.n_textures])) + eglglessink->eglglesctx->texture[eglglessink->eglglesctx-> + n_textures])) goto HANDLE_ERROR; eglglessink->orientation = GST_EGL_IMAGE_ORIENTATION_X_NORMAL_Y_NORMAL; @@ -2282,7 +1325,7 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf) else if (i == 2) glActiveTexture (GL_TEXTURE2); - glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[i]); + glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[i]); glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, gst_egl_image_memory_get_image (mem)); if (got_gl_error ("glEGLImageTargetTexture2DOES")) @@ -2331,7 +1374,7 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) * calling party explicitly ask us not to by setting * force_aspect_ratio to FALSE. */ - if (gst_eglglessink_update_surface_dimensions (eglglessink) || + if (gst_egl_adaptation_update_surface_dimensions (eglglessink->egl_context) || eglglessink->render_region_changed || !eglglessink->display_region.w || !eglglessink->display_region.h || eglglessink->crop_changed) { @@ -2340,8 +1383,8 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) if (!eglglessink->render_region_user) { eglglessink->render_region.x = 0; eglglessink->render_region.y = 0; - eglglessink->render_region.w = eglglessink->eglglesctx.surface_width; - eglglessink->render_region.h = eglglessink->eglglesctx.surface_height; + eglglessink->render_region.w = eglglessink->eglglesctx->surface_width; + eglglessink->render_region.h = eglglessink->eglglesctx->surface_height; } eglglessink->render_region_changed = FALSE; eglglessink->crop_changed = FALSE; @@ -2361,7 +1404,7 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) eglglessink->crop.w, eglglessink->crop.h, eglglessink->configured_info.par_n, eglglessink->configured_info.par_d, - eglglessink->eglglesctx.pixel_aspect_ratio, + eglglessink->eglglesctx->pixel_aspect_ratio, EGL_DISPLAY_SCALING)) { GST_WARNING_OBJECT (eglglessink, "Could not compute resulting DAR"); frame.w = eglglessink->crop.w; @@ -2395,13 +1438,13 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) } glViewport (eglglessink->render_region.x, - eglglessink->eglglesctx.surface_height - + eglglessink->eglglesctx->surface_height - eglglessink->render_region.y - eglglessink->render_region.h, eglglessink->render_region.w, eglglessink->render_region.h); /* Clear the surface once if its content is preserved */ - if (eglglessink->eglglesctx.buffer_preserved) { + if (eglglessink->eglglesctx->buffer_preserved) { glClearColor (0.0, 0.0, 0.0, 1.0); glClear (GL_COLOR_BUFFER_BIT); } @@ -2414,12 +1457,12 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) GST_OBJECT_UNLOCK (eglglessink); } - if (!eglglessink->eglglesctx.buffer_preserved) { + if (!eglglessink->eglglesctx->buffer_preserved) { /* Draw black borders */ GST_DEBUG_OBJECT (eglglessink, "Drawing black border 1"); - glUseProgram (eglglessink->eglglesctx.glslprogram[1]); + glUseProgram (eglglessink->eglglesctx->glslprogram[1]); - glVertexAttribPointer (eglglessink->eglglesctx.position_loc[1], 3, + glVertexAttribPointer (eglglessink->eglglesctx->position_loc[1], 3, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (8 * sizeof (coord5))); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; @@ -2430,7 +1473,7 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) GST_DEBUG_OBJECT (eglglessink, "Drawing black border 2"); - glVertexAttribPointer (eglglessink->eglglesctx.position_loc[1], 3, + glVertexAttribPointer (eglglessink->eglglesctx->position_loc[1], 3, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (12 * sizeof (coord5))); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; @@ -2444,58 +1487,58 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) GST_DEBUG_OBJECT (eglglessink, "Drawing video frame"); if (eglglessink->custom_format) { - glUseProgram (eglglessink->eglglesctx.glslprogram[2]); + glUseProgram (eglglessink->eglglesctx->glslprogram[2]); - glUniform1i (eglglessink->eglglesctx.tex_loc[1][0], 0); + glUniform1i (eglglessink->eglglesctx->tex_loc[1][0], 0); if (got_gl_error ("glUniform1i")) goto HANDLE_ERROR; - glVertexAttribPointer (eglglessink->eglglesctx.position_loc[2], 3, + glVertexAttribPointer (eglglessink->eglglesctx->position_loc[2], 3, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (0)); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; - glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc[1], 2, + glVertexAttribPointer (eglglessink->eglglesctx->texpos_loc[1], 2, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (3 * sizeof (gfloat))); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; } else { - glUseProgram (eglglessink->eglglesctx.glslprogram[0]); + glUseProgram (eglglessink->eglglesctx->glslprogram[0]); - glUniform2f (eglglessink->eglglesctx.tex_scale_loc[0][0], + glUniform2f (eglglessink->eglglesctx->tex_scale_loc[0][0], eglglessink->stride[0], 1); - glUniform2f (eglglessink->eglglesctx.tex_scale_loc[0][1], + glUniform2f (eglglessink->eglglesctx->tex_scale_loc[0][1], eglglessink->stride[1], 1); - glUniform2f (eglglessink->eglglesctx.tex_scale_loc[0][2], + glUniform2f (eglglessink->eglglesctx->tex_scale_loc[0][2], eglglessink->stride[2], 1); - for (i = 0; i < eglglessink->eglglesctx.n_textures; i++) { - glUniform1i (eglglessink->eglglesctx.tex_loc[0][i], i); + for (i = 0; i < eglglessink->eglglesctx->n_textures; i++) { + glUniform1i (eglglessink->eglglesctx->tex_loc[0][i], i); if (got_gl_error ("glUniform1i")) goto HANDLE_ERROR; } if (eglglessink->orientation == GST_EGL_IMAGE_ORIENTATION_X_NORMAL_Y_NORMAL) { - glVertexAttribPointer (eglglessink->eglglesctx.position_loc[0], 3, + glVertexAttribPointer (eglglessink->eglglesctx->position_loc[0], 3, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (0 * sizeof (coord5))); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; - glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc[0], 2, + glVertexAttribPointer (eglglessink->eglglesctx->texpos_loc[0], 2, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (3 * sizeof (gfloat))); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; } else if (eglglessink->orientation == GST_EGL_IMAGE_ORIENTATION_X_NORMAL_Y_FLIP) { - glVertexAttribPointer (eglglessink->eglglesctx.position_loc[0], 3, + glVertexAttribPointer (eglglessink->eglglesctx->position_loc[0], 3, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (4 * sizeof (coord5))); if (got_gl_error ("glVertexAttribPointer")) goto HANDLE_ERROR; - glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc[0], 2, + glVertexAttribPointer (eglglessink->eglglesctx->texpos_loc[0], 2, GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (4 * sizeof (coord5) + 3 * sizeof (gfloat))); if (got_gl_error ("glVertexAttribPointer")) @@ -2509,8 +1552,8 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink) if (got_gl_error ("glDrawElements")) goto HANDLE_ERROR; - if ((eglSwapBuffers (gst_egl_display_get (eglglessink->eglglesctx.display), - eglglessink->eglglesctx.surface)) + if ((eglSwapBuffers (gst_egl_display_get (eglglessink->eglglesctx->display), + eglglessink->eglglesctx->surface)) == EGL_FALSE) { got_egl_error ("eglSwapBuffers"); goto HANDLE_ERROR; @@ -2597,9 +1640,9 @@ gst_eglglessink_event (GstBaseSink * bsink, GstEvent * event) if (gst_context_get_egl_display (context, &display)) { GST_OBJECT_LOCK (eglglessink); - if (eglglessink->eglglesctx.set_display) - gst_egl_display_unref (eglglessink->eglglesctx.set_display); - eglglessink->eglglesctx.set_display = display; + if (eglglessink->eglglesctx->set_display) + gst_egl_display_unref (eglglessink->eglglesctx->set_display); + eglglessink->eglglesctx->set_display = display; GST_OBJECT_UNLOCK (eglglessink); } @@ -2642,7 +1685,7 @@ gst_eglglessink_query (GstBaseSink * bsink, GstQuery * query) context = gst_context_new (); gst_context_set_egl_display (context, - eglglessink->eglglesctx.display); + eglglessink->eglglesctx->display); gst_query_set_context (query, context); break; } @@ -2668,15 +1711,15 @@ gst_eglglessink_set_context (GstElement * element, GstContext * context) if (gst_context_get_egl_display (context, &display)) { GST_OBJECT_LOCK (eglglessink); - if (eglglessink->eglglesctx.set_display) - gst_egl_display_unref (eglglessink->eglglesctx.set_display); - eglglessink->eglglesctx.set_display = display; + if (eglglessink->eglglesctx->set_display) + gst_egl_display_unref (eglglessink->eglglesctx->set_display); + eglglessink->eglglesctx->set_display = display; GST_OBJECT_UNLOCK (eglglessink); } GST_OBJECT_LOCK (eglglessink); context = gst_context_make_writable (context); - gst_context_set_egl_display (context, eglglessink->eglglesctx.display); + gst_context_set_egl_display (context, eglglessink->eglglesctx->display); GST_OBJECT_UNLOCK (eglglessink); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); @@ -2743,7 +1786,7 @@ gst_eglglessink_propose_allocation (GstBaseSink * bsink, GstQuery * query) GST_DEBUG_OBJECT (eglglessink, "create new pool"); pool = gst_egl_image_buffer_pool_new (eglglessink, - eglglessink->eglglesctx.display); + eglglessink->eglglesctx->display); /* the normal size of a frame */ size = info.size; @@ -2812,13 +1855,13 @@ gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps) GST_DEBUG_OBJECT (eglglessink, "Caps are not compatible, reconfiguring"); /* EGL/GLES cleanup */ - gst_eglglessink_wipe_eglglesctx (eglglessink); + gst_egl_adaptation_wipe_eglglesctx (eglglessink->egl_context); gst_caps_unref (eglglessink->configured_caps); eglglessink->configured_caps = NULL; } - if (!gst_eglglessink_choose_config (eglglessink)) { + if (!gst_egl_adaptation_choose_config (eglglessink->egl_context)) { GST_ERROR_OBJECT (eglglessink, "Couldn't choose EGL config"); goto HANDLE_ERROR; } @@ -2842,18 +1885,19 @@ gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps) goto HANDLE_ERROR; } eglglessink->using_own_window = TRUE; - eglglessink->eglglesctx.window = window; + eglglessink->eglglesctx->window = window; eglglessink->have_window = TRUE; } GST_DEBUG_OBJECT (eglglessink, "Using window handle %p", - (gpointer) eglglessink->eglglesctx.window); - eglglessink->eglglesctx.used_window = eglglessink->eglglesctx.window; + (gpointer) eglglessink->eglglesctx->window); + eglglessink->eglglesctx->used_window = eglglessink->eglglesctx->window; GST_OBJECT_UNLOCK (eglglessink); gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (eglglessink), - (guintptr) eglglessink->eglglesctx.used_window); + (guintptr) eglglessink->eglglesctx->used_window); - if (!eglglessink->have_surface) { - if (!gst_eglglessink_init_egl_surface (eglglessink)) { + if (!eglglessink->egl_context->have_surface) { + if (!gst_egl_adaptation_init_egl_surface (eglglessink->egl_context, + eglglessink->configured_info.finfo->format)) { GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL surface from window"); goto HANDLE_ERROR; } @@ -2896,7 +1940,7 @@ gst_eglglessink_setcaps (GstBaseSink * bsink, GstCaps * caps) newpool = gst_egl_image_buffer_pool_new (eglglessink, - eglglessink->eglglesctx.display); + eglglessink->eglglesctx->display); config = gst_buffer_pool_get_config (newpool); /* we need at least 2 buffer because we hold on to the last one */ gst_buffer_pool_config_set_params (config, caps, info.size, 2, 0); @@ -2933,9 +1977,9 @@ gst_eglglessink_open (GstEglGlesSink * eglglessink) static gboolean gst_eglglessink_close (GstEglGlesSink * eglglessink) { - if (eglglessink->eglglesctx.display) { - gst_egl_display_unref (eglglessink->eglglesctx.display); - eglglessink->eglglesctx.display = NULL; + if (eglglessink->eglglesctx->display) { + gst_egl_display_unref (eglglessink->eglglesctx->display); + eglglessink->eglglesctx->display = NULL; } gst_caps_unref (eglglessink->sinkcaps); @@ -3010,6 +2054,8 @@ gst_eglglessink_finalize (GObject * object) eglglessink = GST_EGLGLESSINK (object); + gst_egl_adaptation_context_free (eglglessink->egl_context); + if (eglglessink->queue) g_object_unref (eglglessink->queue); eglglessink->queue = NULL; @@ -3133,13 +2179,17 @@ queue_check_full_func (GstDataQueue * queue, guint visible, guint bytes, static void gst_eglglessink_init (GstEglGlesSink * eglglessink) { + eglglessink->egl_context = + gst_egl_adaptation_context_new (GST_ELEMENT_CAST (eglglessink)); + eglglessink->eglglesctx = &eglglessink->egl_context->eglglesctx; + /* Init defaults */ /** Flags */ eglglessink->have_window = FALSE; - eglglessink->have_surface = FALSE; - eglglessink->have_vbo = FALSE; - eglglessink->have_texture = FALSE; + eglglessink->egl_context->have_surface = FALSE; + eglglessink->egl_context->have_vbo = FALSE; + eglglessink->egl_context->have_texture = FALSE; eglglessink->egl_started = FALSE; eglglessink->using_own_window = FALSE; @@ -3225,7 +2275,7 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), &size); if (mem[0]) { @@ -3266,8 +2316,8 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, goto mem_error; image = - eglCreateImageKHR (gst_egl_display_get (eglglessink-> - eglglesctx.display), eglglessink->eglglesctx.eglcontext, + eglCreateImageKHR (gst_egl_display_get (eglglessink->eglglesctx-> + display), eglglessink->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) (guintptr) data->texture, NULL); if (got_egl_error ("eglCreateImageKHR")) @@ -3275,7 +2325,7 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_wrap (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, image, GST_EGL_IMAGE_MEMORY_TYPE_RGB, flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free); n_mem = 1; @@ -3288,7 +2338,7 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), &size); if (mem[0]) { @@ -3330,8 +2380,8 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, goto mem_error; image = - eglCreateImageKHR (gst_egl_display_get (eglglessink-> - eglglesctx.display), eglglessink->eglglesctx.eglcontext, + eglCreateImageKHR (gst_egl_display_get (eglglessink->eglglesctx-> + display), eglglessink->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) (guintptr) data->texture, NULL); if (got_egl_error ("eglCreateImageKHR")) @@ -3339,7 +2389,7 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_wrap (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, image, GST_EGL_IMAGE_MEMORY_TYPE_RGB, flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free); n_mem = 1; @@ -3353,12 +2403,12 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info, 0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]); mem[1] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE_ALPHA, GST_VIDEO_INFO_COMP_WIDTH (&info, 1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]); @@ -3422,15 +2472,15 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, goto mem_error; image = - eglCreateImageKHR (eglglessink->eglglesctx.display, - eglglessink->eglglesctx.eglcontext, EGL_GL_TEXTURE_2D_KHR, + eglCreateImageKHR (eglglessink->eglglesctx->display, + eglglessink->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) (guintptr) data->texture, NULL); if (got_egl_error ("eglCreateImageKHR")) goto mem_error; mem[i] = gst_egl_image_allocator_wrap (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, image, (i == 0 ? GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE : @@ -3453,17 +2503,17 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info, 0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]); mem[1] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info, 1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]); mem[2] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info, 2), GST_VIDEO_INFO_COMP_HEIGHT (&info, 2), &size[2]); @@ -3529,15 +2579,15 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, goto mem_error; image = - eglCreateImageKHR (eglglessink->eglglesctx.display, - eglglessink->eglglesctx.eglcontext, EGL_GL_TEXTURE_2D_KHR, + eglCreateImageKHR (eglglessink->eglglesctx->display, + eglglessink->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) (guintptr) data->texture, NULL); if (got_egl_error ("eglCreateImageKHR")) goto mem_error; mem[i] = gst_egl_image_allocator_wrap (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, image, GST_EGL_IMAGE_MEMORY_TYPE_LUMINANCE, flags, size[i], data, (GDestroyNotify) gst_egl_gles_image_data_free); @@ -3561,7 +2611,7 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_alloc (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, GST_EGL_IMAGE_MEMORY_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), &size); if (mem[0]) { @@ -3602,8 +2652,8 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, goto mem_error; image = - eglCreateImageKHR (gst_egl_display_get (eglglessink-> - eglglesctx.display), eglglessink->eglglesctx.eglcontext, + eglCreateImageKHR (gst_egl_display_get (eglglessink->eglglesctx-> + display), eglglessink->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer) (guintptr) data->texture, NULL); if (got_egl_error ("eglCreateImageKHR")) @@ -3611,7 +2661,7 @@ gst_eglglessink_allocate_eglimage (GstEglGlesSink * eglglessink, mem[0] = gst_egl_image_allocator_wrap (GST_EGL_IMAGE_BUFFER_POOL - (eglglessink->pool)->allocator, eglglessink->eglglesctx.display, + (eglglessink->pool)->allocator, eglglessink->eglglesctx->display, image, GST_EGL_IMAGE_MEMORY_TYPE_RGBA, flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free); diff --git a/ext/eglgles/gsteglglessink.h b/ext/eglgles/gsteglglessink.h index 58fd68a04a..67fee86ccf 100644 --- a/ext/eglgles/gsteglglessink.h +++ b/ext/eglgles/gsteglglessink.h @@ -58,6 +58,7 @@ #include #include "video_platform_wrapper.h" +#include "gstegladaptation.h" G_BEGIN_DECLS #define GST_TYPE_EGLGLESSINK \ @@ -71,78 +72,8 @@ G_BEGIN_DECLS #define GST_IS_EGLGLESSINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EGLGLESSINK)) -#define GST_EGLGLESSINK_EGL_MIN_VERSION 1 typedef struct _GstEglGlesSink GstEglGlesSink; typedef struct _GstEglGlesSinkClass GstEglGlesSinkClass; -typedef struct _GstEglGlesRenderContext GstEglGlesRenderContext; - -typedef struct _GstEglGlesImageFmt GstEglGlesImageFmt; - -typedef struct _coord5 -{ - float x; - float y; - float z; - float a; /* texpos x */ - float b; /* texpos y */ -} coord5; - -/* - * GstEglGlesRenderContext: - * @config: Current EGL config - * @eglcontext: Current EGL context - * @display: Current EGL display connection - * @window: Current EGL window asociated with the display connection - * @used_window: Last seen EGL window asociated with the display connection - * @surface: EGL surface the sink is rendering into - * @fragshader: Fragment shader - * @vertshader: Vertex shader - * @glslprogram: Compiled and linked GLSL program in use for rendering - * @texture Texture units in use - * @surface_width: Pixel width of the surface the sink is rendering into - * @surface_height: Pixel height of the surface the sink is rendering into - * @pixel_aspect_ratio: EGL display aspect ratio - * @egl_minor: EGL version (minor) - * @egl_major: EGL version (major) - * @n_textures: Texture units count - * @position_loc: Index of the position vertex attribute array - * @texpos_loc: Index of the textpos vertex attribute array - * @position_array: VBO position array - * @texpos_array: VBO texpos array - * @index_array: VBO index array - * @position_buffer: Position buffer object name - * @texpos_buffer: Texpos buffer object name - * @index_buffer: Index buffer object name - * - * This struct holds the sink's EGL/GLES rendering context. - */ -struct _GstEglGlesRenderContext -{ - EGLConfig config; - EGLContext eglcontext; - GstEGLDisplay *display, *set_display; - EGLNativeWindowType window, used_window; - EGLSurface surface; - gboolean buffer_preserved; - GLuint fragshader[3]; /* frame, border, frame-custom */ - GLuint vertshader[3]; /* frame, border, frame-custom */ - GLuint glslprogram[3]; /* frame, border, frame-custom */ - GLuint texture[4]; /* RGB/Y, U/UV, V, custom */ - EGLint surface_width; - EGLint surface_height; - EGLint pixel_aspect_ratio; - EGLint egl_minor, egl_major; - gint n_textures; - - /* shader vars */ - GLuint position_loc[3]; /* frame, border, frame-custom */ - GLuint texpos_loc[2]; /* frame, frame-custom */ - GLuint tex_scale_loc[1][3]; /* [frame] RGB/Y, U/UV, V */ - GLuint tex_loc[2][3]; /* [frame,frame-custom] RGB/Y, U/UV, V */ - coord5 position_array[16]; /* 4 x Frame x-normal,y-normal, 4x Frame x-normal,y-flip, 4 x Border1, 4 x Border2 */ - unsigned short index_array[4]; - unsigned int position_buffer, index_buffer; -}; /* * GstEglGlesSink: @@ -155,9 +86,6 @@ struct _GstEglGlesRenderContext * @flow_lock: Simple concurrent access ward to the sink's runtime state * @have_window: Set if the sink has access to a window to hold it's canvas * @using_own_window: Set if the sink created its own window - * @have_surface: Set if the EGL surface setup has been performed - * @have_vbo: Set if the GLES VBO setup has been performed - * @have_texture: Set if the GLES texture setup has been performed * @egl_started: Set if the whole EGL setup has been performed * @create_window: Property value holder to allow/forbid internal window creation * @force_rendering_slow: Property value holder to force slow rendering path @@ -188,14 +116,12 @@ struct _GstEglGlesSink gboolean custom_format; /* If it's a single texture that is just copied */ GstBufferPool *pool; - GstEglGlesRenderContext eglglesctx; + GstEglGlesRenderContext *eglglesctx; + GstEglAdaptationContext *egl_context; /* Runtime flags */ gboolean have_window; gboolean using_own_window; - gboolean have_surface;; - gboolean have_vbo; - gboolean have_texture; gboolean egl_started; gpointer own_window_data;