1949b7985fe92989c033e72d71c162ab6cbe7c58
[platform/upstream/gstreamer.git] / ext / eglgles / gsteglglessink.c
1 /*
2  * GStreamer EGL/GLES Sink
3  * Copyright (C) 2012 Collabora Ltd.
4  *   @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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.
23  *
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
27  * mentioned above:
28  *
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.
33  *
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.
38  *
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.
43  */
44
45 /**
46  * SECTION:element-eglglessink
47  *
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.
53  *
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.
60  *
61  * <refsect2>
62  * <title>Supported EGL/OpenGL ES versions</title>
63  * <para>
64  * This Sink uses EGLv1 and GLESv2
65  * </para>
66  * </refsect2>
67  *
68  * <refsect2>
69  * <title>Example launch line</title>
70  * |[
71  * gst-launch -v -m videotestsrc ! eglglessink
72  * ]|
73  * </refsect2>
74  *
75  * <refsect2>
76  * <title>Example launch line with forced slow path rendering</title>
77  * <para>
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.
81  * </para>
82  * |[
83  * gst-launch -v -m videotestsrc ! eglglessink force_rendering_slow=TRUE
84  * ]|
85  * </refsect2>
86  *
87  * <refsect2>
88  * <title>Example launch line with internal window creation disabled</title>
89  * <para>
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.
95  * </para>
96  * |[
97  * gst-launch -v -m videotestsrc ! eglglessink can_create_window=FALSE
98  * ]|
99  * </refsect2>
100  *
101  * <refsect2>
102  * <title>Scaling</title>
103  * <para>
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.
109  * </para>
110  * <para>
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
113  * information.
114  * </para>
115  * <para>
116  * Here is an example launch line with the PAR/DAR aware scaling disabled:
117  * </para>
118  * |[
119  * gst-launch -v -m videotestsrc ! eglglessink force_aspect_ratio=FALSE
120  * ]|
121  * </refsect2>
122  */
123
124 #ifdef HAVE_CONFIG_H
125 #  include <config.h>
126 #endif
127
128 #include <string.h>
129 #include <gst/gst.h>
130 #include <gst/video/video.h>
131 #include <gst/video/gstvideosink.h>
132 #include <gst/interfaces/xoverlay.h>
133
134 #include <EGL/egl.h>
135 #include <EGL/eglext.h>
136 #include <GLES2/gl2.h>
137 #include <GLES2/gl2ext.h>
138
139 #include <pthread.h>
140
141 #include "video_platform_wrapper.h"
142
143 #include "gsteglglessink.h"
144
145 GST_DEBUG_CATEGORY_STATIC (gst_eglglessink_debug);
146 #define GST_CAT_DEFAULT gst_eglglessink_debug
147
148 /* These are only needed for the fast rendering path */
149 #ifdef EGL_KHR_image
150 static PFNEGLCREATEIMAGEKHRPROC my_eglCreateImageKHR;
151 static PFNEGLDESTROYIMAGEKHRPROC my_eglDestroyImageKHR;
152
153 #ifdef EGL_KHR_lock_surface
154 static PFNEGLLOCKSURFACEKHRPROC my_eglLockSurfaceKHR;
155 static PFNEGLUNLOCKSURFACEKHRPROC my_eglUnlockSurfaceKHR;
156
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,
160   EGL_NONE
161 };
162
163 #ifdef GL_OES_EGL_image
164 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC my_glEGLImageTargetTexture2DOES;
165 #define EGL_FAST_RENDERING_POSSIBLE 1
166 #endif
167 #endif
168 #endif
169
170 /* GLESv2 GLSL Shaders
171  *
172  * OpenGL ES Standard does not mandate YUV support. This is
173  * why most of these shaders deal with Packed/Planar YUV->RGB
174  * conversion.
175  */
176
177 /* *INDENT-OFF* */
178 /* Direct vertex copy */
179 static const char *vert_COPY_prog = {
180       "attribute vec3 position;"
181       "attribute vec2 texpos;"
182       "varying vec2 opos;"
183       "void main(void)"
184       "{"
185       " opos = texpos;"
186       " gl_Position = vec4(position, 1.0);"
187       "}"
188 };
189
190 /* Direct fragments copy */
191 static const char *frag_COPY_prog = {
192   "precision mediump float;"
193       "varying vec2 opos;"
194       "uniform sampler2D tex;"
195       "void main(void)"
196       "{"
197       " vec4 t = texture2D(tex, opos);"
198       " gl_FragColor = vec4(t.xyz, 1.0);"
199       "}"
200 };
201
202 /* Channel reordering for XYZ <-> ZYX conversion */
203 static const char *frag_REORDER_prog = {
204   "precision mediump float;"
205       "varying vec2 opos;"
206       "uniform sampler2D tex;"
207       "void main(void)"
208       "{"
209       " vec4 t = texture2D(tex, opos);"
210       " gl_FragColor = vec4(t.%c, t.%c, t.%c, 1.0);"
211       "}"
212 };
213
214 /* Packed YUV converters */
215
216 /** AYUV to RGB conversion */
217 static const char *frag_AYUV_prog = {
218       "precision mediump float;"
219       "varying vec2 opos;"
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);"
225       "void main(void) {"
226       "  float r,g,b;"
227       "  vec3 yuv;"
228       "  yuv  = texture2D(tex,opos.xy).gba;"
229       "  yuv += offset;"
230       "  r = dot(yuv, rcoeff);"
231       "  g = dot(yuv, gcoeff);"
232       "  b = dot(yuv, bcoeff);"
233       "  gl_FragColor=vec4(r,g,b,1.0);"
234       "}"
235 };
236
237 /** YUY2/YVYU/UYVY to RGB conversion */
238 static const char *frag_YUY2_YVYU_UYVY_prog = {
239       "precision mediump float;"
240       "varying vec2 opos;"
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);"
246       "void main(void) {"
247       "  float r, g, b;"
248       "  vec3 yuv;"
249       "  vec2 oposxy = vec2(opos.x, opos.y);"
250       "  yuv.x = texture2D(Ytex,oposxy).x;"
251       "  yuv.yz = texture2D(UVtex,oposxy).yz;"
252       "  yuv += offset;"
253       "  r = dot(yuv, rcoeff);"
254       "  g = dot(yuv, gcoeff);"
255       "  b = dot(yuv, bcoeff);"
256       "  gl_FragColor=vec4(r,g,b,1.0);"
257       "}"
258 };
259
260 /* Planar YUV converters */
261
262 /** YUV to RGB conversion */
263 static const char *frag_PLANAR_YUV_prog = {
264       "precision mediump float;"
265       "varying vec2 opos;"
266       "uniform sampler2D Ytex,Utex,Vtex;"
267       "void main(void) {"
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);"
274       "  u=u-0.5;"
275       "  v=v-0.5;"
276       "  r=y+1.5958*v;"
277       "  g=y-0.39173*u-0.81290*v;"
278       "  b=y+2.017*u;"
279       "  gl_FragColor=vec4(r,g,b,1.0);"
280       "}"
281 };
282
283 /** NV12/NV21 to RGB conversion */
284 static const char *frag_NV12_NV21_prog = {
285       "precision mediump float;"
286       "varying vec2 opos;"
287       "uniform sampler2D Ytex,UVtex;"
288       "void main(void) {"
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);"
295       "  u=u-0.5;"
296       "  v=v-0.5;"
297       "  r=y+1.5958*v;"
298       "  g=y-0.39173*u-0.81290*v;"
299       "  b=y+2.017*u;"
300       "  gl_FragColor=vec4(r,g,b,1.0);"
301       "}"
302 };
303 /* *INDENT-ON* */
304
305 /* Input capabilities. */
306 static GstStaticPadTemplate gst_eglglessink_sink_template_factory =
307     GST_STATIC_PAD_TEMPLATE ("sink",
308     GST_PAD_SINK,
309     GST_PAD_ALWAYS,
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 ";"
314         GST_VIDEO_CAPS_YUV
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));
317
318 /* Filter signals and args */
319 enum
320 {
321   /* FILL ME */
322   LAST_SIGNAL
323 };
324
325 enum
326 {
327   PROP_0,
328   PROP_CREATE_WINDOW,
329   PROP_FORCE_ASPECT_RATIO,
330   PROP_FORCE_RENDERING_SLOW
331 };
332
333 /* will probably move elsewhere */
334 static const EGLint eglglessink_RGBA8888_attribs[] = {
335   EGL_RED_SIZE, 8,
336   EGL_GREEN_SIZE, 8,
337   EGL_BLUE_SIZE, 8,
338   EGL_ALPHA_SIZE, 8,
339   EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
340   EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
341   EGL_NONE
342 };
343
344 static const EGLint eglglessink_RGB888_attribs[] = {
345   EGL_RED_SIZE, 8,
346   EGL_GREEN_SIZE, 8,
347   EGL_BLUE_SIZE, 8,
348   EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
349   EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
350   EGL_NONE
351 };
352
353 static const EGLint eglglessink_RGB565_attribs[] = {
354   EGL_RED_SIZE, 5,
355   EGL_GREEN_SIZE, 6,
356   EGL_BLUE_SIZE, 5,
357   EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
358   EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
359   EGL_NONE
360 };
361
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,
370     GstBuffer * buf);
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);
377
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);
385
386 /* Actual XOverlay interface funcs */
387 static void gst_eglglessink_expose (GstXOverlay * overlay);
388 static void gst_eglglessink_set_window_handle (GstXOverlay * overlay,
389     guintptr id);
390 static void gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x,
391     gint y, gint width, gint height);
392
393 /* Custom Buffer funcs */
394 static void gst_eglglesbuffer_destroy (GstEglGlesBuffer * eglglessink);
395 static void gst_eglglesbuffer_init (GstEglGlesBuffer * eglglessink,
396     gpointer g_class);
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,
405     GstCaps * caps);
406 static EGLint *gst_eglglesbuffer_create_native (EGLNativeWindowType win,
407     EGLConfig config, EGLNativeDisplayType display, const EGLint * egl_attribs);
408
409 /* Utility */
410 static EGLNativeWindowType gst_eglglessink_create_window (GstEglGlesSink *
411     eglglessink, gint width, gint height);
412 static inline gint
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,
419     gboolean reset);
420 static GstFlowReturn gst_eglglessink_render_and_display (GstEglGlesSink * sink,
421     GstBuffer * buf);
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);
428
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))
434
435
436 GST_BOILERPLATE_FULL (GstEglGlesSink, gst_eglglessink, GstVideoSink,
437     GST_TYPE_VIDEO_SINK, gst_eglglessink_init_interfaces);
438
439 /* Custom Buffer Funcs */
440 /* XXX: Drafted implementation */
441 static EGLint *
442 gst_eglglesbuffer_create_native (EGLNativeWindowType win,
443     EGLConfig config, EGLNativeDisplayType display, const EGLint * egl_attribs)
444 {
445   EGLNativePixmapType pix = 0;
446   EGLSurface pix_surface;
447   EGLint *buffer = NULL;
448
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.
452    */
453
454   pix_surface = eglCreatePixmapSurface (display, config, pix, egl_attribs);
455
456   if (pix_surface == EGL_NO_SURFACE) {
457     show_egl_error ("eglCreatePixmapSurface");
458     GST_CAT_ERROR (GST_CAT_DEFAULT, "Unable to create pixmap surface");
459     goto EGL_ERROR;
460   }
461
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");
465     goto EGL_ERROR;
466   }
467
468   if (eglQuerySurface (display, pix_surface, EGL_BITMAP_POINTER_KHR, buffer)
469       == EGL_FALSE) {
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;
474   }
475
476   return buffer;
477
478 EGL_ERROR_LOCKED:
479   my_eglUnlockSurfaceKHR (display, pix_surface);
480 EGL_ERROR:
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");
485   }
486   return NULL;
487 }
488
489 static GstEglGlesBuffer *
490 gst_eglglesbuffer_new (GstEglGlesSink * eglglessink, GstCaps * caps)
491 {
492   GstEglGlesBuffer *eglglesbuffer = NULL;
493   GstStructure *structure = NULL;
494   GstEglGlesImageFmt *format;
495
496   g_return_val_if_fail (GST_IS_EGLGLESSINK (eglglessink), NULL);
497   g_return_val_if_fail (caps, NULL);
498
499   eglglesbuffer =
500       (GstEglGlesBuffer *) gst_mini_object_new (GST_TYPE_EGLGLESBUFFER);
501   GST_DEBUG_OBJECT (eglglesbuffer, "Creating new GstEglGlesBuffer");
502
503   structure = gst_caps_get_structure (caps, 0);
504
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);
508   }
509
510   GST_LOG_OBJECT (eglglessink, "creating %dx%d", eglglesbuffer->width,
511       eglglesbuffer->height);
512
513   format = gst_eglglessink_get_compat_format_from_caps (eglglessink, caps);
514
515   if (!format) {
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);
521     goto BEACH_UNLOCKED;
522   }
523
524   eglglesbuffer->format = format->fmt;
525   eglglesbuffer->eglglessink = gst_object_ref (eglglessink);
526
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);
534     goto BEACH_UNLOCKED;
535   }
536
537   GST_BUFFER_DATA (eglglesbuffer) = (guchar *) eglglesbuffer->image;
538   GST_BUFFER_SIZE (eglglesbuffer) = eglglesbuffer->size;
539
540   return eglglesbuffer;
541
542 BEACH_UNLOCKED:
543   gst_eglglesbuffer_free (eglglesbuffer);
544   eglglesbuffer = NULL;
545   return NULL;
546 }
547
548 static void
549 gst_eglglesbuffer_destroy (GstEglGlesBuffer * eglglesbuffer)
550 {
551
552   GstEglGlesSink *eglglessink;
553
554   GST_DEBUG_OBJECT (eglglesbuffer, "Destroying buffer");
555
556   eglglessink = eglglesbuffer->eglglessink;
557   if (G_UNLIKELY (eglglessink == NULL))
558     goto NO_SINK;
559
560   g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
561
562   GST_OBJECT_LOCK (eglglessink);
563   GST_DEBUG_OBJECT (eglglessink, "Destroying image");
564
565   if (eglglesbuffer->image) {
566     if (GST_BUFFER_DATA (eglglesbuffer)) {
567       g_free (GST_BUFFER_DATA (eglglesbuffer));
568     }
569     eglglesbuffer->image = NULL;
570     /* XXX: Unallocate EGL/GL especific resources asociated with this
571      * Image here
572      */
573   }
574
575   GST_OBJECT_UNLOCK (eglglessink);
576   eglglesbuffer->eglglessink = NULL;
577   gst_object_unref (eglglessink);
578
579   GST_MINI_OBJECT_CLASS (gsteglglessink_buffer_parent_class)->finalize
580       (GST_MINI_OBJECT (eglglesbuffer));
581
582   return;
583
584 NO_SINK:
585   GST_WARNING ("No sink found");
586   return;
587 }
588
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
594  * destroy func.
595  */
596 static void
597 gst_eglglesbuffer_finalize (GstEglGlesBuffer * eglglesbuffer)
598 {
599   GstEglGlesSink *eglglessink;
600
601   eglglessink = eglglesbuffer->eglglessink;
602   if (G_UNLIKELY (eglglessink == NULL))
603     goto NO_SINK;
604
605   g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
606
607   gst_eglglesbuffer_destroy (eglglesbuffer);
608
609   return;
610
611 NO_SINK:
612   GST_WARNING ("No sink found");
613   return;
614 }
615
616 static void
617 gst_eglglesbuffer_free (GstEglGlesBuffer * eglglesbuffer)
618 {
619   /* Make sure it is not recycled. This is meaningless without
620    * a pool but was left here as a reference
621    */
622   eglglesbuffer->width = -1;
623   eglglesbuffer->height = -1;
624   gst_buffer_unref (GST_BUFFER (eglglesbuffer));
625 }
626
627 static void
628 gst_eglglesbuffer_init (GstEglGlesBuffer * eglglesbuffer, gpointer g_class)
629 {
630   eglglesbuffer->width = 0;
631   eglglesbuffer->height = 0;
632   eglglesbuffer->size = 0;
633   eglglesbuffer->image = NULL;
634   eglglesbuffer->format = GST_EGLGLESSINK_IMAGE_NOFMT;
635 }
636
637 static void
638 gst_eglglesbuffer_class_init (gpointer g_class, gpointer class_data)
639 {
640   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
641
642   gsteglglessink_buffer_parent_class = g_type_class_peek_parent (g_class);
643
644   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
645       gst_eglglesbuffer_finalize;
646 }
647
648 static GType
649 gst_eglglesbuffer_get_type (void)
650 {
651   static GType _gst_eglglessink_buffer_type;
652
653   if (G_UNLIKELY (_gst_eglglessink_buffer_type == 0)) {
654     static const GTypeInfo eglglessink_buffer_info = {
655       sizeof (GstBufferClass),
656       NULL,
657       NULL,
658       gst_eglglesbuffer_class_init,
659       NULL,
660       NULL,
661       sizeof (GstEglGlesBuffer),
662       0,
663       (GInstanceInitFunc) gst_eglglesbuffer_init,
664       NULL
665     };
666     _gst_eglglessink_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
667         "GstEglGlesBuffer", &eglglessink_buffer_info, 0);
668   }
669   return _gst_eglglessink_buffer_type;
670 }
671
672 static GstEglGlesImageFmt *
673 gst_eglglessink_get_compat_format_from_caps (GstEglGlesSink * eglglessink,
674     GstCaps * caps)
675 {
676
677   GList *list;
678   GstEglGlesImageFmt *format;
679
680   g_return_val_if_fail (GST_IS_EGLGLESSINK (eglglessink), 0);
681
682   list = eglglessink->supported_fmts;
683
684   /* Traverse the list trying to find a compatible format */
685   while (list) {
686     format = list->data;
687     GST_DEBUG_OBJECT (eglglessink, "Checking compatibility between listed %"
688         GST_PTR_FORMAT " and %" GST_PTR_FORMAT, format->caps, caps);
689     if (format) {
690       if (gst_caps_can_intersect (caps, format->caps)) {
691         GST_INFO_OBJECT (eglglessink, "Found compatible format %d",
692             format->fmt);
693         GST_DEBUG_OBJECT (eglglessink,
694             "Got caps %" GST_PTR_FORMAT " and this format can do %"
695             GST_PTR_FORMAT, caps, format->caps);
696         return format;
697       }
698     }
699     list = g_list_next (list);
700   }
701
702   return NULL;
703 }
704
705 static GstCaps *
706 gst_eglglessink_different_size_suggestion (GstEglGlesSink * eglglessink,
707     GstCaps * caps)
708 {
709   GstCaps *intersection;
710   GstCaps *new_caps;
711   GstStructure *s;
712   gint width, height;
713   gint par_n = 1, par_d = 1;
714   gint dar_n, dar_d;
715   gint w, h;
716
717   new_caps = gst_caps_copy (caps);
718
719   s = gst_caps_get_structure (new_caps, 0);
720
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);
724
725   gst_structure_remove_field (s, "width");
726   gst_structure_remove_field (s, "height");
727   gst_structure_remove_field (s, "pixel-aspect-ratio");
728
729   intersection = gst_caps_intersect (eglglessink->current_caps, new_caps);
730   gst_caps_unref (new_caps);
731
732   if (gst_caps_is_empty (intersection))
733     return intersection;
734
735   s = gst_caps_get_structure (intersection, 0);
736
737   gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
738
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);
743
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,
746       NULL);
747
748   return intersection;
749 }
750
751 static GstFlowReturn
752 gst_eglglessink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
753     guint size, GstCaps * caps, GstBuffer ** buf)
754 {
755
756   GstEglGlesSink *eglglessink;
757   GstFlowReturn ret = GST_FLOW_OK;
758   GstEglGlesBuffer *eglglesbuffer = NULL;
759   GstCaps *intersection = NULL;
760   GstStructure *structure = NULL;
761   gint width, height;
762   GstEglGlesImageFmt *format;
763
764   eglglessink = GST_EGLGLESSINK (bsink);
765
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");
769     *buf = NULL;
770     return GST_FLOW_OK;
771   }
772
773   if (G_UNLIKELY (!caps))
774     goto NO_CAPS;
775
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);
782
783     goto REUSE_LAST_CAPS;
784   }
785
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);
789
790   /* Check the caps against our current caps */
791   intersection = gst_caps_intersect (eglglessink->current_caps, caps);
792
793   GST_DEBUG_OBJECT (eglglessink, "Intersection in buffer alloc returned %"
794       GST_PTR_FORMAT, intersection);
795
796   if (gst_caps_is_empty (intersection)) {
797     GstCaps *new_caps;
798
799     gst_caps_unref (intersection);
800
801     /* So we don't support this kind of buffer, let's define one we'd like */
802     new_caps = gst_caps_copy (caps);
803
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);
808       goto INVALID;
809     }
810
811     /* Try different dimensions */
812     intersection =
813         gst_eglglessink_different_size_suggestion (eglglessink, new_caps);
814
815     /* YUV not implemented yet */
816     if (gst_caps_is_empty (intersection)) {
817
818       gst_structure_set_name (structure, "video/x-raw-rgb");
819
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");
829
830       /* Reuse intersection with current_caps */
831       intersection = gst_caps_intersect (eglglessink->current_caps, new_caps);
832     }
833
834     /* Try with different dimensions and RGB formats */
835     if (gst_caps_is_empty (intersection))
836       intersection =
837           gst_eglglessink_different_size_suggestion (eglglessink, new_caps);
838
839     /* Clean this copy */
840     gst_caps_unref (new_caps);
841
842     if (gst_caps_is_empty (intersection))
843       goto INCOMPATIBLE;
844   }
845
846   /* Ensure the returned caps are fixed */
847   gst_caps_truncate (intersection);
848
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);
855   }
856
857   /* Get image format from caps */
858   format = gst_eglglessink_get_compat_format_from_caps (eglglessink,
859       intersection);
860
861   if (!format)
862     GST_WARNING_OBJECT (eglglessink, "Can't get a compatible format from caps");
863
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)
868     goto INVALID_CAPS;
869
870 REUSE_LAST_CAPS:
871
872   GST_DEBUG_OBJECT (eglglessink, "Creating eglglesbuffer");
873   eglglesbuffer = gst_eglglesbuffer_new (eglglessink, intersection);
874
875   if (eglglesbuffer) {
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);
879   }
880
881   *buf = GST_BUFFER_CAST (eglglesbuffer);
882
883 BEACH:
884   if (intersection) {
885     gst_caps_unref (intersection);
886   }
887
888   return ret;
889
890   /* ERRORS */
891 INVALID:
892   {
893     GST_DEBUG_OBJECT (eglglessink, "No width/height on caps!?");
894     ret = GST_FLOW_WRONG_STATE;
895     goto BEACH;
896   }
897 INCOMPATIBLE:
898   {
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;
903     goto BEACH;
904   }
905 INVALID_CAPS:
906   {
907     GST_WARNING_OBJECT (eglglessink, "Invalid caps for buffer allocation %"
908         GST_PTR_FORMAT, intersection);
909     ret = GST_FLOW_NOT_NEGOTIATED;
910     goto BEACH;
911   }
912 NO_CAPS:
913   {
914     GST_WARNING_OBJECT (eglglessink, "Have no caps, doing fallback allocation");
915     *buf = NULL;
916     ret = GST_FLOW_OK;
917     goto BEACH;
918   }
919 }
920
921 static inline gint
922 gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink)
923 {
924   gint ret = 0;
925   EGLint cfg_number;
926   GstEglGlesImageFmt *format;
927   GstCaps *caps;
928
929   GST_DEBUG_OBJECT (eglglessink,
930       "Building initial list of wanted eglattribs per format");
931
932   /* Init supported format/caps list */
933   g_mutex_lock (eglglessink->flow_lock);
934
935   caps = gst_caps_new_empty ();
936
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);
981     ret++;
982     gst_caps_append (caps, gst_caps_ref (format->caps));
983   } else {
984     GST_INFO_OBJECT (eglglessink,
985         "EGL display doesn't support RGBA8888 config");
986   }
987
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);
998     ret++;
999     gst_caps_append (caps, gst_caps_ref (format->caps));
1000   } else {
1001     GST_INFO_OBJECT (eglglessink, "EGL display doesn't support RGB888 config");
1002   }
1003
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);
1012     ret++;
1013     gst_caps_append (caps, gst_caps_ref (format->caps));
1014   } else {
1015     GST_INFO_OBJECT (eglglessink, "EGL display doesn't support RGB565 config");
1016   }
1017
1018   gst_caps_replace (&eglglessink->sinkcaps, caps);
1019   gst_caps_unref (caps);
1020
1021   g_mutex_unlock (eglglessink->flow_lock);
1022
1023   return ret;
1024 }
1025
1026 static inline gboolean
1027 egl_init (GstEglGlesSink * eglglessink)
1028 {
1029   if (!platform_wrapper_init ()) {
1030     GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL platform wrapper");
1031     goto HANDLE_ERROR;
1032   }
1033
1034   if (!gst_eglglessink_init_egl_display (eglglessink)) {
1035     GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL display");
1036     goto HANDLE_ERROR;
1037   }
1038
1039   gst_eglglessink_init_egl_exts (eglglessink);
1040
1041   if (!gst_eglglessink_fill_supported_fbuffer_configs (eglglessink)) {
1042     GST_ERROR_OBJECT (eglglessink, "Display support NONE of our configs");
1043     goto HANDLE_ERROR;
1044   }
1045
1046   g_mutex_lock (eglglessink->flow_lock);
1047   eglglessink->egl_started = TRUE;
1048   g_mutex_unlock (eglglessink->flow_lock);
1049
1050   return TRUE;
1051
1052 HANDLE_ERROR:
1053   GST_ERROR_OBJECT (eglglessink, "Failed to perform EGL init");
1054   return FALSE;
1055 }
1056
1057 gboolean
1058 gst_eglglessink_start (GstBaseSink * sink)
1059 {
1060   GstEglGlesSink *eglglessink = GST_EGLGLESSINK (sink);
1061
1062   if (!eglglessink->egl_started) {
1063     GST_ERROR_OBJECT (eglglessink, "EGL uninitialized. Bailing out");
1064     goto HANDLE_ERROR;
1065   }
1066
1067   /* Ask for a window to render to */
1068   if (!eglglessink->have_window)
1069     gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (eglglessink));
1070
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.");
1074     goto HANDLE_ERROR;
1075   }
1076
1077   return TRUE;
1078
1079 HANDLE_ERROR:
1080   GST_ERROR_OBJECT (eglglessink, "Couldn't start");
1081   return FALSE;
1082 }
1083
1084 gboolean
1085 gst_eglglessink_stop (GstBaseSink * sink)
1086 {
1087   GstEglGlesSink *eglglessink = GST_EGLGLESSINK (sink);
1088
1089   /* EGL/GLES2 cleanup */
1090   if (!gst_eglglessink_context_make_current (eglglessink, TRUE, FALSE))
1091     return FALSE;
1092
1093   if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
1094     glUseProgram (0);
1095
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;
1101     }
1102
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;
1108     }
1109
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;
1119     }
1120   }
1121
1122   if (!gst_eglglessink_context_make_current (eglglessink, FALSE, FALSE))
1123     return FALSE;
1124
1125   if (eglglessink->eglglesctx->surface) {
1126     eglDestroySurface (eglglessink->eglglesctx->display,
1127         eglglessink->eglglesctx->surface);
1128     eglglessink->eglglesctx->surface = NULL;
1129     eglglessink->have_surface = FALSE;
1130   }
1131
1132   if (eglglessink->eglglesctx->eglcontext) {
1133     eglDestroyContext (eglglessink->eglglesctx->display,
1134         eglglessink->eglglesctx->eglcontext);
1135     eglglessink->eglglesctx->eglcontext = NULL;
1136   }
1137
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;
1143   }
1144   eglglessink->eglglesctx->used_window = NULL;
1145   if (eglglessink->current_caps) {
1146     gst_caps_unref (eglglessink->current_caps);
1147     eglglessink->current_caps = NULL;
1148   }
1149
1150   return TRUE;
1151 }
1152
1153 static void
1154 gst_eglglessink_xoverlay_init (GstXOverlayClass * iface)
1155 {
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;
1159 }
1160
1161 static gboolean
1162 gst_eglglessink_interface_supported (GstImplementsInterface * iface, GType type)
1163 {
1164   return (type == GST_TYPE_X_OVERLAY);
1165 }
1166
1167 static void
1168 gst_eglglessink_implements_init (GstImplementsInterfaceClass * klass)
1169 {
1170   klass->supported = gst_eglglessink_interface_supported;
1171 }
1172
1173 static inline gboolean
1174 got_gl_error (const char *wtf)
1175 {
1176   GLuint error = GL_NO_ERROR;
1177
1178   if ((error = glGetError ()) != GL_NO_ERROR) {
1179     GST_CAT_ERROR (GST_CAT_DEFAULT, "GL ERROR: %s returned %x", wtf, error);
1180     return TRUE;
1181   }
1182   return FALSE;
1183 }
1184
1185 static inline void
1186 show_egl_error (const char *wtf)
1187 {
1188   EGLint error;
1189
1190   if ((error = eglGetError ()) != EGL_SUCCESS)
1191     GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned %x", wtf, error);
1192 }
1193
1194 static EGLNativeWindowType
1195 gst_eglglessink_create_window (GstEglGlesSink * eglglessink, gint width,
1196     gint height)
1197 {
1198   EGLNativeWindowType window = 0;
1199
1200   if (!eglglessink->create_window) {
1201     GST_ERROR_OBJECT (eglglessink, "This sink can't create a window by itself");
1202     return window;
1203   } else
1204     GST_INFO_OBJECT (eglglessink, "Attempting internal window creation");
1205
1206   window = platform_create_native_window (width, height);
1207   if (!window) {
1208     GST_ERROR_OBJECT (eglglessink, "Could not create window");
1209     return window;
1210   }
1211   gst_x_overlay_got_window_handle (GST_X_OVERLAY (eglglessink),
1212       (guintptr) window);
1213   return window;
1214 }
1215
1216 static void
1217 gst_eglglessink_expose (GstXOverlay * overlay)
1218 {
1219   GstEglGlesSink *eglglessink;
1220   GstFlowReturn ret;
1221
1222   eglglessink = GST_EGLGLESSINK (overlay);
1223   GST_DEBUG_OBJECT (eglglessink, "Expose catched, redisplay");
1224
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");
1229 }
1230
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.
1235  */
1236 static void
1237 gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink)
1238 {
1239   const char *eglexts;
1240   unsigned const char *glexts;
1241
1242   eglexts = eglQueryString (eglglessink->eglglesctx->display, EGL_EXTENSIONS);
1243   glexts = glGetString (GL_EXTENSIONS);
1244
1245   GST_DEBUG_OBJECT (eglglessink, "Available EGL extensions: %s\n", eglexts);
1246   GST_DEBUG_OBJECT (eglglessink, "Available GLES extensions: %s\n", glexts);
1247
1248 #ifdef EGL_FAST_RENDERING_POSSIBLE
1249   /* OK Fast rendering should be possible from the declared
1250    * extensions on the eglexts/glexts.h headers
1251    */
1252
1253   /* Check for support from claimed EGL/GLES extensions */
1254
1255   if (!strstr (eglexts, "EGL_KHR_image"))
1256     goto KHR_IMAGE_NA;
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;
1261
1262   /* Check for actual extension proc addresses */
1263
1264   my_eglCreateImageKHR =
1265       (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress ("eglCreateImageKHR");
1266   my_eglDestroyImageKHR =
1267       (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR");
1268
1269   if (!my_eglCreateImageKHR || !my_eglDestroyImageKHR) {
1270   KHR_IMAGE_NA:
1271     GST_INFO_OBJECT (eglglessink, "Extension missing: EGL_KHR_image");
1272     goto MISSING_EXTS;
1273   }
1274
1275   my_eglLockSurfaceKHR =
1276       (PFNEGLLOCKSURFACEKHRPROC) eglGetProcAddress ("eglLockSurfaceKHR");
1277   my_eglUnlockSurfaceKHR =
1278       (PFNEGLUNLOCKSURFACEKHRPROC) eglGetProcAddress ("eglUnlockSurfaceKHR");
1279
1280   if (!my_eglLockSurfaceKHR || !my_eglUnlockSurfaceKHR) {
1281   SURFACE_LOCK_NA:
1282     GST_INFO_OBJECT (eglglessink, "Extension missing: EGL_KHR_lock_surface");
1283     goto MISSING_EXTS;
1284   }
1285
1286   my_glEGLImageTargetTexture2DOES =
1287       (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress
1288       ("glEGLImageTargetTexture2DOES");
1289
1290   if (!my_glEGLImageTargetTexture2DOES) {
1291   TEXTURE_2DOES_NA:
1292     GST_INFO_OBJECT (eglglessink, "Extension missing: GL_OES_EGL_image");
1293     goto MISSING_EXTS;
1294   }
1295
1296   if (!eglglessink->force_rendering_slow) {
1297     GST_INFO_OBJECT (eglglessink,
1298         "Have needed extensions for fast rendering path");
1299   } else {
1300     GST_WARNING_OBJECT (eglglessink,
1301         "Extension check passed but slow rendering path being forced");
1302     goto SLOW_PATH_SELECTED;
1303   }
1304
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");
1308   return;
1309 #endif
1310
1311 MISSING_EXTS:
1312   GST_WARNING_OBJECT (eglglessink,
1313       "Extensions missing. Can't use fast rendering path");
1314 SLOW_PATH_SELECTED:
1315   eglglessink->rendering_path = GST_EGLGLESSINK_RENDER_SLOW;
1316   GST_INFO_OBJECT (eglglessink, "Using slow rendering path");
1317   return;
1318 }
1319
1320 static gboolean
1321 gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
1322 {
1323
1324   g_mutex_lock (eglglessink->flow_lock);
1325
1326   GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d",
1327       eglglessink->have_vbo, reset);
1328
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;
1334   }
1335
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;
1341
1342     eglglessink->eglglesctx->position_array[1].x = 1;
1343     eglglessink->eglglesctx->position_array[1].y = -1;
1344     eglglessink->eglglesctx->position_array[1].z = 0;
1345
1346     eglglessink->eglglesctx->position_array[2].x = -1;
1347     eglglessink->eglglesctx->position_array[2].y = 1;
1348     eglglessink->eglglesctx->position_array[2].z = 0;
1349
1350     eglglessink->eglglesctx->position_array[3].x = -1;
1351     eglglessink->eglglesctx->position_array[3].y = -1;
1352     eglglessink->eglglesctx->position_array[3].z = 0;
1353
1354     eglglessink->eglglesctx->texpos_array[0].x = 1;
1355     eglglessink->eglglesctx->texpos_array[0].y = 0;
1356
1357     eglglessink->eglglesctx->texpos_array[1].x = 1;
1358     eglglessink->eglglesctx->texpos_array[1].y = 1;
1359
1360     eglglessink->eglglesctx->texpos_array[2].x = 0;
1361     eglglessink->eglglesctx->texpos_array[2].y = 0;
1362
1363     eglglessink->eglglesctx->texpos_array[3].x = 0;
1364     eglglessink->eglglesctx->texpos_array[3].y = 1;
1365
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;
1370
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;
1376
1377     glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx->position_buffer);
1378     if (got_gl_error ("glBindBuffer position_buffer"))
1379       goto HANDLE_ERROR_LOCKED;
1380
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;
1386
1387     glVertexAttribPointer (eglglessink->eglglesctx->position_loc, 3, GL_FLOAT,
1388         GL_FALSE, 0, 0);
1389     if (got_gl_error ("glVertexAttribPointer"))
1390       goto HANDLE_ERROR_LOCKED;
1391
1392     glEnableVertexAttribArray (eglglessink->eglglesctx->position_loc);
1393     if (got_gl_error ("glEnableVertexAttribArray"))
1394       goto HANDLE_ERROR_LOCKED;
1395
1396     glBindBuffer (GL_ARRAY_BUFFER, eglglessink->eglglesctx->texpos_buffer);
1397     if (got_gl_error ("glBindBuffer texpos_buffer"))
1398       goto HANDLE_ERROR_LOCKED;
1399
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;
1405
1406     glVertexAttribPointer (eglglessink->eglglesctx->texpos_loc, 2, GL_FLOAT,
1407         GL_FALSE, 0, 0);
1408     if (got_gl_error ("glVertexAttribPointer"))
1409       goto HANDLE_ERROR_LOCKED;
1410
1411     glEnableVertexAttribArray (eglglessink->eglglesctx->texpos_loc);
1412     if (got_gl_error ("glEnableVertexAttribArray"))
1413       goto HANDLE_ERROR_LOCKED;
1414
1415     glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
1416         eglglessink->eglglesctx->index_buffer);
1417     if (got_gl_error ("glBindBuffer index_buffer"))
1418       goto HANDLE_ERROR_LOCKED;
1419
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;
1425
1426     eglglessink->have_vbo = TRUE;
1427   } else {
1428     GST_INFO_OBJECT (eglglessink, "Won't perform VBO setup");
1429   }
1430
1431   g_mutex_unlock (eglglessink->flow_lock);
1432   return TRUE;
1433
1434 HANDLE_ERROR_LOCKED:
1435   g_mutex_unlock (eglglessink->flow_lock);
1436   GST_ERROR_OBJECT (eglglessink, "Unable to perform VBO setup");
1437   return FALSE;
1438 }
1439
1440 /* XXX: Lock eglgles context? */
1441 static gboolean
1442 gst_eglglessink_update_surface_dimensions (GstEglGlesSink * eglglessink)
1443 {
1444   gint width, height;
1445
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);
1451
1452   /* Save Pixel Aspect Ratio
1453    *
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.
1458    */
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);
1463   } else {
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;
1467   }
1468
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;
1473   }
1474
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);
1480     return TRUE;
1481   }
1482
1483   return FALSE;
1484 }
1485
1486 static pthread_key_t context_key;
1487
1488 static void
1489 detach_context (void *data)
1490 {
1491   GstEglGlesSink *eglglessink = data;
1492
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);
1497 }
1498
1499 static gboolean
1500 gst_eglglessink_context_make_current (GstEglGlesSink * eglglessink,
1501     gboolean bind, gboolean streaming_thread)
1502 {
1503   g_assert (eglglessink->eglglesctx->display != NULL);
1504
1505   if (bind && eglglessink->eglglesctx->surface &&
1506       eglglessink->eglglesctx->eglcontext) {
1507     if (streaming_thread) {
1508       EGLContext *ctx = eglGetCurrentContext ();
1509
1510       if (ctx == eglglessink->eglglesctx->eglcontext) {
1511         GST_DEBUG_OBJECT (eglglessink, "Already attached the context");
1512         return TRUE;
1513       }
1514
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");
1522         return FALSE;
1523       }
1524
1525       if (!pthread_getspecific (context_key)) {
1526         pthread_setspecific (context_key, gst_object_ref (eglglessink));
1527       }
1528     } else {
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");
1536         return FALSE;
1537       }
1538     }
1539   } else {
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");
1545       return FALSE;
1546     }
1547   }
1548
1549   return TRUE;
1550 }
1551
1552 static gboolean
1553 gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
1554 {
1555   GLint test;
1556   GLboolean ret;
1557   GLchar *info_log;
1558   const gchar *texnames[3] = { NULL, };
1559   gchar *tmp_prog = NULL;
1560
1561   GST_DEBUG_OBJECT (eglglessink, "Enter EGL surface setup");
1562
1563   g_mutex_lock (eglglessink->flow_lock);
1564
1565   eglglessink->eglglesctx->surface =
1566       eglCreateWindowSurface (eglglessink->eglglesctx->display,
1567       eglglessink->eglglesctx->config, eglglessink->eglglesctx->used_window,
1568       NULL);
1569
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;
1574   }
1575
1576   if (!gst_eglglessink_context_make_current (eglglessink, TRUE, TRUE))
1577     goto HANDLE_EGL_ERROR_LOCKED;
1578
1579   /* Save surface dims */
1580   gst_eglglessink_update_surface_dimensions (eglglessink);
1581
1582   /* We have a surface! */
1583   eglglessink->have_surface = TRUE;
1584   g_mutex_unlock (eglglessink->flow_lock);
1585
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.
1588    *
1589    * Note: Shader compiler support is optional but we currently rely on it.
1590    */
1591
1592   glGetBooleanv (GL_SHADER_COMPILER, &ret);
1593   if (ret == GL_FALSE) {
1594     GST_ERROR_OBJECT (eglglessink, "Shader compiler support is unavailable!");
1595     goto HANDLE_ERROR;
1596   }
1597
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,
1602       NULL);
1603   if (got_gl_error ("glShaderSource vertex"))
1604     goto HANDLE_ERROR;
1605
1606   glCompileShader (eglglessink->eglglesctx->vertshader);
1607   if (got_gl_error ("glCompileShader vertex"))
1608     goto HANDLE_ERROR;
1609
1610   glGetShaderiv (eglglessink->eglglesctx->vertshader, GL_COMPILE_STATUS, &test);
1611   if (test != GL_FALSE)
1612     GST_DEBUG_OBJECT (eglglessink, "Successfully compiled vertex shader");
1613   else {
1614     GST_ERROR_OBJECT (eglglessink, "Couldn't compile vertex shader");
1615     glGetShaderiv (eglglessink->eglglesctx->vertshader, GL_INFO_LOG_LENGTH,
1616         &test);
1617     info_log = g_new0 (GLchar, test);
1618     glGetShaderInfoLog (eglglessink->eglglesctx->vertshader, test, NULL,
1619         info_log);
1620     GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
1621     g_free (info_log);
1622     goto HANDLE_ERROR;
1623   }
1624
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,
1629           NULL);
1630       eglglessink->eglglesctx->n_textures = 1;
1631       texnames[0] = "tex";
1632       break;
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";
1644       break;
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";
1652       break;
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";
1660       break;
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";
1668       break;
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";
1676       break;
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";
1684       break;
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";
1693       break;
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";
1701       break;
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";
1709       break;
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,
1715           NULL);
1716       eglglessink->eglglesctx->n_textures = 1;
1717       texnames[0] = "tex";
1718       break;
1719     default:
1720       g_assert_not_reached ();
1721       break;
1722   }
1723
1724   if (got_gl_error ("glShaderSource fragment"))
1725     goto HANDLE_ERROR;
1726
1727   glCompileShader (eglglessink->eglglesctx->fragshader);
1728   if (got_gl_error ("glCompileShader fragment"))
1729     goto HANDLE_ERROR;
1730
1731   glGetShaderiv (eglglessink->eglglesctx->fragshader, GL_COMPILE_STATUS, &test);
1732   if (test != GL_FALSE)
1733     GST_DEBUG_OBJECT (eglglessink, "Successfully compiled fragment shader");
1734   else {
1735     GST_ERROR_OBJECT (eglglessink, "Couldn't compile fragment shader");
1736     glGetShaderiv (eglglessink->eglglesctx->fragshader, GL_INFO_LOG_LENGTH,
1737         &test);
1738     info_log = g_new0 (GLchar, test);
1739     glGetShaderInfoLog (eglglessink->eglglesctx->fragshader, test, NULL,
1740         info_log);
1741     GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
1742     g_free (info_log);
1743     goto HANDLE_ERROR;
1744   }
1745
1746   eglglessink->eglglesctx->glslprogram = glCreateProgram ();
1747   if (got_gl_error ("glCreateProgram"))
1748     goto HANDLE_ERROR;
1749   glAttachShader (eglglessink->eglglesctx->glslprogram,
1750       eglglessink->eglglesctx->vertshader);
1751   if (got_gl_error ("glAttachShader vertices"))
1752     goto HANDLE_ERROR;
1753   glAttachShader (eglglessink->eglglesctx->glslprogram,
1754       eglglessink->eglglesctx->fragshader);
1755   if (got_gl_error ("glAttachShader fragments"))
1756     goto HANDLE_ERROR;
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");
1761   else {
1762     GST_ERROR_OBJECT (eglglessink, "Couldn't link program");
1763     goto HANDLE_ERROR;
1764   }
1765
1766   glUseProgram (eglglessink->eglglesctx->glslprogram);
1767   if (got_gl_error ("glUseProgram"))
1768     goto HANDLE_ERROR;
1769
1770   eglglessink->eglglesctx->position_loc =
1771       glGetAttribLocation (eglglessink->eglglesctx->glslprogram, "position");
1772   eglglessink->eglglesctx->texpos_loc =
1773       glGetAttribLocation (eglglessink->eglglesctx->glslprogram, "texpos");
1774
1775   /* Generate and bind texture */
1776   if (!eglglessink->have_texture) {
1777     gint i;
1778
1779     GST_INFO_OBJECT (eglglessink, "Performing initial texture setup");
1780
1781     g_mutex_lock (eglglessink->flow_lock);
1782
1783     for (i = 0; i < eglglessink->eglglesctx->n_textures; i++) {
1784       if (i == 0)
1785         glActiveTexture (GL_TEXTURE0);
1786       else if (i == 1)
1787         glActiveTexture (GL_TEXTURE1);
1788       else if (i == 2)
1789         glActiveTexture (GL_TEXTURE2);
1790
1791       glGenTextures (1, &eglglessink->eglglesctx->texture[i]);
1792       if (got_gl_error ("glGenTextures"))
1793         goto HANDLE_ERROR_LOCKED;
1794
1795       glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx->texture[i]);
1796       if (got_gl_error ("glBindTexture"))
1797         goto HANDLE_ERROR_LOCKED;
1798
1799       eglglessink->eglglesctx->tex_loc[i] =
1800           glGetUniformLocation (eglglessink->eglglesctx->glslprogram,
1801           texnames[i]);
1802       glUniform1i (eglglessink->eglglesctx->tex_loc[i], i);
1803
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;
1815     }
1816
1817     eglglessink->have_texture = TRUE;
1818     g_mutex_unlock (eglglessink->flow_lock);
1819   }
1820
1821   g_free (tmp_prog);
1822
1823   return TRUE;
1824
1825   /* Errors */
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);
1830 HANDLE_ERROR:
1831   GST_ERROR_OBJECT (eglglessink, "Couldn't setup EGL surface");
1832   g_free (tmp_prog);
1833   return FALSE;
1834 }
1835
1836 static gboolean
1837 gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink)
1838 {
1839   GST_DEBUG_OBJECT (eglglessink, "Enter EGL initial configuration");
1840
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() */
1845   }
1846
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;
1853   }
1854
1855   /* Check against required EGL version
1856    * XXX: Need to review the version requirement in terms of the needed API
1857    */
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);
1862     goto HANDLE_ERROR;
1863   }
1864
1865   GST_INFO_OBJECT (eglglessink, "System reports supported EGL version v%d.%d",
1866       eglglessink->eglglesctx->egl_major, eglglessink->eglglesctx->egl_minor);
1867
1868   eglBindAPI (EGL_OPENGL_ES_API);
1869
1870   return TRUE;
1871
1872   /* Errors */
1873 HANDLE_EGL_ERROR:
1874   GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1875 HANDLE_ERROR:
1876   GST_ERROR_OBJECT (eglglessink, "Couldn't setup window/surface from handle");
1877   return FALSE;
1878 }
1879
1880 static gboolean
1881 gst_eglglessink_choose_config (GstEglGlesSink * eglglessink)
1882 {
1883   EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
1884   GLint egl_configs;
1885
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;
1893   }
1894
1895   if (egl_configs < 1) {
1896     GST_ERROR_OBJECT (eglglessink,
1897         "Could not find matching framebuffer config");
1898     goto HANDLE_ERROR;
1899   }
1900
1901   eglglessink->eglglesctx->eglcontext =
1902       eglCreateContext (eglglessink->eglglesctx->display,
1903       eglglessink->eglglesctx->config, EGL_NO_CONTEXT, con_attribs);
1904
1905   if (eglglessink->eglglesctx->eglcontext == EGL_NO_CONTEXT) {
1906     GST_ERROR_OBJECT (eglglessink, "Error getting context, eglCreateContext");
1907     goto HANDLE_EGL_ERROR;
1908   }
1909
1910   GST_DEBUG_OBJECT (eglglessink, "EGL Context: %p",
1911       eglglessink->eglglesctx->eglcontext);
1912
1913   return TRUE;
1914
1915   /* Errors */
1916 HANDLE_EGL_ERROR:
1917   GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1918 HANDLE_ERROR:
1919   GST_ERROR_OBJECT (eglglessink, "Couldn't choose an usable config");
1920   return FALSE;
1921 }
1922
1923 static void
1924 gst_eglglessink_set_window_handle (GstXOverlay * overlay, guintptr id)
1925 {
1926   GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
1927
1928   g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
1929   GST_DEBUG_OBJECT (eglglessink, "We got a window handle!");
1930
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);
1936
1937   return;
1938 }
1939
1940 static void
1941 gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
1942     gint width, gint height)
1943 {
1944   GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
1945
1946   g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
1947
1948   g_mutex_lock (eglglessink->flow_lock);
1949
1950   if (width == -1 && height == -1) {
1951     /* This is the set-defaults condition according to
1952      * the xOverlay interface docs
1953      */
1954     eglglessink->display_region.w = 0;
1955     eglglessink->display_region.h = 0;
1956   } else {
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;
1962   }
1963
1964   g_mutex_unlock (eglglessink->flow_lock);
1965
1966   return;
1967 }
1968
1969 /* Rendering and display */
1970 static GstFlowReturn
1971 gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
1972     GstBuffer * buf)
1973 {
1974   GstVideoRectangle frame, surface;
1975   gint w, h;
1976   guint dar_n, dar_d;
1977
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
1982   };
1983 #endif
1984
1985   if (!gst_eglglessink_context_make_current (eglglessink, TRUE, TRUE))
1986     goto HANDLE_EGL_ERROR;
1987
1988   w = GST_VIDEO_SINK_WIDTH (eglglessink);
1989   h = GST_VIDEO_SINK_HEIGHT (eglglessink);
1990
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);
1994
1995   switch (eglglessink->rendering_path) {
1996 #ifdef EGL_FAST_RENDERING_POSSIBLE
1997     case GST_EGLGLESSINK_RENDER_FAST:
1998       /* XXX: Not Fully implemented */
1999       img =
2000           my_eglCreateImageKHR (eglglessink->eglglesctx->display,
2001           EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
2002           (EGLClientBuffer) GST_BUFFER_DATA (buf), attrs);
2003
2004       if (img == EGL_NO_IMAGE_KHR) {
2005         GST_ERROR_OBJECT (eglglessink, "my_eglCreateImageKHR failed");
2006         goto HANDLE_EGL_ERROR;
2007       }
2008
2009       my_glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, img);
2010
2011       break;
2012 #endif
2013     default:                   /* case GST_EGLGLESSINK_RENDER_SLOW */
2014
2015       if (buf) {
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));
2022             break;
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));
2028             break;
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));
2044                 break;
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));
2051                 break;
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;
2058
2059                 coffset =
2060                     gst_video_format_get_component_offset (eglglessink->format,
2061                     0, w, h);
2062                 cw = gst_video_format_get_component_width (eglglessink->format,
2063                     0, w);
2064                 ch = gst_video_format_get_component_height (eglglessink->format,
2065                     0, h);
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);
2072                 coffset =
2073                     gst_video_format_get_component_offset (eglglessink->format,
2074                     1, w, h);
2075                 cw = gst_video_format_get_component_width (eglglessink->format,
2076                     1, w);
2077                 ch = gst_video_format_get_component_height (eglglessink->format,
2078                     1, h);
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);
2085                 coffset =
2086                     gst_video_format_get_component_offset (eglglessink->format,
2087                     2, w, h);
2088                 cw = gst_video_format_get_component_width (eglglessink->format,
2089                     2, w);
2090                 ch = gst_video_format_get_component_height (eglglessink->format,
2091                     2, h);
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);
2098                 break;
2099               }
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));
2114                 break;
2115               case GST_VIDEO_FORMAT_NV12:
2116               case GST_VIDEO_FORMAT_NV21:{
2117                 gint coffset, cw, ch;
2118
2119                 coffset =
2120                     gst_video_format_get_component_offset (eglglessink->format,
2121                     0, w, h);
2122                 cw = gst_video_format_get_component_width (eglglessink->format,
2123                     0, w);
2124                 ch = gst_video_format_get_component_height (eglglessink->format,
2125                     0, h);
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);
2132
2133                 coffset =
2134                     gst_video_format_get_component_offset (eglglessink->format,
2135                     (eglglessink->format == GST_VIDEO_FORMAT_NV12 ? 1 : 2), w,
2136                     h);
2137                 cw = gst_video_format_get_component_width (eglglessink->format,
2138                     1, w);
2139                 ch = gst_video_format_get_component_height (eglglessink->format,
2140                     1, h);
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);
2147                 break;
2148               }
2149               default:
2150                 g_assert_not_reached ();
2151                 break;
2152             }
2153         }
2154
2155         if (got_gl_error ("glTexImage2D"))
2156           goto HANDLE_ERROR;
2157       }
2158
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.
2165        */
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;
2176         } else {
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");
2182             frame.w = w;
2183             frame.h = h;
2184           } else {
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?
2189              */
2190             if (h % dar_d == 0) {
2191               frame.w = gst_util_uint64_scale_int (h, dar_n, dar_d);
2192               frame.h = h;
2193             } else if (w % dar_n == 0) {
2194               frame.h = gst_util_uint64_scale_int (w, dar_d, dar_n);
2195               frame.w = w;
2196             } else {
2197               /* Neither width nor height can be precisely scaled.
2198                * Prefer to leave height untouched. See comment above.
2199                */
2200               frame.w = gst_util_uint64_scale_int (h, dar_n, dar_d);
2201               frame.h = h;
2202             }
2203           }
2204
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);
2209         }
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);
2214       }
2215
2216       glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
2217       if (got_gl_error ("glDrawElements"))
2218         goto HANDLE_ERROR;
2219
2220       if ((eglSwapBuffers (eglglessink->eglglesctx->display,
2221                   eglglessink->eglglesctx->surface))
2222           == EGL_FALSE) {
2223         show_egl_error ("eglSwapBuffers");
2224         goto HANDLE_ERROR;
2225       }
2226   }
2227
2228   GST_DEBUG_OBJECT (eglglessink, "Succesfully rendered 1 frame");
2229   return GST_FLOW_OK;
2230
2231 HANDLE_EGL_ERROR:
2232   GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
2233 HANDLE_ERROR:
2234   GST_ERROR_OBJECT (eglglessink, "Rendering disabled for this frame");
2235
2236   return GST_FLOW_ERROR;
2237 }
2238
2239 static GstFlowReturn
2240 gst_eglglessink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
2241 {
2242   GstEglGlesSink *eglglessink;
2243
2244   g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
2245
2246   eglglessink = GST_EGLGLESSINK (vsink);
2247   GST_DEBUG_OBJECT (eglglessink, "Got buffer: %p", buf);
2248
2249   if (!eglglessink->have_window) {
2250     GST_ERROR_OBJECT (eglglessink, "I don't have a window to render to");
2251     return GST_FLOW_ERROR;
2252   }
2253
2254   if (!eglglessink->have_surface) {
2255     GST_ERROR_OBJECT (eglglessink, "I don't have a surface to render to");
2256     return GST_FLOW_ERROR;
2257   }
2258 #ifndef EGL_ANDROID_image_native_buffer
2259   GST_WARNING_OBJECT (eglglessink, "EGL_ANDROID_image_native_buffer not "
2260       "available");
2261 #endif
2262
2263   return gst_eglglessink_render_and_display (eglglessink, buf);
2264 }
2265
2266 static GstCaps *
2267 gst_eglglessink_getcaps (GstBaseSink * bsink)
2268 {
2269   GstEglGlesSink *eglglessink;
2270   GstCaps *ret = NULL;
2271
2272   eglglessink = GST_EGLGLESSINK (bsink);
2273
2274   g_mutex_lock (eglglessink->flow_lock);
2275   if (eglglessink->sinkcaps) {
2276     ret = gst_caps_ref (eglglessink->sinkcaps);
2277   } else {
2278     ret =
2279         gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
2280             (bsink)));
2281   }
2282
2283   g_mutex_unlock (eglglessink->flow_lock);
2284
2285   return ret;
2286 }
2287
2288 static gboolean
2289 gst_eglglessink_setcaps (GstBaseSink * bsink, GstCaps * caps)
2290 {
2291   GstEglGlesSink *eglglessink;
2292   gboolean ret = TRUE;
2293   gint width, height;
2294   int par_n, par_d;
2295   EGLNativeWindowType window;
2296   GstEglGlesImageFmt *format;
2297
2298   eglglessink = GST_EGLGLESSINK (bsink);
2299
2300   GST_DEBUG_OBJECT (eglglessink,
2301       "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
2302       GST_PTR_FORMAT, eglglessink->current_caps, caps);
2303
2304   if (!(ret = gst_video_format_parse_caps (caps, &eglglessink->format, &width,
2305               &height))) {
2306     GST_ERROR_OBJECT (eglglessink, "Got weird and/or incomplete caps");
2307     goto HANDLE_ERROR;
2308   }
2309
2310   if (!(ret = gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d))) {
2311     par_n = 1;
2312     par_d = 1;
2313     GST_WARNING_OBJECT (eglglessink,
2314         "Can't parse PAR from caps. Using default: 1");
2315   }
2316
2317   format = gst_eglglessink_get_compat_format_from_caps (eglglessink, caps);
2318   if (!format) {
2319     GST_ERROR_OBJECT (eglglessink,
2320         "No supported and compatible EGL/GLES format found for given caps");
2321     goto HANDLE_ERROR;
2322   } else
2323     GST_INFO_OBJECT (eglglessink, "Selected compatible EGL/GLES format %d",
2324         format->fmt);
2325
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);
2333
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");
2338       goto SUCCEED;
2339     }
2340
2341     GST_DEBUG_OBJECT (eglglessink, "Caps are not compatible, reconfiguring");
2342
2343     /* Cleanup */
2344
2345     if (!gst_eglglessink_context_make_current (eglglessink, TRUE, TRUE))
2346       return FALSE;
2347
2348     if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
2349       glUseProgram (0);
2350
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;
2356       }
2357
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;
2363       }
2364
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;
2374       }
2375     }
2376
2377     if (!gst_eglglessink_context_make_current (eglglessink, FALSE, TRUE))
2378       return FALSE;
2379
2380     if (eglglessink->eglglesctx->surface) {
2381       eglDestroySurface (eglglessink->eglglesctx->display,
2382           eglglessink->eglglesctx->surface);
2383       eglglessink->eglglesctx->surface = NULL;
2384       eglglessink->have_surface = FALSE;
2385     }
2386
2387     if (eglglessink->eglglesctx->eglcontext) {
2388       eglDestroyContext (eglglessink->eglglesctx->display,
2389           eglglessink->eglglesctx->eglcontext);
2390       eglglessink->eglglesctx->eglcontext = NULL;
2391     }
2392
2393     g_mutex_lock (eglglessink->flow_lock);
2394     /* Reset display region
2395      * XXX: Should probably keep old ones if set_render_rect()
2396      * has been called.
2397      */
2398     eglglessink->display_region.w = 0;
2399     eglglessink->display_region.h = 0;
2400
2401     gst_caps_unref (eglglessink->current_caps);
2402     eglglessink->current_caps = NULL;
2403     g_mutex_unlock (eglglessink->flow_lock);
2404   }
2405
2406   if (!gst_eglglessink_choose_config (eglglessink)) {
2407     GST_ERROR_OBJECT (eglglessink, "Couldn't choose EGL config");
2408     goto HANDLE_ERROR;
2409   }
2410
2411   g_mutex_lock (eglglessink->flow_lock);
2412   eglglessink->current_caps = gst_caps_ref (caps);
2413   g_mutex_unlock (eglglessink->flow_lock);
2414
2415   /* By now the application should have set a window
2416    * if it meant to do so
2417    */
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!");
2423       goto HANDLE_ERROR;
2424     }
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),
2429         (guintptr) window);
2430   }
2431   eglglessink->eglglesctx->used_window = eglglessink->eglglesctx->window;
2432
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");
2436       goto HANDLE_ERROR;
2437     }
2438   }
2439
2440   if (!eglglessink->have_vbo) {
2441     if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
2442       GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
2443       goto HANDLE_ERROR;
2444     }
2445   }
2446
2447 SUCCEED:
2448   GST_INFO_OBJECT (eglglessink, "Setcaps succeed");
2449   return TRUE;
2450
2451 HANDLE_ERROR:
2452   GST_ERROR_OBJECT (eglglessink, "Setcaps failed");
2453   return FALSE;
2454 }
2455
2456 static void
2457 gst_eglglessink_wipe_fmt (gpointer data)
2458 {
2459   GstEglGlesImageFmt *format = data;
2460   gst_caps_unref (format->caps);
2461   g_free (format);
2462 }
2463
2464 static GstStateChangeReturn
2465 gst_eglglessink_change_state (GstElement * element, GstStateChange transition)
2466 {
2467   GstEglGlesSink *eglglessink;
2468   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2469
2470   eglglessink = GST_EGLGLESSINK (element);
2471
2472   switch (transition) {
2473     case GST_STATE_CHANGE_NULL_TO_READY:
2474       if (!egl_init (eglglessink)) {
2475         ret = GST_STATE_CHANGE_FAILURE;
2476         goto done;
2477       }
2478       break;
2479     default:
2480       break;
2481   }
2482
2483   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2484   if (ret == GST_STATE_CHANGE_FAILURE)
2485     return ret;
2486
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;
2493       }
2494
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);
2502       break;
2503     default:
2504       break;
2505   }
2506
2507 done:
2508   return ret;
2509 }
2510
2511 static void
2512 gst_eglglessink_finalize (GObject * object)
2513 {
2514   GstEglGlesSink *eglglessink;
2515
2516   g_return_if_fail (GST_IS_EGLGLESSINK (object));
2517
2518   eglglessink = GST_EGLGLESSINK (object);
2519
2520   g_mutex_free (eglglessink->flow_lock);
2521   eglglessink->flow_lock = NULL;
2522
2523   g_free (eglglessink->eglglesctx);
2524   eglglessink->eglglesctx = NULL;
2525
2526   G_OBJECT_CLASS (parent_class)->finalize (object);
2527 }
2528
2529 static void
2530 gst_eglglessink_set_property (GObject * object, guint prop_id,
2531     const GValue * value, GParamSpec * pspec)
2532 {
2533   GstEglGlesSink *eglglessink;
2534
2535   g_return_if_fail (GST_IS_EGLGLESSINK (object));
2536
2537   eglglessink = GST_EGLGLESSINK (object);
2538
2539   switch (prop_id) {
2540     case PROP_CREATE_WINDOW:
2541       eglglessink->create_window = g_value_get_boolean (value);
2542       break;
2543     case PROP_FORCE_RENDERING_SLOW:
2544       eglglessink->force_rendering_slow = g_value_get_boolean (value);
2545       break;
2546     case PROP_FORCE_ASPECT_RATIO:
2547       eglglessink->force_aspect_ratio = g_value_get_boolean (value);
2548       break;
2549     default:
2550       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2551       break;
2552   }
2553 }
2554
2555 static void
2556 gst_eglglessink_get_property (GObject * object, guint prop_id,
2557     GValue * value, GParamSpec * pspec)
2558 {
2559   GstEglGlesSink *eglglessink;
2560
2561   g_return_if_fail (GST_IS_EGLGLESSINK (object));
2562
2563   eglglessink = GST_EGLGLESSINK (object);
2564
2565   switch (prop_id) {
2566     case PROP_CREATE_WINDOW:
2567       g_value_set_boolean (value, eglglessink->create_window);
2568       break;
2569     case PROP_FORCE_RENDERING_SLOW:
2570       g_value_set_boolean (value, eglglessink->force_rendering_slow);
2571       break;
2572     case PROP_FORCE_ASPECT_RATIO:
2573       g_value_set_boolean (value, eglglessink->force_aspect_ratio);
2574       break;
2575     default:
2576       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2577       break;
2578   }
2579 }
2580
2581 static void
2582 gst_eglglessink_base_init (gpointer gclass)
2583 {
2584   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
2585
2586   gst_element_class_set_details_simple (element_class,
2587       "EGL/GLES vout Sink",
2588       "Sink/Video",
2589       "An EGL/GLES Video Output Sink Implementing the XOverlay interface",
2590       "Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>");
2591
2592   gst_element_class_add_pad_template (element_class,
2593       gst_static_pad_template_get (&gst_eglglessink_sink_template_factory));
2594 }
2595
2596 /* initialize the eglglessink's class */
2597 static void
2598 gst_eglglessink_class_init (GstEglGlesSinkClass * klass)
2599 {
2600   GObjectClass *gobject_class;
2601   GstElementClass *gstelement_class;
2602   GstBaseSinkClass *gstbasesink_class;
2603   GstVideoSinkClass *gstvideosink_class;
2604
2605   gobject_class = (GObjectClass *) klass;
2606   gstelement_class = (GstElementClass *) klass;
2607   gstbasesink_class = (GstBaseSinkClass *) klass;
2608   gstvideosink_class = (GstVideoSinkClass *) klass;
2609
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;
2613
2614   gstelement_class->change_state = gst_eglglessink_change_state;
2615
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);
2622
2623   gstvideosink_class->show_frame =
2624       GST_DEBUG_FUNCPTR (gst_eglglessink_show_frame);
2625
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));
2645 }
2646
2647
2648 static void
2649 gst_eglglessink_init (GstEglGlesSink * eglglessink,
2650     GstEglGlesSinkClass * gclass)
2651 {
2652   /* Init defaults */
2653
2654   /** Flags */
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;
2661
2662   /** Props */
2663   eglglessink->create_window = TRUE;
2664   eglglessink->force_aspect_ratio = TRUE;
2665   eglglessink->force_rendering_slow = FALSE;
2666
2667   eglglessink->par_n = 1;
2668   eglglessink->par_d = 1;
2669   eglglessink->eglglesctx = g_new0 (GstEglGlesRenderContext, 1);
2670   eglglessink->flow_lock = g_mutex_new ();
2671 }
2672
2673 /* Interface initializations. Used here for initializing the XOverlay
2674  * Interface.
2675  */
2676 static void
2677 gst_eglglessink_init_interfaces (GType type)
2678 {
2679   static const GInterfaceInfo implements_info = {
2680     (GInterfaceInitFunc) gst_eglglessink_implements_init, NULL, NULL
2681   };
2682
2683   static const GInterfaceInfo xoverlay_info = {
2684     (GInterfaceInitFunc) gst_eglglessink_xoverlay_init, NULL, NULL
2685   };
2686
2687   g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
2688       &implements_info);
2689   g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
2690
2691 }
2692
2693 /* entry point to initialize the plug-in
2694  * initialize the plug-in itself
2695  * register the element factories and other features
2696  */
2697 static gboolean
2698 eglglessink_plugin_init (GstPlugin * plugin)
2699 {
2700   /* debug category for fltering log messages */
2701   GST_DEBUG_CATEGORY_INIT (gst_eglglessink_debug, "eglglessink",
2702       0, "Simple EGL/GLES Sink");
2703
2704   pthread_key_create (&context_key, detach_context);
2705
2706   return gst_element_register (plugin, "eglglessink", GST_RANK_PRIMARY,
2707       GST_TYPE_EGLGLESSINK);
2708 }
2709
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.
2714  */
2715 #ifndef PACKAGE
2716 #define PACKAGE "EGL/GLES Sink"
2717 #endif
2718
2719 #ifndef VERSION
2720 #define VERSION "0.911"
2721 #endif
2722
2723 /* gstreamer looks for this structure to register eglglessinks */
2724 GST_PLUGIN_DEFINE2 (GST_VERSION_MAJOR,
2725     GST_VERSION_MINOR,
2726     eglglessink,
2727     "EGL/GLES sink",
2728     eglglessink_plugin_init,
2729     VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")