2 * Copyright (C) 2012-2013 Collabora Ltd.
3 * @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
4 * @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * @author: Thiago Santos <thiago.sousa.santos@collabora.com>
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
25 * Alternatively, the contents of this file may be used under the
26 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
27 * which case the following provisions apply instead of the ones
30 * This library is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Library General Public
32 * License as published by the Free Software Foundation; either
33 * version 2 of the License, or (at your option) any later version.
35 * This library is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 * Library General Public License for more details.
40 * You should have received a copy of the GNU Library General Public
41 * License along with this library; if not, write to the
42 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
43 * Boston, MA 02111-1307, USA.
46 #include "gstegladaptation.h"
47 #include "video_platform_wrapper.h"
51 #include <EGL/eglext.h>
52 #include <GLES2/gl2.h>
53 #include <GLES2/gl2ext.h>
54 #include <gst/egl/egl.h>
56 #define GST_CAT_DEFAULT egladaption_debug
58 /* Some EGL implementations are reporting wrong
59 * values for the display's EGL_PIXEL_ASPECT_RATIO.
60 * They are required by the khronos specs to report
61 * this value as w/h * EGL_DISPLAY_SCALING (Which is
62 * a constant with value 10000) but at least the
63 * Galaxy SIII (Android) is reporting just 1 when
64 * w = h. We use these two to bound returned values to
67 #define EGL_SANE_DAR_MIN ((EGL_DISPLAY_SCALING)/10)
68 #define EGL_SANE_DAR_MAX ((EGL_DISPLAY_SCALING)*10)
71 * GstEglGlesRenderContext:
72 * @config: Current EGL config
73 * @eglcontext: Current EGL context
74 * @egl_minor: EGL version (minor)
75 * @egl_major: EGL version (major)
77 * This struct holds the sink's EGL/GLES rendering context.
79 struct _GstEglGlesRenderContext
82 EGLContext eglcontext;
84 EGLint egl_minor, egl_major;
88 got_egl_error (const char *wtf)
92 if ((error = eglGetError ()) != EGL_SUCCESS) {
93 GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned 0x%04x", wtf,
101 /* Prints available EGL/GLES extensions
102 * If another rendering path is implemented this is the place
103 * where you want to check for the availability of its supporting
104 * EGL/GLES extensions.
107 gst_egl_adaptation_init_egl_exts (GstEglAdaptationContext * ctx)
110 unsigned const char *glexts;
112 eglexts = eglQueryString (gst_egl_display_get (ctx->display), EGL_EXTENSIONS);
113 glexts = glGetString (GL_EXTENSIONS);
115 GST_DEBUG_OBJECT (ctx->element, "Available EGL extensions: %s\n",
116 GST_STR_NULL (eglexts));
117 GST_DEBUG_OBJECT (ctx->element, "Available GLES extensions: %s\n",
118 GST_STR_NULL ((const char *) glexts));
124 gst_egl_adaptation_init_egl_display (GstEglAdaptationContext * ctx)
128 GST_DEBUG_OBJECT (ctx->element, "Enter EGL initial configuration");
130 if (!platform_wrapper_init ()) {
131 GST_ERROR_OBJECT (ctx->element, "Couldn't init EGL platform wrapper");
135 /* See https://github.com/raspberrypi/firmware/issues/99 */
136 if (!eglMakeCurrent ((EGLDisplay) 1, EGL_NO_SURFACE, EGL_NO_SURFACE,
138 got_egl_error ("eglMakeCurrent");
139 GST_ERROR_OBJECT (ctx->element, "Couldn't unbind context");
144 msg = gst_message_new_need_context (GST_OBJECT_CAST (ctx->element));
145 gst_message_add_context_type (msg, GST_EGL_DISPLAY_CONTEXT_TYPE);
146 gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg);
148 GST_OBJECT_LOCK (ctx->element);
149 if (ctx->set_display) {
152 ctx->display = gst_egl_display_ref (ctx->set_display);
153 GST_OBJECT_UNLOCK (ctx->element);
154 context = gst_element_get_context (GST_ELEMENT_CAST (ctx->element));
156 context = gst_context_new ();
157 context = gst_context_make_writable (context);
158 gst_context_set_egl_display (context, ctx->display);
159 gst_element_set_context (GST_ELEMENT_CAST (ctx->element), context);
160 gst_context_unref (context);
164 GST_OBJECT_UNLOCK (ctx->element);
166 display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
167 if (display == EGL_NO_DISPLAY) {
168 GST_ERROR_OBJECT (ctx->element, "Could not get EGL display connection");
169 goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */
171 ctx->display = gst_egl_display_new (display);
173 context = gst_context_new ();
174 gst_context_set_egl_display (context, ctx->display);
176 msg = gst_message_new_have_context (GST_OBJECT (ctx->element), context);
177 gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg);
180 context = gst_element_get_context (GST_ELEMENT_CAST (ctx->element));
182 context = gst_context_new ();
183 context = gst_context_make_writable (context);
184 gst_context_set_egl_display (context, ctx->display);
185 gst_element_set_context (GST_ELEMENT_CAST (ctx->element), context);
186 gst_context_unref (context);
189 if (!eglInitialize (gst_egl_display_get (ctx->display),
190 &ctx->eglglesctx->egl_major, &ctx->eglglesctx->egl_minor)) {
191 got_egl_error ("eglInitialize");
192 GST_ERROR_OBJECT (ctx->element, "Could not init EGL display connection");
193 goto HANDLE_EGL_ERROR;
196 /* Check against required EGL version
197 * XXX: Need to review the version requirement in terms of the needed API
199 if (ctx->eglglesctx->egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) {
200 GST_ERROR_OBJECT (ctx->element, "EGL v%d needed, but you only have v%d.%d",
201 GST_EGLGLESSINK_EGL_MIN_VERSION, ctx->eglglesctx->egl_major,
202 ctx->eglglesctx->egl_minor);
206 GST_INFO_OBJECT (ctx->element, "System reports supported EGL version v%d.%d",
207 ctx->eglglesctx->egl_major, ctx->eglglesctx->egl_minor);
209 eglBindAPI (EGL_OPENGL_ES_API);
215 GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ());
217 GST_ERROR_OBJECT (ctx->element, "Couldn't setup window/surface from handle");
222 gst_egl_adaptation_context_make_current (GstEglAdaptationContext * ctx,
225 g_assert (ctx->display != NULL);
227 if (bind && ctx->eglglesctx->surface && ctx->eglglesctx->eglcontext) {
228 EGLContext *cur_ctx = eglGetCurrentContext ();
230 if (cur_ctx == ctx->eglglesctx->eglcontext) {
231 GST_DEBUG_OBJECT (ctx->element,
232 "Already attached the context to thread %p", g_thread_self ());
236 GST_DEBUG_OBJECT (ctx->element, "Attaching context to thread %p",
238 if (!eglMakeCurrent (gst_egl_display_get (ctx->display),
239 ctx->eglglesctx->surface, ctx->eglglesctx->surface,
240 ctx->eglglesctx->eglcontext)) {
241 got_egl_error ("eglMakeCurrent");
242 GST_ERROR_OBJECT (ctx->element, "Couldn't bind context");
246 GST_DEBUG_OBJECT (ctx->element, "Detaching context from thread %p",
248 if (!eglMakeCurrent (gst_egl_display_get (ctx->display),
249 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
250 got_egl_error ("eglMakeCurrent");
251 GST_ERROR_OBJECT (ctx->element, "Couldn't unbind context");
259 /* XXX: Lock eglgles context? */
261 gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext * ctx)
265 /* Save surface dims */
266 eglQuerySurface (gst_egl_display_get (ctx->display),
267 ctx->eglglesctx->surface, EGL_WIDTH, &width);
268 eglQuerySurface (gst_egl_display_get (ctx->display),
269 ctx->eglglesctx->surface, EGL_HEIGHT, &height);
271 if (width != ctx->surface_width || height != ctx->surface_height) {
272 ctx->surface_width = width;
273 ctx->surface_height = height;
274 GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels", width,
283 gst_egl_adaptation_context_swap_buffers (GstEglAdaptationContext * ctx)
285 gboolean ret = eglSwapBuffers (gst_egl_display_get (ctx->display),
286 ctx->eglglesctx->surface);
287 if (ret == EGL_FALSE) {
288 got_egl_error ("eglSwapBuffers");
294 _gst_egl_choose_config (GstEglAdaptationContext * ctx, gboolean try_only,
299 EGLConfig *config = NULL;
302 config = &ctx->eglglesctx->config;
304 ret = eglChooseConfig (gst_egl_display_get (ctx->display),
305 eglglessink_RGBA8888_attribs, config, 1, &cfg_number) != EGL_FALSE;
308 got_egl_error ("eglChooseConfig");
309 else if (num_configs)
310 *num_configs = cfg_number;
315 gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
317 ctx->eglglesctx->surface =
318 eglCreateWindowSurface (gst_egl_display_get (ctx->display),
319 ctx->eglglesctx->config, ctx->used_window, NULL);
321 if (ctx->eglglesctx->surface == EGL_NO_SURFACE) {
322 got_egl_error ("eglCreateWindowSurface");
323 GST_ERROR_OBJECT (ctx->element, "Can't create surface");
330 gst_egl_adaptation_query_buffer_preserved (GstEglAdaptationContext * ctx)
332 EGLint swap_behavior;
334 ctx->buffer_preserved = FALSE;
335 if (eglQuerySurface (gst_egl_display_get (ctx->display),
336 ctx->eglglesctx->surface, EGL_SWAP_BEHAVIOR, &swap_behavior)) {
337 GST_DEBUG_OBJECT (ctx->element, "Buffer swap behavior %x", swap_behavior);
338 ctx->buffer_preserved = swap_behavior == EGL_BUFFER_PRESERVED;
340 GST_DEBUG_OBJECT (ctx->element, "Can't query buffer swap behavior");
345 gst_egl_adaptation_query_par (GstEglAdaptationContext * ctx)
350 ctx->pixel_aspect_ratio_d = EGL_DISPLAY_SCALING;
352 /* Save display's pixel aspect ratio
354 * DAR is reported as w/h * EGL_DISPLAY_SCALING wich is
355 * a constant with value 10000. This attribute is only
356 * supported if the EGL version is >= 1.2
357 * XXX: Setup this as a property.
358 * or some other one time check. Right now it's being called once
361 if (ctx->eglglesctx->egl_major == 1 && ctx->eglglesctx->egl_minor < 2) {
362 GST_DEBUG_OBJECT (ctx->element, "Can't query PAR. Using default: %dx%d",
363 EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
364 ctx->pixel_aspect_ratio_n = EGL_DISPLAY_SCALING;
366 eglQuerySurface (gst_egl_display_get (ctx->display),
367 ctx->eglglesctx->surface, EGL_PIXEL_ASPECT_RATIO, &display_par);
368 /* Fix for outbound DAR reporting on some implementations not
369 * honoring the 'should return w/h * EGL_DISPLAY_SCALING' spec
372 if (display_par == EGL_UNKNOWN || display_par < EGL_SANE_DAR_MIN ||
373 display_par > EGL_SANE_DAR_MAX) {
374 GST_DEBUG_OBJECT (ctx->element, "Nonsensical PAR value returned: %d. "
375 "Bad EGL implementation? "
376 "Will use default: %d/%d", ctx->pixel_aspect_ratio_n,
377 EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
378 ctx->pixel_aspect_ratio_n = EGL_DISPLAY_SCALING;
380 ctx->pixel_aspect_ratio_n = display_par;
386 gst_egl_adaptation_create_egl_context (GstEglAdaptationContext * ctx)
388 EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
390 ctx->eglglesctx->eglcontext =
391 eglCreateContext (gst_egl_display_get (ctx->display),
392 ctx->eglglesctx->config, EGL_NO_CONTEXT, con_attribs);
394 if (ctx->eglglesctx->eglcontext == EGL_NO_CONTEXT) {
395 GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x",
400 GST_DEBUG_OBJECT (ctx->element, "EGL Context: %p",
401 ctx->eglglesctx->eglcontext);
407 gst_egl_gles_image_data_free (GstEGLGLESImageData * data)
409 glDeleteTextures (1, &data->texture);
410 g_slice_free (GstEGLGLESImageData, data);
415 gst_egl_adaptation_allocate_eglimage (GstEglAdaptationContext * ctx,
416 GstAllocator * allocator, GstVideoFormat format, gint width, gint height)
418 GstEGLGLESImageData *data = NULL;
424 GstMemory *mem[3] = { NULL, NULL, NULL };
426 GstMemoryFlags flags = 0;
428 memset (stride, 0, sizeof (stride));
429 memset (offset, 0, sizeof (offset));
431 if (!gst_egl_image_memory_is_mappable ())
432 flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
433 /* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */
434 flags |= GST_MEMORY_FLAG_NO_SHARE;
436 gst_video_info_set_format (&info, format, width, height);
439 case GST_VIDEO_FORMAT_RGB:
440 case GST_VIDEO_FORMAT_BGR:{
445 gst_egl_image_allocator_alloc (allocator, ctx->display,
446 GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
447 GST_VIDEO_INFO_HEIGHT (&info), &size);
449 stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
451 GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
453 data = g_slice_new0 (GstEGLGLESImageData);
455 stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 3);
456 size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);
458 glGenTextures (1, &data->texture);
459 if (got_gl_error ("glGenTextures"))
462 glBindTexture (GL_TEXTURE_2D, data->texture);
463 if (got_gl_error ("glBindTexture"))
466 /* Set 2D resizing params */
467 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
468 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
470 /* If these are not set the texture image unit will return
471 * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
472 * * frames. For a deeper explanation take a look at the OpenGL ES
473 * * documentation for glTexParameter */
474 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
475 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
476 if (got_gl_error ("glTexParameteri"))
479 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
480 GST_VIDEO_INFO_WIDTH (&info),
481 GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
482 if (got_gl_error ("glTexImage2D"))
486 eglCreateImageKHR (gst_egl_display_get (ctx->display),
487 ctx->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR,
488 (EGLClientBuffer) (guintptr) data->texture, NULL);
489 if (got_egl_error ("eglCreateImageKHR"))
493 gst_egl_image_allocator_wrap (allocator, ctx->display,
494 image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
495 flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
500 case GST_VIDEO_FORMAT_RGB16:{
505 gst_egl_image_allocator_alloc (allocator, ctx->display,
506 GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
507 GST_VIDEO_INFO_HEIGHT (&info), &size);
509 stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
511 GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
513 data = g_slice_new0 (GstEGLGLESImageData);
515 stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 2);
516 size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);
518 glGenTextures (1, &data->texture);
519 if (got_gl_error ("glGenTextures"))
522 glBindTexture (GL_TEXTURE_2D, data->texture);
523 if (got_gl_error ("glBindTexture"))
526 /* Set 2D resizing params */
527 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
528 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
530 /* If these are not set the texture image unit will return
531 * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
532 * * frames. For a deeper explanation take a look at the OpenGL ES
533 * * documentation for glTexParameter */
534 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
535 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
536 if (got_gl_error ("glTexParameteri"))
539 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
540 GST_VIDEO_INFO_WIDTH (&info),
541 GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
543 if (got_gl_error ("glTexImage2D"))
547 eglCreateImageKHR (gst_egl_display_get (ctx->display),
548 ctx->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR,
549 (EGLClientBuffer) (guintptr) data->texture, NULL);
550 if (got_egl_error ("eglCreateImageKHR"))
554 gst_egl_image_allocator_wrap (allocator, ctx->display,
555 image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
556 flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
561 case GST_VIDEO_FORMAT_NV12:
562 case GST_VIDEO_FORMAT_NV21:{
567 gst_egl_image_allocator_alloc (allocator, ctx->display,
568 GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
569 0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
571 gst_egl_image_allocator_alloc (allocator, ctx->display,
572 GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
573 GST_VIDEO_INFO_COMP_WIDTH (&info, 1),
574 GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
576 if (mem[0] && mem[1]) {
577 stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
579 stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
581 GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
582 GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
585 gst_memory_unref (mem[0]);
587 gst_memory_unref (mem[1]);
588 mem[0] = mem[1] = NULL;
590 stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
591 stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1) * 2);
592 offset[1] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
594 size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
596 for (i = 0; i < 2; i++) {
597 data = g_slice_new0 (GstEGLGLESImageData);
599 glGenTextures (1, &data->texture);
600 if (got_gl_error ("glGenTextures"))
603 glBindTexture (GL_TEXTURE_2D, data->texture);
604 if (got_gl_error ("glBindTexture"))
607 /* Set 2D resizing params */
608 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
609 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
611 /* If these are not set the texture image unit will return
612 * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
613 * * frames. For a deeper explanation take a look at the OpenGL ES
614 * * documentation for glTexParameter */
615 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
616 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
617 if (got_gl_error ("glTexParameteri"))
621 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
622 GST_VIDEO_INFO_COMP_WIDTH (&info, i),
623 GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
624 GL_UNSIGNED_BYTE, NULL);
626 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
627 GST_VIDEO_INFO_COMP_WIDTH (&info, i),
628 GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE_ALPHA,
629 GL_UNSIGNED_BYTE, NULL);
631 if (got_gl_error ("glTexImage2D"))
635 eglCreateImageKHR (gst_egl_display_get (ctx->display),
636 ctx->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR,
637 (EGLClientBuffer) (guintptr) data->texture, NULL);
638 if (got_egl_error ("eglCreateImageKHR"))
642 gst_egl_image_allocator_wrap (allocator, ctx->display,
645 0 ? GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE :
646 GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA),
647 flags, size[i], data,
648 (GDestroyNotify) gst_egl_gles_image_data_free);
655 case GST_VIDEO_FORMAT_I420:
656 case GST_VIDEO_FORMAT_YV12:
657 case GST_VIDEO_FORMAT_Y444:
658 case GST_VIDEO_FORMAT_Y42B:
659 case GST_VIDEO_FORMAT_Y41B:{
664 gst_egl_image_allocator_alloc (allocator, ctx->display,
665 GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
666 0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
668 gst_egl_image_allocator_alloc (allocator, ctx->display,
669 GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
670 1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
672 gst_egl_image_allocator_alloc (allocator, ctx->display,
673 GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
674 2), GST_VIDEO_INFO_COMP_HEIGHT (&info, 2), &size[2]);
676 if (mem[0] && mem[1] && mem[2]) {
677 stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
679 stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
681 stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (&info);
683 GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
684 GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
685 GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
688 gst_memory_unref (mem[0]);
690 gst_memory_unref (mem[1]);
692 gst_memory_unref (mem[2]);
693 mem[0] = mem[1] = mem[2] = NULL;
695 stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
696 stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1));
697 stride[2] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 2));
698 size[0] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
699 size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
700 size[2] = stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 2);
703 offset[2] = offset[1] + size[1];
705 for (i = 0; i < 3; i++) {
706 data = g_slice_new0 (GstEGLGLESImageData);
708 glGenTextures (1, &data->texture);
709 if (got_gl_error ("glGenTextures"))
712 glBindTexture (GL_TEXTURE_2D, data->texture);
713 if (got_gl_error ("glBindTexture"))
716 /* Set 2D resizing params */
717 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
718 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
720 /* If these are not set the texture image unit will return
721 * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
722 * * frames. For a deeper explanation take a look at the OpenGL ES
723 * * documentation for glTexParameter */
724 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
725 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
726 if (got_gl_error ("glTexParameteri"))
729 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
730 GST_VIDEO_INFO_COMP_WIDTH (&info, i),
731 GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
732 GL_UNSIGNED_BYTE, NULL);
734 if (got_gl_error ("glTexImage2D"))
738 eglCreateImageKHR (gst_egl_display_get (ctx->display),
739 ctx->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR,
740 (EGLClientBuffer) (guintptr) data->texture, NULL);
741 if (got_egl_error ("eglCreateImageKHR"))
745 gst_egl_image_allocator_wrap (allocator, ctx->display,
746 image, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE,
747 flags, size[i], data,
748 (GDestroyNotify) gst_egl_gles_image_data_free);
755 case GST_VIDEO_FORMAT_RGBA:
756 case GST_VIDEO_FORMAT_BGRA:
757 case GST_VIDEO_FORMAT_ARGB:
758 case GST_VIDEO_FORMAT_ABGR:
759 case GST_VIDEO_FORMAT_RGBx:
760 case GST_VIDEO_FORMAT_BGRx:
761 case GST_VIDEO_FORMAT_xRGB:
762 case GST_VIDEO_FORMAT_xBGR:
763 case GST_VIDEO_FORMAT_AYUV:{
768 gst_egl_image_allocator_alloc (allocator, ctx->display,
769 GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info),
770 GST_VIDEO_INFO_HEIGHT (&info), &size);
772 stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
774 GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
776 data = g_slice_new0 (GstEGLGLESImageData);
778 stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4);
779 size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);
781 glGenTextures (1, &data->texture);
782 if (got_gl_error ("glGenTextures"))
785 glBindTexture (GL_TEXTURE_2D, data->texture);
786 if (got_gl_error ("glBindTexture"))
789 /* Set 2D resizing params */
790 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
791 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
793 /* If these are not set the texture image unit will return
794 * * (R, G, B, A) = black on glTexImage2D for non-POT width/height
795 * * frames. For a deeper explanation take a look at the OpenGL ES
796 * * documentation for glTexParameter */
797 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
798 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
799 if (got_gl_error ("glTexParameteri"))
802 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
803 GST_VIDEO_INFO_WIDTH (&info),
804 GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
805 if (got_gl_error ("glTexImage2D"))
809 eglCreateImageKHR (gst_egl_display_get (ctx->display),
810 ctx->eglglesctx->eglcontext, EGL_GL_TEXTURE_2D_KHR,
811 (EGLClientBuffer) (guintptr) data->texture, NULL);
812 if (got_egl_error ("eglCreateImageKHR"))
816 gst_egl_image_allocator_wrap (allocator, ctx->display,
817 image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA,
818 flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
825 g_assert_not_reached ();
829 buffer = gst_buffer_new ();
830 gst_buffer_add_video_meta_full (buffer, 0, format, width, height,
831 GST_VIDEO_INFO_N_PLANES (&info), offset, stride);
833 for (i = 0; i < n_mem; i++)
834 gst_buffer_append_memory (buffer, mem[i]);
840 GST_ERROR_OBJECT (ctx->element, "Failed to create EGLImage");
843 gst_egl_gles_image_data_free (data);
846 gst_memory_unref (mem[0]);
848 gst_memory_unref (mem[1]);
850 gst_memory_unref (mem[2]);
857 gst_egl_adaptation_destroy_native_window (GstEglAdaptationContext * ctx,
858 gpointer * own_window_data)
860 platform_destroy_native_window (gst_egl_display_get
861 (ctx->display), ctx->used_window, own_window_data);
862 ctx->used_window = 0;
866 gst_egl_adaptation_create_native_window (GstEglAdaptationContext * ctx,
867 gint width, gint height, gpointer * own_window_data)
869 EGLNativeWindowType window =
870 platform_create_native_window (width, height, own_window_data);
872 gst_egl_adaptation_set_window (ctx, (guintptr) window);
873 GST_DEBUG_OBJECT (ctx->element, "Using window handle %p", (gpointer) window);
878 gst_egl_adaptation_set_window (GstEglAdaptationContext * ctx, guintptr window)
880 ctx->window = (EGLNativeWindowType) window;
884 gst_egl_adaptation_init (GstEglAdaptationContext * ctx)
886 ctx->eglglesctx = g_new0 (GstEglGlesRenderContext, 1);
890 gst_egl_adaptation_deinit (GstEglAdaptationContext * ctx)
892 g_free (ctx->eglglesctx);
896 gst_egl_adaptation_destroy_surface (GstEglAdaptationContext * ctx)
898 if (ctx->eglglesctx->surface) {
899 eglDestroySurface (gst_egl_display_get (ctx->display),
900 ctx->eglglesctx->surface);
901 ctx->eglglesctx->surface = NULL;
902 ctx->have_surface = FALSE;
907 gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx)
909 if (ctx->eglglesctx->eglcontext) {
910 eglDestroyContext (gst_egl_display_get (ctx->display),
911 ctx->eglglesctx->eglcontext);
912 ctx->eglglesctx->eglcontext = NULL;