2 * GStreamer EGL/GLES Sink
3 * Copyright (C) 2012 Collabora Ltd.
4 * @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Alternatively, the contents of this file may be used under the
25 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
26 * which case the following provisions apply instead of the ones
29 * This library is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU Library General Public
31 * License as published by the Free Software Foundation; either
32 * version 2 of the License, or (at your option) any later version.
34 * This library is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * Library General Public License for more details.
39 * You should have received a copy of the GNU Library General Public
40 * License along with this library; if not, write to the
41 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
42 * Boston, MA 02111-1307, USA.
46 * SECTION:element-eglglessink
48 * EglGlesSink renders video frames on a EGL surface it sets up
49 * from a window it either creates (on X11) or gets a handle to
50 * through it's xOverlay interface. All the display/surface logic
51 * in this sink uses EGL to interact with the native window system.
52 * The rendering logic, in turn, uses OpenGL ES v2.
54 * This sink has been tested to work on X11/Mesa and on Android
55 * (From Gingerbread on to Jelly Bean) and while it's currently
56 * using an slow copy-over rendering path it has proven to be fast
57 * enough on the devices we have tried it on. That being said, there's
58 * an currently unfinished and drafted fast rendering path in the code,
59 * relying on a set of EGL/GLES extensions.
62 * <title>Supported EGL/OpenGL ES versions</title>
64 * This Sink uses EGLv1 and GLESv2
69 * <title>Example launch line</title>
71 * gst-launch -v -m videotestsrc ! eglglessink
76 * <title>Example launch line with forced slow path rendering</title>
78 * By setting the force_rendering_slow property you can force the sink
79 * to chose the buffer-copy slow rendering path even if the needed
80 * EGL/GLES extensions for the fast rendering path are available.
83 * gst-launch -v -m videotestsrc ! eglglessink force_rendering_slow=TRUE
88 * <title>Example launch line with internal window creation disabled</title>
90 * By setting the can_create_window property to FALSE you can force the
91 * sink to wait for a window handle through it's xOverlay interface even
92 * if internal window creation is supported by the platform. Window creation
93 * is only supported in X11 right now but it should be trivial to add support
94 * for different platforms.
97 * gst-launch -v -m videotestsrc ! eglglessink can_create_window=FALSE
102 * <title>Scaling</title>
104 * The sink will try it's best to consider the incoming frame's and display's
105 * pixel aspect ratio and fill the corresponding surface without altering the
106 * decoded frame's geometry when scaling. You can disable this logic by setting
107 * the force_aspect_ratio property to FALSE, in which case the sink will just
108 * fill the entire surface it has access to regardles of the PAR/DAR relationship.
111 * Querying the display aspect ratio is only supported with EGL versions >= 1.2.
112 * The sink will just assume the DAR to be 1/1 if it can't get access to this
116 * Here is an example launch line with the PAR/DAR aware scaling disabled:
119 * gst-launch -v -m videotestsrc ! eglglessink force_aspect_ratio=FALSE
130 #include <gst/video/video.h>
131 #include <gst/video/gstvideosink.h>
132 #include <gst/interfaces/xoverlay.h>
135 #include <EGL/eglext.h>
136 #include <GLES2/gl2.h>
137 #include <GLES2/gl2ext.h>
141 #include "video_platform_wrapper.h"
143 #include "gsteglglessink.h"
145 GST_DEBUG_CATEGORY_STATIC (gst_eglglessink_debug);
146 #define GST_CAT_DEFAULT gst_eglglessink_debug
148 /* These are only needed for the fast rendering path */
150 static PFNEGLCREATEIMAGEKHRPROC my_eglCreateImageKHR;
151 static PFNEGLDESTROYIMAGEKHRPROC my_eglDestroyImageKHR;
153 #ifdef EGL_KHR_lock_surface
154 static PFNEGLLOCKSURFACEKHRPROC my_eglLockSurfaceKHR;
155 static PFNEGLUNLOCKSURFACEKHRPROC my_eglUnlockSurfaceKHR;
157 static EGLint lock_attribs[] = {
158 EGL_MAP_PRESERVE_PIXELS_KHR, EGL_TRUE,
159 EGL_LOCK_USAGE_HINT_KHR, EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR,
163 #ifdef GL_OES_EGL_image
164 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC my_glEGLImageTargetTexture2DOES;
165 #define EGL_FAST_RENDERING_POSSIBLE 1
170 /* GLESv2 GLSL Shaders
172 * OpenGL ES Standard does not mandate YUV support. This is
173 * why most of these shaders deal with Packed/Planar YUV->RGB
178 /* Direct vertex copy */
179 static const char *vert_COPY_prog = {
180 "attribute vec3 position;"
181 "attribute vec2 texpos;"
186 " gl_Position = vec4(position, 1.0);"
190 /* Direct fragments copy */
191 static const char *frag_COPY_prog = {
192 "precision mediump float;"
194 "uniform sampler2D tex;"
197 " vec4 t = texture2D(tex, opos);"
198 " gl_FragColor = vec4(t.xyz, 1.0);"
202 /* Channel reordering for XYZ <-> ZYX conversion */
203 static const char *frag_REORDER_prog = {
204 "precision mediump float;"
206 "uniform sampler2D tex;"
209 " vec4 t = texture2D(tex, opos);"
210 " gl_FragColor = vec4(t.%c, t.%c, t.%c, 1.0);"
214 /* Packed YUV converters */
216 /** AYUV to RGB conversion */
217 static const char *frag_AYUV_prog = {
218 "precision mediump float;"
220 "uniform sampler2D tex;"
221 "const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
222 "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);"
223 "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);"
224 "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);"
228 " yuv = texture2D(tex,opos.xy).gba;"
230 " r = dot(yuv, rcoeff);"
231 " g = dot(yuv, gcoeff);"
232 " b = dot(yuv, bcoeff);"
233 " gl_FragColor=vec4(r,g,b,1.0);"
237 /** YUY2/YVYU/UYVY to RGB conversion */
238 static const char *frag_YUY2_YVYU_UYVY_prog = {
239 "precision mediump float;"
241 "uniform sampler2D Ytex, UVtex;"
242 "const vec3 offset = vec3(-0.0625, -0.5, -0.5);"
243 "const vec3 rcoeff = vec3(1.164, 0.000, 1.596);"
244 "const vec3 gcoeff = vec3(1.164,-0.391,-0.813);"
245 "const vec3 bcoeff = vec3(1.164, 2.018, 0.000);"
249 " vec2 oposxy = vec2(opos.x, opos.y);"
250 " yuv.x = texture2D(Ytex,oposxy).x;"
251 " yuv.yz = texture2D(UVtex,oposxy).yz;"
253 " r = dot(yuv, rcoeff);"
254 " g = dot(yuv, gcoeff);"
255 " b = dot(yuv, bcoeff);"
256 " gl_FragColor=vec4(r,g,b,1.0);"
260 /* Planar YUV converters */
262 /** YUV to RGB conversion */
263 static const char *frag_PLANAR_YUV_prog = {
264 "precision mediump float;"
266 "uniform sampler2D Ytex,Utex,Vtex;"
268 " float r,g,b,y,u,v;"
269 " vec2 nxy = opos.xy;"
270 " y=texture2D(Ytex,nxy).r;"
271 " u=texture2D(Utex,nxy).r;"
272 " v=texture2D(Vtex,nxy).r;"
273 " y=1.1643*(y-0.0625);"
277 " g=y-0.39173*u-0.81290*v;"
279 " gl_FragColor=vec4(r,g,b,1.0);"
283 /** NV12/NV21 to RGB conversion */
284 static const char *frag_NV12_NV21_prog = {
285 "precision mediump float;"
287 "uniform sampler2D Ytex,UVtex;"
289 " float r,g,b,y,u,v;"
290 " vec2 nxy = opos.xy;"
291 " y=texture2D(Ytex,nxy).r;"
292 " u=texture2D(UVtex,nxy).%c;"
293 " v=texture2D(UVtex,nxy).%c;"
294 " y=1.1643*(y-0.0625);"
298 " g=y-0.39173*u-0.81290*v;"
300 " gl_FragColor=vec4(r,g,b,1.0);"
305 /* Input capabilities. */
306 static GstStaticPadTemplate gst_eglglessink_sink_template_factory =
307 GST_STATIC_PAD_TEMPLATE ("sink",
310 GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";"
311 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";"
312 GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
313 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
315 ("{ AYUV, Y444, I420, YV12, NV12, NV21, YUY2, YVYU, UYVY, Y42B, Y41B }") ";"
316 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";" GST_VIDEO_CAPS_RGB_16));
318 /* Filter signals and args */
329 PROP_FORCE_ASPECT_RATIO,
330 PROP_FORCE_RENDERING_SLOW
333 /* will probably move elsewhere */
334 static const EGLint eglglessink_RGBA8888_attribs[] = {
339 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
340 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
344 static const EGLint eglglessink_RGB888_attribs[] = {
348 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
349 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
353 static const EGLint eglglessink_RGB565_attribs[] = {
357 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
358 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
362 static void gst_eglglessink_finalize (GObject * object);
363 static void gst_eglglessink_get_property (GObject * object, guint prop_id,
364 GValue * value, GParamSpec * pspec);
365 static void gst_eglglessink_set_property (GObject * object, guint prop_id,
366 const GValue * value, GParamSpec * pspec);
367 static GstStateChangeReturn gst_eglglessink_change_state (GstElement * element,
368 GstStateChange transition);
369 static GstFlowReturn gst_eglglessink_show_frame (GstVideoSink * vsink,
371 static gboolean gst_eglglessink_setcaps (GstBaseSink * bsink, GstCaps * caps);
372 static gboolean gst_eglglessink_start (GstBaseSink * sink);
373 static gboolean gst_eglglessink_stop (GstBaseSink * sink);
374 static GstFlowReturn gst_eglglessink_buffer_alloc (GstBaseSink * sink,
375 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
376 static GstCaps *gst_eglglessink_getcaps (GstBaseSink * bsink);
378 /* XOverlay interface cruft */
379 static gboolean gst_eglglessink_interface_supported
380 (GstImplementsInterface * iface, GType type);
381 static void gst_eglglessink_implements_init
382 (GstImplementsInterfaceClass * klass);
383 static void gst_eglglessink_xoverlay_init (GstXOverlayClass * iface);
384 static void gst_eglglessink_init_interfaces (GType type);
386 /* Actual XOverlay interface funcs */
387 static void gst_eglglessink_expose (GstXOverlay * overlay);
388 static void gst_eglglessink_set_window_handle (GstXOverlay * overlay,
390 static void gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x,
391 gint y, gint width, gint height);
393 /* Custom Buffer funcs */
394 static void gst_eglglesbuffer_destroy (GstEglGlesBuffer * eglglessink);
395 static void gst_eglglesbuffer_init (GstEglGlesBuffer * eglglessink,
397 static GType gst_eglglesbuffer_get_type (void);
398 static GstEglGlesImageFmt *gst_eglglessink_get_compat_format_from_caps
399 (GstEglGlesSink * eglglessink, GstCaps * caps);
400 static void gst_eglglesbuffer_finalize (GstEglGlesBuffer * eglglessink);
401 static void gst_eglglesbuffer_class_init (gpointer g_class,
402 gpointer class_data);
403 static void gst_eglglesbuffer_free (GstEglGlesBuffer * eglglesbuffer);
404 static GstEglGlesBuffer *gst_eglglesbuffer_new (GstEglGlesSink * eglglessink,
406 static EGLint *gst_eglglesbuffer_create_native (EGLNativeWindowType win,
407 EGLConfig config, EGLNativeDisplayType display, const EGLint * egl_attribs);
410 static EGLNativeWindowType gst_eglglessink_create_window (GstEglGlesSink *
411 eglglessink, gint width, gint height);
413 gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink);
414 static gboolean gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink);
415 static gboolean gst_eglglessink_choose_config (GstEglGlesSink * eglglessink);
416 static gboolean gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink);
417 static void gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink);
418 static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink,
420 static GstFlowReturn gst_eglglessink_render_and_display (GstEglGlesSink * sink,
422 static inline gboolean got_gl_error (const char *wtf);
423 static inline void show_egl_error (const char *wtf);
424 static void gst_eglglessink_wipe_fmt (gpointer data);
425 static inline gboolean egl_init (GstEglGlesSink * eglglessink);
426 static gboolean gst_eglglessink_context_make_current (GstEglGlesSink *
427 eglglessink, gboolean bind, gboolean streaming_thread);
429 static GstBufferClass *gsteglglessink_buffer_parent_class = NULL;
430 #define GST_TYPE_EGLGLESBUFFER (gst_eglglesbuffer_get_type())
431 #define GST_IS_EGLGLESBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EGLGLESBUFFER))
432 #define GST_EGLGLESBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EGLGLESBUFFER, GstEglGlesBuffer))
433 #define GST_EGLGLESBUFFER_CAST(obj) ((GstEglGlesBuffer *)(obj))
436 GST_BOILERPLATE_FULL (GstEglGlesSink, gst_eglglessink, GstVideoSink,
437 GST_TYPE_VIDEO_SINK, gst_eglglessink_init_interfaces);
439 /* Custom Buffer Funcs */
440 /* XXX: Drafted implementation */
442 gst_eglglesbuffer_create_native (EGLNativeWindowType win,
443 EGLConfig config, EGLNativeDisplayType display, const EGLint * egl_attribs)
445 EGLNativePixmapType pix = 0;
446 EGLSurface pix_surface;
447 EGLint *buffer = NULL;
449 /* XXX: Need to figure out how to create an egl_native_pixmap_t to
450 * feed to eglCreatePixmapSurface. An option on android: create an
451 * android_native_buffer_t to pass straight to eglCreateImageKHR.
454 pix_surface = eglCreatePixmapSurface (display, config, pix, egl_attribs);
456 if (pix_surface == EGL_NO_SURFACE) {
457 show_egl_error ("eglCreatePixmapSurface");
458 GST_CAT_ERROR (GST_CAT_DEFAULT, "Unable to create pixmap surface");
462 if (my_eglLockSurfaceKHR (display, pix_surface, lock_attribs) == EGL_FALSE) {
463 show_egl_error ("eglLockSurfaceKHR");
464 GST_CAT_ERROR (GST_CAT_DEFAULT, "Unable to lock surface");
468 if (eglQuerySurface (display, pix_surface, EGL_BITMAP_POINTER_KHR, buffer)
470 show_egl_error ("eglQuerySurface");
471 GST_CAT_ERROR (GST_CAT_DEFAULT,
472 "Unable to query surface for bitmap pointer");
473 goto EGL_ERROR_LOCKED;
479 my_eglUnlockSurfaceKHR (display, pix_surface);
481 GST_CAT_ERROR (GST_CAT_DEFAULT, "EGL call returned error %x", eglGetError ());
482 if (!eglDestroySurface (display, pix_surface)) {
483 show_egl_error ("eglDestroySurface");
484 GST_CAT_ERROR (GST_CAT_DEFAULT, "Couldn't destroy surface");
489 static GstEglGlesBuffer *
490 gst_eglglesbuffer_new (GstEglGlesSink * eglglessink, GstCaps * caps)
492 GstEglGlesBuffer *eglglesbuffer = NULL;
493 GstStructure *structure = NULL;
494 GstEglGlesImageFmt *format;
496 g_return_val_if_fail (GST_IS_EGLGLESSINK (eglglessink), NULL);
497 g_return_val_if_fail (caps, NULL);
500 (GstEglGlesBuffer *) gst_mini_object_new (GST_TYPE_EGLGLESBUFFER);
501 GST_DEBUG_OBJECT (eglglesbuffer, "Creating new GstEglGlesBuffer");
503 structure = gst_caps_get_structure (caps, 0);
505 if (!gst_structure_get_int (structure, "width", &eglglesbuffer->width) ||
506 !gst_structure_get_int (structure, "height", &eglglesbuffer->height)) {
507 GST_WARNING ("Failed getting geometry from caps %" GST_PTR_FORMAT, caps);
510 GST_LOG_OBJECT (eglglessink, "creating %dx%d", eglglesbuffer->width,
511 eglglesbuffer->height);
513 format = gst_eglglessink_get_compat_format_from_caps (eglglessink, caps);
516 GST_WARNING_OBJECT (eglglessink,
517 "Failed to get format from caps %" GST_PTR_FORMAT, caps);
518 GST_ERROR_OBJECT (eglglessink,
519 "Invalid input caps. Failed to create %dx%d buffer",
520 eglglesbuffer->width, eglglesbuffer->height);
524 eglglesbuffer->format = format->fmt;
525 eglglesbuffer->eglglessink = gst_object_ref (eglglessink);
527 eglglesbuffer->image = gst_eglglesbuffer_create_native
528 (eglglessink->eglglesctx->used_window, eglglessink->eglglesctx->config,
529 eglglessink->eglglesctx->display, NULL);
530 if (!eglglesbuffer->image) {
531 GST_ERROR_OBJECT (eglglessink,
532 "Failed to create native %dx%d image buffer", eglglesbuffer->width,
533 eglglesbuffer->height);
537 GST_BUFFER_DATA (eglglesbuffer) = (guchar *) eglglesbuffer->image;
538 GST_BUFFER_SIZE (eglglesbuffer) = eglglesbuffer->size;
540 return eglglesbuffer;
543 gst_eglglesbuffer_free (eglglesbuffer);
544 eglglesbuffer = NULL;
549 gst_eglglesbuffer_destroy (GstEglGlesBuffer * eglglesbuffer)
552 GstEglGlesSink *eglglessink;
554 GST_DEBUG_OBJECT (eglglesbuffer, "Destroying buffer");
556 eglglessink = eglglesbuffer->eglglessink;
557 if (G_UNLIKELY (eglglessink == NULL))
560 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
562 GST_OBJECT_LOCK (eglglessink);
563 GST_DEBUG_OBJECT (eglglessink, "Destroying image");
565 if (eglglesbuffer->image) {
566 if (GST_BUFFER_DATA (eglglesbuffer)) {
567 g_free (GST_BUFFER_DATA (eglglesbuffer));
569 eglglesbuffer->image = NULL;
570 /* XXX: Unallocate EGL/GL especific resources asociated with this
575 GST_OBJECT_UNLOCK (eglglessink);
576 eglglesbuffer->eglglessink = NULL;
577 gst_object_unref (eglglessink);
579 GST_MINI_OBJECT_CLASS (gsteglglessink_buffer_parent_class)->finalize
580 (GST_MINI_OBJECT (eglglesbuffer));
585 GST_WARNING ("No sink found");
589 /* XXX: Missing implementation.
590 * This function will have the code for maintaing the pool. readding or
591 * destroying the buffers on size or runing/status change. Right now all
592 * it does is to call _destroy.
593 * for a proper implementation take a look at xvimagesink's image buffer
597 gst_eglglesbuffer_finalize (GstEglGlesBuffer * eglglesbuffer)
599 GstEglGlesSink *eglglessink;
601 eglglessink = eglglesbuffer->eglglessink;
602 if (G_UNLIKELY (eglglessink == NULL))
605 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
607 gst_eglglesbuffer_destroy (eglglesbuffer);
612 GST_WARNING ("No sink found");
617 gst_eglglesbuffer_free (GstEglGlesBuffer * eglglesbuffer)
619 /* Make sure it is not recycled. This is meaningless without
620 * a pool but was left here as a reference
622 eglglesbuffer->width = -1;
623 eglglesbuffer->height = -1;
624 gst_buffer_unref (GST_BUFFER (eglglesbuffer));
628 gst_eglglesbuffer_init (GstEglGlesBuffer * eglglesbuffer, gpointer g_class)
630 eglglesbuffer->width = 0;
631 eglglesbuffer->height = 0;
632 eglglesbuffer->size = 0;
633 eglglesbuffer->image = NULL;
634 eglglesbuffer->format = GST_EGLGLESSINK_IMAGE_NOFMT;
638 gst_eglglesbuffer_class_init (gpointer g_class, gpointer class_data)
640 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
642 gsteglglessink_buffer_parent_class = g_type_class_peek_parent (g_class);
644 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
645 gst_eglglesbuffer_finalize;
649 gst_eglglesbuffer_get_type (void)
651 static GType _gst_eglglessink_buffer_type;
653 if (G_UNLIKELY (_gst_eglglessink_buffer_type == 0)) {
654 static const GTypeInfo eglglessink_buffer_info = {
655 sizeof (GstBufferClass),
658 gst_eglglesbuffer_class_init,
661 sizeof (GstEglGlesBuffer),
663 (GInstanceInitFunc) gst_eglglesbuffer_init,
666 _gst_eglglessink_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
667 "GstEglGlesBuffer", &eglglessink_buffer_info, 0);
669 return _gst_eglglessink_buffer_type;
672 static GstEglGlesImageFmt *
673 gst_eglglessink_get_compat_format_from_caps (GstEglGlesSink * eglglessink,
678 GstEglGlesImageFmt *format;
680 g_return_val_if_fail (GST_IS_EGLGLESSINK (eglglessink), 0);
682 list = eglglessink->supported_fmts;
684 /* Traverse the list trying to find a compatible format */
687 GST_DEBUG_OBJECT (eglglessink, "Checking compatibility between listed %"
688 GST_PTR_FORMAT " and %" GST_PTR_FORMAT, format->caps, caps);
690 if (gst_caps_can_intersect (caps, format->caps)) {
691 GST_INFO_OBJECT (eglglessink, "Found compatible format %d",
693 GST_DEBUG_OBJECT (eglglessink,
694 "Got caps %" GST_PTR_FORMAT " and this format can do %"
695 GST_PTR_FORMAT, caps, format->caps);
699 list = g_list_next (list);
706 gst_eglglessink_different_size_suggestion (GstEglGlesSink * eglglessink,
709 GstCaps *intersection;
713 gint par_n = 1, par_d = 1;
717 new_caps = gst_caps_copy (caps);
719 s = gst_caps_get_structure (new_caps, 0);
721 gst_structure_get_int (s, "width", &width);
722 gst_structure_get_int (s, "height", &height);
723 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
725 gst_structure_remove_field (s, "width");
726 gst_structure_remove_field (s, "height");
727 gst_structure_remove_field (s, "pixel-aspect-ratio");
729 intersection = gst_caps_intersect (eglglessink->current_caps, new_caps);
730 gst_caps_unref (new_caps);
732 if (gst_caps_is_empty (intersection))
735 s = gst_caps_get_structure (intersection, 0);
737 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
739 gst_structure_fixate_field_nearest_int (s, "width", width);
740 gst_structure_fixate_field_nearest_int (s, "height", height);
741 gst_structure_get_int (s, "width", &w);
742 gst_structure_get_int (s, "height", &h);
744 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
745 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
752 gst_eglglessink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
753 guint size, GstCaps * caps, GstBuffer ** buf)
756 GstEglGlesSink *eglglessink;
757 GstFlowReturn ret = GST_FLOW_OK;
758 GstEglGlesBuffer *eglglesbuffer = NULL;
759 GstCaps *intersection = NULL;
760 GstStructure *structure = NULL;
762 GstEglGlesImageFmt *format;
764 eglglessink = GST_EGLGLESSINK (bsink);
766 /* No custom alloc for the slow rendering path */
767 if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
768 GST_INFO_OBJECT (eglglessink, "No custom alloc for slow rendering path");
773 if (G_UNLIKELY (!caps))
776 if (G_LIKELY (gst_caps_is_equal (caps, eglglessink->current_caps))) {
777 GST_LOG_OBJECT (eglglessink,
778 "Buffer alloc for same last_caps, reusing caps");
779 intersection = gst_caps_ref (caps);
780 width = GST_VIDEO_SINK_WIDTH (eglglessink);
781 height = GST_VIDEO_SINK_HEIGHT (eglglessink);
783 goto REUSE_LAST_CAPS;
786 GST_DEBUG_OBJECT (eglglessink, "Buffer alloc requested size %d with caps %"
787 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
788 caps, eglglessink->current_caps);
790 /* Check the caps against our current caps */
791 intersection = gst_caps_intersect (eglglessink->current_caps, caps);
793 GST_DEBUG_OBJECT (eglglessink, "Intersection in buffer alloc returned %"
794 GST_PTR_FORMAT, intersection);
796 if (gst_caps_is_empty (intersection)) {
799 gst_caps_unref (intersection);
801 /* So we don't support this kind of buffer, let's define one we'd like */
802 new_caps = gst_caps_copy (caps);
804 structure = gst_caps_get_structure (new_caps, 0);
805 if (!gst_structure_has_field (structure, "width") ||
806 !gst_structure_has_field (structure, "height")) {
807 gst_caps_unref (new_caps);
811 /* Try different dimensions */
813 gst_eglglessink_different_size_suggestion (eglglessink, new_caps);
815 /* YUV not implemented yet */
816 if (gst_caps_is_empty (intersection)) {
818 gst_structure_set_name (structure, "video/x-raw-rgb");
820 /* Remove format specific fields */
821 gst_structure_remove_field (structure, "format");
822 gst_structure_remove_field (structure, "endianness");
823 gst_structure_remove_field (structure, "depth");
824 gst_structure_remove_field (structure, "bpp");
825 gst_structure_remove_field (structure, "red_mask");
826 gst_structure_remove_field (structure, "green_mask");
827 gst_structure_remove_field (structure, "blue_mask");
828 gst_structure_remove_field (structure, "alpha_mask");
830 /* Reuse intersection with current_caps */
831 intersection = gst_caps_intersect (eglglessink->current_caps, new_caps);
834 /* Try with different dimensions and RGB formats */
835 if (gst_caps_is_empty (intersection))
837 gst_eglglessink_different_size_suggestion (eglglessink, new_caps);
839 /* Clean this copy */
840 gst_caps_unref (new_caps);
842 if (gst_caps_is_empty (intersection))
846 /* Ensure the returned caps are fixed */
847 gst_caps_truncate (intersection);
849 GST_DEBUG_OBJECT (eglglessink, "Allocating a buffer with caps %"
850 GST_PTR_FORMAT, intersection);
851 if (gst_caps_is_equal (intersection, caps)) {
852 /* Things work better if we return a buffer with the same caps ptr
853 * as was asked for when we can */
854 gst_caps_replace (&intersection, caps);
857 /* Get image format from caps */
858 format = gst_eglglessink_get_compat_format_from_caps (eglglessink,
862 GST_WARNING_OBJECT (eglglessink, "Can't get a compatible format from caps");
864 /* Get geometry from caps */
865 structure = gst_caps_get_structure (intersection, 0);
866 if (!gst_structure_get_int (structure, "width", &width) ||
867 !gst_structure_get_int (structure, "height", &height) || !format)
872 GST_DEBUG_OBJECT (eglglessink, "Creating eglglesbuffer");
873 eglglesbuffer = gst_eglglesbuffer_new (eglglessink, intersection);
876 /* Make sure the buffer is cleared of any previously used flags */
877 GST_MINI_OBJECT_CAST (eglglesbuffer)->flags = 0;
878 gst_buffer_set_caps (GST_BUFFER_CAST (eglglesbuffer), intersection);
881 *buf = GST_BUFFER_CAST (eglglesbuffer);
885 gst_caps_unref (intersection);
893 GST_DEBUG_OBJECT (eglglessink, "No width/height on caps!?");
894 ret = GST_FLOW_WRONG_STATE;
899 GST_WARNING_OBJECT (eglglessink, "We were requested a buffer with "
900 "caps %" GST_PTR_FORMAT ", but our current caps %" GST_PTR_FORMAT
901 " are completely incompatible!", caps, eglglessink->current_caps);
902 ret = GST_FLOW_NOT_NEGOTIATED;
907 GST_WARNING_OBJECT (eglglessink, "Invalid caps for buffer allocation %"
908 GST_PTR_FORMAT, intersection);
909 ret = GST_FLOW_NOT_NEGOTIATED;
914 GST_WARNING_OBJECT (eglglessink, "Have no caps, doing fallback allocation");
922 gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink)
926 GstEglGlesImageFmt *format;
929 GST_DEBUG_OBJECT (eglglessink,
930 "Building initial list of wanted eglattribs per format");
932 /* Init supported format/caps list */
933 g_mutex_lock (eglglessink->flow_lock);
935 caps = gst_caps_new_empty ();
937 if (eglChooseConfig (eglglessink->eglglesctx->display,
938 eglglessink_RGBA8888_attribs, NULL, 1, &cfg_number) != EGL_FALSE) {
939 format = g_new0 (GstEglGlesImageFmt, 1);
940 format->fmt = GST_EGLGLESSINK_IMAGE_RGBA8888;
941 format->attribs = eglglessink_RGBA8888_attribs;
942 format->caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBA);
943 gst_caps_append (format->caps,
944 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRA));
945 gst_caps_append (format->caps,
946 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ARGB));
947 gst_caps_append (format->caps,
948 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ABGR));
949 gst_caps_append (format->caps,
950 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBx));
951 gst_caps_append (format->caps,
952 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRx));
953 gst_caps_append (format->caps,
954 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xRGB));
955 gst_caps_append (format->caps,
956 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xBGR));
957 gst_caps_append (format->caps,
958 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_AYUV));
959 gst_caps_append (format->caps,
960 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y444));
961 gst_caps_append (format->caps,
962 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_I420));
963 gst_caps_append (format->caps,
964 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YV12));
965 gst_caps_append (format->caps,
966 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV12));
967 gst_caps_append (format->caps,
968 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV21));
969 gst_caps_append (format->caps,
970 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YUY2));
971 gst_caps_append (format->caps,
972 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YVYU));
973 gst_caps_append (format->caps,
974 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_UYVY));
975 gst_caps_append (format->caps,
976 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y42B));
977 gst_caps_append (format->caps,
978 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y41B));
979 eglglessink->supported_fmts =
980 g_list_append (eglglessink->supported_fmts, format);
982 gst_caps_append (caps, gst_caps_ref (format->caps));
984 GST_INFO_OBJECT (eglglessink,
985 "EGL display doesn't support RGBA8888 config");
988 if (eglChooseConfig (eglglessink->eglglesctx->display,
989 eglglessink_RGB888_attribs, NULL, 1, &cfg_number) != EGL_FALSE) {
990 format = g_new0 (GstEglGlesImageFmt, 1);
991 format->fmt = GST_EGLGLESSINK_IMAGE_RGB888;
992 format->attribs = eglglessink_RGB888_attribs;
993 format->caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB);
994 gst_caps_append (format->caps,
995 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGR));
996 eglglessink->supported_fmts =
997 g_list_append (eglglessink->supported_fmts, format);
999 gst_caps_append (caps, gst_caps_ref (format->caps));
1001 GST_INFO_OBJECT (eglglessink, "EGL display doesn't support RGB888 config");
1004 if (eglChooseConfig (eglglessink->eglglesctx->display,
1005 eglglessink_RGB565_attribs, NULL, 1, &cfg_number) != EGL_FALSE) {
1006 format = g_new0 (GstEglGlesImageFmt, 1);
1007 format->fmt = GST_EGLGLESSINK_IMAGE_RGB565;
1008 format->attribs = eglglessink_RGB565_attribs;
1009 format->caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB16);
1010 eglglessink->supported_fmts =
1011 g_list_append (eglglessink->supported_fmts, format);
1013 gst_caps_append (caps, gst_caps_ref (format->caps));
1015 GST_INFO_OBJECT (eglglessink, "EGL display doesn't support RGB565 config");
1018 gst_caps_replace (&eglglessink->sinkcaps, caps);
1019 gst_caps_unref (caps);
1021 g_mutex_unlock (eglglessink->flow_lock);
1026 static inline gboolean
1027 egl_init (GstEglGlesSink * eglglessink)
1029 if (!platform_wrapper_init ()) {
1030 GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL platform wrapper");
1034 if (!gst_eglglessink_init_egl_display (eglglessink)) {
1035 GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL display");
1039 gst_eglglessink_init_egl_exts (eglglessink);
1041 if (!gst_eglglessink_fill_supported_fbuffer_configs (eglglessink)) {
1042 GST_ERROR_OBJECT (eglglessink, "Display support NONE of our configs");
1046 g_mutex_lock (eglglessink->flow_lock);
1047 eglglessink->egl_started = TRUE;
1048 g_mutex_unlock (eglglessink->flow_lock);
1053 GST_ERROR_OBJECT (eglglessink, "Failed to perform EGL init");
1058 gst_eglglessink_start (GstBaseSink * sink)
1060 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (sink);
1062 if (!eglglessink->egl_started) {
1063 GST_ERROR_OBJECT (eglglessink, "EGL uninitialized. Bailing out");
1067 /* Ask for a window to render to */
1068 if (!eglglessink->have_window)
1069 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (eglglessink));
1071 if (!eglglessink->have_window && !eglglessink->create_window) {
1072 GST_ERROR_OBJECT (eglglessink, "Window handle unavailable and we "
1073 "were instructed not to create an internal one. Bailing out.");
1080 GST_ERROR_OBJECT (eglglessink, "Couldn't start");
1085 gst_eglglessink_stop (GstBaseSink * sink)
1087 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (sink);
1089 /* EGL/GLES2 cleanup */
1090 if (!gst_eglglessink_context_make_current (eglglessink, TRUE, FALSE))
1093 if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
1096 if (eglglessink->have_vbo) {
1097 glDeleteBuffers (1, &eglglessink->eglglesctx->position_buffer);
1098 glDeleteBuffers (1, &eglglessink->eglglesctx->texpos_buffer);
1099 glDeleteBuffers (1, &eglglessink->eglglesctx->index_buffer);
1100 eglglessink->have_vbo = FALSE;
1103 if (eglglessink->have_texture) {
1104 glDeleteTextures (eglglessink->eglglesctx->n_textures,
1105 eglglessink->eglglesctx->texture);
1106 eglglessink->have_texture = FALSE;
1107 eglglessink->eglglesctx->n_textures = 0;
1110 if (eglglessink->eglglesctx->glslprogram) {
1111 glDetachShader (eglglessink->eglglesctx->glslprogram,
1112 eglglessink->eglglesctx->fragshader);
1113 glDetachShader (eglglessink->eglglesctx->glslprogram,
1114 eglglessink->eglglesctx->vertshader);
1115 glDeleteProgram (eglglessink->eglglesctx->glslprogram);
1116 glDeleteShader (eglglessink->eglglesctx->fragshader);
1117 glDeleteShader (eglglessink->eglglesctx->vertshader);
1118 eglglessink->eglglesctx->glslprogram = 0;
1122 if (!gst_eglglessink_context_make_current (eglglessink, FALSE, FALSE))
1125 if (eglglessink->eglglesctx->surface) {
1126 eglDestroySurface (eglglessink->eglglesctx->display,
1127 eglglessink->eglglesctx->surface);
1128 eglglessink->eglglesctx->surface = NULL;
1129 eglglessink->have_surface = FALSE;
1132 if (eglglessink->eglglesctx->eglcontext) {
1133 eglDestroyContext (eglglessink->eglglesctx->display,
1134 eglglessink->eglglesctx->eglcontext);
1135 eglglessink->eglglesctx->eglcontext = NULL;
1138 if (eglglessink->using_own_window) {
1139 platform_destroy_native_window (eglglessink->eglglesctx->display,
1140 eglglessink->eglglesctx->used_window);
1141 eglglessink->eglglesctx->used_window = NULL;
1142 eglglessink->have_window = FALSE;
1144 eglglessink->eglglesctx->used_window = NULL;
1145 if (eglglessink->current_caps) {
1146 gst_caps_unref (eglglessink->current_caps);
1147 eglglessink->current_caps = NULL;
1154 gst_eglglessink_xoverlay_init (GstXOverlayClass * iface)
1156 iface->set_window_handle = gst_eglglessink_set_window_handle;
1157 iface->expose = gst_eglglessink_expose;
1158 iface->set_render_rectangle = gst_eglglessink_set_render_rectangle;
1162 gst_eglglessink_interface_supported (GstImplementsInterface * iface, GType type)
1164 return (type == GST_TYPE_X_OVERLAY);
1168 gst_eglglessink_implements_init (GstImplementsInterfaceClass * klass)
1170 klass->supported = gst_eglglessink_interface_supported;
1173 static inline gboolean
1174 got_gl_error (const char *wtf)
1176 GLuint error = GL_NO_ERROR;
1178 if ((error = glGetError ()) != GL_NO_ERROR) {
1179 GST_CAT_ERROR (GST_CAT_DEFAULT, "GL ERROR: %s returned %x", wtf, error);
1186 show_egl_error (const char *wtf)
1190 if ((error = eglGetError ()) != EGL_SUCCESS)
1191 GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned %x", wtf, error);
1194 static EGLNativeWindowType
1195 gst_eglglessink_create_window (GstEglGlesSink * eglglessink, gint width,
1198 EGLNativeWindowType window = 0;
1200 if (!eglglessink->create_window) {
1201 GST_ERROR_OBJECT (eglglessink, "This sink can't create a window by itself");
1204 GST_INFO_OBJECT (eglglessink, "Attempting internal window creation");
1206 window = platform_create_native_window (width, height);
1208 GST_ERROR_OBJECT (eglglessink, "Could not create window");
1211 gst_x_overlay_got_window_handle (GST_X_OVERLAY (eglglessink),
1217 gst_eglglessink_expose (GstXOverlay * overlay)
1219 GstEglGlesSink *eglglessink;
1222 eglglessink = GST_EGLGLESSINK (overlay);
1223 GST_DEBUG_OBJECT (eglglessink, "Expose catched, redisplay");
1225 /* Render from last seen buffer */
1226 ret = gst_eglglessink_render_and_display (eglglessink, NULL);
1227 if (ret == GST_FLOW_ERROR)
1228 GST_ERROR_OBJECT (eglglessink, "Redisplay failed");
1231 /* Checks available EGL/GLES extensions and chooses
1232 * a suitable rendering path from GstEglGlesSinkRenderingPath
1233 * accordingly. This function can only be called after an
1234 * EGL context has been made current.
1237 gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink)
1239 const char *eglexts;
1240 unsigned const char *glexts;
1242 eglexts = eglQueryString (eglglessink->eglglesctx->display, EGL_EXTENSIONS);
1243 glexts = glGetString (GL_EXTENSIONS);
1245 GST_DEBUG_OBJECT (eglglessink, "Available EGL extensions: %s\n", eglexts);
1246 GST_DEBUG_OBJECT (eglglessink, "Available GLES extensions: %s\n", glexts);
1248 #ifdef EGL_FAST_RENDERING_POSSIBLE
1249 /* OK Fast rendering should be possible from the declared
1250 * extensions on the eglexts/glexts.h headers
1253 /* Check for support from claimed EGL/GLES extensions */
1255 if (!strstr (eglexts, "EGL_KHR_image"))
1257 if (!strstr (eglexts, "EGL_KHR_lock_surface"))
1258 goto SURFACE_LOCK_NA;
1259 if (!strstr ((char *) glexts, "GL_OES_EGL_image"))
1260 goto TEXTURE_2DOES_NA;
1262 /* Check for actual extension proc addresses */
1264 my_eglCreateImageKHR =
1265 (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress ("eglCreateImageKHR");
1266 my_eglDestroyImageKHR =
1267 (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR");
1269 if (!my_eglCreateImageKHR || !my_eglDestroyImageKHR) {
1271 GST_INFO_OBJECT (eglglessink, "Extension missing: EGL_KHR_image");
1275 my_eglLockSurfaceKHR =
1276 (PFNEGLLOCKSURFACEKHRPROC) eglGetProcAddress ("eglLockSurfaceKHR");
1277 my_eglUnlockSurfaceKHR =
1278 (PFNEGLUNLOCKSURFACEKHRPROC) eglGetProcAddress ("eglUnlockSurfaceKHR");
1280 if (!my_eglLockSurfaceKHR || !my_eglUnlockSurfaceKHR) {
1282 GST_INFO_OBJECT (eglglessink, "Extension missing: EGL_KHR_lock_surface");
1286 my_glEGLImageTargetTexture2DOES =
1287 (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress
1288 ("glEGLImageTargetTexture2DOES");
1290 if (!my_glEGLImageTargetTexture2DOES) {
1292 GST_INFO_OBJECT (eglglessink, "Extension missing: GL_OES_EGL_image");
1296 if (!eglglessink->force_rendering_slow) {
1297 GST_INFO_OBJECT (eglglessink,
1298 "Have needed extensions for fast rendering path");
1300 GST_WARNING_OBJECT (eglglessink,
1301 "Extension check passed but slow rendering path being forced");
1302 goto SLOW_PATH_SELECTED;
1305 /* Extension check passed. Enable fast rendering path */
1306 eglglessink->rendering_path = GST_EGLGLESSINK_RENDER_FAST;
1307 GST_INFO_OBJECT (eglglessink, "Using fast rendering path");
1312 GST_WARNING_OBJECT (eglglessink,
1313 "Extensions missing. Can't use fast rendering path");
1315 eglglessink->rendering_path = GST_EGLGLESSINK_RENDER_SLOW;
1316 GST_INFO_OBJECT (eglglessink, "Using slow rendering path");
1321 gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
1324 g_mutex_lock (eglglessink->flow_lock);
1326 GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d",
1327 eglglessink->have_vbo, reset);
1329 if (eglglessink->have_vbo && reset) {
1330 glDeleteBuffers (1, &eglglessink->eglglesctx->position_buffer);
1331 glDeleteBuffers (1, &eglglessink->eglglesctx->texpos_buffer);
1332 glDeleteBuffers (1, &eglglessink->eglglesctx->index_buffer);
1333 eglglessink->have_vbo = FALSE;
1336 if (!eglglessink->have_vbo) {
1337 GST_DEBUG_OBJECT (eglglessink, "Performing VBO setup");
1338 eglglessink->eglglesctx->position_array[0].x = 1;
1339 eglglessink->eglglesctx->position_array[0].y = 1;
1340 eglglessink->eglglesctx->position_array[0].z = 0;
1342 eglglessink->eglglesctx->position_array[1].x = 1;
1343 eglglessink->eglglesctx->position_array[1].y = -1;
1344 eglglessink->eglglesctx->position_array[1].z = 0;
1346 eglglessink->eglglesctx->position_array[2].x = -1;
1347 eglglessink->eglglesctx->position_array[2].y = 1;
1348 eglglessink->eglglesctx->position_array[2].z = 0;
1350 eglglessink->eglglesctx->position_array[3].x = -1;
1351 eglglessink->eglglesctx->position_array[3].y = -1;
1352 eglglessink->eglglesctx->position_array[3].z = 0;
1354 eglglessink->eglglesctx->texpos_array[0].x = 1;
1355 eglglessink->eglglesctx->texpos_array[0].y = 0;
1357 eglglessink->eglglesctx->texpos_array[1].x = 1;
1358 eglglessink->eglglesctx->texpos_array[1].y = 1;
1360 eglglessink->eglglesctx->texpos_array[2].x = 0;
1361 eglglessink->eglglesctx->texpos_array[2].y = 0;
1363 eglglessink->eglglesctx->texpos_array[3].x = 0;
1364 eglglessink->eglglesctx->texpos_array[3].y = 1;
1366 eglglessink->eglglesctx->index_array[0] = 0;
1367 eglglessink->eglglesctx->index_array[1] = 1;
1368 eglglessink->eglglesctx->index_array[2] = 2;
1369 eglglessink->eglglesctx->index_array[3] = 3;
1371 glGenBuffers (1, &eglglessink->eglglesctx->position_buffer);
1372 glGenBuffers (1, &eglglessink->eglglesctx->texpos_buffer);
1373 glGenBuffers (1, &eglglessink->eglglesctx->index_buffer);
1374 if (got_gl_error ("glGenBuffers"))
1375 goto HANDLE_ERROR_LOCKED;
1377 glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx->position_buffer);
1378 if (got_gl_error ("glBindBuffer position_buffer"))
1379 goto HANDLE_ERROR_LOCKED;
1381 glBufferData (GL_ARRAY_BUFFER,
1382 sizeof (eglglessink->eglglesctx->position_array),
1383 eglglessink->eglglesctx->position_array, GL_STATIC_DRAW);
1384 if (got_gl_error ("glBufferData position_buffer"))
1385 goto HANDLE_ERROR_LOCKED;
1387 glVertexAttribPointer (eglglessink->eglglesctx->position_loc, 3, GL_FLOAT,
1389 if (got_gl_error ("glVertexAttribPointer"))
1390 goto HANDLE_ERROR_LOCKED;
1392 glEnableVertexAttribArray (eglglessink->eglglesctx->position_loc);
1393 if (got_gl_error ("glEnableVertexAttribArray"))
1394 goto HANDLE_ERROR_LOCKED;
1396 glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx->texpos_buffer);
1397 if (got_gl_error ("glBindBuffer texpos_buffer"))
1398 goto HANDLE_ERROR_LOCKED;
1400 glBufferData (GL_ARRAY_BUFFER,
1401 sizeof (eglglessink->eglglesctx->texpos_array),
1402 eglglessink->eglglesctx->texpos_array, GL_STATIC_DRAW);
1403 if (got_gl_error ("glBufferData texpos_buffer"))
1404 goto HANDLE_ERROR_LOCKED;
1406 glVertexAttribPointer (eglglessink->eglglesctx->texpos_loc, 2, GL_FLOAT,
1408 if (got_gl_error ("glVertexAttribPointer"))
1409 goto HANDLE_ERROR_LOCKED;
1411 glEnableVertexAttribArray (eglglessink->eglglesctx->texpos_loc);
1412 if (got_gl_error ("glEnableVertexAttribArray"))
1413 goto HANDLE_ERROR_LOCKED;
1415 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
1416 eglglessink->eglglesctx->index_buffer);
1417 if (got_gl_error ("glBindBuffer index_buffer"))
1418 goto HANDLE_ERROR_LOCKED;
1420 glBufferData (GL_ELEMENT_ARRAY_BUFFER,
1421 sizeof (eglglessink->eglglesctx->index_array),
1422 eglglessink->eglglesctx->index_array, GL_STATIC_DRAW);
1423 if (got_gl_error ("glBufferData index_buffer"))
1424 goto HANDLE_ERROR_LOCKED;
1426 eglglessink->have_vbo = TRUE;
1428 GST_INFO_OBJECT (eglglessink, "Won't perform VBO setup");
1431 g_mutex_unlock (eglglessink->flow_lock);
1434 HANDLE_ERROR_LOCKED:
1435 g_mutex_unlock (eglglessink->flow_lock);
1436 GST_ERROR_OBJECT (eglglessink, "Unable to perform VBO setup");
1440 /* XXX: Lock eglgles context? */
1442 gst_eglglessink_update_surface_dimensions (GstEglGlesSink * eglglessink)
1446 /* Save surface dims */
1447 eglQuerySurface (eglglessink->eglglesctx->display,
1448 eglglessink->eglglesctx->surface, EGL_WIDTH, &width);
1449 eglQuerySurface (eglglessink->eglglesctx->display,
1450 eglglessink->eglglesctx->surface, EGL_HEIGHT, &height);
1452 /* Save Pixel Aspect Ratio
1454 * PAR is reported as w/h * EGL_DISPLAY_SCALING wich is
1455 * a constant with value 10000. This attribute is only
1456 * supported if the EGL version is >= 1.2
1457 * XXX: Setup this as a property.
1459 if (eglglessink->eglglesctx->egl_minor > 1) {
1460 eglQuerySurface (eglglessink->eglglesctx->display,
1461 eglglessink->eglglesctx->surface, EGL_PIXEL_ASPECT_RATIO,
1462 &eglglessink->eglglesctx->pixel_aspect_ratio);
1464 GST_DEBUG_OBJECT (eglglessink, "Can't query PAR. Using default: %dx%d",
1465 EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
1466 eglglessink->eglglesctx->pixel_aspect_ratio = EGL_DISPLAY_SCALING;
1469 if (eglglessink->eglglesctx->pixel_aspect_ratio == EGL_UNKNOWN) {
1470 GST_DEBUG_OBJECT (eglglessink, "PAR value returned doesn't make sense. "
1471 "Will use default: %d/%d", EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
1472 eglglessink->eglglesctx->pixel_aspect_ratio = EGL_DISPLAY_SCALING;
1475 if (width != eglglessink->eglglesctx->surface_width ||
1476 height != eglglessink->eglglesctx->surface_height) {
1477 eglglessink->eglglesctx->surface_width = width;
1478 eglglessink->eglglesctx->surface_height = height;
1479 GST_INFO_OBJECT (eglglessink, "Got surface of %dx%d pixels", width, height);
1486 static pthread_key_t context_key;
1489 detach_context (void *data)
1491 GstEglGlesSink *eglglessink = data;
1493 GST_DEBUG_OBJECT (eglglessink,
1494 "Detaching current context from streaming thread");
1495 gst_eglglessink_context_make_current (eglglessink, FALSE, TRUE);
1496 gst_object_unref (eglglessink);
1500 gst_eglglessink_context_make_current (GstEglGlesSink * eglglessink,
1501 gboolean bind, gboolean streaming_thread)
1503 g_assert (eglglessink->eglglesctx->display != NULL);
1505 if (bind && eglglessink->eglglesctx->surface &&
1506 eglglessink->eglglesctx->eglcontext) {
1507 if (streaming_thread) {
1508 EGLContext *ctx = eglGetCurrentContext ();
1510 if (ctx == eglglessink->eglglesctx->eglcontext) {
1511 GST_DEBUG_OBJECT (eglglessink, "Already attached the context");
1515 GST_DEBUG_OBJECT (eglglessink, "Attaching context to streaming thread");
1516 if (!eglMakeCurrent (eglglessink->eglglesctx->display,
1517 eglglessink->eglglesctx->surface,
1518 eglglessink->eglglesctx->surface,
1519 eglglessink->eglglesctx->eglcontext)) {
1520 show_egl_error ("eglMakeCurrent");
1521 GST_ERROR_OBJECT (eglglessink, "Couldn't bind context");
1525 if (!pthread_getspecific (context_key)) {
1526 pthread_setspecific (context_key, gst_object_ref (eglglessink));
1529 GST_DEBUG_OBJECT (eglglessink, "Attaching context");
1530 if (!eglMakeCurrent (eglglessink->eglglesctx->display,
1531 eglglessink->eglglesctx->surface,
1532 eglglessink->eglglesctx->surface,
1533 eglglessink->eglglesctx->eglcontext)) {
1534 show_egl_error ("eglMakeCurrent");
1535 GST_ERROR_OBJECT (eglglessink, "Couldn't bind context");
1540 GST_DEBUG_OBJECT (eglglessink, "Detaching context");
1541 if (!eglMakeCurrent (eglglessink->eglglesctx->display,
1542 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
1543 show_egl_error ("eglMakeCurrent");
1544 GST_ERROR_OBJECT (eglglessink, "Couldn't unbind context");
1553 gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
1558 const gchar *texnames[3] = { NULL, };
1559 gchar *tmp_prog = NULL;
1561 GST_DEBUG_OBJECT (eglglessink, "Enter EGL surface setup");
1563 g_mutex_lock (eglglessink->flow_lock);
1565 eglglessink->eglglesctx->surface =
1566 eglCreateWindowSurface (eglglessink->eglglesctx->display,
1567 eglglessink->eglglesctx->config, eglglessink->eglglesctx->used_window,
1570 if (eglglessink->eglglesctx->surface == EGL_NO_SURFACE) {
1571 show_egl_error ("eglCreateWindowSurface");
1572 GST_ERROR_OBJECT (eglglessink, "Can't create surface");
1573 goto HANDLE_EGL_ERROR_LOCKED;
1576 if (!gst_eglglessink_context_make_current (eglglessink, TRUE, TRUE))
1577 goto HANDLE_EGL_ERROR_LOCKED;
1579 /* Save surface dims */
1580 gst_eglglessink_update_surface_dimensions (eglglessink);
1582 /* We have a surface! */
1583 eglglessink->have_surface = TRUE;
1584 g_mutex_unlock (eglglessink->flow_lock);
1586 /* Init vertex and fragment GLSL shaders. This entire block might need to be
1587 * runtime conditional once the fast rendering path gets fully implemented.
1589 * Note: Shader compiler support is optional but we currently rely on it.
1592 glGetBooleanv (GL_SHADER_COMPILER, &ret);
1593 if (ret == GL_FALSE) {
1594 GST_ERROR_OBJECT (eglglessink, "Shader compiler support is unavailable!");
1598 eglglessink->eglglesctx->vertshader = glCreateShader (GL_VERTEX_SHADER);
1599 GST_DEBUG_OBJECT (eglglessink, "Sending %s to handle %d", vert_COPY_prog,
1600 eglglessink->eglglesctx->vertshader);
1601 glShaderSource (eglglessink->eglglesctx->vertshader, 1, &vert_COPY_prog,
1603 if (got_gl_error ("glShaderSource vertex"))
1606 glCompileShader (eglglessink->eglglesctx->vertshader);
1607 if (got_gl_error ("glCompileShader vertex"))
1610 glGetShaderiv (eglglessink->eglglesctx->vertshader, GL_COMPILE_STATUS, &test);
1611 if (test != GL_FALSE)
1612 GST_DEBUG_OBJECT (eglglessink, "Successfully compiled vertex shader");
1614 GST_ERROR_OBJECT (eglglessink, "Couldn't compile vertex shader");
1615 glGetShaderiv (eglglessink->eglglesctx->vertshader, GL_INFO_LOG_LENGTH,
1617 info_log = g_new0 (GLchar, test);
1618 glGetShaderInfoLog (eglglessink->eglglesctx->vertshader, test, NULL,
1620 GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
1625 eglglessink->eglglesctx->fragshader = glCreateShader (GL_FRAGMENT_SHADER);
1626 switch (eglglessink->format) {
1627 case GST_VIDEO_FORMAT_AYUV:
1628 glShaderSource (eglglessink->eglglesctx->fragshader, 1, &frag_AYUV_prog,
1630 eglglessink->eglglesctx->n_textures = 1;
1631 texnames[0] = "tex";
1633 case GST_VIDEO_FORMAT_Y444:
1634 case GST_VIDEO_FORMAT_I420:
1635 case GST_VIDEO_FORMAT_YV12:
1636 case GST_VIDEO_FORMAT_Y42B:
1637 case GST_VIDEO_FORMAT_Y41B:
1638 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1639 &frag_PLANAR_YUV_prog, NULL);
1640 eglglessink->eglglesctx->n_textures = 3;
1641 texnames[0] = "Ytex";
1642 texnames[1] = "Utex";
1643 texnames[2] = "Vtex";
1645 case GST_VIDEO_FORMAT_YUY2:
1646 tmp_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'g', 'a');
1647 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1648 (const GLchar **) &tmp_prog, NULL);
1649 eglglessink->eglglesctx->n_textures = 2;
1650 texnames[0] = "Ytex";
1651 texnames[1] = "UVtex";
1653 case GST_VIDEO_FORMAT_YVYU:
1654 tmp_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'r', 'a', 'g');
1655 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1656 (const GLchar **) &tmp_prog, NULL);
1657 eglglessink->eglglesctx->n_textures = 2;
1658 texnames[0] = "Ytex";
1659 texnames[1] = "UVtex";
1661 case GST_VIDEO_FORMAT_UYVY:
1662 tmp_prog = g_strdup_printf (frag_YUY2_YVYU_UYVY_prog, 'a', 'r', 'b');
1663 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1664 (const GLchar **) &tmp_prog, NULL);
1665 eglglessink->eglglesctx->n_textures = 2;
1666 texnames[0] = "Ytex";
1667 texnames[1] = "UVtex";
1669 case GST_VIDEO_FORMAT_NV12:
1670 tmp_prog = g_strdup_printf (frag_NV12_NV21_prog, 'r', 'a');
1671 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1672 (const GLchar **) &tmp_prog, NULL);
1673 eglglessink->eglglesctx->n_textures = 2;
1674 texnames[0] = "Ytex";
1675 texnames[1] = "UVtex";
1677 case GST_VIDEO_FORMAT_NV21:
1678 tmp_prog = g_strdup_printf (frag_NV12_NV21_prog, 'a', 'r');
1679 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1680 (const GLchar **) &tmp_prog, NULL);
1681 eglglessink->eglglesctx->n_textures = 2;
1682 texnames[0] = "Ytex";
1683 texnames[1] = "UVtex";
1685 case GST_VIDEO_FORMAT_BGR:
1686 case GST_VIDEO_FORMAT_BGRx:
1687 case GST_VIDEO_FORMAT_BGRA:
1688 tmp_prog = g_strdup_printf (frag_REORDER_prog, 'b', 'g', 'r');
1689 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1690 (const GLchar **) &tmp_prog, NULL);
1691 eglglessink->eglglesctx->n_textures = 1;
1692 texnames[0] = "tex";
1694 case GST_VIDEO_FORMAT_xRGB:
1695 case GST_VIDEO_FORMAT_ARGB:
1696 tmp_prog = g_strdup_printf (frag_REORDER_prog, 'g', 'b', 'a');
1697 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1698 (const GLchar **) &tmp_prog, NULL);
1699 eglglessink->eglglesctx->n_textures = 1;
1700 texnames[0] = "tex";
1702 case GST_VIDEO_FORMAT_xBGR:
1703 case GST_VIDEO_FORMAT_ABGR:
1704 tmp_prog = g_strdup_printf (frag_REORDER_prog, 'a', 'b', 'g');
1705 glShaderSource (eglglessink->eglglesctx->fragshader, 1,
1706 (const GLchar **) &tmp_prog, NULL);
1707 eglglessink->eglglesctx->n_textures = 1;
1708 texnames[0] = "tex";
1710 case GST_VIDEO_FORMAT_RGB:
1711 case GST_VIDEO_FORMAT_RGBx:
1712 case GST_VIDEO_FORMAT_RGBA:
1713 case GST_VIDEO_FORMAT_RGB16:
1714 glShaderSource (eglglessink->eglglesctx->fragshader, 1, &frag_COPY_prog,
1716 eglglessink->eglglesctx->n_textures = 1;
1717 texnames[0] = "tex";
1720 g_assert_not_reached ();
1724 if (got_gl_error ("glShaderSource fragment"))
1727 glCompileShader (eglglessink->eglglesctx->fragshader);
1728 if (got_gl_error ("glCompileShader fragment"))
1731 glGetShaderiv (eglglessink->eglglesctx->fragshader, GL_COMPILE_STATUS, &test);
1732 if (test != GL_FALSE)
1733 GST_DEBUG_OBJECT (eglglessink, "Successfully compiled fragment shader");
1735 GST_ERROR_OBJECT (eglglessink, "Couldn't compile fragment shader");
1736 glGetShaderiv (eglglessink->eglglesctx->fragshader, GL_INFO_LOG_LENGTH,
1738 info_log = g_new0 (GLchar, test);
1739 glGetShaderInfoLog (eglglessink->eglglesctx->fragshader, test, NULL,
1741 GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
1746 eglglessink->eglglesctx->glslprogram = glCreateProgram ();
1747 if (got_gl_error ("glCreateProgram"))
1749 glAttachShader (eglglessink->eglglesctx->glslprogram,
1750 eglglessink->eglglesctx->vertshader);
1751 if (got_gl_error ("glAttachShader vertices"))
1753 glAttachShader (eglglessink->eglglesctx->glslprogram,
1754 eglglessink->eglglesctx->fragshader);
1755 if (got_gl_error ("glAttachShader fragments"))
1757 glLinkProgram (eglglessink->eglglesctx->glslprogram);
1758 glGetProgramiv (eglglessink->eglglesctx->glslprogram, GL_LINK_STATUS, &test);
1759 if (test != GL_FALSE)
1760 GST_DEBUG_OBJECT (eglglessink, "GLES: Successfully linked program");
1762 GST_ERROR_OBJECT (eglglessink, "Couldn't link program");
1766 glUseProgram (eglglessink->eglglesctx->glslprogram);
1767 if (got_gl_error ("glUseProgram"))
1770 eglglessink->eglglesctx->position_loc =
1771 glGetAttribLocation (eglglessink->eglglesctx->glslprogram, "position");
1772 eglglessink->eglglesctx->texpos_loc =
1773 glGetAttribLocation (eglglessink->eglglesctx->glslprogram, "texpos");
1775 /* Generate and bind texture */
1776 if (!eglglessink->have_texture) {
1779 GST_INFO_OBJECT (eglglessink, "Performing initial texture setup");
1781 g_mutex_lock (eglglessink->flow_lock);
1783 for (i = 0; i < eglglessink->eglglesctx->n_textures; i++) {
1785 glActiveTexture (GL_TEXTURE0);
1787 glActiveTexture (GL_TEXTURE1);
1789 glActiveTexture (GL_TEXTURE2);
1791 glGenTextures (1, &eglglessink->eglglesctx->texture[i]);
1792 if (got_gl_error ("glGenTextures"))
1793 goto HANDLE_ERROR_LOCKED;
1795 glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[i]);
1796 if (got_gl_error ("glBindTexture"))
1797 goto HANDLE_ERROR_LOCKED;
1799 eglglessink->eglglesctx->tex_loc[i] =
1800 glGetUniformLocation (eglglessink->eglglesctx->glslprogram,
1802 glUniform1i (eglglessink->eglglesctx->tex_loc[i], i);
1804 /* Set 2D resizing params */
1805 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1806 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1807 /* If these are not set the texture image unit will return
1808 * (R, G, B, A) = black on glTexImage2D for non-POT width/height
1809 * frames. For a deeper explanation take a look at the OpenGL ES
1810 * documentation for glTexParameter */
1811 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1812 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1813 if (got_gl_error ("glTexParameteri"))
1814 goto HANDLE_ERROR_LOCKED;
1817 eglglessink->have_texture = TRUE;
1818 g_mutex_unlock (eglglessink->flow_lock);
1826 HANDLE_EGL_ERROR_LOCKED:
1827 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1828 HANDLE_ERROR_LOCKED:
1829 g_mutex_unlock (eglglessink->flow_lock);
1831 GST_ERROR_OBJECT (eglglessink, "Couldn't setup EGL surface");
1837 gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink)
1839 GST_DEBUG_OBJECT (eglglessink, "Enter EGL initial configuration");
1841 eglglessink->eglglesctx->display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
1842 if (eglglessink->eglglesctx->display == EGL_NO_DISPLAY) {
1843 GST_ERROR_OBJECT (eglglessink, "Could not get EGL display connection");
1844 goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */
1847 if (!eglInitialize (eglglessink->eglglesctx->display,
1848 &eglglessink->eglglesctx->egl_major,
1849 &eglglessink->eglglesctx->egl_minor)) {
1850 show_egl_error ("eglInitialize");
1851 GST_ERROR_OBJECT (eglglessink, "Could not init EGL display connection");
1852 goto HANDLE_EGL_ERROR;
1855 /* Check against required EGL version
1856 * XXX: Need to review the version requirement in terms of the needed API
1858 if (eglglessink->eglglesctx->egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) {
1859 GST_ERROR_OBJECT (eglglessink, "EGL v%d needed, but you only have v%d.%d",
1860 GST_EGLGLESSINK_EGL_MIN_VERSION, eglglessink->eglglesctx->egl_major,
1861 eglglessink->eglglesctx->egl_minor);
1865 GST_INFO_OBJECT (eglglessink, "System reports supported EGL version v%d.%d",
1866 eglglessink->eglglesctx->egl_major, eglglessink->eglglesctx->egl_minor);
1868 eglBindAPI (EGL_OPENGL_ES_API);
1874 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1876 GST_ERROR_OBJECT (eglglessink, "Couldn't setup window/surface from handle");
1881 gst_eglglessink_choose_config (GstEglGlesSink * eglglessink)
1883 EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
1886 if ((eglChooseConfig (eglglessink->eglglesctx->display,
1887 eglglessink->selected_fmt->attribs,
1888 &eglglessink->eglglesctx->config, 1,
1889 &egl_configs)) == EGL_FALSE) {
1890 show_egl_error ("eglChooseConfig");
1891 GST_ERROR_OBJECT (eglglessink, "eglChooseConfig failed");
1892 goto HANDLE_EGL_ERROR;
1895 if (egl_configs < 1) {
1896 GST_ERROR_OBJECT (eglglessink,
1897 "Could not find matching framebuffer config");
1901 eglglessink->eglglesctx->eglcontext =
1902 eglCreateContext (eglglessink->eglglesctx->display,
1903 eglglessink->eglglesctx->config, EGL_NO_CONTEXT, con_attribs);
1905 if (eglglessink->eglglesctx->eglcontext == EGL_NO_CONTEXT) {
1906 GST_ERROR_OBJECT (eglglessink, "Error getting context, eglCreateContext");
1907 goto HANDLE_EGL_ERROR;
1910 GST_DEBUG_OBJECT (eglglessink, "EGL Context: %p",
1911 eglglessink->eglglesctx->eglcontext);
1917 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1919 GST_ERROR_OBJECT (eglglessink, "Couldn't choose an usable config");
1924 gst_eglglessink_set_window_handle (GstXOverlay * overlay, guintptr id)
1926 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
1928 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
1929 GST_DEBUG_OBJECT (eglglessink, "We got a window handle!");
1931 /* OK, we have a new window */
1932 g_mutex_lock (eglglessink->flow_lock);
1933 eglglessink->eglglesctx->window = (EGLNativeWindowType) id;
1934 eglglessink->have_window = TRUE;
1935 g_mutex_unlock (eglglessink->flow_lock);
1941 gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
1942 gint width, gint height)
1944 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
1946 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
1948 g_mutex_lock (eglglessink->flow_lock);
1950 if (width == -1 && height == -1) {
1951 /* This is the set-defaults condition according to
1952 * the xOverlay interface docs
1954 eglglessink->display_region.w = 0;
1955 eglglessink->display_region.h = 0;
1957 g_mutex_lock (eglglessink->flow_lock);
1958 eglglessink->display_region.x = x;
1959 eglglessink->display_region.y = y;
1960 eglglessink->display_region.w = width;
1961 eglglessink->display_region.h = height;
1964 g_mutex_unlock (eglglessink->flow_lock);
1969 /* Rendering and display */
1970 static GstFlowReturn
1971 gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
1974 GstVideoRectangle frame, surface;
1978 #ifdef EGL_FAST_RENDERING_POSSIBLE
1979 EGLImageKHR img = EGL_NO_IMAGE_KHR;
1980 EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR,
1981 EGL_FALSE, EGL_NONE, EGL_NONE
1985 if (!gst_eglglessink_context_make_current (eglglessink, TRUE, TRUE))
1986 goto HANDLE_EGL_ERROR;
1988 w = GST_VIDEO_SINK_WIDTH (eglglessink);
1989 h = GST_VIDEO_SINK_HEIGHT (eglglessink);
1991 GST_DEBUG_OBJECT (eglglessink,
1992 "Got good buffer %p. Sink geometry is %dx%d size %d", buf, w, h,
1993 buf ? GST_BUFFER_SIZE (buf) : -1);
1995 switch (eglglessink->rendering_path) {
1996 #ifdef EGL_FAST_RENDERING_POSSIBLE
1997 case GST_EGLGLESSINK_RENDER_FAST:
1998 /* XXX: Not Fully implemented */
2000 my_eglCreateImageKHR (eglglessink->eglglesctx->display,
2001 EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
2002 (EGLClientBuffer) GST_BUFFER_DATA (buf), attrs);
2004 if (img == EGL_NO_IMAGE_KHR) {
2005 GST_ERROR_OBJECT (eglglessink, "my_eglCreateImageKHR failed");
2006 goto HANDLE_EGL_ERROR;
2009 my_glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, img);
2013 default: /* case GST_EGLGLESSINK_RENDER_SLOW */
2016 switch (eglglessink->selected_fmt->fmt) {
2017 case GST_EGLGLESSINK_IMAGE_RGB888:
2018 glActiveTexture (GL_TEXTURE0);
2019 glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
2020 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
2021 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
2023 case GST_EGLGLESSINK_IMAGE_RGB565:
2024 glActiveTexture (GL_TEXTURE0);
2025 glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[0]);
2026 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
2027 GL_UNSIGNED_SHORT_5_6_5, GST_BUFFER_DATA (buf));
2029 case GST_EGLGLESSINK_IMAGE_RGBA8888:
2030 switch (eglglessink->format) {
2031 case GST_VIDEO_FORMAT_RGBA:
2032 case GST_VIDEO_FORMAT_BGRA:
2033 case GST_VIDEO_FORMAT_ARGB:
2034 case GST_VIDEO_FORMAT_ABGR:
2035 case GST_VIDEO_FORMAT_RGBx:
2036 case GST_VIDEO_FORMAT_BGRx:
2037 case GST_VIDEO_FORMAT_xRGB:
2038 case GST_VIDEO_FORMAT_xBGR:
2039 glActiveTexture (GL_TEXTURE0);
2040 glBindTexture (GL_TEXTURE_2D,
2041 eglglessink->eglglesctx->texture[0]);
2042 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
2043 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
2045 case GST_VIDEO_FORMAT_AYUV:
2046 glActiveTexture (GL_TEXTURE0);
2047 glBindTexture (GL_TEXTURE_2D,
2048 eglglessink->eglglesctx->texture[0]);
2049 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
2050 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
2052 case GST_VIDEO_FORMAT_Y444:
2053 case GST_VIDEO_FORMAT_I420:
2054 case GST_VIDEO_FORMAT_YV12:
2055 case GST_VIDEO_FORMAT_Y42B:
2056 case GST_VIDEO_FORMAT_Y41B:{
2057 gint coffset, cw, ch;
2060 gst_video_format_get_component_offset (eglglessink->format,
2062 cw = gst_video_format_get_component_width (eglglessink->format,
2064 ch = gst_video_format_get_component_height (eglglessink->format,
2066 glActiveTexture (GL_TEXTURE0);
2067 glBindTexture (GL_TEXTURE_2D,
2068 eglglessink->eglglesctx->texture[0]);
2069 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
2070 GL_LUMINANCE, GL_UNSIGNED_BYTE,
2071 GST_BUFFER_DATA (buf) + coffset);
2073 gst_video_format_get_component_offset (eglglessink->format,
2075 cw = gst_video_format_get_component_width (eglglessink->format,
2077 ch = gst_video_format_get_component_height (eglglessink->format,
2079 glActiveTexture (GL_TEXTURE1);
2080 glBindTexture (GL_TEXTURE_2D,
2081 eglglessink->eglglesctx->texture[1]);
2082 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
2083 GL_LUMINANCE, GL_UNSIGNED_BYTE,
2084 GST_BUFFER_DATA (buf) + coffset);
2086 gst_video_format_get_component_offset (eglglessink->format,
2088 cw = gst_video_format_get_component_width (eglglessink->format,
2090 ch = gst_video_format_get_component_height (eglglessink->format,
2092 glActiveTexture (GL_TEXTURE2);
2093 glBindTexture (GL_TEXTURE_2D,
2094 eglglessink->eglglesctx->texture[2]);
2095 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
2096 GL_LUMINANCE, GL_UNSIGNED_BYTE,
2097 GST_BUFFER_DATA (buf) + coffset);
2100 case GST_VIDEO_FORMAT_YUY2:
2101 case GST_VIDEO_FORMAT_YVYU:
2102 case GST_VIDEO_FORMAT_UYVY:
2103 glActiveTexture (GL_TEXTURE0);
2104 glBindTexture (GL_TEXTURE_2D,
2105 eglglessink->eglglesctx->texture[0]);
2106 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0,
2107 GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2108 GST_BUFFER_DATA (buf));
2109 glActiveTexture (GL_TEXTURE1);
2110 glBindTexture (GL_TEXTURE_2D,
2111 eglglessink->eglglesctx->texture[1]);
2112 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, GST_ROUND_UP_2 (w) / 2,
2113 h, 0, GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
2115 case GST_VIDEO_FORMAT_NV12:
2116 case GST_VIDEO_FORMAT_NV21:{
2117 gint coffset, cw, ch;
2120 gst_video_format_get_component_offset (eglglessink->format,
2122 cw = gst_video_format_get_component_width (eglglessink->format,
2124 ch = gst_video_format_get_component_height (eglglessink->format,
2126 glActiveTexture (GL_TEXTURE0);
2127 glBindTexture (GL_TEXTURE_2D,
2128 eglglessink->eglglesctx->texture[0]);
2129 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
2130 GL_LUMINANCE, GL_UNSIGNED_BYTE,
2131 GST_BUFFER_DATA (buf) + coffset);
2134 gst_video_format_get_component_offset (eglglessink->format,
2135 (eglglessink->format == GST_VIDEO_FORMAT_NV12 ? 1 : 2), w,
2137 cw = gst_video_format_get_component_width (eglglessink->format,
2139 ch = gst_video_format_get_component_height (eglglessink->format,
2141 glActiveTexture (GL_TEXTURE1);
2142 glBindTexture (GL_TEXTURE_2D,
2143 eglglessink->eglglesctx->texture[1]);
2144 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, cw, ch, 0,
2145 GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
2146 GST_BUFFER_DATA (buf) + coffset);
2150 g_assert_not_reached ();
2155 if (got_gl_error ("glTexImage2D"))
2159 /* If no one has set a display rectangle on us initialize
2160 * a sane default. According to the docs on the xOverlay
2161 * interface we are supposed to fill the overlay 100%. We
2162 * do this trying to take PAR/DAR into account unless the
2163 * calling party explicitly ask us not to by setting
2164 * force_aspect_ratio to FALSE.
2166 if (gst_eglglessink_update_surface_dimensions (eglglessink) ||
2167 !eglglessink->display_region.w || !eglglessink->display_region.h) {
2168 g_mutex_lock (eglglessink->flow_lock);
2169 if (!eglglessink->force_aspect_ratio) {
2170 eglglessink->display_region.x = 0;
2171 eglglessink->display_region.y = 0;
2172 eglglessink->display_region.w =
2173 eglglessink->eglglesctx->surface_width;
2174 eglglessink->display_region.h =
2175 eglglessink->eglglesctx->surface_height;
2177 if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, w, h,
2178 eglglessink->par_n, eglglessink->par_d,
2179 eglglessink->eglglesctx->pixel_aspect_ratio,
2180 EGL_DISPLAY_SCALING)) {
2181 GST_WARNING_OBJECT (eglglessink, "Could not compute resulting DAR");
2185 /* Find suitable matching new size acording to dar & par
2186 * rationale for prefering leaving the height untouched
2187 * comes from interlacing considerations.
2188 * XXX: Move this to gstutils?
2190 if (h % dar_d == 0) {
2191 frame.w = gst_util_uint64_scale_int (h, dar_n, dar_d);
2193 } else if (w % dar_n == 0) {
2194 frame.h = gst_util_uint64_scale_int (w, dar_d, dar_n);
2197 /* Neither width nor height can be precisely scaled.
2198 * Prefer to leave height untouched. See comment above.
2200 frame.w = gst_util_uint64_scale_int (h, dar_n, dar_d);
2205 surface.w = eglglessink->eglglesctx->surface_width;
2206 surface.h = eglglessink->eglglesctx->surface_height;
2207 gst_video_sink_center_rect (frame, surface,
2208 &eglglessink->display_region, TRUE);
2210 g_mutex_unlock (eglglessink->flow_lock);
2211 glViewport (eglglessink->display_region.x,
2212 eglglessink->display_region.y,
2213 eglglessink->display_region.w, eglglessink->display_region.h);
2216 glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
2217 if (got_gl_error ("glDrawElements"))
2220 if ((eglSwapBuffers (eglglessink->eglglesctx->display,
2221 eglglessink->eglglesctx->surface))
2223 show_egl_error ("eglSwapBuffers");
2228 GST_DEBUG_OBJECT (eglglessink, "Succesfully rendered 1 frame");
2232 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
2234 GST_ERROR_OBJECT (eglglessink, "Rendering disabled for this frame");
2236 return GST_FLOW_ERROR;
2239 static GstFlowReturn
2240 gst_eglglessink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
2242 GstEglGlesSink *eglglessink;
2244 g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
2246 eglglessink = GST_EGLGLESSINK (vsink);
2247 GST_DEBUG_OBJECT (eglglessink, "Got buffer: %p", buf);
2249 if (!eglglessink->have_window) {
2250 GST_ERROR_OBJECT (eglglessink, "I don't have a window to render to");
2251 return GST_FLOW_ERROR;
2254 if (!eglglessink->have_surface) {
2255 GST_ERROR_OBJECT (eglglessink, "I don't have a surface to render to");
2256 return GST_FLOW_ERROR;
2258 #ifndef EGL_ANDROID_image_native_buffer
2259 GST_WARNING_OBJECT (eglglessink, "EGL_ANDROID_image_native_buffer not "
2263 return gst_eglglessink_render_and_display (eglglessink, buf);
2267 gst_eglglessink_getcaps (GstBaseSink * bsink)
2269 GstEglGlesSink *eglglessink;
2270 GstCaps *ret = NULL;
2272 eglglessink = GST_EGLGLESSINK (bsink);
2274 g_mutex_lock (eglglessink->flow_lock);
2275 if (eglglessink->sinkcaps) {
2276 ret = gst_caps_ref (eglglessink->sinkcaps);
2279 gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
2283 g_mutex_unlock (eglglessink->flow_lock);
2289 gst_eglglessink_setcaps (GstBaseSink * bsink, GstCaps * caps)
2291 GstEglGlesSink *eglglessink;
2292 gboolean ret = TRUE;
2295 EGLNativeWindowType window;
2296 GstEglGlesImageFmt *format;
2298 eglglessink = GST_EGLGLESSINK (bsink);
2300 GST_DEBUG_OBJECT (eglglessink,
2301 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
2302 GST_PTR_FORMAT, eglglessink->current_caps, caps);
2304 if (!(ret = gst_video_format_parse_caps (caps, &eglglessink->format, &width,
2306 GST_ERROR_OBJECT (eglglessink, "Got weird and/or incomplete caps");
2310 if (!(ret = gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d))) {
2313 GST_WARNING_OBJECT (eglglessink,
2314 "Can't parse PAR from caps. Using default: 1");
2317 format = gst_eglglessink_get_compat_format_from_caps (eglglessink, caps);
2319 GST_ERROR_OBJECT (eglglessink,
2320 "No supported and compatible EGL/GLES format found for given caps");
2323 GST_INFO_OBJECT (eglglessink, "Selected compatible EGL/GLES format %d",
2326 g_mutex_lock (eglglessink->flow_lock);
2327 eglglessink->selected_fmt = format;
2328 eglglessink->par_n = par_n;
2329 eglglessink->par_d = par_d;
2330 GST_VIDEO_SINK_WIDTH (eglglessink) = width;
2331 GST_VIDEO_SINK_HEIGHT (eglglessink) = height;
2332 g_mutex_unlock (eglglessink->flow_lock);
2334 if (eglglessink->current_caps) {
2335 GST_ERROR_OBJECT (eglglessink, "Caps were already set");
2336 if (gst_caps_can_intersect (caps, eglglessink->current_caps)) {
2337 GST_INFO_OBJECT (eglglessink, "Caps are compatible anyway");
2341 GST_DEBUG_OBJECT (eglglessink, "Caps are not compatible, reconfiguring");
2345 if (!gst_eglglessink_context_make_current (eglglessink, TRUE, TRUE))
2348 if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
2351 if (eglglessink->have_vbo) {
2352 glDeleteBuffers (1, &eglglessink->eglglesctx->position_buffer);
2353 glDeleteBuffers (1, &eglglessink->eglglesctx->texpos_buffer);
2354 glDeleteBuffers (1, &eglglessink->eglglesctx->index_buffer);
2355 eglglessink->have_vbo = FALSE;
2358 if (eglglessink->have_texture) {
2359 glDeleteTextures (eglglessink->eglglesctx->n_textures,
2360 eglglessink->eglglesctx->texture);
2361 eglglessink->have_texture = FALSE;
2362 eglglessink->eglglesctx->n_textures = 0;
2365 if (eglglessink->eglglesctx->glslprogram) {
2366 glDetachShader (eglglessink->eglglesctx->glslprogram,
2367 eglglessink->eglglesctx->fragshader);
2368 glDetachShader (eglglessink->eglglesctx->glslprogram,
2369 eglglessink->eglglesctx->vertshader);
2370 glDeleteProgram (eglglessink->eglglesctx->glslprogram);
2371 glDeleteShader (eglglessink->eglglesctx->fragshader);
2372 glDeleteShader (eglglessink->eglglesctx->vertshader);
2373 eglglessink->eglglesctx->glslprogram = 0;
2377 if (!gst_eglglessink_context_make_current (eglglessink, FALSE, TRUE))
2380 if (eglglessink->eglglesctx->surface) {
2381 eglDestroySurface (eglglessink->eglglesctx->display,
2382 eglglessink->eglglesctx->surface);
2383 eglglessink->eglglesctx->surface = NULL;
2384 eglglessink->have_surface = FALSE;
2387 if (eglglessink->eglglesctx->eglcontext) {
2388 eglDestroyContext (eglglessink->eglglesctx->display,
2389 eglglessink->eglglesctx->eglcontext);
2390 eglglessink->eglglesctx->eglcontext = NULL;
2393 g_mutex_lock (eglglessink->flow_lock);
2394 /* Reset display region
2395 * XXX: Should probably keep old ones if set_render_rect()
2398 eglglessink->display_region.w = 0;
2399 eglglessink->display_region.h = 0;
2401 gst_caps_unref (eglglessink->current_caps);
2402 eglglessink->current_caps = NULL;
2403 g_mutex_unlock (eglglessink->flow_lock);
2406 if (!gst_eglglessink_choose_config (eglglessink)) {
2407 GST_ERROR_OBJECT (eglglessink, "Couldn't choose EGL config");
2411 g_mutex_lock (eglglessink->flow_lock);
2412 eglglessink->current_caps = gst_caps_ref (caps);
2413 g_mutex_unlock (eglglessink->flow_lock);
2415 /* By now the application should have set a window
2416 * if it meant to do so
2418 if (!eglglessink->have_window) {
2419 GST_INFO_OBJECT (eglglessink,
2420 "No window. Will attempt internal window creation");
2421 if (!(window = gst_eglglessink_create_window (eglglessink, width, height))) {
2422 GST_ERROR_OBJECT (eglglessink, "Internal window creation failed!");
2425 g_mutex_lock (eglglessink->flow_lock);
2426 eglglessink->using_own_window = TRUE;
2427 g_mutex_unlock (eglglessink->flow_lock);
2428 gst_eglglessink_set_window_handle (GST_X_OVERLAY (eglglessink),
2431 eglglessink->eglglesctx->used_window = eglglessink->eglglesctx->window;
2433 if (!eglglessink->have_surface) {
2434 if (!gst_eglglessink_init_egl_surface (eglglessink)) {
2435 GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL surface from window");
2440 if (!eglglessink->have_vbo) {
2441 if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
2442 GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
2448 GST_INFO_OBJECT (eglglessink, "Setcaps succeed");
2452 GST_ERROR_OBJECT (eglglessink, "Setcaps failed");
2457 gst_eglglessink_wipe_fmt (gpointer data)
2459 GstEglGlesImageFmt *format = data;
2460 gst_caps_unref (format->caps);
2464 static GstStateChangeReturn
2465 gst_eglglessink_change_state (GstElement * element, GstStateChange transition)
2467 GstEglGlesSink *eglglessink;
2468 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2470 eglglessink = GST_EGLGLESSINK (element);
2472 switch (transition) {
2473 case GST_STATE_CHANGE_NULL_TO_READY:
2474 if (!egl_init (eglglessink)) {
2475 ret = GST_STATE_CHANGE_FAILURE;
2483 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2484 if (ret == GST_STATE_CHANGE_FAILURE)
2487 switch (transition) {
2488 case GST_STATE_CHANGE_READY_TO_NULL:
2489 g_mutex_lock (eglglessink->flow_lock);
2490 if (eglglessink->eglglesctx->display) {
2491 eglTerminate (eglglessink->eglglesctx->display);
2492 eglglessink->eglglesctx->display = NULL;
2495 eglglessink->selected_fmt = NULL;
2496 g_list_free_full (eglglessink->supported_fmts, gst_eglglessink_wipe_fmt);
2497 eglglessink->supported_fmts = NULL;
2498 gst_caps_unref (eglglessink->sinkcaps);
2499 eglglessink->sinkcaps = NULL;
2500 eglglessink->egl_started = FALSE;
2501 g_mutex_unlock (eglglessink->flow_lock);
2512 gst_eglglessink_finalize (GObject * object)
2514 GstEglGlesSink *eglglessink;
2516 g_return_if_fail (GST_IS_EGLGLESSINK (object));
2518 eglglessink = GST_EGLGLESSINK (object);
2520 g_mutex_free (eglglessink->flow_lock);
2521 eglglessink->flow_lock = NULL;
2523 g_free (eglglessink->eglglesctx);
2524 eglglessink->eglglesctx = NULL;
2526 G_OBJECT_CLASS (parent_class)->finalize (object);
2530 gst_eglglessink_set_property (GObject * object, guint prop_id,
2531 const GValue * value, GParamSpec * pspec)
2533 GstEglGlesSink *eglglessink;
2535 g_return_if_fail (GST_IS_EGLGLESSINK (object));
2537 eglglessink = GST_EGLGLESSINK (object);
2540 case PROP_CREATE_WINDOW:
2541 eglglessink->create_window = g_value_get_boolean (value);
2543 case PROP_FORCE_RENDERING_SLOW:
2544 eglglessink->force_rendering_slow = g_value_get_boolean (value);
2546 case PROP_FORCE_ASPECT_RATIO:
2547 eglglessink->force_aspect_ratio = g_value_get_boolean (value);
2550 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2556 gst_eglglessink_get_property (GObject * object, guint prop_id,
2557 GValue * value, GParamSpec * pspec)
2559 GstEglGlesSink *eglglessink;
2561 g_return_if_fail (GST_IS_EGLGLESSINK (object));
2563 eglglessink = GST_EGLGLESSINK (object);
2566 case PROP_CREATE_WINDOW:
2567 g_value_set_boolean (value, eglglessink->create_window);
2569 case PROP_FORCE_RENDERING_SLOW:
2570 g_value_set_boolean (value, eglglessink->force_rendering_slow);
2572 case PROP_FORCE_ASPECT_RATIO:
2573 g_value_set_boolean (value, eglglessink->force_aspect_ratio);
2576 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2582 gst_eglglessink_base_init (gpointer gclass)
2584 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
2586 gst_element_class_set_details_simple (element_class,
2587 "EGL/GLES vout Sink",
2589 "An EGL/GLES Video Output Sink Implementing the XOverlay interface",
2590 "Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>");
2592 gst_element_class_add_pad_template (element_class,
2593 gst_static_pad_template_get (&gst_eglglessink_sink_template_factory));
2596 /* initialize the eglglessink's class */
2598 gst_eglglessink_class_init (GstEglGlesSinkClass * klass)
2600 GObjectClass *gobject_class;
2601 GstElementClass *gstelement_class;
2602 GstBaseSinkClass *gstbasesink_class;
2603 GstVideoSinkClass *gstvideosink_class;
2605 gobject_class = (GObjectClass *) klass;
2606 gstelement_class = (GstElementClass *) klass;
2607 gstbasesink_class = (GstBaseSinkClass *) klass;
2608 gstvideosink_class = (GstVideoSinkClass *) klass;
2610 gobject_class->set_property = gst_eglglessink_set_property;
2611 gobject_class->get_property = gst_eglglessink_get_property;
2612 gobject_class->finalize = gst_eglglessink_finalize;
2614 gstelement_class->change_state = gst_eglglessink_change_state;
2616 gstbasesink_class->start = gst_eglglessink_start;
2617 gstbasesink_class->stop = gst_eglglessink_stop;
2618 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_eglglessink_setcaps);
2619 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_eglglessink_getcaps);
2620 gstbasesink_class->buffer_alloc = GST_DEBUG_FUNCPTR
2621 (gst_eglglessink_buffer_alloc);
2623 gstvideosink_class->show_frame =
2624 GST_DEBUG_FUNCPTR (gst_eglglessink_show_frame);
2626 g_object_class_install_property (gobject_class, PROP_CREATE_WINDOW,
2627 g_param_spec_boolean ("create-window", "Create Window",
2628 "If set to true, the sink will attempt to create it's own window to "
2629 "render to if none is provided. This is currently only supported "
2630 "when the sink is used under X11",
2631 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2632 g_object_class_install_property (gobject_class, PROP_FORCE_RENDERING_SLOW,
2633 g_param_spec_boolean ("force-rendering-slow", "Force slow rendering path",
2634 "If set to true, the sink will use the slow rendering path even "
2635 "if needed EGL/GLES extensions for the fast rendering path are found "
2636 "to be available at runtime",
2637 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2638 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
2639 g_param_spec_boolean ("force-aspect-ratio",
2640 "Respect aspect ratio when scaling",
2641 "If set to true, the sink will attempt to preserve the incoming "
2642 "frame's geometry while scaling, taking both the storage's and "
2643 "display's pixel aspect ratio into account",
2644 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2649 gst_eglglessink_init (GstEglGlesSink * eglglessink,
2650 GstEglGlesSinkClass * gclass)
2655 eglglessink->have_window = FALSE;
2656 eglglessink->have_surface = FALSE;
2657 eglglessink->have_vbo = FALSE;
2658 eglglessink->have_texture = FALSE;
2659 eglglessink->egl_started = FALSE;
2660 eglglessink->using_own_window = FALSE;
2663 eglglessink->create_window = TRUE;
2664 eglglessink->force_aspect_ratio = TRUE;
2665 eglglessink->force_rendering_slow = FALSE;
2667 eglglessink->par_n = 1;
2668 eglglessink->par_d = 1;
2669 eglglessink->eglglesctx = g_new0 (GstEglGlesRenderContext, 1);
2670 eglglessink->flow_lock = g_mutex_new ();
2673 /* Interface initializations. Used here for initializing the XOverlay
2677 gst_eglglessink_init_interfaces (GType type)
2679 static const GInterfaceInfo implements_info = {
2680 (GInterfaceInitFunc) gst_eglglessink_implements_init, NULL, NULL
2683 static const GInterfaceInfo xoverlay_info = {
2684 (GInterfaceInitFunc) gst_eglglessink_xoverlay_init, NULL, NULL
2687 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
2689 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
2693 /* entry point to initialize the plug-in
2694 * initialize the plug-in itself
2695 * register the element factories and other features
2698 eglglessink_plugin_init (GstPlugin * plugin)
2700 /* debug category for fltering log messages */
2701 GST_DEBUG_CATEGORY_INIT (gst_eglglessink_debug, "eglglessink",
2702 0, "Simple EGL/GLES Sink");
2704 pthread_key_create (&context_key, detach_context);
2706 return gst_element_register (plugin, "eglglessink", GST_RANK_PRIMARY,
2707 GST_TYPE_EGLGLESSINK);
2710 /* PACKAGE: this is usually set by autotools depending on some _INIT macro
2711 * in configure.ac and then written into and defined in config.h, but we can
2712 * just set it ourselves here in case someone doesn't use autotools to
2713 * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.
2716 #define PACKAGE "EGL/GLES Sink"
2720 #define VERSION "0.911"
2723 /* gstreamer looks for this structure to register eglglessinks */
2724 GST_PLUGIN_DEFINE2 (GST_VERSION_MAJOR,
2728 eglglessink_plugin_init,
2729 VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")