gstreamer/ext/eglgles/gstegladaptation.c
2013-09-28 20:36:21 +02:00

707 lines
21 KiB
C

/*
* GStreamer EGL/GLES Sink Adaptation
* Copyright (C) 2012-2013 Collabora Ltd.
* @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
* @author: Thiago Santos <thiago.sousa.santos@collabora.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gstegladaptation.h"
#include <gst/video/video.h>
#include <string.h>
#define GST_CAT_DEFAULT egladaption_debug
GST_DEBUG_CATEGORY (egladaption_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 with stride-scaling */
static const char *frag_COPY_prog = {
"precision mediump float;"
"varying vec2 opos;"
"uniform sampler2D tex;"
"uniform vec2 tex_scale0;"
"uniform vec2 tex_scale1;"
"uniform vec2 tex_scale2;"
"void main(void)"
"{"
" vec4 t = texture2D(tex, opos / tex_scale0);"
" gl_FragColor = vec4(t.rgb, 1.0);"
"}"
};
/* Channel reordering for XYZ <-> ZYX conversion */
static const char *frag_REORDER_prog = {
"precision mediump float;"
"varying vec2 opos;"
"uniform sampler2D tex;"
"uniform vec2 tex_scale0;"
"uniform vec2 tex_scale1;"
"uniform vec2 tex_scale2;"
"void main(void)"
"{"
" vec4 t = texture2D(tex, opos / tex_scale0);"
" gl_FragColor = vec4(t.%c, t.%c, t.%c, 1.0);"
"}"
};
/* Packed YUV converters */
/** AYUV to RGB conversion */
static const char *frag_AYUV_prog = {
"precision mediump float;"
"varying vec2 opos;"
"uniform sampler2D tex;"
"uniform vec2 tex_scale0;"
"uniform vec2 tex_scale1;"
"uniform vec2 tex_scale2;"
"const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
"const vec3 rcoeff = vec3(1.164, 0.000, 1.596);"
"const vec3 gcoeff = vec3(1.164,-0.391,-0.813);"
"const vec3 bcoeff = vec3(1.164, 2.018, 0.000);"
"void main(void) {"
" float r,g,b;"
" vec3 yuv;"
" yuv = texture2D(tex,opos / tex_scale0).gba;"
" yuv += offset;"
" r = dot(yuv, rcoeff);"
" g = dot(yuv, gcoeff);"
" b = dot(yuv, bcoeff);"
" gl_FragColor=vec4(r,g,b,1.0);"
"}"
};
/* Planar YUV converters */
/** YUV to RGB conversion */
static const char *frag_PLANAR_YUV_prog = {
"precision mediump float;"
"varying vec2 opos;"
"uniform sampler2D Ytex,Utex,Vtex;"
"uniform vec2 tex_scale0;"
"uniform vec2 tex_scale1;"
"uniform vec2 tex_scale2;"
"const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
"const vec3 rcoeff = vec3(1.164, 0.000, 1.596);"
"const vec3 gcoeff = vec3(1.164,-0.391,-0.813);"
"const vec3 bcoeff = vec3(1.164, 2.018, 0.000);"
"void main(void) {"
" float r,g,b;"
" vec3 yuv;"
" yuv.x=texture2D(Ytex,opos / tex_scale0).r;"
" yuv.y=texture2D(Utex,opos / tex_scale1).r;"
" yuv.z=texture2D(Vtex,opos / tex_scale2).r;"
" yuv += offset;"
" r = dot(yuv, rcoeff);"
" g = dot(yuv, gcoeff);"
" b = dot(yuv, bcoeff);"
" gl_FragColor=vec4(r,g,b,1.0);"
"}"
};
/** NV12/NV21 to RGB conversion */
static const char *frag_NV12_NV21_prog = {
"precision mediump float;"
"varying vec2 opos;"
"uniform sampler2D Ytex,UVtex;"
"uniform vec2 tex_scale0;"
"uniform vec2 tex_scale1;"
"uniform vec2 tex_scale2;"
"const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
"const vec3 rcoeff = vec3(1.164, 0.000, 1.596);"
"const vec3 gcoeff = vec3(1.164,-0.391,-0.813);"
"const vec3 bcoeff = vec3(1.164, 2.018, 0.000);"
"void main(void) {"
" float r,g,b;"
" vec3 yuv;"
" yuv.x=texture2D(Ytex,opos / tex_scale0).r;"
" yuv.yz=texture2D(UVtex,opos / tex_scale1).%c%c;"
" yuv += offset;"
" r = dot(yuv, rcoeff);"
" g = dot(yuv, gcoeff);"
" b = dot(yuv, bcoeff);"
" gl_FragColor=vec4(r,g,b,1.0);"
"}"
};
/* *INDENT-ON* */
void
gst_egl_adaption_init (void)
{
GST_DEBUG_CATEGORY_INIT (egladaption_debug, "egladaption", 0,
"EGL adaption layer");
}
static GstCaps *
_gst_video_format_new_template_caps (GstVideoFormat format)
{
return gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, gst_video_format_to_string (format),
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
}
GstCaps *
gst_egl_adaptation_fill_supported_fbuffer_configs (GstEglAdaptationContext *
ctx)
{
GstCaps *caps = NULL, *copy1, *copy2;
guint i, n;
GST_DEBUG_OBJECT (ctx->element,
"Building initial list of wanted eglattribs per format");
/* Init supported format/caps list */
if (_gst_egl_choose_config (ctx, TRUE, NULL)) {
caps = gst_caps_new_empty ();
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBA));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRA));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ARGB));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ABGR));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBx));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRx));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xRGB));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xBGR));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_AYUV));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y444));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGR));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_I420));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YV12));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV12));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV21));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y42B));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y41B));
gst_caps_append (caps,
_gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB16));
copy1 = gst_caps_copy (caps);
copy2 = gst_caps_copy (caps);
#ifndef HAVE_IOS
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
GstCapsFeatures *features =
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, NULL);
gst_caps_set_features (caps, i, features);
}
#endif
n = gst_caps_get_size (copy1);
for (i = 0; i < n; i++) {
GstCapsFeatures *features =
gst_caps_features_new
(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, NULL);
gst_caps_set_features (copy1, i, features);
}
gst_caps_append (caps, copy1);
gst_caps_append (caps, copy2);
} else {
GST_INFO_OBJECT (ctx->element,
"EGL display doesn't support RGBA8888 config");
}
return caps;
}
void
gst_egl_adaptation_cleanup (GstEglAdaptationContext * ctx)
{
gint i;
glUseProgram (0);
if (ctx->have_vbo) {
glDeleteBuffers (1, &ctx->position_buffer);
glDeleteBuffers (1, &ctx->index_buffer);
ctx->have_vbo = FALSE;
}
if (ctx->have_texture) {
glDeleteTextures (ctx->n_textures, ctx->texture);
ctx->have_texture = FALSE;
ctx->n_textures = 0;
}
for (i = 0; i < 2; i++) {
if (ctx->glslprogram[i]) {
glDetachShader (ctx->glslprogram[i], ctx->fragshader[i]);
glDetachShader (ctx->glslprogram[i], ctx->vertshader[i]);
glDeleteProgram (ctx->glslprogram[i]);
glDeleteShader (ctx->fragshader[i]);
glDeleteShader (ctx->vertshader[i]);
ctx->glslprogram[i] = 0;
ctx->fragshader[i] = 0;
ctx->vertshader[i] = 0;
}
}
gst_egl_adaptation_context_make_current (ctx, FALSE);
gst_egl_adaptation_destroy_surface (ctx);
gst_egl_adaptation_destroy_context (ctx);
}
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 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_surface (GstEglAdaptationContext * ctx,
GstVideoFormat format)
{
GLboolean ret;
const gchar *texnames[3] = { NULL, };
gchar *frag_prog = NULL;
gboolean free_frag_prog = FALSE;
gint i;
GST_DEBUG_OBJECT (ctx->element, "Enter EGL surface setup");
if (!gst_egl_adaptation_create_surface (ctx)) {
GST_ERROR_OBJECT (ctx->element, "Can't create surface");
goto HANDLE_ERROR_LOCKED;
}
if (!gst_egl_adaptation_context_make_current (ctx, TRUE))
goto HANDLE_ERROR_LOCKED;
gst_egl_adaptation_query_buffer_preserved (ctx);
gst_egl_adaptation_init_exts (ctx);
/* Save surface dims */
gst_egl_adaptation_update_surface_dimensions (ctx);
/* Save display's pixel aspect ratio
*
* DAR is reported as w/h * EGL_DISPLAY_SCALING wich is
* a constant with value 10000. This attribute is only
* supported if the EGL version is >= 1.2
* XXX: Setup this as a property.
* or some other one time check. Right now it's being called once
* per frame.
*/
gst_egl_adaptation_query_par (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->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->n_textures = 3;
texnames[0] = "Ytex";
texnames[1] = "Utex";
texnames[2] = "Vtex";
break;
case GST_VIDEO_FORMAT_NV12:
frag_prog = g_strdup_printf (frag_NV12_NV21_prog, 'r', 'a');
free_frag_prog = TRUE;
ctx->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->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->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->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->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->n_textures = 1;
texnames[0] = "tex";
break;
default:
g_assert_not_reached ();
break;
}
if (!create_shader_program (ctx,
&ctx->glslprogram[0],
&ctx->vertshader[0],
&ctx->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->position_loc[0] = glGetAttribLocation (ctx->glslprogram[0], "position");
ctx->texpos_loc[0] = glGetAttribLocation (ctx->glslprogram[0], "texpos");
ctx->tex_scale_loc[0][0] =
glGetUniformLocation (ctx->glslprogram[0], "tex_scale0");
ctx->tex_scale_loc[0][1] =
glGetUniformLocation (ctx->glslprogram[0], "tex_scale1");
ctx->tex_scale_loc[0][2] =
glGetUniformLocation (ctx->glslprogram[0], "tex_scale2");
glEnableVertexAttribArray (ctx->position_loc[0]);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR;
glEnableVertexAttribArray (ctx->texpos_loc[0]);
if (got_gl_error ("glEnableVertexAttribArray"))
goto HANDLE_ERROR;
for (i = 0; i < ctx->n_textures; i++) {
ctx->tex_loc[0][i] =
glGetUniformLocation (ctx->glslprogram[0], texnames[i]);
}
if (!ctx->buffer_preserved) {
/* Build shader program for black borders */
if (!create_shader_program (ctx,
&ctx->glslprogram[1],
&ctx->vertshader[1],
&ctx->fragshader[1], vert_COPY_prog_no_tex, frag_BLACK_prog))
goto HANDLE_ERROR;
ctx->position_loc[1] =
glGetAttribLocation (ctx->glslprogram[1], "position");
glEnableVertexAttribArray (ctx->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->n_textures, ctx->texture);
if (got_gl_error ("glGenTextures"))
goto HANDLE_ERROR_LOCKED;
for (i = 0; i < ctx->n_textures; i++) {
glBindTexture (GL_TEXTURE_2D, ctx->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_ERROR_LOCKED:
HANDLE_ERROR:
GST_ERROR_OBJECT (ctx->element, "Couldn't setup EGL surface");
return FALSE;
}
gboolean
gst_egl_adaptation_choose_config (GstEglAdaptationContext * ctx)
{
gint egl_configs;
if (!_gst_egl_choose_config (ctx, FALSE, &egl_configs)) {
GST_ERROR_OBJECT (ctx->element, "eglChooseConfig failed");
goto HANDLE_ERROR;
}
if (egl_configs < 1) {
GST_ERROR_OBJECT (ctx->element,
"Could not find matching framebuffer config");
goto HANDLE_ERROR;
}
if (!gst_egl_adaptation_create_egl_context (ctx)) {
GST_ERROR_OBJECT (ctx->element, "Error getting context, eglCreateContext");
goto HANDLE_ERROR;
}
return TRUE;
/* Errors */
HANDLE_ERROR:
GST_ERROR_OBJECT (ctx->element, "Couldn't choose an usable config");
return FALSE;
}
GstEglAdaptationContext *
gst_egl_adaptation_context_new (GstElement * element)
{
GstEglAdaptationContext *ctx = g_new0 (GstEglAdaptationContext, 1);
ctx->element = gst_object_ref (element);
gst_egl_adaptation_init (ctx);
return ctx;
}
void
gst_egl_adaptation_context_free (GstEglAdaptationContext * ctx)
{
gst_egl_adaptation_deinit (ctx);
gst_object_unref (ctx->element);
g_free (ctx);
}