eglglessink: refactor egl functions/data to a separate file
authorThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 10 Apr 2013 17:53:48 +0000 (14:53 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Tue, 16 Apr 2013 18:58:12 +0000 (15:58 -0300)
This is part of the changes required to make
eglglessink work with both EGL and Apple's EAGL

ext/eglgles/Makefile.am
ext/eglgles/gstegladaptation.c [new file with mode: 0644]
ext/eglgles/gstegladaptation.h [new file with mode: 0644]
ext/eglgles/gsteglglessink.c
ext/eglgles/gsteglglessink.h

index 22f767c..c20646d 100644 (file)
@@ -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 (file)
index 0000000..28193d0
--- /dev/null
@@ -0,0 +1,1011 @@
+/*
+ * GStreamer EGL/GLES Sink Adaptation
+ * Copyright (C) 2012-2013 Collabora Ltd.
+ *   @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
+ *   @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *   @author: Thiago Santos <thiago.sousa.santos@collabora.com>
+ *
+ * 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 <gst/video/video.h>
+#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 (file)
index 0000000..697e800
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * GStreamer EGL/GLES Sink Adaptation
+ * Copyright (C) 2012-2013 Collabora Ltd.
+ *   @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
+ *   @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *   @author: Thiago Santos <thiago.sousa.santos@collabora.com>
+ *
+ * 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 <gst/gst.h>
+#include <gst/egl/egl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#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__ */
index 961d8bc..36c6725 100644 (file)
 
 #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[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[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[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[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;
 
   /* 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 + 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 + 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 + 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 + 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;
 
 
   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);
 
index 58fd68a..67fee86 100644 (file)
@@ -58,6 +58,7 @@
 #include <GLES2/gl2ext.h>
 
 #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;