summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Santos <thiago.sousa.santos@collabora.com>2013-03-12 20:01:19 -0300
committerThiago Santos <thiago.sousa.santos@collabora.com>2013-04-16 16:08:50 -0300
commit554108df935ec6f83ab85d30b68b218a84501af3 (patch)
tree7c457fd4fe189f5e987271d4d791687a9476e79f
parentca8a4ec35fc4ad787484e6d31d567550f4207b4e (diff)
downloadgstreamer-plugins-bad-554108df935ec6f83ab85d30b68b218a84501af3.tar.gz
eglglessink: refactor egl function to a separate file
This is part of the changes required to make eglglessink work with both EGL and Apple's EAGL
-rw-r--r--ext/eglgles/Makefile.am4
-rw-r--r--ext/eglgles/gstegladaptation.c982
-rw-r--r--ext/eglgles/gstegladaptation.h191
-rw-r--r--ext/eglgles/gsteglglessink.c1152
-rw-r--r--ext/eglgles/gsteglglessink.h81
5 files changed, 1320 insertions, 1090 deletions
diff --git a/ext/eglgles/Makefile.am b/ext/eglgles/Makefile.am
index 0ce49cff6..229b82c2d 100644
--- a/ext/eglgles/Makefile.am
+++ b/ext/eglgles/Makefile.am
@@ -1,6 +1,6 @@
plugin_LTLIBRARIES = libgsteglglessink.la
-libgsteglglessink_la_SOURCES = gsteglglessink.c video_platform_wrapper.c
+libgsteglglessink_la_SOURCES = gsteglglessink.c video_platform_wrapper.c gstegladaptation.c
libgsteglglessink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
@@ -15,4 +15,4 @@ libgsteglglessink_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \
libgsteglglessink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgsteglglessink_la_LIBTOOLFLAGS = --tag=disable-static
-noinst_HEADERS = gsteglglessink.h video_platform_wrapper.h
+noinst_HEADERS = gsteglglessink.h video_platform_wrapper.h gstegladaptation.h
diff --git a/ext/eglgles/gstegladaptation.c b/ext/eglgles/gstegladaptation.c
new file mode 100644
index 000000000..db6357d04
--- /dev/null
+++ b/ext/eglgles/gstegladaptation.c
@@ -0,0 +1,982 @@
+/*
+ * GStreamer EGL/GLES Sink Adaptation
+ * Copyright (C) 2013 Collabora Ltd.
+ * @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.
+ */
+
+/* *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 */
+static const char *frag_COPY_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;"
+ "void main(void)"
+ "{"
+ " vec4 t = texture2D(tex, opos);"
+ " 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;"
+ "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).gba;"
+ " yuv += offset;"
+ " r = dot(yuv, rcoeff);"
+ " g = dot(yuv, gcoeff);"
+ " b = dot(yuv, bcoeff);"
+ " gl_FragColor=vec4(r,g,b,1.0);"
+ "}"
+};
+
+/** YUY2/YVYU/UYVY to RGB conversion */
+static const char *frag_YUY2_YVYU_UYVY_prog = {
+ "precision mediump float;"
+ "varying vec2 opos;"
+ "uniform sampler2D Ytex, UVtex;"
+ "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).%c;"
+ " yuv.yz = texture2D(UVtex,opos).%c%c;"
+ " 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;"
+ "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).r;"
+ " yuv.y=texture2D(Utex,opos).r;"
+ " yuv.z=texture2D(Vtex,opos).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;"
+ "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).r;"
+ " yuv.yz=texture2D(UVtex,opos).%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* */
+
+/* will probably move elsewhere */
+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
+};
+
+static const EGLint eglglessink_RGB888_attribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+};
+
+static const EGLint eglglessink_RGB565_attribs[] = {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+};
+
+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_display (GstEglAdaptationContext * ctx)
+{
+ 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
+
+ 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 = display;
+
+ if (!eglInitialize (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;
+}
+
+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);
+}
+
+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;
+}
+
+gboolean
+gst_egl_adaptation_choose_config (GstEglAdaptationContext * ctx)
+{
+ EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ GLint egl_configs;
+
+ if ((eglChooseConfig (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 (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;
+}
+
+gint gst_egl_adaptation_context_fill_supported_fbuffer_configs
+ (GstEglAdaptationContext * ctx, GstCaps ** ret_caps)
+{
+ gboolean ret = FALSE;
+ EGLint cfg_number;
+ GstCaps *caps;
+
+ GST_DEBUG_OBJECT (ctx->element,
+ "Building initial list of wanted eglattribs per format");
+
+ /* Init supported format/caps list */
+ caps = gst_caps_new_empty ();
+
+ if (eglChooseConfig (ctx->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_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_YUY2));
+ gst_caps_append (caps,
+ gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YVYU));
+ gst_caps_append (caps,
+ gst_video_format_new_template_caps (GST_VIDEO_FORMAT_UYVY));
+ 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));
+ ret = TRUE;
+ } else {
+ GST_INFO_OBJECT (ctx->element,
+ "EGL display doesn't support RGBA8888 config");
+ }
+
+ GST_OBJECT_LOCK (ctx->element);
+ gst_caps_replace (ret_caps, caps);
+ GST_OBJECT_UNLOCK (ctx->element);
+ gst_caps_unref (caps);
+
+ return ret;
+}
+
+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 (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 (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;
+}
+
+void
+gst_egl_adaptation_context_cleanup (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,
+ ctx->eglglesctx.texture);
+ ctx->have_texture = FALSE;
+ ctx->eglglesctx.n_textures = 0;
+ }
+
+ for (i = 0; i < 2; 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 (ctx->eglglesctx.display,
+ ctx->eglglesctx.surface);
+ ctx->eglglesctx.surface = NULL;
+ ctx->have_surface = FALSE;
+ }
+
+ if (ctx->eglglesctx.eglcontext) {
+ eglDestroyContext (ctx->eglglesctx.display,
+ ctx->eglglesctx.eglcontext);
+ ctx->eglglesctx.eglcontext = NULL;
+ }
+}
+
+/* XXX: Lock eglgles context? */
+gboolean
+gst_egl_adaptation_context_update_surface_dimensions (GstEglAdaptationContext *
+ ctx)
+{
+ gint width, height;
+
+ /* Save surface dims */
+ eglQuerySurface (ctx->eglglesctx.display,
+ ctx->eglglesctx.surface, EGL_WIDTH, &width);
+ eglQuerySurface (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_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 (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 (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;
+
+ /* 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 (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_context_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_YUY2:
+ frag_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'g', 'a');
+ free_frag_prog = TRUE;
+ ctx->eglglesctx.n_textures = 2;
+ texnames[0] = "Ytex";
+ texnames[1] = "UVtex";
+ break;
+ case GST_VIDEO_FORMAT_YVYU:
+ frag_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'a', 'g');
+ free_frag_prog = TRUE;
+ ctx->eglglesctx.n_textures = 2;
+ texnames[0] = "Ytex";
+ texnames[1] = "UVtex";
+ break;
+ case GST_VIDEO_FORMAT_UYVY:
+ frag_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'a', 'r', 'b');
+ free_frag_prog = TRUE;
+ ctx->eglglesctx.n_textures = 2;
+ texnames[0] = "Ytex";
+ texnames[1] = "UVtex";
+ 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");
+
+ 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]);
+ }
+
+ 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,
+ ctx->eglglesctx.texture);
+ if (got_gl_error ("glGenTextures"))
+ goto HANDLE_ERROR_LOCKED;
+
+ for (i = 0; i < ctx->eglglesctx.n_textures; 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
+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;
+}
+
+
+void
+gst_egl_adaptation_context_terminate_display (GstEglAdaptationContext * ctx)
+{
+ if (ctx->eglglesctx.display) {
+ eglTerminate (ctx->eglglesctx.display);
+ ctx->eglglesctx.display = NULL;
+ }
+}
+
+void
+gst_egl_adaptation_context_bind_API (GstEglAdaptationContext * ctx)
+{
+ eglBindAPI (EGL_OPENGL_ES_API);
+}
+
+gboolean
+gst_egl_adaptation_context_swap_buffers (GstEglAdaptationContext * ctx)
+{
+ gboolean ret =
+ eglSwapBuffers (ctx->eglglesctx.display, ctx->eglglesctx.surface);
+ if (ret == EGL_FALSE) {
+ got_egl_error ("eglSwapBuffers");
+ }
+ return ret;
+}
+
+/* Prints avilable 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_context_init_egl_exts (GstEglAdaptationContext * ctx)
+{
+ const char *eglexts;
+ unsigned const char *glexts;
+
+ eglexts = eglQueryString (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;
+}
diff --git a/ext/eglgles/gstegladaptation.h b/ext/eglgles/gstegladaptation.h
new file mode 100644
index 000000000..52de204c7
--- /dev/null
+++ b/ext/eglgles/gstegladaptation.h
@@ -0,0 +1,191 @@
+/*
+ * GStreamer EGL/GLES Sink Adaptation
+ * Copyright (C) 2013 Collabora Ltd.
+ * @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 <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#ifdef USE_EGL_RPI
+#include <bcm_host.h>
+#endif
+
+#include "video_platform_wrapper.h"
+
+#define GST_EGLGLESSINK_IMAGE_NOFMT 0
+#define GST_EGLGLESSINK_IMAGE_RGB888 1
+#define GST_EGLGLESSINK_IMAGE_RGB565 2
+#define GST_EGLGLESSINK_IMAGE_RGBA8888 3
+#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;
+ EGLDisplay display;
+ EGLNativeWindowType window, used_window;
+ EGLSurface surface;
+ gboolean buffer_preserved;
+ GLuint fragshader[3]; /* frame, border, frame-platform */
+ GLuint vertshader[3]; /* frame, border, frame-platform */
+ GLuint glslprogram[3]; /* frame, border, frame-platform */
+ GLuint texture[3]; /* RGB/Y, U/UV, V */
+ 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-platform */
+ GLuint texpos_loc[2]; /* frame, frame-platform */
+ GLuint tex_loc[2][3]; /* [frame, frame-platform] RGB/Y, U/UV, V */
+ coord5 position_array[12]; /* 4 x Frame, 4 x Border1, 4 x Border2 */
+ unsigned short index_array[4];
+ unsigned int position_buffer, index_buffer;
+};
+
+/*
+ * GstEglGlesImageFmt:
+ * @fmt: Internal identifier for the EGL attribs / GST caps pairing
+ * @attribs: Pointer to the set of EGL attributes asociated with this format
+ * @caps: Pointer to the GST caps asociated with this format
+ *
+ * This struct holds a pairing between GST caps and the matching EGL attributes
+ * associated with a given pixel format
+ */
+struct _GstEglGlesImageFmt
+{
+ gint fmt; /* Private identifier */
+ const EGLint *attribs; /* EGL Attributes */
+ GstCaps *caps; /* Matching caps for the attribs */
+};
+
+
+/*
+ * 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);
+
+gboolean gst_egl_adaptation_init_display (GstEglAdaptationContext * ctx);
+gboolean gst_egl_adaptation_choose_config (GstEglAdaptationContext * ctx);
+gint gst_egl_adaptation_context_fill_supported_fbuffer_configs (GstEglAdaptationContext * ctx, GstCaps ** ret_caps);
+gboolean gst_egl_adaptation_context_make_current (GstEglAdaptationContext * ctx, gboolean bind);
+void gst_egl_adaptation_context_cleanup (GstEglAdaptationContext * ctx);
+gboolean gst_egl_adaptation_init_egl_surface (GstEglAdaptationContext * ctx, GstVideoFormat format);
+gboolean gst_egl_adaptation_context_update_surface_dimensions (GstEglAdaptationContext * ctx);
+void gst_egl_adaptation_context_terminate_display(GstEglAdaptationContext * ctx);
+void gst_egl_adaptation_context_bind_API (GstEglAdaptationContext * ctx);
+gboolean gst_egl_adaptation_context_swap_buffers (GstEglAdaptationContext * ctx);
+void gst_egl_adaptation_context_init_egl_exts (GstEglAdaptationContext * ctx);
+
+gboolean got_egl_error (const char *wtf);
+gboolean got_gl_error (const char *wtf);
+
+G_END_DECLS
+
+#endif /* __GST_EGL_ADAPTATION_H__ */
diff --git a/ext/eglgles/gsteglglessink.c b/ext/eglgles/gsteglglessink.c
index ad4734b9c..6cefb818e 100644
--- a/ext/eglgles/gsteglglessink.c
+++ b/ext/eglgles/gsteglglessink.c
@@ -131,174 +131,9 @@
#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
-/* 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 */
-static const char *frag_COPY_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;"
- "void main(void)"
- "{"
- " vec4 t = texture2D(tex, opos);"
- " 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;"
- "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).gba;"
- " yuv += offset;"
- " r = dot(yuv, rcoeff);"
- " g = dot(yuv, gcoeff);"
- " b = dot(yuv, bcoeff);"
- " gl_FragColor=vec4(r,g,b,1.0);"
- "}"
-};
-
-/** YUY2/YVYU/UYVY to RGB conversion */
-static const char *frag_YUY2_YVYU_UYVY_prog = {
- "precision mediump float;"
- "varying vec2 opos;"
- "uniform sampler2D Ytex, UVtex;"
- "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).%c;"
- " yuv.yz = texture2D(UVtex,opos).%c%c;"
- " 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;"
- "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).r;"
- " yuv.y=texture2D(Utex,opos).r;"
- " yuv.z=texture2D(Vtex,opos).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;"
- "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).r;"
- " yuv.yz=texture2D(UVtex,opos).%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,
@@ -368,12 +203,6 @@ static void gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x,
/* 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
@@ -383,85 +212,11 @@ static GstFlowReturn gst_eglglessink_upload (GstEglGlesSink * sink,
static GstFlowReturn gst_eglglessink_render (GstEglGlesSink * sink);
static GstFlowReturn gst_eglglessink_queue_buffer (GstEglGlesSink * sink,
GstBuffer * buf);
-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);
GST_BOILERPLATE_FULL (GstEglGlesSink, gst_eglglessink, GstVideoSink,
GST_TYPE_VIDEO_SINK, gst_eglglessink_init_interfaces);
-
-
-static gboolean
-gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink)
-{
- gboolean ret = FALSE;
- EGLint cfg_number;
- GstCaps *caps;
-
- GST_DEBUG_OBJECT (eglglessink,
- "Building initial list of wanted eglattribs per format");
-
- /* Init supported format/caps list */
- caps = gst_caps_new_empty ();
-
- if (eglChooseConfig (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_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_YUY2));
- gst_caps_append (caps,
- gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YVYU));
- gst_caps_append (caps,
- gst_video_format_new_template_caps (GST_VIDEO_FORMAT_UYVY));
- 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));
- 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)
{
@@ -470,14 +225,15 @@ egl_init (GstEglGlesSink * eglglessink)
goto HANDLE_ERROR;
}
- if (!gst_eglglessink_init_egl_display (eglglessink)) {
+ if (!gst_egl_adaptation_init_display (eglglessink->egl_context)) {
GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL display");
goto HANDLE_ERROR;
}
- gst_eglglessink_init_egl_exts (eglglessink);
+ gst_egl_adaptation_context_init_egl_exts (eglglessink->egl_context);
- if (!gst_eglglessink_fill_supported_fbuffer_configs (eglglessink)) {
+ if (!gst_egl_adaptation_context_fill_supported_fbuffer_configs
+ (eglglessink->egl_context, &eglglessink->sinkcaps)) {
GST_ERROR_OBJECT (eglglessink, "Display support NONE of our configs");
goto HANDLE_ERROR;
}
@@ -508,7 +264,7 @@ render_thread_func (GstEglGlesSink * eglglessink)
gst_element_post_message (GST_ELEMENT_CAST (eglglessink), message);
g_value_unset (&val);
- eglBindAPI (EGL_OPENGL_ES_API);
+ gst_egl_adaptation_context_bind_API (eglglessink->egl_context);
while (gst_data_queue_pop (eglglessink->queue, &item)) {
GstBuffer *buf = NULL;
@@ -573,7 +329,7 @@ render_thread_func (GstEglGlesSink * eglglessink)
GST_DEBUG_OBJECT (eglglessink, "Shutting down thread");
/* EGL/GLES cleanup */
- gst_eglglessink_wipe_eglglesctx (eglglessink);
+ gst_egl_adaptation_context_cleanup (eglglessink->egl_context);
if (eglglessink->configured_caps) {
gst_caps_unref (eglglessink->configured_caps);
@@ -592,57 +348,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,
- eglglessink->eglglesctx.texture);
- eglglessink->have_texture = FALSE;
- eglglessink->eglglesctx.n_textures = 0;
- }
-
- for (i = 0; i < 2; 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 (eglglessink->eglglesctx.display,
- eglglessink->eglglesctx.surface);
- eglglessink->eglglesctx.surface = NULL;
- eglglessink->have_surface = FALSE;
- }
-
- if (eglglessink->eglglesctx.eglcontext) {
- eglDestroyContext (eglglessink->eglglesctx.display,
- eglglessink->eglglesctx.eglcontext);
- eglglessink->eglglesctx.eglcontext = NULL;
- }
-}
-
static gboolean
gst_eglglessink_start (GstEglGlesSink * eglglessink)
{
@@ -710,12 +415,12 @@ gst_eglglessink_stop (GstEglGlesSink * eglglessink)
eglglessink->last_flow = GST_FLOW_WRONG_STATE;
if (eglglessink->using_own_window) {
- platform_destroy_native_window (eglglessink->eglglesctx.display,
- eglglessink->eglglesctx.used_window, &eglglessink->own_window_data);
- eglglessink->eglglesctx.used_window = 0;
+ platform_destroy_native_window (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;
@@ -746,32 +451,6 @@ gst_eglglessink_implements_init (GstImplementsInterfaceClass * klass)
klass->supported = gst_eglglessink_interface_supported;
}
-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)
@@ -809,28 +488,6 @@ gst_eglglessink_expose (GstXOverlay * 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 (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));
-
- return;
-}
-
static gboolean
gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
{
@@ -838,12 +495,12 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
gdouble x1, x2, y1, y2;
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;
@@ -858,131 +515,131 @@ gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
y2 = ((eglglessink->display_region.y +
eglglessink->display_region.h) / render_height) * 2.0 - 1;
- 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 = 1;
- eglglessink->eglglesctx.position_array[0].b = 0;
-
- 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 = 1;
- eglglessink->eglglesctx.position_array[1].b = 1;
-
- 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 = 0;
- eglglessink->eglglesctx.position_array[2].b = 0;
-
- 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 = 0;
- eglglessink->eglglesctx.position_array[3].b = 1;
+ 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 = 1;
+ eglglessink->eglglesctx->position_array[0].b = 0;
+
+ 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 = 1;
+ eglglessink->eglglesctx->position_array[1].b = 1;
+
+ 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 = 0;
+ eglglessink->eglglesctx->position_array[2].b = 0;
+
+ 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 = 0;
+ eglglessink->eglglesctx->position_array[3].b = 1;
if (eglglessink->display_region.x == 0) {
/* Borders top/bottom */
- eglglessink->eglglesctx.position_array[4 + 0].x = 1;
- eglglessink->eglglesctx.position_array[4 + 0].y = 1;
- eglglessink->eglglesctx.position_array[4 + 0].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 0].x = 1;
+ eglglessink->eglglesctx->position_array[4 + 0].y = 1;
+ eglglessink->eglglesctx->position_array[4 + 0].z = 0;
- eglglessink->eglglesctx.position_array[4 + 1].x = x2;
- eglglessink->eglglesctx.position_array[4 + 1].y = y2;
- eglglessink->eglglesctx.position_array[4 + 1].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 1].x = x2;
+ eglglessink->eglglesctx->position_array[4 + 1].y = y2;
+ eglglessink->eglglesctx->position_array[4 + 1].z = 0;
- eglglessink->eglglesctx.position_array[4 + 2].x = -1;
- eglglessink->eglglesctx.position_array[4 + 2].y = 1;
- eglglessink->eglglesctx.position_array[4 + 2].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 2].x = -1;
+ eglglessink->eglglesctx->position_array[4 + 2].y = 1;
+ eglglessink->eglglesctx->position_array[4 + 2].z = 0;
- eglglessink->eglglesctx.position_array[4 + 3].x = x1;
- eglglessink->eglglesctx.position_array[4 + 3].y = y2;
- eglglessink->eglglesctx.position_array[4 + 3].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 3].x = x1;
+ eglglessink->eglglesctx->position_array[4 + 3].y = y2;
+ eglglessink->eglglesctx->position_array[4 + 3].z = 0;
- eglglessink->eglglesctx.position_array[8 + 0].x = 1;
- eglglessink->eglglesctx.position_array[8 + 0].y = y1;
- eglglessink->eglglesctx.position_array[8 + 0].z = 0;
+ eglglessink->eglglesctx->position_array[8 + 0].x = 1;
+ eglglessink->eglglesctx->position_array[8 + 0].y = y1;
+ eglglessink->eglglesctx->position_array[8 + 0].z = 0;
- eglglessink->eglglesctx.position_array[8 + 1].x = 1;
- eglglessink->eglglesctx.position_array[8 + 1].y = -1;
- eglglessink->eglglesctx.position_array[8 + 1].z = 0;
+ eglglessink->eglglesctx->position_array[8 + 1].x = 1;
+ eglglessink->eglglesctx->position_array[8 + 1].y = -1;
+ eglglessink->eglglesctx->position_array[8 + 1].z = 0;
- eglglessink->eglglesctx.position_array[8 + 2].x = x1;
- eglglessink->eglglesctx.position_array[8 + 2].y = y1;
- eglglessink->eglglesctx.position_array[8 + 2].z = 0;
+ eglglessink->eglglesctx->position_array[8 + 2].x = x1;
+ eglglessink->eglglesctx->position_array[8 + 2].y = y1;
+ 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;
} else {
/* Borders left/right */
- eglglessink->eglglesctx.position_array[4 + 0].x = x1;
- eglglessink->eglglesctx.position_array[4 + 0].y = 1;
- eglglessink->eglglesctx.position_array[4 + 0].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 0].x = x1;
+ eglglessink->eglglesctx->position_array[4 + 0].y = 1;
+ eglglessink->eglglesctx->position_array[4 + 0].z = 0;
- eglglessink->eglglesctx.position_array[4 + 1].x = x1;
- eglglessink->eglglesctx.position_array[4 + 1].y = -1;
- eglglessink->eglglesctx.position_array[4 + 1].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 1].x = x1;
+ eglglessink->eglglesctx->position_array[4 + 1].y = -1;
+ eglglessink->eglglesctx->position_array[4 + 1].z = 0;
- eglglessink->eglglesctx.position_array[4 + 2].x = -1;
- eglglessink->eglglesctx.position_array[4 + 2].y = 1;
- eglglessink->eglglesctx.position_array[4 + 2].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 2].x = -1;
+ eglglessink->eglglesctx->position_array[4 + 2].y = 1;
+ eglglessink->eglglesctx->position_array[4 + 2].z = 0;
- eglglessink->eglglesctx.position_array[4 + 3].x = -1;
- eglglessink->eglglesctx.position_array[4 + 3].y = -1;
- eglglessink->eglglesctx.position_array[4 + 3].z = 0;
+ eglglessink->eglglesctx->position_array[4 + 3].x = -1;
+ eglglessink->eglglesctx->position_array[4 + 3].y = -1;
+ eglglessink->eglglesctx->position_array[4 + 3].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 + 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 = 1;
- eglglessink->eglglesctx.position_array[8 + 1].y = -1;
- eglglessink->eglglesctx.position_array[8 + 1].z = 0;
+ eglglessink->eglglesctx->position_array[8 + 1].x = 1;
+ eglglessink->eglglesctx->position_array[8 + 1].y = -1;
+ eglglessink->eglglesctx->position_array[8 + 1].z = 0;
- eglglessink->eglglesctx.position_array[8 + 2].x = x2;
- eglglessink->eglglesctx.position_array[8 + 2].y = y2;
- eglglessink->eglglesctx.position_array[8 + 2].z = 0;
+ eglglessink->eglglesctx->position_array[8 + 2].x = x2;
+ eglglessink->eglglesctx->position_array[8 + 2].y = y2;
+ eglglessink->eglglesctx->position_array[8 + 2].z = 0;
- eglglessink->eglglesctx.position_array[8 + 3].x = x2;
- eglglessink->eglglesctx.position_array[8 + 3].y = -1;
- eglglessink->eglglesctx.position_array[8 + 3].z = 0;
+ eglglessink->eglglesctx->position_array[8 + 3].x = x2;
+ eglglessink->eglglesctx->position_array[8 + 3].y = -1;
+ eglglessink->eglglesctx->position_array[8 + 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;
@@ -992,532 +649,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 (eglglessink->eglglesctx.display,
- eglglessink->eglglesctx.surface, EGL_WIDTH, &width);
- eglQuerySurface (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 (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 (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 (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 (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;
-
- /* 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 (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->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_YUY2:
- frag_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'g', 'a');
- free_frag_prog = TRUE;
- eglglessink->eglglesctx.n_textures = 2;
- texnames[0] = "Ytex";
- texnames[1] = "UVtex";
- break;
- case GST_VIDEO_FORMAT_YVYU:
- frag_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'a', 'g');
- free_frag_prog = TRUE;
- eglglessink->eglglesctx.n_textures = 2;
- texnames[0] = "Ytex";
- texnames[1] = "UVtex";
- break;
- case GST_VIDEO_FORMAT_UYVY:
- frag_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'a', 'r', 'b');
- free_frag_prog = TRUE;
- eglglessink->eglglesctx.n_textures = 2;
- texnames[0] = "Ytex";
- texnames[1] = "UVtex";
- 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");
-
- 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]);
- }
-
- 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,
- eglglessink->eglglesctx.texture);
- if (got_gl_error ("glGenTextures"))
- goto HANDLE_ERROR_LOCKED;
-
- for (i = 0; i < eglglessink->eglglesctx.n_textures; 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)
-{
- 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
-
- 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 = display;
-
- if (!eglInitialize (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 (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 (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 (GstXOverlay * overlay, guintptr id)
{
@@ -1528,7 +659,7 @@ gst_eglglessink_set_window_handle (GstXOverlay * 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);
@@ -1628,13 +759,13 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_xBGR:
glActiveTexture (GL_TEXTURE0);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
break;
case GST_VIDEO_FORMAT_AYUV:
glActiveTexture (GL_TEXTURE0);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
break;
@@ -1650,7 +781,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
cw = gst_video_format_get_component_width (eglglessink->format, 0, w);
ch = gst_video_format_get_component_height (eglglessink->format, 0, h);
glActiveTexture (GL_TEXTURE0);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
coffset =
@@ -1658,7 +789,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
cw = gst_video_format_get_component_width (eglglessink->format, 1, w);
ch = gst_video_format_get_component_height (eglglessink->format, 1, h);
glActiveTexture (GL_TEXTURE1);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[1]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
coffset =
@@ -1666,7 +797,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
cw = gst_video_format_get_component_width (eglglessink->format, 2, w);
ch = gst_video_format_get_component_height (eglglessink->format, 2, h);
glActiveTexture (GL_TEXTURE2);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[2]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[2]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
break;
@@ -1675,11 +806,11 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
case GST_VIDEO_FORMAT_YVYU:
case GST_VIDEO_FORMAT_UYVY:
glActiveTexture (GL_TEXTURE0);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
glActiveTexture (GL_TEXTURE1);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[1]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, GST_ROUND_UP_2 (w) / 2,
h, 0, GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
break;
@@ -1692,7 +823,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
cw = gst_video_format_get_component_width (eglglessink->format, 0, w);
ch = gst_video_format_get_component_height (eglglessink->format, 0, h);
glActiveTexture (GL_TEXTURE0);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
@@ -1702,7 +833,7 @@ gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
cw = gst_video_format_get_component_width (eglglessink->format, 1, w);
ch = gst_video_format_get_component_height (eglglessink->format, 1, h);
glActiveTexture (GL_TEXTURE1);
- glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
+ glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[1]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, cw, ch, 0,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
GST_BUFFER_DATA (buf) + coffset);
@@ -1759,7 +890,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_context_update_surface_dimensions (eglglessink->egl_context) ||
eglglessink->render_region_changed ||
!eglglessink->display_region.w || !eglglessink->display_region.h ||
eglglessink->size_changed) {
@@ -1768,8 +899,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->size_changed = FALSE;
@@ -1789,7 +920,7 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink)
w, h,
eglglessink->par_n,
eglglessink->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 = w;
@@ -1820,13 +951,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);
}
@@ -1839,12 +970,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) (4 * sizeof (coord5)));
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR;
@@ -1855,7 +986,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) (8 * sizeof (coord5)));
if (got_gl_error ("glVertexAttribPointer"))
goto HANDLE_ERROR;
@@ -1867,20 +998,20 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink)
/* Draw video frame */
GST_DEBUG_OBJECT (eglglessink, "Drawing video frame");
- glUseProgram (eglglessink->eglglesctx.glslprogram[0]);
+ glUseProgram (eglglessink->eglglesctx->glslprogram[0]);
- 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;
}
- 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, GL_FLOAT,
+ 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;
@@ -1889,10 +1020,8 @@ gst_eglglessink_render (GstEglGlesSink * eglglessink)
if (got_gl_error ("glDrawElements"))
goto HANDLE_ERROR;
- if ((eglSwapBuffers (eglglessink->eglglesctx.display,
- eglglessink->eglglesctx.surface))
+ if ((gst_egl_adaptation_context_swap_buffers (eglglessink->egl_context))
== EGL_FALSE) {
- got_egl_error ("eglSwapBuffers");
goto HANDLE_ERROR;
}
@@ -1978,13 +1107,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_context_cleanup (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;
}
@@ -2006,18 +1135,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",
- eglglessink->eglglesctx.window);
- eglglessink->eglglesctx.used_window = eglglessink->eglglesctx.window;
+ eglglessink->eglglesctx->window);
+ eglglessink->eglglesctx->used_window = eglglessink->eglglesctx->window;
GST_OBJECT_UNLOCK (eglglessink);
gst_x_overlay_got_window_handle (GST_X_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->format)) {
GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL surface from window");
goto HANDLE_ERROR;
}
@@ -2061,10 +1191,7 @@ gst_eglglessink_open (GstEglGlesSink * eglglessink)
static gboolean
gst_eglglessink_close (GstEglGlesSink * eglglessink)
{
- if (eglglessink->eglglesctx.display) {
- eglTerminate (eglglessink->eglglesctx.display);
- eglglessink->eglglesctx.display = NULL;
- }
+ gst_egl_adaptation_context_terminate_display (eglglessink->egl_context);
gst_caps_unref (eglglessink->sinkcaps);
eglglessink->sinkcaps = NULL;
@@ -2139,6 +1266,8 @@ gst_eglglessink_finalize (GObject * object)
g_cond_free (eglglessink->render_cond);
g_mutex_free (eglglessink->render_lock);
+ gst_egl_adaptation_context_free (eglglessink->egl_context);
+
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -2260,9 +1389,6 @@ gst_eglglessink_init (GstEglGlesSink * eglglessink,
/** Flags */
eglglessink->have_window = FALSE;
- eglglessink->have_surface = FALSE;
- eglglessink->have_vbo = FALSE;
- eglglessink->have_texture = FALSE;
eglglessink->egl_started = FALSE;
eglglessink->using_own_window = FALSE;
@@ -2284,6 +1410,10 @@ gst_eglglessink_init (GstEglGlesSink * eglglessink,
eglglessink->render_cond = g_cond_new ();
eglglessink->queue = gst_data_queue_new (queue_check_full_func, NULL);
eglglessink->last_flow = GST_FLOW_WRONG_STATE;
+
+ eglglessink->egl_context =
+ gst_egl_adaptation_context_new (GST_ELEMENT_CAST (eglglessink));
+ eglglessink->eglglesctx = &eglglessink->egl_context->eglglesctx;
}
/* Interface initializations. Used here for initializing the XOverlay
diff --git a/ext/eglgles/gsteglglessink.h b/ext/eglgles/gsteglglessink.h
index 97fd7264e..2b7af1aa4 100644
--- a/ext/eglgles/gsteglglessink.h
+++ b/ext/eglgles/gsteglglessink.h
@@ -55,6 +55,8 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include "gstegladaptation.h"
+
G_BEGIN_DECLS
#define GST_TYPE_EGLGLESSINK \
(gst_eglglessink_get_type())
@@ -66,78 +68,8 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EGLGLESSINK))
#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;
- EGLDisplay display;
- EGLNativeWindowType window, used_window;
- EGLSurface surface;
- gboolean buffer_preserved;
- GLuint fragshader[3]; /* frame, border, frame-platform */
- GLuint vertshader[3]; /* frame, border, frame-platform */
- GLuint glslprogram[3]; /* frame, border, frame-platform */
- GLuint texture[3]; /* RGB/Y, U/UV, V */
- 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-platform */
- GLuint texpos_loc[2]; /* frame, frame-platform */
- GLuint tex_loc[2][3]; /* [frame, frame-platform] RGB/Y, U/UV, V */
- coord5 position_array[12]; /* 4 x Frame, 4 x Border1, 4 x Border2 */
- unsigned short index_array[4];
- unsigned int position_buffer, index_buffer;
-};
/*
* GstEglGlesSink:
@@ -152,9 +84,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
@@ -182,14 +111,12 @@ struct _GstEglGlesSink
GstCaps *sinkcaps;
GstCaps *current_caps, *configured_caps;
- GstEglGlesRenderContext eglglesctx;
+ GstEglAdaptationContext *egl_context;
+ GstEglGlesRenderContext *eglglesctx;
/* 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;