2 * GStreamer EGL/GLES Sink
3 * Copyright (C) 2012 Collabora Ltd.
4 * @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Alternatively, the contents of this file may be used under the
25 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
26 * which case the following provisions apply instead of the ones
29 * This library is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU Library General Public
31 * License as published by the Free Software Foundation; either
32 * version 2 of the License, or (at your option) any later version.
34 * This library is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * Library General Public License for more details.
39 * You should have received a copy of the GNU Library General Public
40 * License along with this library; if not, write to the
41 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
42 * Boston, MA 02111-1307, USA.
46 * SECTION:element-eglglessink
48 * This is a vout sink using EGL/GLES.
51 * <title>Rationale on OpenGL ES version</title>
53 * This Sink uses GLESv2
58 * <title>Example launch line</title>
60 * gst-launch -v -m videotestsrc ! eglglessink
65 * <title>Example launch line with forced slow path rendering</title>
67 * The sink will chose a buffer copy-over slow rendering path even
68 * if needed EGL/GLES extensions to use a fast rendering path are
72 * gst-launch -v -m videotestsrc ! eglglessink force_rendering_slow=TRUE
77 * <title>Example launch line with internal window creation disabled</title>
79 * The sink will wait for a window handle through it's xOverlay interface
80 * even if internal window creation is supported by the platform and
84 * gst-launch -v -m videotestsrc ! eglglessink can_create_window=FALSE
95 #include <gst/video/video.h>
96 #include <gst/video/gstvideosink.h>
97 #include <gst/interfaces/xoverlay.h>
100 #include <EGL/eglext.h>
101 #include <GLES2/gl2.h>
102 #include <GLES2/gl2ext.h>
104 #include "video_platform_wrapper.h"
106 #include "gsteglglessink.h"
108 GST_DEBUG_CATEGORY_STATIC (gst_eglglessink_debug);
109 #define GST_CAT_DEFAULT gst_eglglessink_debug
111 /* XXX: These should be defined per model someway
112 * but the Galaxy Nexus's were taken as a reference
115 #define EGLGLESSINK_MAX_FRAME_WIDTH 1280
116 #define EGLGLESSINK_MAX_FRAME_HEIGHT 720
118 /* These are only needed for the fast rendering path */
120 static PFNEGLCREATEIMAGEKHRPROC my_eglCreateImageKHR;
121 static PFNEGLDESTROYIMAGEKHRPROC my_eglDestroyImageKHR;
123 #ifdef EGL_KHR_lock_surface
124 static PFNEGLLOCKSURFACEKHRPROC my_eglLockSurfaceKHR;
125 static PFNEGLUNLOCKSURFACEKHRPROC my_eglUnlockSurfaceKHR;
127 static EGLint lock_attribs[] = {
128 EGL_MAP_PRESERVE_PIXELS_KHR, EGL_TRUE,
129 EGL_LOCK_USAGE_HINT_KHR, EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR,
133 #ifdef GL_OES_EGL_image
134 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC my_glEGLImageTargetTexture2DOES;
135 #define EGL_FAST_RENDERING_POSSIBLE 1
141 static const char *vert_COPY_prog = {
142 "attribute vec3 position;"
143 "attribute vec2 texpos;"
148 " gl_Position = vec4(position, 1.0);"
152 static const char *frag_COPY_prog = {
153 "precision mediump float;"
155 "uniform sampler2D tex;"
158 " vec4 t = texture2D(tex, opos);"
159 " gl_FragColor = vec4(t.xyz, 1.0);"
163 static const char *frag_REORDER_prog = {
164 "precision mediump float;"
166 "uniform sampler2D tex;"
170 " r = texture2D(tex, opos).%c;"
171 " g = texture2D(tex, opos).%c;"
172 " b = texture2D(tex, opos).%c;"
173 " gl_FragColor = vec4(r, g, b, 1.0);"
177 /* From gst-plugins-gl */
178 static const char *frag_AYUV_prog = {
179 "precision mediump float;"
181 "uniform sampler2D tex;"
183 " float r,g,b,y,u,v;"
184 " vec2 nxy = opos.xy;"
185 " y=texture2D(tex,nxy).g;"
186 " u=texture2D(tex,nxy).b;"
187 " v=texture2D(tex,nxy).a;"
188 " y=1.1643*(y-0.0625);"
192 " g=y-0.39173*u-0.81290*v;"
194 " gl_FragColor=vec4(r,g,b,1.0);"
198 static const char *frag_PLANAR_YUV_prog = {
199 "precision mediump float;"
201 "uniform sampler2D Ytex,Utex,Vtex;"
203 " float r,g,b,y,u,v;"
204 " vec2 nxy = opos.xy;"
205 " y=texture2D(Ytex,nxy).r;"
206 " u=texture2D(Utex,nxy).r;"
207 " v=texture2D(Vtex,nxy).r;"
208 " y=1.1643*(y-0.0625);"
212 " g=y-0.39173*u-0.81290*v;"
214 " gl_FragColor=vec4(r,g,b,1.0);"
218 static const char *frag_NV12_NV21_prog = {
219 "precision mediump float;"
221 "uniform sampler2D Ytex,UVtex;"
223 " float r,g,b,y,u,v;"
224 " vec2 nxy = opos.xy;"
225 " y=texture2D(Ytex,nxy).r;"
226 " u=texture2D(UVtex,nxy).%c;"
227 " v=texture2D(UVtex,nxy).%c;"
228 " y=1.1643*(y-0.0625);"
232 " g=y-0.39173*u-0.81290*v;"
234 " gl_FragColor=vec4(r,g,b,1.0);"
238 static const char *frag_YUY2_UYVY_prog = {
239 "precision mediump float;"
241 "uniform sampler2D Ytex, UVtex;"
243 " float fx, fy, y, u, v, r, g, b;"
246 " y = texture2D(Ytex,vec2(fx,fy)).%c;"
247 " u = texture2D(UVtex,vec2(fx,fy)).%c;"
248 " v = texture2D(UVtex,vec2(fx,fy)).%c;"
249 " y=1.1643*(y-0.0625);"
253 " g=y-0.39173*u-0.81290*v;"
255 " gl_FragColor=vec4(r,g,b,1.0);"
262 /* Input capabilities.
264 * Note: OpenGL ES Standard does not mandate YUV support.
266 static GstStaticPadTemplate gst_eglglessink_sink_template_factory =
267 GST_STATIC_PAD_TEMPLATE ("sink",
270 GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";"
271 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_ABGR ";"
272 GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx ";"
273 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
275 ("{ AYUV, Y444, I420, YV12, NV12, NV21, YUY2, UYVY, Y42B, Y41B }") ";"
276 GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";" GST_VIDEO_CAPS_RGB_16));
278 /* Filter signals and args */
290 PROP_FORCE_ASPECT_RATIO,
293 PROP_FORCE_RENDERING_SLOW
296 /* will probably move elsewhere */
297 static const EGLint eglglessink_RGBA8888_attribs[] = {
302 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
303 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
307 static const EGLint eglglessink_RGB888_attribs[] = {
311 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
312 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
316 static const EGLint eglglessink_RGB565_attribs[] = {
320 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
321 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
325 static void gst_eglglessink_finalize (GObject * object);
326 static void gst_eglglessink_get_property (GObject * object, guint prop_id,
327 GValue * value, GParamSpec * pspec);
328 static void gst_eglglessink_set_property (GObject * object, guint prop_id,
329 const GValue * value, GParamSpec * pspec);
330 static GstStateChangeReturn gst_eglglessink_change_state (GstElement * element,
331 GstStateChange transition);
332 static GstFlowReturn gst_eglglessink_show_frame (GstVideoSink * vsink,
334 static gboolean gst_eglglessink_setcaps (GstBaseSink * bsink, GstCaps * caps);
335 static gboolean gst_eglglessink_start (GstBaseSink * sink);
336 static gboolean gst_eglglessink_stop (GstBaseSink * sink);
337 static GstFlowReturn gst_eglglessink_buffer_alloc (GstBaseSink * sink,
338 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
339 static GstCaps *gst_eglglessink_getcaps (GstBaseSink * bsink);
341 /* XOverlay interface cruft */
342 static gboolean gst_eglglessink_interface_supported
343 (GstImplementsInterface * iface, GType type);
344 static void gst_eglglessink_implements_init
345 (GstImplementsInterfaceClass * klass);
346 static void gst_eglglessink_xoverlay_init (GstXOverlayClass * iface);
347 static void gst_eglglessink_init_interfaces (GType type);
349 /* Actual XOverlay interface funcs */
350 static void gst_eglglessink_expose (GstXOverlay * overlay);
351 static void gst_eglglessink_set_window_handle (GstXOverlay * overlay,
353 static void gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x,
354 gint y, gint width, gint height);
356 /* Custom Buffer funcs */
357 static void gst_eglglesbuffer_destroy (GstEglGlesBuffer * eglglessink);
358 static void gst_eglglesbuffer_init (GstEglGlesBuffer * eglglessink,
360 static GType gst_eglglesbuffer_get_type (void);
361 static GstEglGlesImageFmt *gst_eglglessink_get_compat_format_from_caps
362 (GstEglGlesSink * eglglessink, GstCaps * caps);
363 static void gst_eglglesbuffer_finalize (GstEglGlesBuffer * eglglessink);
364 static void gst_eglglesbuffer_class_init (gpointer g_class,
365 gpointer class_data);
366 static void gst_eglglesbuffer_free (GstEglGlesBuffer * eglglesbuffer);
367 static GstEglGlesBuffer *gst_eglglesbuffer_new (GstEglGlesSink * eglglessink,
369 static EGLint *gst_eglglesbuffer_create_native (EGLNativeWindowType win,
370 EGLConfig config, EGLNativeDisplayType display, const EGLint * egl_attribs);
373 static EGLNativeWindowType gst_eglglessink_create_window (GstEglGlesSink *
374 eglglessink, gint width, gint height);
376 gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink);
377 static gboolean gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink);
378 static gboolean gst_eglglessink_choose_config (GstEglGlesSink * eglglessink);
379 static gboolean gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink);
380 static void gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink);
381 static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink,
383 static GstFlowReturn gst_eglglessink_render_and_display (GstEglGlesSink * sink,
385 static inline gboolean got_gl_error (const char *wtf);
386 static inline void show_egl_error (const char *wtf);
387 static void gst_eglglessink_wipe_fmt (gpointer data);
388 static inline gboolean egl_init (GstEglGlesSink * eglglessink);
390 static GstBufferClass *gsteglglessink_buffer_parent_class = NULL;
391 #define GST_TYPE_EGLGLESBUFFER (gst_eglglesbuffer_get_type())
392 #define GST_IS_EGLGLESBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EGLGLESBUFFER))
393 #define GST_EGLGLESBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EGLGLESBUFFER, GstEglGlesBuffer))
394 #define GST_EGLGLESBUFFER_CAST(obj) ((GstEglGlesBuffer *)(obj))
397 GST_BOILERPLATE_FULL (GstEglGlesSink, gst_eglglessink, GstVideoSink,
398 GST_TYPE_VIDEO_SINK, gst_eglglessink_init_interfaces);
400 /* Custom Buffer Funcs */
401 /* XXX: Drafted implementation */
403 gst_eglglesbuffer_create_native (EGLNativeWindowType win,
404 EGLConfig config, EGLNativeDisplayType display, const EGLint * egl_attribs)
406 EGLNativePixmapType pix = 0;
407 EGLSurface pix_surface;
408 EGLint *buffer = NULL;
410 /* XXX: Need to figure out how to create an egl_native_pixmap_t to
411 * feed to eglCreatePixmapSurface. An option on android: create an
412 * android_native_buffer_t to pass straight to eglCreateImageKHR.
415 pix_surface = eglCreatePixmapSurface (display, config, pix, egl_attribs);
417 if (pix_surface == EGL_NO_SURFACE) {
418 show_egl_error ("eglCreatePixmapSurface");
419 GST_CAT_ERROR (GST_CAT_DEFAULT, "Unable to create pixmap surface");
423 if (my_eglLockSurfaceKHR (display, pix_surface, lock_attribs) == EGL_FALSE) {
424 show_egl_error ("eglLockSurfaceKHR");
425 GST_CAT_ERROR (GST_CAT_DEFAULT, "Unable to lock surface");
429 if (eglQuerySurface (display, pix_surface, EGL_BITMAP_POINTER_KHR, buffer)
431 show_egl_error ("eglQuerySurface");
432 GST_CAT_ERROR (GST_CAT_DEFAULT,
433 "Unable to query surface for bitmap pointer");
434 goto EGL_ERROR_LOCKED;
440 my_eglUnlockSurfaceKHR (display, pix_surface);
442 GST_CAT_ERROR (GST_CAT_DEFAULT, "EGL call returned error %x", eglGetError ());
443 if (!eglDestroySurface (display, pix_surface)) {
444 show_egl_error ("eglDestroySurface");
445 GST_CAT_ERROR (GST_CAT_DEFAULT, "Couldn't destroy surface");
450 static GstEglGlesBuffer *
451 gst_eglglesbuffer_new (GstEglGlesSink * eglglessink, GstCaps * caps)
453 GstEglGlesBuffer *eglglesbuffer = NULL;
454 GstStructure *structure = NULL;
455 GstEglGlesImageFmt *format;
457 g_return_val_if_fail (GST_IS_EGLGLESSINK (eglglessink), NULL);
458 g_return_val_if_fail (caps, NULL);
461 (GstEglGlesBuffer *) gst_mini_object_new (GST_TYPE_EGLGLESBUFFER);
462 GST_DEBUG_OBJECT (eglglesbuffer, "Creating new GstEglGlesBuffer");
464 structure = gst_caps_get_structure (caps, 0);
466 if (!gst_structure_get_int (structure, "width", &eglglesbuffer->width) ||
467 !gst_structure_get_int (structure, "height", &eglglesbuffer->height)) {
468 GST_WARNING ("Failed getting geometry from caps %" GST_PTR_FORMAT, caps);
471 GST_LOG_OBJECT (eglglessink, "creating %dx%d", eglglesbuffer->width,
472 eglglesbuffer->height);
474 format = gst_eglglessink_get_compat_format_from_caps (eglglessink, caps);
477 GST_WARNING_OBJECT (eglglessink,
478 "Failed to get format from caps %" GST_PTR_FORMAT, caps);
479 GST_ERROR_OBJECT (eglglessink,
480 "Invalid input caps. Failed to create %dx%d buffer",
481 eglglesbuffer->width, eglglesbuffer->height);
485 eglglesbuffer->format = format->fmt;
486 eglglesbuffer->eglglessink = gst_object_ref (eglglessink);
488 eglglesbuffer->image = gst_eglglesbuffer_create_native
489 (eglglessink->window, eglglessink->config, eglglessink->display, NULL);
490 if (!eglglesbuffer->image) {
491 GST_ERROR_OBJECT (eglglessink,
492 "Failed to create native %dx%d image buffer", eglglesbuffer->width,
493 eglglesbuffer->height);
497 GST_BUFFER_DATA (eglglesbuffer) = (guchar *) eglglesbuffer->image;
498 GST_BUFFER_SIZE (eglglesbuffer) = eglglesbuffer->size;
500 return eglglesbuffer;
503 gst_eglglesbuffer_free (eglglesbuffer);
504 eglglesbuffer = NULL;
509 gst_eglglesbuffer_destroy (GstEglGlesBuffer * eglglesbuffer)
512 GstEglGlesSink *eglglessink;
514 GST_DEBUG_OBJECT (eglglesbuffer, "Destroying buffer");
516 eglglessink = eglglesbuffer->eglglessink;
517 if (G_UNLIKELY (eglglessink == NULL))
520 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
522 GST_OBJECT_LOCK (eglglessink);
523 GST_DEBUG_OBJECT (eglglessink, "Destroying image");
525 if (eglglesbuffer->image) {
526 if (GST_BUFFER_DATA (eglglesbuffer)) {
527 g_free (GST_BUFFER_DATA (eglglesbuffer));
529 eglglesbuffer->image = NULL;
530 /* XXX: Unallocate EGL/GL especific resources asociated with this
535 GST_OBJECT_UNLOCK (eglglessink);
536 eglglesbuffer->eglglessink = NULL;
537 gst_object_unref (eglglessink);
539 GST_MINI_OBJECT_CLASS (gsteglglessink_buffer_parent_class)->finalize
540 (GST_MINI_OBJECT (eglglesbuffer));
545 GST_WARNING ("No sink found");
549 /* XXX: Missing implementation.
550 * This function will have the code for maintaing the pool. readding or
551 * destroying the buffers on size or runing/status change. Right now all
552 * it does is to call _destroy.
553 * for a proper implementation take a look at xvimagesink's image buffer
557 gst_eglglesbuffer_finalize (GstEglGlesBuffer * eglglesbuffer)
559 GstEglGlesSink *eglglessink;
561 eglglessink = eglglesbuffer->eglglessink;
562 if (G_UNLIKELY (eglglessink == NULL))
565 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
567 gst_eglglesbuffer_destroy (eglglesbuffer);
572 GST_WARNING ("No sink found");
577 gst_eglglesbuffer_free (GstEglGlesBuffer * eglglesbuffer)
579 /* Make sure it is not recycled. This is meaningless without
580 * a pool but was left here as a reference
582 eglglesbuffer->width = -1;
583 eglglesbuffer->height = -1;
584 gst_buffer_unref (GST_BUFFER (eglglesbuffer));
588 gst_eglglesbuffer_init (GstEglGlesBuffer * eglglesbuffer, gpointer g_class)
590 eglglesbuffer->width = 0;
591 eglglesbuffer->height = 0;
592 eglglesbuffer->size = 0;
593 eglglesbuffer->image = NULL;
594 eglglesbuffer->format = GST_EGLGLESSINK_IMAGE_NOFMT;
598 gst_eglglesbuffer_class_init (gpointer g_class, gpointer class_data)
600 GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
602 gsteglglessink_buffer_parent_class = g_type_class_peek_parent (g_class);
604 mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
605 gst_eglglesbuffer_finalize;
609 gst_eglglesbuffer_get_type (void)
611 static GType _gst_eglglessink_buffer_type;
613 if (G_UNLIKELY (_gst_eglglessink_buffer_type == 0)) {
614 static const GTypeInfo eglglessink_buffer_info = {
615 sizeof (GstBufferClass),
618 gst_eglglesbuffer_class_init,
621 sizeof (GstEglGlesBuffer),
623 (GInstanceInitFunc) gst_eglglesbuffer_init,
626 _gst_eglglessink_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
627 "GstEglGlesBuffer", &eglglessink_buffer_info, 0);
629 return _gst_eglglessink_buffer_type;
632 static GstEglGlesImageFmt *
633 gst_eglglessink_get_compat_format_from_caps (GstEglGlesSink * eglglessink,
638 GstEglGlesImageFmt *format;
640 g_return_val_if_fail (GST_IS_EGLGLESSINK (eglglessink), 0);
642 list = eglglessink->supported_fmts;
644 /* Traverse the list trying to find a compatible format */
647 GST_DEBUG_OBJECT (eglglessink, "Checking compatibility between listed %"
648 GST_PTR_FORMAT " and %" GST_PTR_FORMAT, format->caps, caps);
650 if (gst_caps_can_intersect (caps, format->caps)) {
651 GST_INFO_OBJECT (eglglessink, "Found compatible format %d",
653 GST_DEBUG_OBJECT (eglglessink,
654 "Got caps %" GST_PTR_FORMAT " and this format can do %"
655 GST_PTR_FORMAT, caps, format->caps);
659 list = g_list_next (list);
666 gst_eglglessink_different_size_suggestion (GstEglGlesSink * eglglessink,
669 GstCaps *intersection;
673 gint par_n = 1, par_d = 1;
677 new_caps = gst_caps_copy (caps);
679 s = gst_caps_get_structure (new_caps, 0);
681 gst_structure_get_int (s, "width", &width);
682 gst_structure_get_int (s, "height", &height);
683 gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
685 gst_structure_remove_field (s, "width");
686 gst_structure_remove_field (s, "height");
687 gst_structure_remove_field (s, "pixel-aspect-ratio");
689 intersection = gst_caps_intersect (eglglessink->current_caps, new_caps);
690 gst_caps_unref (new_caps);
692 if (gst_caps_is_empty (intersection))
695 s = gst_caps_get_structure (intersection, 0);
697 gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
699 /* XXX: xvimagesink supports all PARs not sure about our eglglessink
700 * though, need to review this afterwards.
703 gst_structure_fixate_field_nearest_int (s, "width", width);
704 gst_structure_fixate_field_nearest_int (s, "height", height);
705 gst_structure_get_int (s, "width", &w);
706 gst_structure_get_int (s, "height", &h);
708 gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
709 gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
716 gst_eglglessink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
717 guint size, GstCaps * caps, GstBuffer ** buf)
720 GstEglGlesSink *eglglessink;
721 GstFlowReturn ret = GST_FLOW_OK;
722 GstEglGlesBuffer *eglglesbuffer = NULL;
723 GstCaps *intersection = NULL;
724 GstStructure *structure = NULL;
726 GstEglGlesImageFmt *format;
728 eglglessink = GST_EGLGLESSINK (bsink);
730 /* No custom alloc for the slow rendering path */
731 if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
732 GST_INFO_OBJECT (eglglessink, "No custom alloc for slow rendering path");
737 if (G_UNLIKELY (!caps))
740 if (G_LIKELY (gst_caps_is_equal (caps, eglglessink->current_caps))) {
741 GST_LOG_OBJECT (eglglessink,
742 "Buffer alloc for same last_caps, reusing caps");
743 intersection = gst_caps_ref (caps);
744 width = GST_VIDEO_SINK_WIDTH (eglglessink);
745 height = GST_VIDEO_SINK_HEIGHT (eglglessink);
747 goto REUSE_LAST_CAPS;
750 GST_DEBUG_OBJECT (eglglessink, "Buffer alloc requested size %d with caps %"
751 GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
752 caps, eglglessink->current_caps);
754 /* Check the caps against our current caps */
755 intersection = gst_caps_intersect (eglglessink->current_caps, caps);
757 GST_DEBUG_OBJECT (eglglessink, "Intersection in buffer alloc returned %"
758 GST_PTR_FORMAT, intersection);
760 if (gst_caps_is_empty (intersection)) {
763 gst_caps_unref (intersection);
765 /* So we don't support this kind of buffer, let's define one we'd like */
766 new_caps = gst_caps_copy (caps);
768 structure = gst_caps_get_structure (new_caps, 0);
769 if (!gst_structure_has_field (structure, "width") ||
770 !gst_structure_has_field (structure, "height")) {
771 gst_caps_unref (new_caps);
775 /* Try different dimensions */
777 gst_eglglessink_different_size_suggestion (eglglessink, new_caps);
779 /* YUV not implemented yet */
780 if (gst_caps_is_empty (intersection)) {
782 gst_structure_set_name (structure, "video/x-raw-rgb");
784 /* Remove format specific fields */
785 gst_structure_remove_field (structure, "format");
786 gst_structure_remove_field (structure, "endianness");
787 gst_structure_remove_field (structure, "depth");
788 gst_structure_remove_field (structure, "bpp");
789 gst_structure_remove_field (structure, "red_mask");
790 gst_structure_remove_field (structure, "green_mask");
791 gst_structure_remove_field (structure, "blue_mask");
792 gst_structure_remove_field (structure, "alpha_mask");
794 /* Reuse intersection with current_caps */
795 intersection = gst_caps_intersect (eglglessink->current_caps, new_caps);
798 /* Try with different dimensions and RGB formats */
799 if (gst_caps_is_empty (intersection))
801 gst_eglglessink_different_size_suggestion (eglglessink, new_caps);
803 /* Clean this copy */
804 gst_caps_unref (new_caps);
806 if (gst_caps_is_empty (intersection))
810 /* Ensure the returned caps are fixed */
811 gst_caps_truncate (intersection);
813 GST_DEBUG_OBJECT (eglglessink, "Allocating a buffer with caps %"
814 GST_PTR_FORMAT, intersection);
815 if (gst_caps_is_equal (intersection, caps)) {
816 /* Things work better if we return a buffer with the same caps ptr
817 * as was asked for when we can */
818 gst_caps_replace (&intersection, caps);
821 /* Get image format from caps */
822 format = gst_eglglessink_get_compat_format_from_caps (eglglessink,
826 GST_WARNING_OBJECT (eglglessink, "Can't get a compatible format from caps");
828 /* Get geometry from caps */
829 structure = gst_caps_get_structure (intersection, 0);
830 if (!gst_structure_get_int (structure, "width", &width) ||
831 !gst_structure_get_int (structure, "height", &height) || !format)
836 GST_DEBUG_OBJECT (eglglessink, "Creating eglglesbuffer");
837 eglglesbuffer = gst_eglglesbuffer_new (eglglessink, intersection);
840 /* Make sure the buffer is cleared of any previously used flags */
841 GST_MINI_OBJECT_CAST (eglglesbuffer)->flags = 0;
842 gst_buffer_set_caps (GST_BUFFER_CAST (eglglesbuffer), intersection);
845 *buf = GST_BUFFER_CAST (eglglesbuffer);
849 gst_caps_unref (intersection);
857 GST_DEBUG_OBJECT (eglglessink, "No width/height on caps!?");
858 ret = GST_FLOW_WRONG_STATE;
863 GST_WARNING_OBJECT (eglglessink, "We were requested a buffer with "
864 "caps %" GST_PTR_FORMAT ", but our current caps %" GST_PTR_FORMAT
865 " are completely incompatible!", caps, eglglessink->current_caps);
866 ret = GST_FLOW_NOT_NEGOTIATED;
871 GST_WARNING_OBJECT (eglglessink, "Invalid caps for buffer allocation %"
872 GST_PTR_FORMAT, intersection);
873 ret = GST_FLOW_NOT_NEGOTIATED;
878 GST_WARNING_OBJECT (eglglessink, "Have no caps, doing fallback allocation");
886 gst_eglglessink_fill_supported_fbuffer_configs (GstEglGlesSink * eglglessink)
890 GstEglGlesImageFmt *format;
893 GST_DEBUG_OBJECT (eglglessink,
894 "Building initial list of wanted eglattribs per format");
896 /* Init supported format/caps list */
897 g_mutex_lock (eglglessink->flow_lock);
899 caps = gst_caps_new_empty ();
901 if (eglChooseConfig (eglglessink->display, eglglessink_RGBA8888_attribs,
902 NULL, 1, &cfg_number) != EGL_FALSE) {
903 format = g_new0 (GstEglGlesImageFmt, 1);
904 format->fmt = GST_EGLGLESSINK_IMAGE_RGBA8888;
905 format->attribs = eglglessink_RGBA8888_attribs;
906 format->caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBA);
907 gst_caps_append (format->caps,
908 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRA));
909 gst_caps_append (format->caps,
910 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ARGB));
911 gst_caps_append (format->caps,
912 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_ABGR));
913 gst_caps_append (format->caps,
914 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGBx));
915 gst_caps_append (format->caps,
916 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGRx));
917 gst_caps_append (format->caps,
918 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xRGB));
919 gst_caps_append (format->caps,
920 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_xBGR));
921 gst_caps_append (format->caps,
922 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_AYUV));
923 gst_caps_append (format->caps,
924 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y444));
925 gst_caps_append (format->caps,
926 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_I420));
927 gst_caps_append (format->caps,
928 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YV12));
929 gst_caps_append (format->caps,
930 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV12));
931 gst_caps_append (format->caps,
932 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_NV21));
933 gst_caps_append (format->caps,
934 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_YUY2));
935 gst_caps_append (format->caps,
936 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_UYVY));
937 gst_caps_append (format->caps,
938 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y42B));
939 gst_caps_append (format->caps,
940 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_Y41B));
941 eglglessink->supported_fmts =
942 g_list_append (eglglessink->supported_fmts, format);
944 gst_caps_append (caps, gst_caps_ref (format->caps));
946 GST_INFO_OBJECT (eglglessink,
947 "EGL display doesn't support RGBA8888 config");
950 if (eglChooseConfig (eglglessink->display, eglglessink_RGB888_attribs,
951 NULL, 1, &cfg_number) != EGL_FALSE) {
952 format = g_new0 (GstEglGlesImageFmt, 1);
953 format->fmt = GST_EGLGLESSINK_IMAGE_RGB888;
954 format->attribs = eglglessink_RGB888_attribs;
955 format->caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB);
956 gst_caps_append (format->caps,
957 gst_video_format_new_template_caps (GST_VIDEO_FORMAT_BGR));
958 eglglessink->supported_fmts =
959 g_list_append (eglglessink->supported_fmts, format);
961 gst_caps_append (caps, gst_caps_ref (format->caps));
963 GST_INFO_OBJECT (eglglessink, "EGL display doesn't support RGB888 config");
966 if (eglChooseConfig (eglglessink->display, eglglessink_RGB565_attribs,
967 NULL, 1, &cfg_number) != EGL_FALSE) {
968 format = g_new0 (GstEglGlesImageFmt, 1);
969 format->fmt = GST_EGLGLESSINK_IMAGE_RGB565;
970 format->attribs = eglglessink_RGB565_attribs;
971 format->caps = gst_video_format_new_template_caps (GST_VIDEO_FORMAT_RGB16);
972 eglglessink->supported_fmts =
973 g_list_append (eglglessink->supported_fmts, format);
975 gst_caps_append (caps, gst_caps_ref (format->caps));
977 GST_INFO_OBJECT (eglglessink, "EGL display doesn't support RGB565 config");
980 gst_caps_replace (&eglglessink->sinkcaps, caps);
981 gst_caps_unref (caps);
983 g_mutex_unlock (eglglessink->flow_lock);
988 static inline gboolean
989 egl_init (GstEglGlesSink * eglglessink)
991 if (!platform_wrapper_init ()) {
992 GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL platform wrapper");
996 if (!gst_eglglessink_init_egl_display (eglglessink)) {
997 GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL display");
1001 gst_eglglessink_init_egl_exts (eglglessink);
1003 if (!gst_eglglessink_fill_supported_fbuffer_configs (eglglessink)) {
1004 GST_ERROR_OBJECT (eglglessink, "Display support NONE of our configs");
1008 g_mutex_lock (eglglessink->flow_lock);
1009 eglglessink->egl_started = TRUE;
1010 g_mutex_unlock (eglglessink->flow_lock);
1015 GST_ERROR_OBJECT (eglglessink, "Failed to perform EGL init");
1020 gst_eglglessink_start (GstBaseSink * sink)
1022 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (sink);
1024 if (!eglglessink->egl_started) {
1025 GST_ERROR_OBJECT (eglglessink, "EGL uninitialized. Bailing out");
1029 /* Ask for a window to render to */
1030 if (!eglglessink->have_window)
1031 gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (eglglessink));
1033 if (!eglglessink->have_window && !eglglessink->can_create_window) {
1034 GST_ERROR_OBJECT (eglglessink, "Window handle unavailable and we "
1035 "were instructed not to create an internal one. Bailing out.");
1042 GST_ERROR_OBJECT (eglglessink, "Couldn't start");
1048 gst_eglglessink_stop (GstBaseSink * sink)
1050 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (sink);
1052 /* EGL/GLES2 cleanup */
1054 if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
1055 glDeleteBuffers (1, &eglglessink->vdata);
1056 glDeleteBuffers (1, &eglglessink->tdata);
1057 glDeleteBuffers (1, &eglglessink->idata);
1058 eglglessink->have_vbo = FALSE;
1060 glDeleteShader (eglglessink->fragshader);
1061 glDeleteShader (eglglessink->vertshader);
1063 glDeleteTextures (eglglessink->n_textures, eglglessink->texture);
1064 eglglessink->have_texture = FALSE;
1065 eglglessink->n_textures = 0;
1067 glDeleteProgram (eglglessink->program);
1070 if (eglglessink->surface) {
1071 eglDestroySurface (eglglessink->display, eglglessink->surface);
1072 eglglessink->surface = NULL;
1073 eglglessink->have_surface = FALSE;
1076 if (eglglessink->context) {
1077 eglDestroyContext (eglglessink->display, eglglessink->context);
1078 eglglessink->context = NULL;
1081 if (eglglessink->using_own_window) {
1082 platform_destroy_native_window (eglglessink->display, eglglessink->window);
1083 eglglessink->window = NULL;
1084 eglglessink->have_window = FALSE;
1087 if (eglglessink->current_caps) {
1088 gst_caps_unref (eglglessink->current_caps);
1089 eglglessink->current_caps = NULL;
1096 gst_eglglessink_xoverlay_init (GstXOverlayClass * iface)
1098 iface->set_window_handle = gst_eglglessink_set_window_handle;
1099 iface->expose = gst_eglglessink_expose;
1100 iface->set_render_rectangle = gst_eglglessink_set_render_rectangle;
1104 gst_eglglessink_interface_supported (GstImplementsInterface * iface, GType type)
1106 return (type == GST_TYPE_X_OVERLAY);
1110 gst_eglglessink_implements_init (GstImplementsInterfaceClass * klass)
1112 klass->supported = gst_eglglessink_interface_supported;
1115 static inline gboolean
1116 got_gl_error (const char *wtf)
1118 GLuint error = GL_NO_ERROR;
1120 if ((error = glGetError ()) != GL_NO_ERROR) {
1121 GST_CAT_ERROR (GST_CAT_DEFAULT, "GL ERROR: %s returned %x", wtf, error);
1128 show_egl_error (const char *wtf)
1132 if ((error = eglGetError ()) != EGL_SUCCESS)
1133 GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned %x", wtf, error);
1136 static EGLNativeWindowType
1137 gst_eglglessink_create_window (GstEglGlesSink * eglglessink, gint width,
1140 EGLNativeWindowType window = 0;
1142 if (!eglglessink->can_create_window) {
1143 GST_ERROR_OBJECT (eglglessink, "This sink can't create a window by itself");
1146 GST_INFO_OBJECT (eglglessink, "Attempting internal window creation");
1148 if (!width && !height) { /* Create a default size window */
1149 width = eglglessink->window_default_width;
1150 height = eglglessink->window_default_height;
1153 window = platform_create_native_window (width, height);
1155 GST_ERROR_OBJECT (eglglessink, "Could not create window");
1158 gst_x_overlay_got_window_handle (GST_X_OVERLAY (eglglessink),
1163 /* XXX: Should implement (redisplay)
1164 * We need at least the last buffer stored for this to work
1167 gst_eglglessink_expose (GstXOverlay * overlay)
1169 GstEglGlesSink *eglglessink;
1172 eglglessink = GST_EGLGLESSINK (overlay);
1173 GST_DEBUG_OBJECT (eglglessink, "Expose catched, redisplay");
1175 /* Logic would be to get _render_and_display() to use
1176 * last seen buffer to render from when NULL it's
1178 GST_WARNING_OBJECT (eglglessink, "_expose() not implemented");
1179 ret = gst_eglglessink_render_and_display (eglglessink, NULL);
1180 if (ret == GST_FLOW_ERROR)
1181 GST_ERROR_OBJECT (eglglessink, "Redisplay failed");
1184 /* Checks available egl/gles extensions and chooses
1185 * a suitable rendering path from GstEglGlesSinkRenderingPath
1186 * accordingly. This function can only be called after an
1187 * EGL context has been made current.
1190 gst_eglglessink_init_egl_exts (GstEglGlesSink * eglglessink)
1192 const char *eglexts;
1193 unsigned const char *glexts;
1195 eglexts = eglQueryString (eglglessink->display, EGL_EXTENSIONS);
1196 glexts = glGetString (GL_EXTENSIONS);
1198 GST_DEBUG_OBJECT (eglglessink, "Available EGL extensions: %s\n", eglexts);
1199 GST_DEBUG_OBJECT (eglglessink, "Available GLES extensions: %s\n", glexts);
1201 #ifdef EGL_FAST_RENDERING_POSSIBLE
1202 /* OK Fast rendering should be possible from the declared
1203 * extensions on the eglexts/glexts.h headers
1206 /* Check for support from claimed EGL/GLES extensions */
1208 if (!strstr (eglexts, "EGL_KHR_image"))
1210 if (!strstr (eglexts, "EGL_KHR_lock_surface"))
1211 goto SURFACE_LOCK_NA;
1212 if (!strstr ((char *) glexts, "GL_OES_EGL_image"))
1213 goto TEXTURE_2DOES_NA;
1215 /* Check for actual extension proc addresses */
1217 my_eglCreateImageKHR =
1218 (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress ("eglCreateImageKHR");
1219 my_eglDestroyImageKHR =
1220 (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR");
1222 if (!my_eglCreateImageKHR || !my_eglDestroyImageKHR) {
1224 GST_INFO_OBJECT (eglglessink, "Extension missing: EGL_KHR_image");
1228 my_eglLockSurfaceKHR =
1229 (PFNEGLLOCKSURFACEKHRPROC) eglGetProcAddress ("eglLockSurfaceKHR");
1230 my_eglUnlockSurfaceKHR =
1231 (PFNEGLUNLOCKSURFACEKHRPROC) eglGetProcAddress ("eglUnlockSurfaceKHR");
1233 if (!my_eglLockSurfaceKHR || !my_eglUnlockSurfaceKHR) {
1235 GST_INFO_OBJECT (eglglessink, "Extension missing: EGL_KHR_lock_surface");
1239 my_glEGLImageTargetTexture2DOES =
1240 (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress
1241 ("glEGLImageTargetTexture2DOES");
1243 if (!my_glEGLImageTargetTexture2DOES) {
1245 GST_INFO_OBJECT (eglglessink, "Extension missing: GL_OES_EGL_image");
1249 if (!eglglessink->force_rendering_slow) {
1250 GST_INFO_OBJECT (eglglessink,
1251 "Have needed extensions for fast rendering path");
1253 GST_WARNING_OBJECT (eglglessink,
1254 "Extension check passed but slow rendering path being forced");
1255 goto SLOW_PATH_SELECTED;
1258 /* Extension check passed. Enable fast rendering path */
1259 eglglessink->rendering_path = GST_EGLGLESSINK_RENDER_FAST;
1260 GST_INFO_OBJECT (eglglessink, "Using fast rendering path");
1265 GST_WARNING_OBJECT (eglglessink,
1266 "Extensions missing. Can't use fast rendering path");
1268 eglglessink->rendering_path = GST_EGLGLESSINK_RENDER_SLOW;
1269 GST_INFO_OBJECT (eglglessink, "Using slow rendering path");
1274 gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink, gboolean reset)
1277 g_mutex_lock (eglglessink->flow_lock);
1279 GST_INFO_OBJECT (eglglessink, "VBO setup. have_vbo:%d, should reset %d",
1280 eglglessink->have_vbo, reset);
1282 if (eglglessink->have_vbo && reset) {
1283 glDeleteBuffers (1, &eglglessink->vdata);
1284 glDeleteBuffers (1, &eglglessink->tdata);
1285 glDeleteBuffers (1, &eglglessink->idata);
1286 eglglessink->have_vbo = FALSE;
1289 if (!eglglessink->have_vbo) {
1290 GST_DEBUG_OBJECT (eglglessink, "Performing VBO setup");
1291 eglglessink->coordarray[0].x = 1;
1292 eglglessink->coordarray[0].y = 1;
1293 eglglessink->coordarray[0].z = 0;
1295 eglglessink->coordarray[1].x = 1;
1296 eglglessink->coordarray[1].y = -1;
1297 eglglessink->coordarray[1].z = 0;
1299 eglglessink->coordarray[2].x = -1;
1300 eglglessink->coordarray[2].y = 1;
1301 eglglessink->coordarray[2].z = 0;
1303 eglglessink->coordarray[3].x = -1;
1304 eglglessink->coordarray[3].y = -1;
1305 eglglessink->coordarray[3].z = 0;
1307 eglglessink->texarray[0].x = 1;
1308 eglglessink->texarray[0].y = 0;
1310 eglglessink->texarray[1].x = 1;
1311 eglglessink->texarray[1].y = 1;
1313 eglglessink->texarray[2].x = 0;
1314 eglglessink->texarray[2].y = 0;
1316 eglglessink->texarray[3].x = 0;
1317 eglglessink->texarray[3].y = 1;
1319 eglglessink->indexarray[0] = 0;
1320 eglglessink->indexarray[1] = 1;
1321 eglglessink->indexarray[2] = 2;
1322 eglglessink->indexarray[3] = 3;
1324 glGenBuffers (1, &eglglessink->vdata);
1325 glGenBuffers (1, &eglglessink->tdata);
1326 glGenBuffers (1, &eglglessink->idata);
1327 if (got_gl_error ("glGenBuffers"))
1328 goto HANDLE_ERROR_LOCKED;
1330 glBindBuffer (GL_ARRAY_BUFFER, eglglessink->vdata);
1331 if (got_gl_error ("glBindBuffer vdata"))
1332 goto HANDLE_ERROR_LOCKED;
1334 glBufferData (GL_ARRAY_BUFFER, sizeof (eglglessink->coordarray),
1335 eglglessink->coordarray, GL_STATIC_DRAW);
1336 if (got_gl_error ("glBufferData vdata"))
1337 goto HANDLE_ERROR_LOCKED;
1339 glVertexAttribPointer (eglglessink->coord_pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
1340 if (got_gl_error ("glVertexAttribPointer"))
1341 goto HANDLE_ERROR_LOCKED;
1343 glEnableVertexAttribArray (eglglessink->coord_pos);
1344 if (got_gl_error ("glEnableVertexAttribArray"))
1345 goto HANDLE_ERROR_LOCKED;
1347 glBindBuffer (GL_ARRAY_BUFFER, eglglessink->tdata);
1348 if (got_gl_error ("glBindBuffer tdata"))
1349 goto HANDLE_ERROR_LOCKED;
1351 glBufferData (GL_ARRAY_BUFFER, sizeof (eglglessink->texarray),
1352 eglglessink->texarray, GL_STATIC_DRAW);
1353 if (got_gl_error ("glBufferData tdata"))
1354 goto HANDLE_ERROR_LOCKED;
1356 glVertexAttribPointer (eglglessink->tex_pos, 2, GL_FLOAT, GL_FALSE, 0, 0);
1357 if (got_gl_error ("glVertexAttribPointer"))
1358 goto HANDLE_ERROR_LOCKED;
1360 glEnableVertexAttribArray (eglglessink->tex_pos);
1361 if (got_gl_error ("glEnableVertexAttribArray"))
1362 goto HANDLE_ERROR_LOCKED;
1364 glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, eglglessink->idata);
1365 if (got_gl_error ("glBindBuffer idata"))
1366 goto HANDLE_ERROR_LOCKED;
1368 glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (eglglessink->indexarray),
1369 eglglessink->indexarray, GL_STATIC_DRAW);
1370 if (got_gl_error ("glBufferData idata"))
1371 goto HANDLE_ERROR_LOCKED;
1373 eglglessink->have_vbo = TRUE;
1375 GST_INFO_OBJECT (eglglessink, "Won't perform VBO setup");
1378 g_mutex_unlock (eglglessink->flow_lock);
1381 HANDLE_ERROR_LOCKED:
1382 g_mutex_unlock (eglglessink->flow_lock);
1383 GST_ERROR_OBJECT (eglglessink, "Unable to perform VBO setup");
1388 gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
1393 const gchar *texnames[3] = { NULL, };
1394 gchar *tmp_prog = NULL;
1396 GST_DEBUG_OBJECT (eglglessink, "Enter EGL surface setup");
1398 g_mutex_lock (eglglessink->flow_lock);
1400 eglglessink->surface = eglCreateWindowSurface (eglglessink->display,
1401 eglglessink->config, eglglessink->window, NULL);
1403 if (eglglessink->surface == EGL_NO_SURFACE) {
1404 show_egl_error ("eglCreateWindowSurface");
1405 GST_ERROR_OBJECT (eglglessink, "Can't create surface");
1406 goto HANDLE_EGL_ERROR_LOCKED;
1409 if (!eglMakeCurrent (eglglessink->display, eglglessink->surface,
1410 eglglessink->surface, eglglessink->context)) {
1411 show_egl_error ("eglCreateWindowSurface");
1412 GST_ERROR_OBJECT (eglglessink, "Couldn't bind surface/context");
1413 goto HANDLE_EGL_ERROR_LOCKED;
1416 /* Save surface dims */
1417 eglQuerySurface (eglglessink->display, eglglessink->surface, EGL_WIDTH,
1418 &eglglessink->surface_width);
1419 eglQuerySurface (eglglessink->display, eglglessink->surface, EGL_HEIGHT,
1420 &eglglessink->surface_height);
1422 GST_INFO_OBJECT (eglglessink, "Got surface of %dx%d pixels",
1423 eglglessink->surface_width, eglglessink->surface_height);
1425 /* We have a surface! */
1426 eglglessink->have_surface = TRUE;
1427 g_mutex_unlock (eglglessink->flow_lock);
1429 /* Init vertex and fragment progs.
1430 * XXX: Need to be runtime conditional or ifdefed
1433 /* Shader compiler support it's optional byt we
1434 * currently rely on it.
1437 glGetBooleanv (GL_SHADER_COMPILER, &ret);
1438 if (ret == GL_FALSE) {
1439 GST_ERROR_OBJECT (eglglessink, "Shader compiler support is unavailable!");
1443 eglglessink->vertshader = glCreateShader (GL_VERTEX_SHADER);
1444 GST_DEBUG_OBJECT (eglglessink, "Sending %s to handle %d", vert_COPY_prog,
1445 eglglessink->vertshader);
1446 glShaderSource (eglglessink->vertshader, 1, &vert_COPY_prog, NULL);
1447 if (got_gl_error ("glShaderSource vertex"))
1450 glCompileShader (eglglessink->vertshader);
1451 if (got_gl_error ("glCompileShader vertex"))
1454 glGetShaderiv (eglglessink->vertshader, GL_COMPILE_STATUS, &test);
1455 if (test != GL_FALSE)
1456 GST_DEBUG_OBJECT (eglglessink, "Successfully compiled vertex shader");
1458 GST_ERROR_OBJECT (eglglessink, "Couldn't compile vertex shader");
1459 glGetShaderiv (eglglessink->vertshader, GL_INFO_LOG_LENGTH, &test);
1460 info_log = g_new0 (GLchar, test);
1461 glGetShaderInfoLog (eglglessink->vertshader, test, NULL, info_log);
1462 GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
1467 eglglessink->fragshader = glCreateShader (GL_FRAGMENT_SHADER);
1468 switch (eglglessink->format) {
1469 case GST_VIDEO_FORMAT_AYUV:
1470 glShaderSource (eglglessink->fragshader, 1, &frag_AYUV_prog, NULL);
1471 eglglessink->n_textures = 1;
1472 texnames[0] = "tex";
1474 case GST_VIDEO_FORMAT_Y444:
1475 case GST_VIDEO_FORMAT_I420:
1476 case GST_VIDEO_FORMAT_YV12:
1477 case GST_VIDEO_FORMAT_Y42B:
1478 case GST_VIDEO_FORMAT_Y41B:
1479 glShaderSource (eglglessink->fragshader, 1, &frag_PLANAR_YUV_prog, NULL);
1480 eglglessink->n_textures = 3;
1481 texnames[0] = "Ytex";
1482 texnames[1] = "Utex";
1483 texnames[2] = "Vtex";
1485 case GST_VIDEO_FORMAT_YUY2:
1486 tmp_prog = g_strdup_printf (frag_YUY2_UYVY_prog, 'r', 'g', 'a');
1487 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1489 eglglessink->n_textures = 2;
1490 texnames[0] = "Ytex";
1491 texnames[1] = "UVtex";
1493 case GST_VIDEO_FORMAT_UYVY:
1494 tmp_prog = g_strdup_printf (frag_YUY2_UYVY_prog, 'a', 'r', 'b');
1495 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1497 eglglessink->n_textures = 2;
1498 texnames[0] = "Ytex";
1499 texnames[1] = "UVtex";
1501 case GST_VIDEO_FORMAT_NV12:
1502 tmp_prog = g_strdup_printf (frag_NV12_NV21_prog, 'r', 'a');
1503 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1505 eglglessink->n_textures = 2;
1506 texnames[0] = "Ytex";
1507 texnames[1] = "UVtex";
1509 case GST_VIDEO_FORMAT_NV21:
1510 tmp_prog = g_strdup_printf (frag_NV12_NV21_prog, 'a', 'r');
1511 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1513 eglglessink->n_textures = 2;
1514 texnames[0] = "Ytex";
1515 texnames[1] = "UVtex";
1517 case GST_VIDEO_FORMAT_BGR:
1518 case GST_VIDEO_FORMAT_BGRx:
1519 case GST_VIDEO_FORMAT_BGRA:
1520 tmp_prog = g_strdup_printf (frag_REORDER_prog, 'b', 'g', 'r');
1521 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1523 eglglessink->n_textures = 1;
1524 texnames[0] = "tex";
1526 case GST_VIDEO_FORMAT_xRGB:
1527 case GST_VIDEO_FORMAT_ARGB:
1528 tmp_prog = g_strdup_printf (frag_REORDER_prog, 'g', 'b', 'a');
1529 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1531 eglglessink->n_textures = 1;
1532 texnames[0] = "tex";
1534 case GST_VIDEO_FORMAT_xBGR:
1535 case GST_VIDEO_FORMAT_ABGR:
1536 tmp_prog = g_strdup_printf (frag_REORDER_prog, 'a', 'b', 'g');
1537 glShaderSource (eglglessink->fragshader, 1, (const GLchar **) &tmp_prog,
1539 eglglessink->n_textures = 1;
1540 texnames[0] = "tex";
1542 case GST_VIDEO_FORMAT_RGB:
1543 case GST_VIDEO_FORMAT_RGBx:
1544 case GST_VIDEO_FORMAT_RGBA:
1545 case GST_VIDEO_FORMAT_RGB16:
1546 glShaderSource (eglglessink->fragshader, 1, &frag_COPY_prog, NULL);
1547 eglglessink->n_textures = 1;
1548 texnames[0] = "tex";
1551 g_assert_not_reached ();
1555 if (got_gl_error ("glShaderSource fragment"))
1558 glCompileShader (eglglessink->fragshader);
1559 if (got_gl_error ("glCompileShader fragment"))
1562 glGetShaderiv (eglglessink->fragshader, GL_COMPILE_STATUS, &test);
1563 if (test != GL_FALSE)
1564 GST_DEBUG_OBJECT (eglglessink, "Successfully compiled fragment shader");
1566 GST_ERROR_OBJECT (eglglessink, "Couldn't compile fragment shader");
1567 glGetShaderiv (eglglessink->fragshader, GL_INFO_LOG_LENGTH, &test);
1568 info_log = g_new0 (GLchar, test);
1569 glGetShaderInfoLog (eglglessink->fragshader, test, NULL, info_log);
1570 GST_INFO_OBJECT (eglglessink, "Compilation info log:\n%s", info_log);
1575 eglglessink->program = glCreateProgram ();
1576 if (got_gl_error ("glCreateProgram"))
1578 glAttachShader (eglglessink->program, eglglessink->vertshader);
1579 if (got_gl_error ("glAttachShader vertices"))
1581 glAttachShader (eglglessink->program, eglglessink->fragshader);
1582 if (got_gl_error ("glAttachShader fragments"))
1584 glLinkProgram (eglglessink->program);
1585 glGetProgramiv (eglglessink->program, GL_LINK_STATUS, &test);
1586 if (test != GL_FALSE)
1587 GST_DEBUG_OBJECT (eglglessink, "GLES: Successfully linked program");
1589 GST_ERROR_OBJECT (eglglessink, "Couldn't link program");
1593 glUseProgram (eglglessink->program);
1594 if (got_gl_error ("glUseProgram"))
1597 eglglessink->coord_pos =
1598 glGetAttribLocation (eglglessink->program, "position");
1599 eglglessink->tex_pos = glGetAttribLocation (eglglessink->program, "texpos");
1601 /* Generate and bind texture */
1602 if (!eglglessink->have_texture) {
1605 GST_INFO_OBJECT (eglglessink, "Performing initial texture setup");
1607 g_mutex_lock (eglglessink->flow_lock);
1609 for (i = 0; i < eglglessink->n_textures; i++) {
1611 glActiveTexture (GL_TEXTURE0);
1613 glActiveTexture (GL_TEXTURE1);
1615 glActiveTexture (GL_TEXTURE2);
1617 glGenTextures (1, &eglglessink->texture[i]);
1618 if (got_gl_error ("glGenTextures"))
1619 goto HANDLE_ERROR_LOCKED;
1621 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[i]);
1622 if (got_gl_error ("glBindTexture"))
1623 goto HANDLE_ERROR_LOCKED;
1625 eglglessink->tex_uniform[i] = glGetUniformLocation (eglglessink->program,
1627 glUniform1i (eglglessink->tex_uniform[i], i);
1629 /* Set 2D resizing params */
1630 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1631 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1632 /* The following two calls are for non-POT width/height cases. If these
1633 * are not set the texture image unit returns (R, G, B, A) = black
1634 * on glTexImage2D. For a deeper explanation take a look at
1635 * the OpenGl ES docs for glTexParameter */
1636 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1637 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1638 if (got_gl_error ("glTexParameteri"))
1639 goto HANDLE_ERROR_LOCKED;
1642 eglglessink->have_texture = TRUE;
1643 g_mutex_unlock (eglglessink->flow_lock);
1651 HANDLE_EGL_ERROR_LOCKED:
1652 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1653 HANDLE_ERROR_LOCKED:
1654 g_mutex_unlock (eglglessink->flow_lock);
1656 GST_ERROR_OBJECT (eglglessink, "Couldn't setup EGL surface");
1662 gst_eglglessink_init_egl_display (GstEglGlesSink * eglglessink)
1664 EGLint egl_major, egl_minor;
1666 GST_DEBUG_OBJECT (eglglessink, "Enter EGL initial configuration");
1668 eglglessink->display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
1669 if (eglglessink->display == EGL_NO_DISPLAY) {
1670 GST_ERROR_OBJECT (eglglessink, "Could not get EGL display connection");
1671 goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */
1674 if (!eglInitialize (eglglessink->display, &egl_major, &egl_minor)) {
1675 show_egl_error ("eglInitialize");
1676 GST_ERROR_OBJECT (eglglessink, "Could not init EGL display connection");
1677 goto HANDLE_EGL_ERROR;
1680 /* Check against required EGL version */
1681 if (egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) {
1682 GST_ERROR_OBJECT (eglglessink, "EGL v%d\n needed, but you only have v%d.%d",
1683 GST_EGLGLESSINK_EGL_MIN_VERSION, egl_major, egl_minor);
1687 GST_INFO_OBJECT (eglglessink, "System reports supported EGL version v%d.%d",
1688 egl_major, egl_minor);
1690 eglBindAPI (EGL_OPENGL_ES_API);
1696 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1698 GST_ERROR_OBJECT (eglglessink, "Couldn't setup window/surface from handle");
1703 gst_eglglessink_choose_config (GstEglGlesSink * eglglessink)
1705 EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
1708 if ((eglChooseConfig (eglglessink->display,
1709 eglglessink->selected_fmt->attribs, &eglglessink->config, 1,
1710 &egl_configs)) == EGL_FALSE) {
1711 show_egl_error ("eglChooseConfig");
1712 GST_ERROR_OBJECT (eglglessink, "eglChooseConfig failed");
1713 goto HANDLE_EGL_ERROR;
1716 if (egl_configs < 1) {
1717 GST_ERROR_OBJECT (eglglessink,
1718 "Could not find matching framebuffer config");
1722 eglglessink->context = eglCreateContext (eglglessink->display,
1723 eglglessink->config, EGL_NO_CONTEXT, con_attribs);
1725 if (eglglessink->context == EGL_NO_CONTEXT) {
1726 GST_ERROR_OBJECT (eglglessink, "Error getting context, eglCreateContext");
1727 goto HANDLE_EGL_ERROR;
1730 GST_DEBUG_OBJECT (eglglessink, "EGL Context: %p", eglglessink->context);
1736 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
1738 GST_ERROR_OBJECT (eglglessink, "Couldn't choose an usable config");
1743 gst_eglglessink_set_window_handle (GstXOverlay * overlay, guintptr id)
1745 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
1747 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
1748 GST_DEBUG_OBJECT (eglglessink, "We got a window handle!");
1750 if (eglglessink->have_window) {
1751 GST_WARNING_OBJECT (eglglessink,
1752 "We already have a window. Ignoring request");
1757 GST_ERROR_OBJECT (eglglessink, "Window handle is invalid");
1761 /* OK, we have a new window */
1762 g_mutex_lock (eglglessink->flow_lock);
1763 eglglessink->window = (EGLNativeWindowType) id;
1764 eglglessink->have_window = TRUE;
1765 g_mutex_unlock (eglglessink->flow_lock);
1771 GST_ERROR_OBJECT (eglglessink, "Couldn't setup window/surface from handle");
1777 gst_eglglessink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y,
1778 gint width, gint height)
1780 GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
1782 g_return_if_fail (GST_IS_EGLGLESSINK (eglglessink));
1784 g_mutex_lock (eglglessink->flow_lock);
1786 if (width == -1 && height == -1) {
1787 /* This is the set_defaults condition according to
1788 * the xOverlay interface docs
1790 eglglessink->display_region.w = 0;
1791 eglglessink->display_region.h = 0;
1793 g_mutex_lock (eglglessink->flow_lock);
1794 eglglessink->display_region.x = x;
1795 eglglessink->display_region.y = y;
1796 eglglessink->display_region.w = width;
1797 eglglessink->display_region.h = height;
1800 g_mutex_unlock (eglglessink->flow_lock);
1805 /* Rendering and display */
1806 static GstFlowReturn
1807 gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
1810 GstVideoRectangle frame, surface;
1813 #ifdef EGL_FAST_RENDERING_POSSIBLE
1814 EGLImageKHR img = EGL_NO_IMAGE_KHR;
1815 EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR,
1816 EGL_FALSE, EGL_NONE, EGL_NONE
1821 GST_ERROR_OBJECT (eglglessink, "Null buffer, no past queue implemented");
1825 w = GST_VIDEO_SINK_WIDTH (eglglessink);
1826 h = GST_VIDEO_SINK_HEIGHT (eglglessink);
1828 GST_DEBUG_OBJECT (eglglessink,
1829 "Got good buffer %p. Sink geometry is %dx%d size %d", buf, w, h,
1830 GST_BUFFER_SIZE (buf));
1832 switch (eglglessink->rendering_path) {
1833 #ifdef EGL_FAST_RENDERING_POSSIBLE
1834 case GST_EGLGLESSINK_RENDER_FAST:
1835 /* XXX: Not Fully implemented */
1836 img = my_eglCreateImageKHR (eglglessink->display, EGL_NO_CONTEXT,
1837 EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer) GST_BUFFER_DATA (buf),
1840 if (img == EGL_NO_IMAGE_KHR) {
1841 GST_ERROR_OBJECT (eglglessink, "my_eglCreateImageKHR failed");
1842 goto HANDLE_EGL_ERROR;
1845 my_glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, img);
1849 default: /* case GST_EGLGLESSINK_RENDER_SLOW */
1851 switch (eglglessink->selected_fmt->fmt) {
1852 case GST_EGLGLESSINK_IMAGE_RGB888:
1853 glActiveTexture (GL_TEXTURE0);
1854 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1855 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
1856 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
1858 case GST_EGLGLESSINK_IMAGE_RGB565:
1859 glActiveTexture (GL_TEXTURE0);
1860 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1861 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
1862 GL_UNSIGNED_SHORT_5_6_5, GST_BUFFER_DATA (buf));
1864 case GST_EGLGLESSINK_IMAGE_RGBA8888:
1865 switch (eglglessink->format) {
1866 case GST_VIDEO_FORMAT_RGBA:
1867 case GST_VIDEO_FORMAT_BGRA:
1868 case GST_VIDEO_FORMAT_ARGB:
1869 case GST_VIDEO_FORMAT_ABGR:
1870 case GST_VIDEO_FORMAT_RGBx:
1871 case GST_VIDEO_FORMAT_BGRx:
1872 case GST_VIDEO_FORMAT_xRGB:
1873 case GST_VIDEO_FORMAT_xBGR:
1874 glActiveTexture (GL_TEXTURE0);
1875 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1876 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1877 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
1879 case GST_VIDEO_FORMAT_AYUV:
1880 glActiveTexture (GL_TEXTURE0);
1881 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1882 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
1883 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
1885 case GST_VIDEO_FORMAT_Y444:
1886 case GST_VIDEO_FORMAT_I420:
1887 case GST_VIDEO_FORMAT_YV12:
1888 case GST_VIDEO_FORMAT_Y42B:
1889 case GST_VIDEO_FORMAT_Y41B:{
1890 gint coffset, cw, ch;
1893 gst_video_format_get_component_offset (eglglessink->format, 0,
1895 cw = gst_video_format_get_component_width (eglglessink->format, 0,
1897 ch = gst_video_format_get_component_height (eglglessink->format,
1899 glActiveTexture (GL_TEXTURE0);
1900 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1901 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
1902 cw, ch, 0, GL_LUMINANCE,
1903 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
1905 gst_video_format_get_component_offset (eglglessink->format, 1,
1907 cw = gst_video_format_get_component_width (eglglessink->format, 1,
1909 ch = gst_video_format_get_component_height (eglglessink->format,
1911 glActiveTexture (GL_TEXTURE1);
1912 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[1]);
1913 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
1914 cw, ch, 0, GL_LUMINANCE,
1915 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
1917 gst_video_format_get_component_offset (eglglessink->format, 2,
1919 cw = gst_video_format_get_component_width (eglglessink->format, 2,
1921 ch = gst_video_format_get_component_height (eglglessink->format,
1923 glActiveTexture (GL_TEXTURE2);
1924 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[2]);
1925 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
1926 cw, ch, 0, GL_LUMINANCE,
1927 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
1930 case GST_VIDEO_FORMAT_YUY2:
1931 case GST_VIDEO_FORMAT_UYVY:
1932 glActiveTexture (GL_TEXTURE0);
1933 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1934 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
1935 w, h, 0, GL_LUMINANCE_ALPHA,
1936 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
1937 glActiveTexture (GL_TEXTURE1);
1938 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[1]);
1939 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
1940 GST_ROUND_UP_2 (w) / 2, h, 0, GL_RGBA,
1941 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
1943 case GST_VIDEO_FORMAT_NV12:
1944 case GST_VIDEO_FORMAT_NV21:{
1945 gint coffset, cw, ch;
1948 gst_video_format_get_component_offset (eglglessink->format, 0,
1950 cw = gst_video_format_get_component_width (eglglessink->format, 0,
1952 ch = gst_video_format_get_component_height (eglglessink->format,
1954 glActiveTexture (GL_TEXTURE0);
1955 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[0]);
1956 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
1957 cw, ch, 0, GL_LUMINANCE,
1958 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
1961 gst_video_format_get_component_offset (eglglessink->format,
1962 (eglglessink->format == GST_VIDEO_FORMAT_NV12 ? 1 : 2), w, h);
1963 cw = gst_video_format_get_component_width (eglglessink->format, 1,
1965 ch = gst_video_format_get_component_height (eglglessink->format,
1967 glActiveTexture (GL_TEXTURE1);
1968 glBindTexture (GL_TEXTURE_2D, eglglessink->texture[1]);
1969 glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
1970 cw, ch, 0, GL_LUMINANCE_ALPHA,
1971 GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
1975 g_assert_not_reached ();
1980 if (got_gl_error ("glTexImage2D"))
1983 /* If no one has set a display rectangle on us initialize
1984 * a sane default. According to the docs on the xOverlay
1985 * interface we are supposed to fill the overlay 100%
1987 if (!eglglessink->display_region.w || !eglglessink->display_region.h) {
1988 g_mutex_lock (eglglessink->flow_lock);
1989 if (!eglglessink->keep_aspect_ratio) {
1990 eglglessink->display_region.x = 0;
1991 eglglessink->display_region.y = 0;
1992 eglglessink->display_region.w = eglglessink->surface_width;
1993 eglglessink->display_region.h = eglglessink->surface_height;
1995 /* XXX: Proly consider display pixel aspect ratio too? */
1998 surface.w = eglglessink->surface_width;
1999 surface.h = eglglessink->surface_height;
2000 gst_video_sink_center_rect (frame, surface,
2001 &eglglessink->display_region, TRUE);
2003 g_mutex_unlock (eglglessink->flow_lock);
2004 glViewport (eglglessink->display_region.x,
2005 eglglessink->display_region.y, eglglessink->display_region.w,
2006 eglglessink->display_region.h);
2009 glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
2010 if (got_gl_error ("glDrawElements"))
2013 if ((eglSwapBuffers (eglglessink->display, eglglessink->surface))
2015 show_egl_error ("eglSwapBuffers");
2020 GST_DEBUG_OBJECT (eglglessink, "Succesfully rendered 1 frame");
2024 GST_ERROR_OBJECT (eglglessink, "EGL call returned error %x", eglGetError ());
2026 GST_ERROR_OBJECT (eglglessink, "Rendering disabled for this frame");
2027 return GST_FLOW_ERROR;
2030 static GstFlowReturn
2031 gst_eglglessink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
2033 GstEglGlesSink *eglglessink;
2035 g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
2037 eglglessink = GST_EGLGLESSINK (vsink);
2038 GST_DEBUG_OBJECT (eglglessink, "Got buffer: %p", buf);
2040 if (!eglglessink->have_window) {
2041 GST_ERROR_OBJECT (eglglessink, "I don't have a window to render to");
2042 return GST_FLOW_ERROR;
2045 if (!eglglessink->have_surface) {
2046 GST_ERROR_OBJECT (eglglessink, "I don't have a surface to render to");
2047 return GST_FLOW_ERROR;
2049 #ifndef EGL_ANDROID_image_native_buffer
2050 GST_WARNING_OBJECT (eglglessink, "EGL_ANDROID_image_native_buffer not "
2054 return gst_eglglessink_render_and_display (eglglessink, buf);
2058 gst_eglglessink_getcaps (GstBaseSink * bsink)
2060 GstEglGlesSink *eglglessink;
2061 GstCaps *ret = NULL;
2063 eglglessink = GST_EGLGLESSINK (bsink);
2065 g_mutex_lock (eglglessink->flow_lock);
2066 if (eglglessink->sinkcaps) {
2067 ret = gst_caps_ref (eglglessink->sinkcaps);
2070 gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
2074 g_mutex_unlock (eglglessink->flow_lock);
2080 gst_eglglessink_setcaps (GstBaseSink * bsink, GstCaps * caps)
2082 GstEglGlesSink *eglglessink;
2083 gboolean ret = TRUE;
2085 EGLNativeWindowType window;
2086 GstEglGlesImageFmt *format;
2088 eglglessink = GST_EGLGLESSINK (bsink);
2090 GST_DEBUG_OBJECT (eglglessink,
2091 "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
2092 GST_PTR_FORMAT, eglglessink->current_caps, caps);
2094 if (!(ret = gst_video_format_parse_caps (caps, &eglglessink->format, &width,
2096 GST_ERROR_OBJECT (eglglessink, "Got weird and/or incomplete caps");
2100 format = gst_eglglessink_get_compat_format_from_caps (eglglessink, caps);
2102 GST_ERROR_OBJECT (eglglessink,
2103 "No supported and compatible egl/gles format " "found for given caps");
2106 GST_INFO_OBJECT (eglglessink, "Selected compatible egl/gles format %d",
2109 g_mutex_lock (eglglessink->flow_lock);
2110 eglglessink->selected_fmt = format;
2111 GST_VIDEO_SINK_WIDTH (eglglessink) = width;
2112 GST_VIDEO_SINK_HEIGHT (eglglessink) = height;
2113 g_mutex_unlock (eglglessink->flow_lock);
2115 if (eglglessink->current_caps) {
2116 GST_ERROR_OBJECT (eglglessink, "Caps already set. Won't do it again");
2117 if (gst_caps_can_intersect (caps, eglglessink->current_caps)) {
2118 GST_INFO_OBJECT (eglglessink, "Caps are compatible anyway");
2122 GST_DEBUG_OBJECT (eglglessink, "Caps are not compatible, reconfiguring");
2123 if (eglglessink->rendering_path == GST_EGLGLESSINK_RENDER_SLOW) {
2124 glDeleteBuffers (1, &eglglessink->vdata);
2125 glDeleteBuffers (1, &eglglessink->tdata);
2126 glDeleteBuffers (1, &eglglessink->idata);
2127 eglglessink->have_vbo = FALSE;
2129 glDeleteShader (eglglessink->fragshader);
2130 glDeleteShader (eglglessink->vertshader);
2132 glDeleteTextures (eglglessink->n_textures, eglglessink->texture);
2133 eglglessink->have_texture = FALSE;
2134 eglglessink->n_textures = 0;
2136 glDeleteProgram (eglglessink->program);
2139 if (eglglessink->surface) {
2140 eglDestroySurface (eglglessink->display, eglglessink->surface);
2141 eglglessink->surface = NULL;
2142 eglglessink->have_surface = FALSE;
2145 if (eglglessink->context) {
2146 eglDestroyContext (eglglessink->display, eglglessink->context);
2147 eglglessink->context = NULL;
2150 g_mutex_lock (eglglessink->flow_lock);
2151 gst_caps_unref (eglglessink->current_caps);
2152 eglglessink->current_caps = NULL;
2153 g_mutex_unlock (eglglessink->flow_lock);
2156 if (!gst_eglglessink_choose_config (eglglessink)) {
2157 GST_ERROR_OBJECT (eglglessink, "Couldn't choose EGL config");
2161 g_mutex_lock (eglglessink->flow_lock);
2162 eglglessink->current_caps = gst_caps_ref (caps);
2163 g_mutex_unlock (eglglessink->flow_lock);
2165 /* By now the application should have set a window
2166 * already if it meant to do so
2168 if (!eglglessink->have_window) {
2169 GST_INFO_OBJECT (eglglessink,
2170 "No window. Will attempt internal window creation");
2171 if (!(window = gst_eglglessink_create_window (eglglessink, width, height))) {
2172 GST_ERROR_OBJECT (eglglessink, "Internal window creation failed!");
2175 g_mutex_lock (eglglessink->flow_lock);
2176 eglglessink->using_own_window = TRUE;
2177 g_mutex_unlock (eglglessink->flow_lock);
2178 gst_eglglessink_set_window_handle (GST_X_OVERLAY (eglglessink),
2182 if (!eglglessink->have_surface) {
2183 if (!gst_eglglessink_init_egl_surface (eglglessink)) {
2184 GST_ERROR_OBJECT (eglglessink, "Couldn't init EGL surface from window");
2189 if (!eglglessink->have_vbo) {
2190 if (!gst_eglglessink_setup_vbo (eglglessink, FALSE)) {
2191 GST_ERROR_OBJECT (eglglessink, "VBO setup failed");
2197 GST_INFO_OBJECT (eglglessink, "Setcaps succeed");
2202 GST_ERROR_OBJECT (eglglessink, "Setcaps failed");
2207 gst_eglglessink_wipe_fmt (gpointer data)
2209 GstEglGlesImageFmt *format = data;
2210 gst_caps_unref (format->caps);
2214 static GstStateChangeReturn
2215 gst_eglglessink_change_state (GstElement * element, GstStateChange transition)
2217 GstEglGlesSink *eglglessink;
2218 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2220 eglglessink = GST_EGLGLESSINK (element);
2222 switch (transition) {
2223 case GST_STATE_CHANGE_NULL_TO_READY:
2224 if (!egl_init (eglglessink)) {
2225 ret = GST_STATE_CHANGE_FAILURE;
2233 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2234 if (ret == GST_STATE_CHANGE_FAILURE)
2237 switch (transition) {
2238 case GST_STATE_CHANGE_READY_TO_NULL:
2239 g_mutex_lock (eglglessink->flow_lock);
2240 if (eglglessink->display) {
2241 eglTerminate (eglglessink->display);
2242 eglglessink->display = NULL;
2245 eglglessink->selected_fmt = NULL;
2246 g_list_free_full (eglglessink->supported_fmts, gst_eglglessink_wipe_fmt);
2247 eglglessink->supported_fmts = NULL;
2248 gst_caps_unref (eglglessink->sinkcaps);
2249 eglglessink->sinkcaps = NULL;
2250 eglglessink->egl_started = FALSE;
2251 g_mutex_unlock (eglglessink->flow_lock);
2262 gst_eglglessink_finalize (GObject * object)
2264 GstEglGlesSink *eglglessink;
2266 g_return_if_fail (GST_IS_EGLGLESSINK (object));
2268 eglglessink = GST_EGLGLESSINK (object);
2270 g_mutex_free (eglglessink->flow_lock);
2271 eglglessink->flow_lock = NULL;
2273 G_OBJECT_CLASS (parent_class)->finalize (object);
2277 gst_eglglessink_set_property (GObject * object, guint prop_id,
2278 const GValue * value, GParamSpec * pspec)
2280 GstEglGlesSink *eglglessink;
2282 g_return_if_fail (GST_IS_EGLGLESSINK (object));
2284 eglglessink = GST_EGLGLESSINK (object);
2288 eglglessink->silent = g_value_get_boolean (value);
2290 case PROP_CREATE_WINDOW:
2291 eglglessink->can_create_window = g_value_get_boolean (value);
2293 case PROP_DEFAULT_HEIGHT:
2294 eglglessink->window_default_height = g_value_get_int (value);
2296 case PROP_DEFAULT_WIDTH:
2297 eglglessink->window_default_width = g_value_get_int (value);
2299 case PROP_FORCE_RENDERING_SLOW:
2300 eglglessink->force_rendering_slow = g_value_get_boolean (value);
2302 case PROP_FORCE_ASPECT_RATIO:
2303 eglglessink->keep_aspect_ratio = g_value_get_boolean (value);
2306 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2312 gst_eglglessink_get_property (GObject * object, guint prop_id,
2313 GValue * value, GParamSpec * pspec)
2315 GstEglGlesSink *eglglessink;
2317 g_return_if_fail (GST_IS_EGLGLESSINK (object));
2319 eglglessink = GST_EGLGLESSINK (object);
2323 g_value_set_boolean (value, eglglessink->silent);
2325 case PROP_CREATE_WINDOW:
2326 g_value_set_boolean (value, eglglessink->can_create_window);
2328 case PROP_DEFAULT_HEIGHT:
2329 g_value_set_int (value, eglglessink->window_default_height);
2331 case PROP_DEFAULT_WIDTH:
2332 g_value_set_int (value, eglglessink->window_default_width);
2334 case PROP_FORCE_RENDERING_SLOW:
2335 g_value_set_boolean (value, eglglessink->force_rendering_slow);
2337 case PROP_FORCE_ASPECT_RATIO:
2338 g_value_set_boolean (value, eglglessink->keep_aspect_ratio);
2341 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2347 gst_eglglessink_base_init (gpointer gclass)
2349 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
2351 gst_element_class_set_details_simple (element_class,
2352 "EGL/GLES vout Sink",
2354 "An EGL/GLES Video Output Sink Implementing the XOverlay interface",
2355 "Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>");
2357 gst_element_class_add_pad_template (element_class,
2358 gst_static_pad_template_get (&gst_eglglessink_sink_template_factory));
2361 /* initialize the eglglessink's class */
2363 gst_eglglessink_class_init (GstEglGlesSinkClass * klass)
2365 GObjectClass *gobject_class;
2366 GstElementClass *gstelement_class;
2367 GstBaseSinkClass *gstbasesink_class;
2368 GstVideoSinkClass *gstvideosink_class;
2370 gobject_class = (GObjectClass *) klass;
2371 gstelement_class = (GstElementClass *) klass;
2372 gstbasesink_class = (GstBaseSinkClass *) klass;
2373 gstvideosink_class = (GstVideoSinkClass *) klass;
2375 gobject_class->set_property = gst_eglglessink_set_property;
2376 gobject_class->get_property = gst_eglglessink_get_property;
2377 gobject_class->finalize = gst_eglglessink_finalize;
2379 gstelement_class->change_state = gst_eglglessink_change_state;
2381 gstbasesink_class->start = gst_eglglessink_start;
2382 gstbasesink_class->stop = gst_eglglessink_stop;
2383 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_eglglessink_setcaps);
2384 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_eglglessink_getcaps);
2385 gstbasesink_class->buffer_alloc = GST_DEBUG_FUNCPTR
2386 (gst_eglglessink_buffer_alloc);
2388 gstvideosink_class->show_frame =
2389 GST_DEBUG_FUNCPTR (gst_eglglessink_show_frame);
2391 g_object_class_install_property (gobject_class, PROP_SILENT,
2392 g_param_spec_boolean ("silent", "Silent", "Produce no output",
2393 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2394 g_object_class_install_property (gobject_class, PROP_CREATE_WINDOW,
2395 g_param_spec_boolean ("create-window", "Create Window",
2396 "Attempt to create a window if none is provided",
2397 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2398 g_object_class_install_property (gobject_class, PROP_FORCE_RENDERING_SLOW,
2399 g_param_spec_boolean ("force-rendering-slow", "Force Slow Rendering",
2400 "Force slow rendering path", FALSE,
2401 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2402 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
2403 g_param_spec_boolean ("force-aspect-ratio", "Force Aspect Ratio",
2404 "When enabled, scaling will respect original aspect ratio",
2405 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2406 g_object_class_install_property (gobject_class, PROP_DEFAULT_WIDTH,
2407 g_param_spec_int ("window-default-width", "Default Width",
2408 "Default width for self created windows", 0,
2409 EGLGLESSINK_MAX_FRAME_WIDTH, EGLGLESSINK_MAX_FRAME_WIDTH,
2410 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2411 g_object_class_install_property (gobject_class, PROP_DEFAULT_HEIGHT,
2412 g_param_spec_int ("window-default-height", "Default Height",
2413 "Default height for self created windows", 0,
2414 EGLGLESSINK_MAX_FRAME_HEIGHT, EGLGLESSINK_MAX_FRAME_HEIGHT,
2415 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
2420 gst_eglglessink_init (GstEglGlesSink * eglglessink,
2421 GstEglGlesSinkClass * gclass)
2424 eglglessink->have_window = FALSE;
2425 eglglessink->have_surface = FALSE;
2426 eglglessink->have_vbo = FALSE;
2427 eglglessink->have_texture = FALSE;
2428 eglglessink->egl_started = FALSE;
2429 eglglessink->can_create_window = TRUE;
2430 eglglessink->force_rendering_slow = FALSE;
2431 eglglessink->keep_aspect_ratio = TRUE;
2432 eglglessink->using_own_window = FALSE;
2433 eglglessink->flow_lock = g_mutex_new ();
2436 /* Interface initializations. Used here for initializing the XOverlay
2440 gst_eglglessink_init_interfaces (GType type)
2442 static const GInterfaceInfo implements_info = {
2443 (GInterfaceInitFunc) gst_eglglessink_implements_init, NULL, NULL
2446 static const GInterfaceInfo xoverlay_info = {
2447 (GInterfaceInitFunc) gst_eglglessink_xoverlay_init, NULL, NULL
2450 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
2452 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
2456 /* entry point to initialize the plug-in
2457 * initialize the plug-in itself
2458 * register the element factories and other features
2461 eglglessink_plugin_init (GstPlugin * plugin)
2463 /* debug category for fltering log messages */
2464 GST_DEBUG_CATEGORY_INIT (gst_eglglessink_debug, "eglglessink",
2465 0, "Simple EGL/GLES Sink");
2467 return gst_element_register (plugin, "eglglessink", GST_RANK_PRIMARY,
2468 GST_TYPE_EGLGLESSINK);
2471 /* PACKAGE: this is usually set by autotools depending on some _INIT macro
2472 * in configure.ac and then written into and defined in config.h, but we can
2473 * just set it ourselves here in case someone doesn't use autotools to
2474 * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.
2477 #define PACKAGE "EGL/GLES Sink"
2481 #define VERSION "0.911"
2484 /* gstreamer looks for this structure to register eglglessinks */
2485 GST_PLUGIN_DEFINE2 (GST_VERSION_MAJOR,
2489 eglglessink_plugin_init,
2490 VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")