egl/eglglessink: remove since EGLImage and iOS support have been added in glimagesink

https://bugzilla.gnome.org/show_bug.cgi?id=703343
This commit is contained in:
Julien Isorce 2014-04-15 17:58:34 +01:00
parent d93ed2b870
commit 09116bf10d
20 changed files with 70 additions and 6544 deletions

View file

@ -242,7 +242,7 @@ PKG_CHECK_MODULES(GMODULE_EXPORT, gmodule-export-2.0, HAVE_GMODULE_EXPORT=yes, H
dnl Needed by plugins that use g_module_*() API
PKG_CHECK_MODULES(GMODULE_NO_EXPORT, gmodule-no-export-2.0)
dnl x11 is optional for librfb and eglglessink
dnl x11 is optional for librfb
HAVE_X11=NO
PKG_CHECK_MODULES(X11, x11, HAVE_X11=yes, HAVE_X11=no)
AC_SUBST(X11_LIBS)
@ -458,163 +458,6 @@ else
AG_GST_DISABLE_PLUGIN(dccp)
fi
dnl *** gst-libs/gst/egl ***
AC_ARG_WITH([egl-window-system],
AS_HELP_STRING([--with-egl-window-system],[EGL window system to use (x11, mali-fb, rpi, none)]),
[EGL_WINDOW_SYSTEM="$withval"],
[EGL_WINDOW_SYSTEM="auto"])
if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then
dnl Mali
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
LIBS="$LIBS -lUMP $EGL_LIBS"
CFLAGS="$CFLAGS $EGL_CFLAGS"
AC_CHECK_LIB([Mali], [mali_image_create], [EGL_WINDOW_SYSTEM="mali-fb"], [EGL_WINDOW_SYSTEM="auto"])
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
dnl RPi
if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
LIBS="$LIBS -lvcos -lvchiq_arm"
CFLAGS="$CFLAGS"
AC_CHECK_LIB([bcm_host], [bcm_host_init],
[
LIBS="$LIBS -lbcm_host"
AC_CHECK_HEADER([bcm_host.h], [EGL_WINDOW_SYSTEM="rpi"], [EGL_WINDOW_SYSTEM="auto"])
])
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
fi
if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then
if test x"$HAVE_X11" = x"yes"; then
EGL_WINDOW_SYSTEM="x11"
fi
fi
if test x"$EGL_WINDOW_SYSTEM" = x"auto"; then
EGL_WINDOW_SYSTEM="auto"
fi
fi
case "$EGL_WINDOW_SYSTEM" in
x11|auto)
PKG_CHECK_MODULES(EGL, egl, HAVE_EGL="yes", [
HAVE_EGL="no"
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
AC_CHECK_LIB([EGL], [eglGetProcAddress],
[
AC_CHECK_HEADER([EGL/egl.h],
[
HAVE_EGL="yes"
EGL_LIBS="-lEGL"
EGL_CFLAGS=""
]
)
]
)
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
])
dnl X11 specific part, above is auto and X11
if test x"$HAVE_EGL" = x"yes" -a x"$EGL_WINDOW_SYSTEM" = x"x11"; then
if test x"$HAVE_X11" != x"yes"; then
AC_MSG_ERROR([libX11 not found and is required for EGL X11 window system])
else
AC_DEFINE(USE_EGL_X11, [1], [Use X11 EGL window system])
EGL_CFLAGS="$EGL_CFLAGS $X11_CFLAGS"
EGL_LIBS="$EGL_LIBS $X11_LIBS"
fi
fi
;;
mali-fb)
dnl FIXME: Mali EGL depends on GLESv1 or GLESv2
HAVE_EGL="no"
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
AC_CHECK_HEADER([EGL/fbdev_window.h],
[
LIBS="$LIBS -lUMP"
AC_CHECK_LIB([Mali], [mali_image_create],
[
LIBS="$LIBS -lMali"
AC_CHECK_LIB([GLESv2], [glEnable],
[
AC_CHECK_HEADER([GLES2/gl2.h],
[
AC_CHECK_LIB([EGL], [eglGetProcAddress],
[
AC_CHECK_HEADER([EGL/egl.h],
[
HAVE_EGL="yes"
EGL_LIBS="-lGLESv2 -lEGL -lMali -lUMP"
EGL_CFLAGS=""
AC_DEFINE(USE_EGL_MALI_FB, [1], [Use Mali FB EGL window system])
])
])
])
])
])
])
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
;;
rpi)
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
dnl FIXME: EGL of RPi depends on GLESv1 or GLESv2
dnl FIXME: GLESv2 of RPi depends on EGL... WTF!
LIBS="$LIBS -lvcos -lvchiq_arm"
AC_CHECK_LIB([bcm_host], [bcm_host_init],
[
LIBS="$LIBS -lbcm_host"
AC_CHECK_HEADER(bcm_host.h,
[
LIBS="$LIBS -lGLESv2"
AC_CHECK_LIB([EGL], [eglGetProcAddress],
[
LIBS="$LIBS -lEGL"
AC_CHECK_HEADER([EGL/egl.h],
[
AC_CHECK_LIB([GLESv2], [glEnable],
[
AC_CHECK_HEADER([GLES2/gl2.h],
[
HAVE_EGL="yes"
EGL_LIBS="-lGLESv2 -lEGL -lbcm_host -lvcos -lvchiq_arm"
EGL_CFLAGS=""
AC_DEFINE(USE_EGL_RPI, [1], [Use RPi EGL window system])
])
])
])
])
])
])
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
;;
none|no)
HAVE_EGL="no"
AC_MSG_WARN([No EGL window system specified, will not build gstreamer-egl])
;;
*)
AC_MSG_ERROR([invalid EGL window system specified])
;;
esac
AC_SUBST(EGL_LIBS)
AC_SUBST(EGL_CFLAGS)
AM_CONDITIONAL(HAVE_EGL, test x"$HAVE_EGL" = x"yes")
dnl *** opengl ***
AC_ARG_ENABLE([opengl],
[ --enable-opengl Enable Desktop OpenGL support @<:@default=auto@:>@],
@ -707,10 +550,7 @@ HAVE_GLU=no
HAVE_GNUSTEP_COCOA=no
HAVE_WAYLAND_EGL=no
HAVE_EGL_RPI="no"
if test x"$HAVE_EGL" = x"yes" -a x"$EGL_WINDOW_SYSTEM" = x"rpi"; then
HAVE_EGL_RPI="yes"
fi
HAVE_EGL_RPI=no
case $host in
*-mingw32* )
@ -729,6 +569,70 @@ case $host in
AG_GST_CHECK_LIBHEADER(GLU, GLU, gluSphere,, GL/glu.h)
AG_GST_CHECK_LIBHEADER(GLES2, GLESv2, glTexImage2D,, GLES2/gl2.h)
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
dnl FIXME: Mali EGL depends on GLESv1 or GLESv2
AC_CHECK_HEADER([EGL/fbdev_window.h],
[
LIBS="$LIBS -lUMP"
AC_CHECK_LIB([Mali], [mali_image_create],
[
LIBS="$LIBS -lMali"
AC_CHECK_LIB([GLESv2], [glEnable],
[
AC_CHECK_HEADER([GLES2/gl2.h],
[
AC_CHECK_LIB([EGL], [eglGetProcAddress],
[
AC_CHECK_HEADER([EGL/egl.h],
[
HAVE_EGL=yes
HAVE_GLES2=yes
EGL_LIBS="-lMali -lUMP"
EGL_CFLAGS=""
AC_DEFINE(USE_EGL_MALI_FB, [1], [Use Mali FB EGL platform])
])
])
])
])
])
])
dnl FIXME: EGL of RPi depends on GLESv1 or GLESv2
dnl FIXME: GLESv2 of RPi depends on EGL... WTF!
LIBS="$LIBS -lvcos -lvchiq_arm"
AC_CHECK_LIB([bcm_host], [bcm_host_init],
[
LIBS="$LIBS -lbcm_host"
AC_CHECK_HEADER(bcm_host.h,
[
LIBS="$LIBS -lGLESv2"
AC_CHECK_LIB([EGL], [eglGetProcAddress],
[
LIBS="$LIBS -lEGL"
AC_CHECK_HEADER([EGL/egl.h],
[
AC_CHECK_LIB([GLESv2], [glEnable],
[
AC_CHECK_HEADER([GLES2/gl2.h],
[
HAVE_EGL=yes
HAVE_GLES2=yes
HAVE_EGL_RPI=yes
EGL_LIBS="-lbcm_host -lvcos -lvchiq_arm"
EGL_CFLAGS=""
AC_DEFINE(USE_EGL_RPI, [1], [Use RPi platform])
])
])
])
])
])
])
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
PKG_CHECK_MODULES(WAYLAND_EGL, wayland-client >= 1.0 wayland-cursor >= 1.0 wayland-egl >= 9.0, HAVE_WAYLAND_EGL=yes, HAVE_WAYLAND_EGL=no)
;;
esac
@ -1200,6 +1104,7 @@ if test "x$GL_APIS" = "x" -o "x$GL_PLATFORMS" = "x" -o "x$GL_WINDOWS" = "x"; the
USE_EGL=no
USE_WGL=no
USE_COCOA=no
USE_EGL_MALI=no
USE_EGL_RPI=no
USE_EAGL=no
@ -1232,6 +1137,7 @@ AM_CONDITIONAL(USE_GLX, test "x$USE_GLX" = "xyes")
AM_CONDITIONAL(USE_EGL, test "x$USE_EGL" = "xyes")
AM_CONDITIONAL(USE_WGL, test "x$USE_WGL" = "xyes")
AM_CONDITIONAL(USE_COCOA, test "x$USE_COCOA" = "xyes")
AM_CONDITIONAL(USE_EGL_MALI, test "x$USE_EGL_MALI" = "xyes")
AM_CONDITIONAL(USE_EGL_RPI, test "x$USE_EGL_RPI" = "xyes")
AM_CONDITIONAL(USE_EAGL, test "x$USE_EAGL" = "xyes")
@ -2599,39 +2505,6 @@ AG_GST_CHECK_FEATURE(RSVG, [rsvg decoder], rsvg, [
AC_SUBST(RSVG_LIBS)
])
dnl *** eglgles ***
translit(dnm, m, l) AM_CONDITIONAL(USE_EGLGLES, true)
AG_GST_CHECK_FEATURE(EGLGLES, [eglgles sink], eglgles, [
HAVE_EGLGLES="no"
if test x"$HAVE_EGL" = x"yes"; then
PKG_CHECK_MODULES(EGLGLES, egl glesv2, HAVE_EGLGLES="yes", [
HAVE_EGLGLES="no"
old_LIBS=$LIBS
old_CFLAGS=$CFLAGS
LIBS="$LIBS $EGL_LIBS"
CFLAGS="$CFLAGS $EGL_CFLAGS"
AC_CHECK_LIB([GLESv2], [glEnable],
[
AC_CHECK_HEADER([GLES2/gl2.h],
[
HAVE_EGLGLES="yes"
EGLGLES_LIBS="-lGLESv2"
EGLGLES_CFLAGS=""
])
])
LIBS=$old_LIBS
CFLAGS=$old_CFLAGS
])
elif test x"$HAVE_IOS" = x"yes"; then
HAVE_EGLGLES="yes"
fi
AC_SUBST(EGLGLES_CFLAGS)
AC_SUBST(EGLGLES_LIBS)
])
dnl *** gl ***
translit(dnm, m, l) AM_CONDITIONAL(USE_GL, true)
AG_GST_CHECK_FEATURE(GL, [gl elements], gl, [
@ -3056,8 +2929,6 @@ AM_CONDITIONAL(USE_OPENJPEG, false)
AM_CONDITIONAL(USE_OPENNI2, false)
AM_CONDITIONAL(USE_OPUS, false)
AM_CONDITIONAL(USE_PVR, false)
AM_CONDITIONAL(USE_RSVG, false)
AM_CONDITIONAL(USE_EGLGLES, false)
AM_CONDITIONAL(USE_LIBVISUAL, false)
AM_CONDITIONAL(USE_TIMIDITY, false)
AM_CONDITIONAL(USE_WILDMIDI, false)
@ -3237,7 +3108,6 @@ gst/yadif/Makefile
gst-libs/Makefile
gst-libs/gst/Makefile
gst-libs/gst/basecamerabinsrc/Makefile
gst-libs/gst/egl/Makefile
gst-libs/gst/gl/Makefile
gst-libs/gst/gl/android/Makefile
gst-libs/gst/gl/cocoa/Makefile
@ -3308,7 +3178,6 @@ ext/directfb/Makefile
ext/wayland/Makefile
ext/daala/Makefile
ext/dts/Makefile
ext/eglgles/Makefile
ext/gl/Makefile
ext/faac/Makefile
ext/faad/Makefile
@ -3371,8 +3240,6 @@ pkgconfig/gstreamer-codecparsers.pc
pkgconfig/gstreamer-codecparsers-uninstalled.pc
pkgconfig/gstreamer-insertbin.pc
pkgconfig/gstreamer-insertbin-uninstalled.pc
pkgconfig/gstreamer-egl.pc
pkgconfig/gstreamer-egl-uninstalled.pc
pkgconfig/gstreamer-gl.pc
pkgconfig/gstreamer-gl-uninstalled.pc
pkgconfig/gstreamer-mpegts.pc

View file

@ -72,7 +72,6 @@ EXTRA_HFILES = \
$(top_srcdir)/ext/dc1394/gstdc1394.h \
$(top_srcdir)/ext/directfb/dfbvideosink.h \
$(top_srcdir)/ext/dts/gstdtsdec.h \
$(top_srcdir)/ext/eglgles/gsteglglessink.h \
$(top_srcdir)/ext/faac/gstfaac.h \
$(top_srcdir)/ext/faad/gstfaad.h \
$(top_srcdir)/ext/kate/gstkateenc.h \

View file

@ -76,12 +76,6 @@ else
DTS_DIR=
endif
if USE_EGLGLES
EGLGLES_DIR=eglgles
else
EGLGLES_DIR=
endif
if USE_GL
GL_DIR=gl
else
@ -416,7 +410,6 @@ SUBDIRS=\
$(DAALA_DIR) \
$(DTS_DIR) \
$(RESINDVD_DIR) \
$(EGLGLES_DIR) \
$(GL_DIR) \
$(FAAC_DIR) \
$(FAAD_DIR) \
@ -492,7 +485,6 @@ DIST_SUBDIRS = \
lv2 \
daala \
dts \
eglgles \
gl \
modplug \
mimic \

View file

@ -1,71 +0,0 @@
LOCAL_PATH := $(call my-dir)
# -------------------------------------
# gsteglglessink library
#
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
gsteglglessink_FILES := gsteglglessink.c
LOCAL_SRC_FILES := $(gsteglglessink_FILES)
LOCAL_C_INCLUDES = $(LOCAL_PATH) \
$(LOCAL_PATH)/include
ifneq ($(NDK_BUILD), true)
LOCAL_C_INCLUDES += $(TOP)/frameworks/base
else
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../android_headers
endif
LOCAL_CFLAGS += -DHAVE_CONFIG_H
LOCAL_CFLAGS += -Wall -Wdeclaration-after-statement -g -O2
LOCAL_CFLAGS += -DANDROID_USE_GSTREAMER \
$(shell $(PKG_CONFIG) gstreamer-plugins-bad-0.10 --cflags) \
$(shell $(PKG_CONFIG) gstreamer-audio-0.10 --cflags)
ifeq ($(USE_AUDIO_PURE_CODEC),true)
LOCAL_CFLAGS += -DAUDIO_PURE_CODEC
endif
LOCAL_SHARED_LIBRARIES += libdl
LOCAL_SHARED_LIBRARIES += \
libgstreamer-0.10 \
libgstbase-0.10 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
libgstvideo-0.10 \
libgstinterfaces-0.10
ifneq ($(NDK_BUILD), true)
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib -llog
else
LOCAL_LDFLAGS := -L$(SYSROOT)/usr/lib -llog -lmedia -lutils
endif
LOCAL_LDFLAGS += -lEGL -lGLESv2
LOCAL_SHARED_LIBRARIES += \
libutils \
libcutils \
libui \
libhardware \
libandroid_runtime \
libmedia
LOCAL_MODULE:= libgsteglglessink
LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
#
# define LOCAL_PRELINK_MODULE to false to not use pre-link map
#
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_TAGS := eng debug
include $(BUILD_SHARED_LIBRARY)
#endif # USE_HARDWARE_MM == true

View file

@ -1,39 +0,0 @@
plugin_LTLIBRARIES = libgsteglglessink.la
if HAVE_IOS
DISTRO_SRC = gstegladaptation_eagl.m
else
DISTRO_SRC = gstegladaptation_egl.c video_platform_wrapper.c
GST_EGL_LIBS = $(top_builddir)/gst-libs/gst/egl/libgstegl-$(GST_API_VERSION).la
endif
libgsteglglessink_la_SOURCES = gsteglglessink.c gstegladaptation.c $(DISTRO_SRC)
libgsteglglessink_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS) \
$(EGL_CFLAGS) \
$(EGLGLES_CFLAGS)
libgsteglglessink_la_OBJCFLAGS = $(GST_PLUGINS_BAD_OBJCFLAGS) \
$(GST_PLUGINS_BASE_OBJCFLAGS) \
$(GST_BASE_OBJCFLAGS) \
$(GST_OBJCFLAGS) \
$(EGLGLES_OBJCFLAGS) \
-fobjc-abi-version=2 -fobjc-legacy-dispatch
libgsteglglessink_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \
$(GST_PLUGINS_BASE_LIBS) $(EGL_LIBS) $(EGLGLES_LIBS) \
-lgstvideo-$(GST_API_VERSION) $(GST_EGL_LIBS)
if HAVE_IOS
libgsteglglessink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework,OpenGLES -Wl,-framework,QuartzCore -Wl,-framework,UIKit -Wl,-framework,CoreGraphics -Wl,-framework,CoreFoundation -Wl,-framework,Foundation -W
else
libgsteglglessink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
endif
libgsteglglessink_la_LIBTOOLFLAGS = --tag=CC $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gsteglglessink.h gstegladaptation.h video_platform_wrapper.h
EXTRA_DIST = gsteglglessink.c gstegladaptation.c gstegladaptation_egl.c video_platform_wrapper.c gstegladaptation_eagl.m $(noinst_HEADERS)

View file

@ -1,11 +0,0 @@
- Correctly handle upstream surface region size changes. Test and debug
set_render_rect
- Make sure we are considering DAR on all scaling/rendering cases
- Test and debug caps renegotiation
- Drop android specifics like the default window h/w
- Move EGL/GLES context to it's own struct. Proly move GLSL stuff to it's
own header too
- Optimize shading routines if possible.
- Either finish implementing or drop fast rendering path logic
- Implement buffer pool
- Finish code documentation

View file

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

View file

@ -1,216 +0,0 @@
/*
* GStreamer EGL/GLES Sink Adaptation
* Copyright (C) 2012-2013 Collabora Ltd.
* @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
* @author: Thiago Santos <thiago.sousa.santos@collabora.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_EGL_ADAPTATION_H__
#define __GST_EGL_ADAPTATION_H__
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/gst.h>
#include <gst/video/gstvideopool.h>
#if defined (USE_EGL_RPI) && defined(__GNUC__)
#ifndef __VCCOREVER__
#define __VCCOREVER__ 0x04000000
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
#pragma GCC optimize ("gnu89-inline")
#endif
#define EGL_EGLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#ifdef HAVE_IOS
#include <OpenGLES/ES2/gl.h>
#else
#include <gst/egl/egl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif
#if defined (USE_EGL_RPI) && defined(__GNUC__)
#pragma GCC reset_options
#pragma GCC diagnostic pop
#endif
G_BEGIN_DECLS
typedef struct _GstEglAdaptationContext GstEglAdaptationContext;
typedef struct _GstEglGlesImageFmt GstEglGlesImageFmt;
#ifdef HAVE_IOS
typedef struct _GstEaglContext GstEaglContext;
#else
typedef struct _GstEglGlesRenderContext GstEglGlesRenderContext;
#endif
typedef struct _coord5
{
float x;
float y;
float z;
float a; /* texpos x */
float b; /* texpos y */
} coord5;
typedef struct
{
GLuint texture;
} GstEGLGLESImageData;
/*
* GstEglAdaptationContext:
* @have_vbo: Set if the GLES VBO setup has been performed
* @have_texture: Set if the GLES texture setup has been performed
* @have_surface: Set if the EGL surface setup has been performed
*
* The #GstEglAdaptationContext data structure.
*/
struct _GstEglAdaptationContext
{
GstElement *element;
#ifdef HAVE_IOS
GstEaglContext *eaglctx;
void * window, *used_window;
#else
GstEglGlesRenderContext *eglglesctx;
GstEGLDisplay *display, *set_display;
EGLNativeWindowType window, used_window;
#endif
GLuint fragshader[2]; /* frame, border */
GLuint vertshader[2]; /* frame, border */
GLuint glslprogram[2]; /* frame, border */
GLuint texture[3]; /* RGB/Y, U/UV, V */
/* shader vars */
GLuint position_loc[2]; /* frame, border */
GLuint texpos_loc[1]; /* frame */
GLuint tex_scale_loc[1][3]; /* [frame] RGB/Y, U/UV, V */
GLuint tex_loc[1][3]; /* [frame] RGB/Y, U/UV, V */
coord5 position_array[16]; /* 4 x Frame x-normal,y-normal, 4x Frame x-normal,y-flip, 4 x Border1, 4 x Border2 */
unsigned short index_array[4];
unsigned int position_buffer, index_buffer;
gint n_textures;
gint surface_width;
gint surface_height;
gint pixel_aspect_ratio_n;
gint pixel_aspect_ratio_d;
gboolean have_vbo;
gboolean have_texture;
gboolean have_surface;
gboolean buffer_preserved;
};
GST_DEBUG_CATEGORY_EXTERN (egladaption_debug);
void gst_egl_adaption_init (void);
GstEglAdaptationContext * gst_egl_adaptation_context_new (GstElement * element);
void gst_egl_adaptation_context_free (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_init (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_deinit (GstEglAdaptationContext * ctx);
gboolean gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_query_buffer_preserved (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_query_par (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_destroy_surface (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx);
gboolean
gst_egl_adaptation_create_egl_context (GstEglAdaptationContext * ctx);
#ifndef HAVE_IOS
EGLContext gst_egl_adaptation_context_get_egl_context (GstEglAdaptationContext * ctx);
#endif
/* platform window */
gboolean gst_egl_adaptation_create_native_window (GstEglAdaptationContext
* ctx, gint width, gint height, gpointer * own_window_data);
void gst_egl_adaptation_destroy_native_window (GstEglAdaptationContext * ctx, gpointer * own_window_data);
GstCaps *gst_egl_adaptation_fill_supported_fbuffer_configs (GstEglAdaptationContext * ctx);
gboolean gst_egl_adaptation_init_display (GstEglAdaptationContext * ctx);
gboolean gst_egl_adaptation_choose_config (GstEglAdaptationContext * ctx);
gboolean gst_egl_adaptation_init_surface (GstEglAdaptationContext * ctx, GstVideoFormat format);
void gst_egl_adaptation_init_exts (GstEglAdaptationContext * ctx);
gboolean gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext * ctx);
gboolean _gst_egl_choose_config (GstEglAdaptationContext * ctx, gboolean try_only, gint * num_configs);
gboolean got_gl_error (const char *wtf);
gboolean got_egl_error (const char *wtf);
void gst_egl_adaptation_set_window (GstEglAdaptationContext * ctx, guintptr window);
gboolean gst_egl_adaptation_context_make_current (GstEglAdaptationContext * ctx, gboolean bind);
void gst_egl_adaptation_cleanup (GstEglAdaptationContext * ctx);
void gst_egl_adaptation_bind_API (GstEglAdaptationContext * ctx);
gboolean gst_egl_adaptation_context_swap_buffers (GstEglAdaptationContext * ctx);
#ifndef HAVE_IOS
/* TODO: The goal is to move this function to gstegl lib (or
* splitted between gstegl lib and gstgl lib) in order to be used in
* webkitVideoSink
* So it has to be independent of GstEglAdaptationContext */
GstBuffer *
gst_egl_image_allocator_alloc_eglimage (GstAllocator * allocator,
GstEGLDisplay * display, EGLContext eglcontext, GstVideoFormat format,
gint width, gint height);
#endif
G_END_DECLS
#endif /* __GST_EGL_ADAPTATION_H__ */

View file

@ -1,349 +0,0 @@
/*
* GStreamer EGL/GLES Sink Adaptation for IOS
* Copyright (C) 2013 Collabora Ltd.
* @author: Thiago Santos <thiago.sousa.santos@collabora.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <OpenGLES/EAGL.h>
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#include <OpenGLES/ES2/gl.h>
#include "gstegladaptation.h"
#define GST_CAT_DEFAULT egladaption_debug
struct _GstEaglContext
{
EAGLContext *eagl_context;
GLuint framebuffer;
GLuint color_renderbuffer;
GLuint depth_renderbuffer;
UIView *window;
UIView *used_window;
};
static gboolean
gst_egl_adaptation_update_surface (GstEglAdaptationContext * ctx);
void
gst_egl_adaptation_init (GstEglAdaptationContext * ctx)
{
ctx->eaglctx = g_new0 (GstEaglContext, 1);
}
void
gst_egl_adaptation_deinit (GstEglAdaptationContext * ctx)
{
g_free (ctx->eaglctx);
}
gboolean
gst_egl_adaptation_init_display (GstEglAdaptationContext * ctx)
{
/* NOP - the display should be initialized by the application */
return TRUE;
}
void
gst_egl_adaptation_bind_API (GstEglAdaptationContext * ctx)
{
/* NOP */
}
gboolean
gst_egl_adaptation_create_native_window (GstEglAdaptationContext * ctx, gint width, gint height, gpointer * own_window_data)
{
return FALSE;
}
void
gst_egl_adaptation_destroy_native_window (GstEglAdaptationContext * ctx, gpointer * own_window_data)
{
}
gboolean
gst_egl_adaptation_create_egl_context (GstEglAdaptationContext * ctx)
{
__block EAGLContext *context;
dispatch_sync(dispatch_get_main_queue(), ^{
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (context == nil) {
GST_ERROR_OBJECT (ctx->element, "Failed to create EAGL GLES2 context");
}
});
ctx->eaglctx->eagl_context = context;
if (context == nil)
return FALSE;
/* EAGL needs the context to be set here to allow surface creation */
return gst_egl_adaptation_context_make_current (ctx, TRUE);
}
gboolean
gst_egl_adaptation_context_make_current (GstEglAdaptationContext * ctx,
gboolean bind)
{
__block EAGLContext *ctx_to_set = nil;
if (bind && ctx->eaglctx->eagl_context) {
EAGLContext *cur_ctx = [EAGLContext currentContext];
if (cur_ctx == ctx->eaglctx->eagl_context) {
GST_DEBUG_OBJECT (ctx->element,
"Already attached the context to thread %p", g_thread_self ());
return TRUE;
}
GST_DEBUG_OBJECT (ctx->element, "Attaching context to thread %p",
g_thread_self ());
if ([EAGLContext setCurrentContext: ctx->eaglctx->eagl_context] == NO) {
got_gl_error ("setCurrentContext");
GST_ERROR_OBJECT (ctx->element, "Couldn't bind context");
return FALSE;
}
ctx_to_set = ctx->eaglctx->eagl_context;
} else {
GST_DEBUG_OBJECT (ctx->element, "Detaching context from thread %p",
g_thread_self ());
if ([EAGLContext setCurrentContext: nil] == NO) {
got_gl_error ("setCurrentContext");
GST_ERROR_OBJECT (ctx->element, "Couldn't unbind context");
return FALSE;
}
}
return TRUE;
}
gboolean
gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
{
__block GLuint framebuffer;
__block GLuint colorRenderbuffer;
__block GLint width;
__block GLint height;
__block GLuint depthRenderbuffer;
__block GLenum status;
__block CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
dispatch_sync(dispatch_get_main_queue(), ^{
gst_egl_adaptation_context_make_current (ctx, TRUE);
if (ctx->eaglctx->framebuffer) {
framebuffer = ctx->eaglctx->framebuffer;
} else {
/* Allocate framebuffer */
glGenFramebuffers(1, &framebuffer);
}
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
/* Allocate color render buffer */
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[ctx->eaglctx->eagl_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, colorRenderbuffer);
/* Get renderbuffer width/height */
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
/* allocate depth render buffer */
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depthRenderbuffer);
gst_egl_adaptation_context_make_current (ctx, FALSE);
});
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
/* check creation status */
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"failed to make complete framebuffer object %x", status);
return FALSE;
}
ctx->eaglctx->framebuffer = framebuffer;
ctx->eaglctx->color_renderbuffer = colorRenderbuffer;
ctx->eaglctx->depth_renderbuffer = colorRenderbuffer;
ctx->surface_width = width;
ctx->surface_height = height;
glBindRenderbuffer(GL_RENDERBUFFER, ctx->eaglctx->color_renderbuffer);
return TRUE;
}
gboolean
_gst_egl_choose_config (GstEglAdaptationContext * ctx, gboolean try_only, gint * num_configs)
{
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
nil];
[eaglLayer setOpaque:YES];
[eaglLayer setDrawableProperties:dict];
if (num_configs)
*num_configs = 1;
return TRUE;
}
void
gst_egl_adaptation_query_buffer_preserved (GstEglAdaptationContext * ctx)
{
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
NSDictionary *dict = [eaglLayer drawableProperties];
ctx->buffer_preserved = FALSE;
if ([dict objectForKey: kEAGLDrawablePropertyRetainedBacking] != nil) {
NSNumber *n = [dict objectForKey: kEAGLDrawablePropertyRetainedBacking];
ctx->buffer_preserved = [n boolValue] != NO;
} else {
GST_DEBUG_OBJECT (ctx->element, "No information about buffer preserving in layer properties");
}
}
void
gst_egl_adaptation_query_par (GstEglAdaptationContext * ctx)
{
/* TODO how can we check this? */
ctx->pixel_aspect_ratio_n = 1;
ctx->pixel_aspect_ratio_d = 1;
}
gboolean
gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext *
ctx)
{
CAEAGLLayer *layer = (CAEAGLLayer *)[ctx->eaglctx->window layer];
CGSize size = layer.frame.size;
if (size.width != ctx->surface_width || size.height != ctx->surface_height) {
ctx->surface_width = size.width;
ctx->surface_height = size.height;
GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels",
(gint) size.width, (gint) size.height);
if (!gst_egl_adaptation_update_surface (ctx)) {
GST_WARNING_OBJECT (ctx->element, "Failed to update surface "
"to new dimensions");
}
return TRUE;
}
return FALSE;
}
void
gst_egl_adaptation_init_exts (GstEglAdaptationContext * ctx)
{
const gchar *extensions = (const gchar *) glGetString(GL_EXTENSIONS);
NSString *extensionsString = NULL;
if (extensions) {
extensionsString= [NSString stringWithCString:extensions encoding: NSASCIIStringEncoding];
}
GST_DEBUG_OBJECT (ctx->element, "Available GL extensions: %s\n",
GST_STR_NULL ([extensionsString UTF8String]));
}
void
gst_egl_adaptation_destroy_surface (GstEglAdaptationContext * ctx)
{
if (ctx->eaglctx->framebuffer) {
glDeleteFramebuffers (1, &ctx->eaglctx->framebuffer);
ctx->eaglctx->framebuffer = 0;
glDeleteRenderbuffers(1, &ctx->eaglctx->depth_renderbuffer);
ctx->eaglctx->depth_renderbuffer = 0;
glDeleteRenderbuffers(1, &ctx->eaglctx->color_renderbuffer);
ctx->eaglctx->color_renderbuffer = 0;
ctx->have_surface = FALSE;
}
}
static gboolean
gst_egl_adaptation_update_surface (GstEglAdaptationContext * ctx)
{
glBindFramebuffer(GL_FRAMEBUFFER, ctx->eaglctx->framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &ctx->eaglctx->depth_renderbuffer);
glBindRenderbuffer (GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &ctx->eaglctx->color_renderbuffer);
return gst_egl_adaptation_create_surface (ctx);
}
void
gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx)
{
if (ctx->eaglctx->eagl_context) {
[ctx->eaglctx->eagl_context release];
ctx->eaglctx->eagl_context = NULL;
}
}
gboolean
gst_egl_adaptation_context_swap_buffers (GstEglAdaptationContext * ctx)
{
[ctx->eaglctx->eagl_context presentRenderbuffer:GL_RENDERBUFFER];
return TRUE;
}
void
gst_egl_adaptation_set_window (GstEglAdaptationContext * ctx, guintptr window)
{
ctx->eaglctx->window = (UIView *) window;
}

View file

@ -1,927 +0,0 @@
/*
* Copyright (C) 2012-2013 Collabora Ltd.
* @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
* @author: Thiago Santos <thiago.sousa.santos@collabora.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gstegladaptation.h"
#include "video_platform_wrapper.h"
#include <string.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <gst/egl/egl.h>
#define GST_CAT_DEFAULT egladaption_debug
/* Some EGL implementations are reporting wrong
* values for the display's EGL_PIXEL_ASPECT_RATIO.
* They are required by the khronos specs to report
* this value as w/h * EGL_DISPLAY_SCALING (Which is
* a constant with value 10000) but at least the
* Galaxy SIII (Android) is reporting just 1 when
* w = h. We use these two to bound returned values to
* sanity.
*/
#define EGL_SANE_DAR_MIN ((EGL_DISPLAY_SCALING)/10)
#define EGL_SANE_DAR_MAX ((EGL_DISPLAY_SCALING)*10)
#define GST_EGLGLESSINK_EGL_MIN_VERSION 1
static const EGLint eglglessink_RGBA8888_attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
/*
* GstEglGlesRenderContext:
* @config: Current EGL config
* @eglcontext: Current EGL context
* @egl_minor: EGL version (minor)
* @egl_major: EGL version (major)
*
* This struct holds the sink's EGL/GLES rendering context.
*/
struct _GstEglGlesRenderContext
{
EGLConfig config;
EGLContext eglcontext;
EGLSurface surface;
EGLint egl_minor, egl_major;
};
gboolean
got_egl_error (const char *wtf)
{
EGLint error;
if ((error = eglGetError ()) != EGL_SUCCESS) {
GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned 0x%04x", wtf,
error);
return TRUE;
}
return FALSE;
}
/* Prints available EGL/GLES extensions
* If another rendering path is implemented this is the place
* where you want to check for the availability of its supporting
* EGL/GLES extensions.
*/
void
gst_egl_adaptation_init_exts (GstEglAdaptationContext * ctx)
{
#ifndef GST_DISABLE_GST_DEBUG
const char *eglexts;
unsigned const char *glexts;
eglexts = eglQueryString (gst_egl_display_get (ctx->display), EGL_EXTENSIONS);
glexts = glGetString (GL_EXTENSIONS);
GST_DEBUG_OBJECT (ctx->element, "Available EGL extensions: %s\n",
GST_STR_NULL (eglexts));
GST_DEBUG_OBJECT (ctx->element, "Available GLES extensions: %s\n",
GST_STR_NULL ((const char *) glexts));
#endif
return;
}
gboolean
gst_egl_adaptation_init_display (GstEglAdaptationContext * ctx)
{
GstQuery *query;
GstMessage *msg;
EGLDisplay display;
GST_DEBUG_OBJECT (ctx->element, "Enter EGL initial configuration");
if (!platform_wrapper_init ()) {
GST_ERROR_OBJECT (ctx->element, "Couldn't init EGL platform wrapper");
goto HANDLE_ERROR;
}
if (!ctx->set_display) {
query = gst_query_new_context (GST_EGL_DISPLAY_CONTEXT_TYPE);
if (gst_pad_peer_query (GST_BASE_SINK_PAD (ctx->element), query)) {
GstContext *context;
gst_query_parse_context (query, &context);
gst_context_get_egl_display (context, &ctx->set_display);
}
gst_query_unref (query);
}
if (!ctx->set_display) {
msg =
gst_message_new_need_context (GST_OBJECT_CAST (ctx->element),
GST_EGL_DISPLAY_CONTEXT_TYPE);
gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg);
}
GST_OBJECT_LOCK (ctx->element);
if (!ctx->set_display) {
GstContext *context;
GST_OBJECT_UNLOCK (ctx->element);
display = eglGetDisplay (EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
GST_ERROR_OBJECT (ctx->element, "Could not get EGL display connection");
goto HANDLE_ERROR; /* No EGL error is set by eglGetDisplay() */
}
ctx->display = gst_egl_display_new (display, (GDestroyNotify) eglTerminate);
context = gst_context_new_egl_display (ctx->display, FALSE);
msg = gst_message_new_have_context (GST_OBJECT (ctx->element), context);
gst_element_post_message (GST_ELEMENT_CAST (ctx->element), msg);
} else {
ctx->display = gst_egl_display_ref (ctx->set_display);
}
if (!eglInitialize (gst_egl_display_get (ctx->display),
&ctx->eglglesctx->egl_major, &ctx->eglglesctx->egl_minor)) {
got_egl_error ("eglInitialize");
GST_ERROR_OBJECT (ctx->element, "Could not init EGL display connection");
goto HANDLE_EGL_ERROR;
}
/* Check against required EGL version
* XXX: Need to review the version requirement in terms of the needed API
*/
if (ctx->eglglesctx->egl_major < GST_EGLGLESSINK_EGL_MIN_VERSION) {
GST_ERROR_OBJECT (ctx->element, "EGL v%d needed, but you only have v%d.%d",
GST_EGLGLESSINK_EGL_MIN_VERSION, ctx->eglglesctx->egl_major,
ctx->eglglesctx->egl_minor);
goto HANDLE_ERROR;
}
GST_INFO_OBJECT (ctx->element, "System reports supported EGL version v%d.%d",
ctx->eglglesctx->egl_major, ctx->eglglesctx->egl_minor);
eglBindAPI (EGL_OPENGL_ES_API);
return TRUE;
/* Errors */
HANDLE_EGL_ERROR:
GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x", eglGetError ());
HANDLE_ERROR:
GST_ERROR_OBJECT (ctx->element, "Couldn't setup window/surface from handle");
return FALSE;
}
gboolean
gst_egl_adaptation_context_make_current (GstEglAdaptationContext * ctx,
gboolean bind)
{
g_assert (ctx->display != NULL);
if (bind && ctx->eglglesctx->surface && ctx->eglglesctx->eglcontext) {
EGLContext *cur_ctx = eglGetCurrentContext ();
if (cur_ctx == ctx->eglglesctx->eglcontext) {
GST_DEBUG_OBJECT (ctx->element,
"Already attached the context to thread %p", g_thread_self ());
return TRUE;
}
GST_DEBUG_OBJECT (ctx->element, "Attaching context to thread %p",
g_thread_self ());
if (!eglMakeCurrent (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface, ctx->eglglesctx->surface,
ctx->eglglesctx->eglcontext)) {
got_egl_error ("eglMakeCurrent");
GST_ERROR_OBJECT (ctx->element, "Couldn't bind context");
return FALSE;
}
} else {
GST_DEBUG_OBJECT (ctx->element, "Detaching context from thread %p",
g_thread_self ());
if (!eglMakeCurrent (gst_egl_display_get (ctx->display),
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
got_egl_error ("eglMakeCurrent");
GST_ERROR_OBJECT (ctx->element, "Couldn't unbind context");
return FALSE;
}
}
return TRUE;
}
/* XXX: Lock eglgles context? */
gboolean
gst_egl_adaptation_update_surface_dimensions (GstEglAdaptationContext * ctx)
{
gint width, height;
/* Save surface dims */
eglQuerySurface (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface, EGL_WIDTH, &width);
eglQuerySurface (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface, EGL_HEIGHT, &height);
if (width != ctx->surface_width || height != ctx->surface_height) {
ctx->surface_width = width;
ctx->surface_height = height;
GST_INFO_OBJECT (ctx->element, "Got surface of %dx%d pixels", width,
height);
return TRUE;
}
return FALSE;
}
void
gst_egl_adaptation_bind_API (GstEglAdaptationContext * ctx)
{
eglBindAPI (EGL_OPENGL_ES_API);
}
gboolean
gst_egl_adaptation_context_swap_buffers (GstEglAdaptationContext * ctx)
{
gboolean ret = eglSwapBuffers (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface);
if (ret == EGL_FALSE) {
got_egl_error ("eglSwapBuffers");
}
return ret;
}
gboolean
_gst_egl_choose_config (GstEglAdaptationContext * ctx, gboolean try_only,
gint * num_configs)
{
EGLint cfg_number;
gboolean ret;
EGLConfig *config = NULL;
if (!try_only)
config = &ctx->eglglesctx->config;
ret = eglChooseConfig (gst_egl_display_get (ctx->display),
eglglessink_RGBA8888_attribs, config, 1, &cfg_number) != EGL_FALSE;
if (!ret)
got_egl_error ("eglChooseConfig");
else if (num_configs)
*num_configs = cfg_number;
return ret;
}
gboolean
gst_egl_adaptation_create_surface (GstEglAdaptationContext * ctx)
{
ctx->eglglesctx->surface =
eglCreateWindowSurface (gst_egl_display_get (ctx->display),
ctx->eglglesctx->config, ctx->used_window, NULL);
if (ctx->eglglesctx->surface == EGL_NO_SURFACE) {
got_egl_error ("eglCreateWindowSurface");
GST_ERROR_OBJECT (ctx->element, "Can't create surface");
return FALSE;
}
return TRUE;
}
void
gst_egl_adaptation_query_buffer_preserved (GstEglAdaptationContext * ctx)
{
EGLint swap_behavior;
ctx->buffer_preserved = FALSE;
if (eglQuerySurface (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface, EGL_SWAP_BEHAVIOR, &swap_behavior)) {
GST_DEBUG_OBJECT (ctx->element, "Buffer swap behavior %x", swap_behavior);
ctx->buffer_preserved = swap_behavior == EGL_BUFFER_PRESERVED;
} else {
GST_DEBUG_OBJECT (ctx->element, "Can't query buffer swap behavior");
}
}
void
gst_egl_adaptation_query_par (GstEglAdaptationContext * ctx)
{
EGLint display_par;
/* fixed value */
ctx->pixel_aspect_ratio_d = EGL_DISPLAY_SCALING;
/* Save display's pixel aspect ratio
*
* DAR is reported as w/h * EGL_DISPLAY_SCALING wich is
* a constant with value 10000. This attribute is only
* supported if the EGL version is >= 1.2
* XXX: Setup this as a property.
* or some other one time check. Right now it's being called once
* per frame.
*/
if (ctx->eglglesctx->egl_major == 1 && ctx->eglglesctx->egl_minor < 2) {
GST_DEBUG_OBJECT (ctx->element, "Can't query PAR. Using default: %dx%d",
EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
ctx->pixel_aspect_ratio_n = EGL_DISPLAY_SCALING;
} else {
eglQuerySurface (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface, EGL_PIXEL_ASPECT_RATIO, &display_par);
/* Fix for outbound DAR reporting on some implementations not
* honoring the 'should return w/h * EGL_DISPLAY_SCALING' spec
* requirement
*/
if (display_par == EGL_UNKNOWN || display_par < EGL_SANE_DAR_MIN ||
display_par > EGL_SANE_DAR_MAX) {
GST_DEBUG_OBJECT (ctx->element, "Nonsensical PAR value returned: %d. "
"Bad EGL implementation? "
"Will use default: %d/%d", ctx->pixel_aspect_ratio_n,
EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
ctx->pixel_aspect_ratio_n = EGL_DISPLAY_SCALING;
} else {
ctx->pixel_aspect_ratio_n = display_par;
}
}
}
gboolean
gst_egl_adaptation_create_egl_context (GstEglAdaptationContext * ctx)
{
EGLint con_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
ctx->eglglesctx->eglcontext =
eglCreateContext (gst_egl_display_get (ctx->display),
ctx->eglglesctx->config, EGL_NO_CONTEXT, con_attribs);
if (ctx->eglglesctx->eglcontext == EGL_NO_CONTEXT) {
GST_ERROR_OBJECT (ctx->element, "EGL call returned error %x",
eglGetError ());
return FALSE;
}
GST_DEBUG_OBJECT (ctx->element, "EGL Context: %p",
ctx->eglglesctx->eglcontext);
return TRUE;
}
EGLContext
gst_egl_adaptation_context_get_egl_context (GstEglAdaptationContext * ctx)
{
g_return_val_if_fail (ctx != NULL, EGL_NO_CONTEXT);
return ctx->eglglesctx->eglcontext;
}
static void
gst_egl_gles_image_data_free (GstEGLGLESImageData * data)
{
glDeleteTextures (1, &data->texture);
g_slice_free (GstEGLGLESImageData, data);
}
GstBuffer *
gst_egl_image_allocator_alloc_eglimage (GstAllocator * allocator,
GstEGLDisplay * display, EGLContext eglcontext, GstVideoFormat format,
gint width, gint height)
{
GstEGLGLESImageData *data = NULL;
GstBuffer *buffer;
GstVideoInfo info;
gint i;
gint stride[3];
gsize offset[3];
GstMemory *mem[3] = { NULL, NULL, NULL };
guint n_mem;
GstMemoryFlags flags = 0;
memset (stride, 0, sizeof (stride));
memset (offset, 0, sizeof (offset));
if (!gst_egl_image_memory_is_mappable ())
flags |= GST_MEMORY_FLAG_NOT_MAPPABLE;
/* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */
flags |= GST_MEMORY_FLAG_NO_SHARE;
gst_video_info_set_format (&info, format, width, height);
switch (format) {
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:{
gsize size;
EGLImageKHR image;
mem[0] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
GST_VIDEO_INFO_HEIGHT (&info), &size);
if (mem[0]) {
stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
n_mem = 1;
GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
} else {
data = g_slice_new0 (GstEGLGLESImageData);
stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 3);
size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);
glGenTextures (1, &data->texture);
if (got_gl_error ("glGenTextures"))
goto mem_error;
glBindTexture (GL_TEXTURE_2D, data->texture);
if (got_gl_error ("glBindTexture"))
goto mem_error;
/* Set 2D resizing params */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* If these are not set the texture image unit will return
* * (R, G, B, A) = black on glTexImage2D for non-POT width/height
* * frames. For a deeper explanation take a look at the OpenGL ES
* * documentation for glTexParameter */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (got_gl_error ("glTexParameteri"))
goto mem_error;
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
GST_VIDEO_INFO_WIDTH (&info),
GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
if (got_gl_error ("glTexImage2D"))
goto mem_error;
image =
eglCreateImageKHR (gst_egl_display_get (display),
eglcontext, EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer) (guintptr) data->texture, NULL);
if (got_egl_error ("eglCreateImageKHR"))
goto mem_error;
mem[0] =
gst_egl_image_allocator_wrap (allocator, display,
image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
n_mem = 1;
}
break;
}
case GST_VIDEO_FORMAT_RGB16:{
EGLImageKHR image;
gsize size;
mem[0] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_RGB, GST_VIDEO_INFO_WIDTH (&info),
GST_VIDEO_INFO_HEIGHT (&info), &size);
if (mem[0]) {
stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
n_mem = 1;
GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
} else {
data = g_slice_new0 (GstEGLGLESImageData);
stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 2);
size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);
glGenTextures (1, &data->texture);
if (got_gl_error ("glGenTextures"))
goto mem_error;
glBindTexture (GL_TEXTURE_2D, data->texture);
if (got_gl_error ("glBindTexture"))
goto mem_error;
/* Set 2D resizing params */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* If these are not set the texture image unit will return
* * (R, G, B, A) = black on glTexImage2D for non-POT width/height
* * frames. For a deeper explanation take a look at the OpenGL ES
* * documentation for glTexParameter */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (got_gl_error ("glTexParameteri"))
goto mem_error;
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
GST_VIDEO_INFO_WIDTH (&info),
GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
NULL);
if (got_gl_error ("glTexImage2D"))
goto mem_error;
image =
eglCreateImageKHR (gst_egl_display_get (display),
eglcontext, EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer) (guintptr) data->texture, NULL);
if (got_egl_error ("eglCreateImageKHR"))
goto mem_error;
mem[0] =
gst_egl_image_allocator_wrap (allocator, display,
image, GST_VIDEO_GL_TEXTURE_TYPE_RGB,
flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
n_mem = 1;
}
break;
}
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV21:{
EGLImageKHR image;
gsize size[2];
mem[0] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
mem[1] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA,
GST_VIDEO_INFO_COMP_WIDTH (&info, 1),
GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
if (mem[0] && mem[1]) {
stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
offset[1] = size[0];
stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
n_mem = 2;
GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
} else {
if (mem[0])
gst_memory_unref (mem[0]);
if (mem[1])
gst_memory_unref (mem[1]);
mem[0] = mem[1] = NULL;
stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1) * 2);
offset[1] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
size[0] = offset[1];
size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
for (i = 0; i < 2; i++) {
data = g_slice_new0 (GstEGLGLESImageData);
glGenTextures (1, &data->texture);
if (got_gl_error ("glGenTextures"))
goto mem_error;
glBindTexture (GL_TEXTURE_2D, data->texture);
if (got_gl_error ("glBindTexture"))
goto mem_error;
/* Set 2D resizing params */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* If these are not set the texture image unit will return
* * (R, G, B, A) = black on glTexImage2D for non-POT width/height
* * frames. For a deeper explanation take a look at the OpenGL ES
* * documentation for glTexParameter */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (got_gl_error ("glTexParameteri"))
goto mem_error;
if (i == 0)
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
GST_VIDEO_INFO_COMP_WIDTH (&info, i),
GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
GST_VIDEO_INFO_COMP_WIDTH (&info, i),
GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE_ALPHA,
GL_UNSIGNED_BYTE, NULL);
if (got_gl_error ("glTexImage2D"))
goto mem_error;
image =
eglCreateImageKHR (gst_egl_display_get (display),
eglcontext, EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer) (guintptr) data->texture, NULL);
if (got_egl_error ("eglCreateImageKHR"))
goto mem_error;
mem[i] =
gst_egl_image_allocator_wrap (allocator, display,
image,
(i ==
0 ? GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE :
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA),
flags, size[i], data,
(GDestroyNotify) gst_egl_gles_image_data_free);
}
n_mem = 2;
}
break;
}
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:{
EGLImageKHR image;
gsize size[3];
mem[0] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
0), GST_VIDEO_INFO_COMP_HEIGHT (&info, 0), &size[0]);
mem[1] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
1), GST_VIDEO_INFO_COMP_HEIGHT (&info, 1), &size[1]);
mem[2] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE, GST_VIDEO_INFO_COMP_WIDTH (&info,
2), GST_VIDEO_INFO_COMP_HEIGHT (&info, 2), &size[2]);
if (mem[0] && mem[1] && mem[2]) {
stride[0] = size[0] / GST_VIDEO_INFO_HEIGHT (&info);
offset[1] = size[0];
stride[1] = size[1] / GST_VIDEO_INFO_HEIGHT (&info);
offset[2] = size[1];
stride[2] = size[2] / GST_VIDEO_INFO_HEIGHT (&info);
n_mem = 3;
GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
GST_MINI_OBJECT_FLAG_SET (mem[1], GST_MEMORY_FLAG_NO_SHARE);
GST_MINI_OBJECT_FLAG_SET (mem[2], GST_MEMORY_FLAG_NO_SHARE);
} else {
if (mem[0])
gst_memory_unref (mem[0]);
if (mem[1])
gst_memory_unref (mem[1]);
if (mem[2])
gst_memory_unref (mem[2]);
mem[0] = mem[1] = mem[2] = NULL;
stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 0));
stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 1));
stride[2] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (&info, 2));
size[0] = stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 0);
size[1] = stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 1);
size[2] = stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&info, 2);
offset[0] = 0;
offset[1] = size[0];
offset[2] = offset[1] + size[1];
for (i = 0; i < 3; i++) {
data = g_slice_new0 (GstEGLGLESImageData);
glGenTextures (1, &data->texture);
if (got_gl_error ("glGenTextures"))
goto mem_error;
glBindTexture (GL_TEXTURE_2D, data->texture);
if (got_gl_error ("glBindTexture"))
goto mem_error;
/* Set 2D resizing params */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* If these are not set the texture image unit will return
* * (R, G, B, A) = black on glTexImage2D for non-POT width/height
* * frames. For a deeper explanation take a look at the OpenGL ES
* * documentation for glTexParameter */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (got_gl_error ("glTexParameteri"))
goto mem_error;
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
GST_VIDEO_INFO_COMP_WIDTH (&info, i),
GST_VIDEO_INFO_COMP_HEIGHT (&info, i), 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, NULL);
if (got_gl_error ("glTexImage2D"))
goto mem_error;
image =
eglCreateImageKHR (gst_egl_display_get (display),
eglcontext, EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer) (guintptr) data->texture, NULL);
if (got_egl_error ("eglCreateImageKHR"))
goto mem_error;
mem[i] =
gst_egl_image_allocator_wrap (allocator, display,
image, GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE,
flags, size[i], data,
(GDestroyNotify) gst_egl_gles_image_data_free);
}
n_mem = 3;
}
break;
}
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_AYUV:{
gsize size;
EGLImageKHR image;
mem[0] =
gst_egl_image_allocator_alloc (allocator, display,
GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info),
GST_VIDEO_INFO_HEIGHT (&info), &size);
if (mem[0]) {
stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info);
n_mem = 1;
GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE);
} else {
data = g_slice_new0 (GstEGLGLESImageData);
stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4);
size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info);
glGenTextures (1, &data->texture);
if (got_gl_error ("glGenTextures"))
goto mem_error;
glBindTexture (GL_TEXTURE_2D, data->texture);
if (got_gl_error ("glBindTexture"))
goto mem_error;
/* Set 2D resizing params */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* If these are not set the texture image unit will return
* * (R, G, B, A) = black on glTexImage2D for non-POT width/height
* * frames. For a deeper explanation take a look at the OpenGL ES
* * documentation for glTexParameter */
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (got_gl_error ("glTexParameteri"))
goto mem_error;
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
GST_VIDEO_INFO_WIDTH (&info),
GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
if (got_gl_error ("glTexImage2D"))
goto mem_error;
image =
eglCreateImageKHR (gst_egl_display_get (display),
eglcontext, EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer) (guintptr) data->texture, NULL);
if (got_egl_error ("eglCreateImageKHR"))
goto mem_error;
mem[0] =
gst_egl_image_allocator_wrap (allocator, display,
image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA,
flags, size, data, (GDestroyNotify) gst_egl_gles_image_data_free);
n_mem = 1;
}
break;
}
default:
g_assert_not_reached ();
break;
}
buffer = gst_buffer_new ();
gst_buffer_add_video_meta_full (buffer, 0, format, width, height,
GST_VIDEO_INFO_N_PLANES (&info), offset, stride);
for (i = 0; i < n_mem; i++)
gst_buffer_append_memory (buffer, mem[i]);
return buffer;
mem_error:
{
GST_ERROR_OBJECT (GST_CAT_DEFAULT, "Failed to create EGLImage");
if (data)
gst_egl_gles_image_data_free (data);
if (mem[0])
gst_memory_unref (mem[0]);
if (mem[1])
gst_memory_unref (mem[1]);
if (mem[2])
gst_memory_unref (mem[2]);
return NULL;
}
}
void
gst_egl_adaptation_destroy_native_window (GstEglAdaptationContext * ctx,
gpointer * own_window_data)
{
platform_destroy_native_window (gst_egl_display_get
(ctx->display), ctx->used_window, own_window_data);
ctx->used_window = 0;
}
gboolean
gst_egl_adaptation_create_native_window (GstEglAdaptationContext * ctx,
gint width, gint height, gpointer * own_window_data)
{
EGLNativeWindowType window =
platform_create_native_window (width, height, own_window_data);
if (window)
gst_egl_adaptation_set_window (ctx, (guintptr) window);
GST_DEBUG_OBJECT (ctx->element, "Using window handle %p", (gpointer) window);
return window != 0;
}
void
gst_egl_adaptation_set_window (GstEglAdaptationContext * ctx, guintptr window)
{
ctx->window = (EGLNativeWindowType) window;
}
void
gst_egl_adaptation_init (GstEglAdaptationContext * ctx)
{
ctx->eglglesctx = g_new0 (GstEglGlesRenderContext, 1);
}
void
gst_egl_adaptation_deinit (GstEglAdaptationContext * ctx)
{
g_free (ctx->eglglesctx);
}
void
gst_egl_adaptation_destroy_surface (GstEglAdaptationContext * ctx)
{
if (ctx->eglglesctx->surface) {
eglDestroySurface (gst_egl_display_get (ctx->display),
ctx->eglglesctx->surface);
ctx->eglglesctx->surface = NULL;
ctx->have_surface = FALSE;
}
}
void
gst_egl_adaptation_destroy_context (GstEglAdaptationContext * ctx)
{
if (ctx->eglglesctx->eglcontext) {
eglDestroyContext (gst_egl_display_get (ctx->display),
ctx->eglglesctx->eglcontext);
ctx->eglglesctx->eglcontext = NULL;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,145 +0,0 @@
/*
* GStreamer EGL/GLES Sink
* Copyright (C) 2012 Collabora Ltd.
* @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_EGLGLESSINK_H__
#define __GST_EGLGLESSINK_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideosink.h>
#include <gst/base/gstdataqueue.h>
#include "gstegladaptation.h"
G_BEGIN_DECLS
#define GST_TYPE_EGLGLESSINK \
(gst_eglglessink_get_type())
#define GST_EGLGLESSINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EGLGLESSINK,GstEglGlesSink))
#define GST_EGLGLESSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EGLGLESSINK,GstEglGlesSinkClass))
#define GST_IS_EGLGLESSINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EGLGLESSINK))
#define GST_IS_EGLGLESSINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EGLGLESSINK))
typedef struct _GstEglGlesSink GstEglGlesSink;
typedef struct _GstEglGlesSinkClass GstEglGlesSinkClass;
/*
* GstEglGlesSink:
* @format: Caps' video format field
* @display_region: Surface region to use as rendering canvas
* @sinkcaps: Full set of suported caps
* @current_caps: Current caps
* @rendering_path: Rendering path (Slow/Fast)
* @eglglesctx: Pointer to the associated EGL/GLESv2 rendering context
* @flow_lock: Simple concurrent access ward to the sink's runtime state
* @have_window: Set if the sink has access to a window to hold it's canvas
* @using_own_window: Set if the sink created its own window
* @egl_started: Set if the whole EGL setup has been performed
* @create_window: Property value holder to allow/forbid internal window creation
* @force_rendering_slow: Property value holder to force slow rendering path
* @force_aspect_ratio: Property value holder to consider PAR/DAR when scaling
*
* The #GstEglGlesSink data structure.
*/
struct _GstEglGlesSink
{
GstVideoSink videosink; /* Element hook */
/* Region of the surface that should be rendered */
GstVideoRectangle render_region;
gboolean render_region_changed;
gboolean render_region_user;
/* Region of render_region that should be filled
* with the video frames */
GstVideoRectangle display_region;
GstVideoRectangle crop;
gboolean crop_changed;
GstCaps *sinkcaps;
GstCaps *current_caps, *configured_caps;
GstVideoInfo configured_info;
gfloat stride[3];
GstVideoGLTextureOrientation orientation;
#ifndef HAVE_IOS
GstBufferPool *pool;
#endif
GstEglAdaptationContext *egl_context;
/* Runtime flags */
gboolean have_window;
gboolean using_own_window;
gboolean egl_started;
gpointer own_window_data;
GThread *thread;
gboolean thread_running;
GstDataQueue *queue;
GCond render_cond;
GMutex render_lock;
GstFlowReturn last_flow;
GstMiniObject *dequeued_object;
GstBuffer *last_buffer;
/* Properties */
gboolean create_window;
gboolean force_aspect_ratio;
};
struct _GstEglGlesSinkClass
{
GstVideoSinkClass parent_class;
};
GType gst_eglglessink_get_type (void);
G_END_DECLS
#endif /* __GST_EGLGLESSINK_H__ */

View file

@ -1,706 +0,0 @@
/*
* GStreamer Android Video Platform Wrapper
* Copyright (C) 2012 Collabora Ltd.
* @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined (USE_EGL_RPI) && defined(__GNUC__)
#ifndef __VCCOREVER__
#define __VCCOREVER__ 0x04000000
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
#pragma GCC optimize ("gnu89-inline")
#endif
#define EGL_EGLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#if defined (USE_EGL_RPI) && defined(__GNUC__)
#pragma GCC reset_options
#pragma GCC diagnostic pop
#endif
#include <string.h>
#include <gst/gst.h>
#include "video_platform_wrapper.h"
GST_DEBUG_CATEGORY_STATIC (eglgles_platform_wrapper);
#define GST_CAT_DEFAULT eglgles_platform_wrapper
/* XXX: Likely to be removed */
gboolean
platform_wrapper_init (void)
{
GST_DEBUG_CATEGORY_INIT (eglgles_platform_wrapper,
"eglglessink-platform", 0,
"Platform dependent native-window utility routines for EglGles");
return TRUE;
}
#ifdef USE_EGL_X11
#include <X11/Xlib.h>
typedef struct
{
Display *display;
} X11WindowData;
EGLNativeWindowType
platform_create_native_window (gint width, gint height, gpointer * window_data)
{
Display *d;
Window w;
int s;
X11WindowData *data;
d = XOpenDisplay (NULL);
if (d == NULL) {
GST_ERROR ("Can't open X11 display");
return (EGLNativeWindowType) 0;
}
s = DefaultScreen (d);
w = XCreateSimpleWindow (d, RootWindow (d, s), 10, 10, width, height, 1,
BlackPixel (d, s), WhitePixel (d, s));
XStoreName (d, w, "eglglessink");
XMapWindow (d, w);
XFlush (d);
*window_data = data = g_slice_new0 (X11WindowData);
data->display = d;
return (EGLNativeWindowType) w;
}
gboolean
platform_destroy_native_window (EGLNativeDisplayType display,
EGLNativeWindowType window, gpointer * window_data)
{
X11WindowData *data = *window_data;
/* XXX: Should proly catch BadWindow */
XDestroyWindow (data->display, (Window) window);
XSync (data->display, FALSE);
XCloseDisplay (data->display);
g_slice_free (X11WindowData, data);
*window_data = NULL;
return TRUE;
}
#endif
#ifdef USE_EGL_MALI_FB
#include <EGL/fbdev_window.h>
EGLNativeWindowType
platform_create_native_window (gint width, gint height, gpointer * window_data)
{
fbdev_window *w = g_slice_new0 (fbdev_window);
w->width = width;
w->height = height;
return (EGLNativeWindowType) w;
}
gboolean
platform_destroy_native_window (EGLNativeDisplayType display,
EGLNativeWindowType window, gpointer * window_data)
{
g_slice_free (fbdev_window, ((fbdev_window *) window));
return TRUE;
}
/* FIXME: Move to gst-libs/gst/egl */
#if 0
#include <mali_egl_image.h>
#include <ump/ump.h>
#include <ump/ump_ref_drv.h>
#include <gst/video/video.h>
static gpointer
eglimage_map (GstMemory * gmem, gsize maxsize, GstMapFlags flags)
{
GstEGLImageMemory *mem;
gint i;
g_return_val_if_fail (strcmp (gmem->allocator->mem_type,
GST_EGL_IMAGE_MEMORY_NAME) == 0, FALSE);
mem = GST_EGL_IMAGE_MEMORY (gmem);
g_mutex_lock (&mem->lock);
for (i = 0; i < mem->n_textures; i++) {
if (mem->memory_refcount[i]) {
/* Only multiple READ maps are allowed */
if ((mem->memory_flags[i] & GST_MAP_WRITE)) {
g_mutex_unlock (&mem->lock);
return NULL;
}
}
}
if (!mem->mapped_memory_refcount) {
EGLint attribs[] = {
MALI_EGL_IMAGE_PLANE, MALI_EGL_IMAGE_PLANE_Y,
MALI_EGL_IMAGE_ACCESS_MODE, MALI_EGL_IMAGE_ACCESS_READ_ONLY,
EGL_NONE
};
GstVideoInfo info;
mali_egl_image *mali_egl_image;
guint8 *plane_memory, *p;
gint stride, h;
gint j;
gst_video_info_set_format (&info, mem->format, mem->width, mem->height);
mem->mapped_memory = g_malloc (mem->parent.size);
for (i = 0; i < mem->n_textures; i++) {
mali_egl_image = mali_egl_image_lock_ptr (mem->image[i]);
if (!mali_egl_image) {
g_free (mem->mapped_memory);
GST_ERROR ("Failed to lock Mali EGL image: 0x%04x",
mali_egl_image_get_error ());
g_mutex_unlock (&mem->lock);
return NULL;
}
plane_memory = mali_egl_image_map_buffer (mali_egl_image, attribs);
if (!plane_memory) {
mali_egl_image_unlock_ptr (mem->image[i]);
g_free (mem->mapped_memory);
GST_ERROR ("Failed to lock Mali map image: 0x%04x",
mali_egl_image_get_error ());
g_mutex_unlock (&mem->lock);
return NULL;
}
p = ((guint8 *) mem->mapped_memory) + mem->offset[i];
stride = mem->stride[i];
h = GST_VIDEO_INFO_COMP_HEIGHT (&info, i);
for (j = 0; j < h; j++) {
memcpy (p, plane_memory, stride);
p += mem->stride[i];
plane_memory += mem->stride[i];
}
mali_egl_image_unmap_buffer (mem->image[i], attribs);
mali_egl_image_unlock_ptr (mem->image[i]);
}
} else {
/* Only multiple READ maps are allowed */
if ((mem->mapped_memory_flags & GST_MAP_WRITE)) {
g_mutex_unlock (&mem->lock);
return NULL;
}
}
mem->mapped_memory_refcount++;
g_mutex_unlock (&mem->lock);
return mem->mapped_memory;
}
static void
eglimage_unmap (GstMemory * gmem)
{
GstEGLImageMemory *mem;
gint i;
g_return_if_fail (strcmp (gmem->allocator->mem_type,
GST_EGL_IMAGE_MEMORY_NAME) == 0);
mem = GST_EGL_IMAGE_MEMORY (gmem);
g_return_if_fail (mem->mapped_memory);
g_mutex_lock (&mem->lock);
mem->mapped_memory_refcount--;
if (mem->mapped_memory_refcount > 0) {
g_mutex_unlock (&mem->lock);
return;
}
/* Write back */
if ((mem->mapped_memory_flags & GST_MAP_WRITE)) {
EGLint attribs[] = {
MALI_EGL_IMAGE_PLANE, MALI_EGL_IMAGE_PLANE_Y,
MALI_EGL_IMAGE_ACCESS_MODE, MALI_EGL_IMAGE_ACCESS_WRITE_ONLY,
EGL_NONE
};
GstVideoInfo info;
mali_egl_image *mali_egl_image;
guint8 *plane_memory, *p;
gint stride, h;
gint j;
gst_video_info_set_format (&info, mem->format, mem->width, mem->height);
for (i = 0; i < mem->n_textures; i++) {
mali_egl_image = mali_egl_image_lock_ptr (mem->image[i]);
if (!mali_egl_image) {
g_free (mem->mapped_memory);
GST_ERROR ("Failed to lock Mali EGL image: 0x%04x",
mali_egl_image_get_error ());
g_mutex_unlock (&mem->lock);
return;
}
plane_memory = mali_egl_image_map_buffer (mali_egl_image, attribs);
if (!plane_memory) {
mali_egl_image_unlock_ptr (mem->image[i]);
g_free (mem->mapped_memory);
GST_ERROR ("Failed to lock Mali map image: 0x%04x",
mali_egl_image_get_error ());
g_mutex_unlock (&mem->lock);
return;
}
p = ((guint8 *) mem->mapped_memory) + mem->offset[i];
stride = mem->stride[i];
h = GST_VIDEO_INFO_COMP_HEIGHT (&info, i);
for (j = 0; j < h; j++) {
memcpy (plane_memory, p, stride);
p += mem->stride[i];
plane_memory += mem->stride[i];
}
mali_egl_image_unmap_buffer (mem->image[i], attribs);
mali_egl_image_unlock_ptr (mem->image[i]);
}
}
g_free (mem->mapped_memory);
g_mutex_unlock (&mem->lock);
}
static gboolean
eglimage_video_map (GstVideoMeta * meta, guint plane,
GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
{
GstMemory *gmem;
GstEGLImageMemory *mem;
GstVideoInfo vinfo;
if (gst_buffer_n_memory (meta->buffer) != 1)
return default_map_video (meta, plane, info, data, stride, flags);
gmem = gst_buffer_peek_memory (meta->buffer, 0);
if (strcmp (gmem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_NAME) != 0)
return default_map_video (meta, plane, info, data, stride, flags);
mem = GST_EGL_IMAGE_MEMORY ((gmem->parent ? gmem->parent : gmem));
g_mutex_lock (&mem->lock);
if (mem->format == GST_VIDEO_FORMAT_YV12) {
if (plane == 1)
plane = 2;
else if (plane == 2)
plane = 1;
}
if (mem->mapped_memory_refcount) {
/* Only multiple READ maps are allowed */
if ((mem->mapped_memory_flags & GST_MAP_WRITE)) {
g_mutex_unlock (&mem->lock);
return FALSE;
}
}
if (!mem->memory_refcount[plane]) {
EGLint attribs[] = {
MALI_EGL_IMAGE_PLANE, MALI_EGL_IMAGE_PLANE_Y,
MALI_EGL_IMAGE_ACCESS_MODE, MALI_EGL_IMAGE_ACCESS_READ_WRITE,
EGL_NONE
};
if ((flags & GST_MAP_READ) && (flags & GST_MAP_WRITE))
attribs[3] = MALI_EGL_IMAGE_ACCESS_READ_WRITE;
else if ((flags & GST_MAP_READ))
attribs[3] = MALI_EGL_IMAGE_ACCESS_READ_ONLY;
else if ((flags & GST_MAP_WRITE))
attribs[3] = MALI_EGL_IMAGE_ACCESS_WRITE_ONLY;
mem->memory_platform_data[plane] =
mali_egl_image_lock_ptr (mem->image[plane]);
if (!mem->memory_platform_data[plane]) {
GST_ERROR ("Failed to lock Mali EGL image: 0x%04x",
mali_egl_image_get_error ());
goto map_error;
}
mem->memory[plane] =
mali_egl_image_map_buffer (mem->memory_platform_data[plane], attribs);
if (!mem->memory[plane])
goto map_error;
mem->memory_flags[plane] = flags;
} else {
/* Only multiple READ maps are allowed */
if ((mem->memory_flags[plane] & GST_MAP_WRITE)) {
g_mutex_unlock (&mem->lock);
return FALSE;
}
}
mem->memory_refcount[plane]++;
gst_video_info_set_format (&vinfo, mem->format, mem->width, mem->height);
*data = mem->memory[plane];
*stride = mem->stride[plane];
g_mutex_unlock (&mem->lock);
return TRUE;
map_error:
{
EGLint attribs[] = {
MALI_EGL_IMAGE_PLANE, MALI_EGL_IMAGE_PLANE_Y,
EGL_NONE
};
GST_ERROR ("Failed to map Mali EGL image: 0x%04x",
mali_egl_image_get_error ());
if (mem->memory_platform_data[plane]) {
mali_egl_image_unmap_buffer (mem->image[plane], attribs);
mali_egl_image_unlock_ptr (mem->image[plane]);
}
mem->memory[plane] = NULL;
mem->memory_platform_data[plane] = NULL;
g_mutex_unlock (&mem->lock);
return FALSE;
}
}
static gboolean
eglimage_video_unmap (GstVideoMeta * meta, guint plane, GstMapInfo * info)
{
GstMemory *gmem;
GstEGLImageMemory *mem;
EGLint attribs[] = {
MALI_EGL_IMAGE_PLANE, MALI_EGL_IMAGE_PLANE_Y,
EGL_NONE
};
if (gst_buffer_n_memory (meta->buffer) != 1)
return default_unmap_video (meta, plane, info);
gmem = gst_buffer_peek_memory (meta->buffer, 0);
if (strcmp (gmem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_NAME) != 0)
return default_unmap_video (meta, plane, info);
mem = GST_EGL_IMAGE_MEMORY ((gmem->parent ? gmem->parent : gmem));
g_mutex_lock (&mem->lock);
if (mem->format == GST_VIDEO_FORMAT_YV12) {
if (plane == 1)
plane = 2;
else if (plane == 2)
plane = 1;
}
if (!mem->memory_refcount[plane]) {
g_mutex_unlock (&mem->lock);
g_return_val_if_reached (FALSE);
}
mem->memory_refcount[plane]--;
if (mem->memory_refcount[plane] > 0) {
g_mutex_unlock (&mem->lock);
return TRUE;
}
/* Unmaps automatically */
if (mem->memory_platform_data[plane]) {
mali_egl_image_unmap_buffer (mem->image[plane], attribs);
mali_egl_image_unlock_ptr (mem->image[plane]);
}
mem->memory[plane] = NULL;
mem->memory_platform_data[plane] = NULL;
g_mutex_unlock (&mem->lock);
return TRUE;
}
gboolean
platform_can_map_eglimage (GstMemoryMapFunction * map,
GstMemoryUnmapFunction * unmap, PlatformMapVideo * video_map,
PlatformUnmapVideo * video_unmap)
{
*map = eglimage_map;
*unmap = eglimage_unmap;
*video_map = eglimage_video_map;
*video_unmap = eglimage_video_unmap;
return TRUE;
}
gboolean
platform_has_custom_eglimage_alloc (void)
{
return TRUE;
}
gboolean
platform_alloc_eglimage (EGLDisplay display, EGLContext context, GLint format,
GLint type, gint width, gint height, GLuint tex_id, EGLImageKHR * image,
gpointer * image_platform_data)
{
fbdev_pixmap pixmap;
pixmap.flags = FBDEV_PIXMAP_SUPPORTS_UMP;
pixmap.width = width;
pixmap.height = height;
switch (format) {
case GL_LUMINANCE:
g_return_val_if_fail (type == GL_UNSIGNED_BYTE, FALSE);
pixmap.red_size = 0;
pixmap.green_size = 0;
pixmap.blue_size = 0;
pixmap.alpha_size = 0;
pixmap.luminance_size = 8;
break;
case GL_LUMINANCE_ALPHA:
g_return_val_if_fail (type == GL_UNSIGNED_BYTE, FALSE);
pixmap.red_size = 0;
pixmap.green_size = 0;
pixmap.blue_size = 0;
pixmap.alpha_size = 8;
pixmap.luminance_size = 8;
break;
case GL_RGB:
if (type == GL_UNSIGNED_BYTE) {
pixmap.red_size = 8;
pixmap.green_size = 8;
pixmap.blue_size = 8;
pixmap.alpha_size = 0;
pixmap.luminance_size = 0;
} else if (type == GL_UNSIGNED_SHORT_5_6_5) {
pixmap.red_size = 5;
pixmap.green_size = 6;
pixmap.blue_size = 5;
pixmap.alpha_size = 0;
pixmap.luminance_size = 0;
} else {
g_return_val_if_reached (FALSE);
}
break;
case GL_RGBA:
g_return_val_if_fail (type == GL_UNSIGNED_BYTE, FALSE);
pixmap.red_size = 8;
pixmap.green_size = 8;
pixmap.blue_size = 8;
pixmap.alpha_size = 8;
pixmap.luminance_size = 0;
break;
default:
g_assert_not_reached ();
return FALSE;
}
pixmap.buffer_size =
pixmap.red_size + pixmap.green_size + pixmap.blue_size +
pixmap.alpha_size + pixmap.luminance_size;
pixmap.bytes_per_pixel = pixmap.buffer_size / 8;
pixmap.format = 0;
if (ump_open () != UMP_OK) {
GST_ERROR ("Failed to open UMP");
return FALSE;
}
pixmap.data =
ump_ref_drv_allocate (GST_ROUND_UP_4 (pixmap.width) * pixmap.height *
pixmap.bytes_per_pixel, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR);
if (pixmap.data == UMP_INVALID_MEMORY_HANDLE) {
GST_ERROR ("Failed to allocate pixmap data via UMP");
ump_close ();
return FALSE;
}
*image_platform_data = g_slice_dup (fbdev_pixmap, &pixmap);
*image =
eglCreateImageKHR (display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer) * image_platform_data, NULL);
if (!image) {
GST_ERROR ("Failed to create EGLImage for pixmap");
ump_reference_release ((ump_handle) pixmap.data);
ump_close ();
g_slice_free (fbdev_pixmap, *image_platform_data);
return FALSE;
}
return TRUE;
}
void
platform_free_eglimage (EGLDisplay display, EGLContext context, GLuint tex_id,
EGLImageKHR * image, gpointer * image_platform_data)
{
fbdev_pixmap *pixmap = *image_platform_data;
eglDestroyImageKHR (display, *image);
ump_reference_release ((ump_handle) pixmap->data);
ump_close ();
g_slice_free (fbdev_pixmap, *image_platform_data);
}
#endif
#endif
#ifdef USE_EGL_RPI
#include <bcm_host.h>
#include <gst/video/gstvideosink.h>
typedef struct
{
EGL_DISPMANX_WINDOW_T w;
DISPMANX_DISPLAY_HANDLE_T d;
} RPIWindowData;
EGLNativeWindowType
platform_create_native_window (gint width, gint height, gpointer * window_data)
{
DISPMANX_ELEMENT_HANDLE_T dispman_element;
DISPMANX_DISPLAY_HANDLE_T dispman_display;
DISPMANX_UPDATE_HANDLE_T dispman_update;
RPIWindowData *data;
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
GstVideoRectangle src, dst, res;
uint32_t dp_height;
uint32_t dp_width;
int ret;
ret = graphics_get_display_size (0, &dp_width, &dp_height);
if (ret < 0) {
GST_ERROR ("Can't open display");
return (EGLNativeWindowType) 0;
}
GST_DEBUG ("Got display size: %dx%d\n", dp_width, dp_height);
GST_DEBUG ("Source size: %dx%d\n", width, height);
/* Center width*height frame inside dp_width*dp_height */
src.w = width;
src.h = height;
src.x = src.y = 0;
dst.w = dp_width;
dst.h = dp_height;
dst.x = dst.y = 0;
gst_video_sink_center_rect (src, dst, &res, TRUE);
dst_rect.x = res.x;
dst_rect.y = res.y;
dst_rect.width = res.w;
dst_rect.height = res.h;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = width << 16;
src_rect.height = height << 16;
dispman_display = vc_dispmanx_display_open (0);
dispman_update = vc_dispmanx_update_start (0);
dispman_element = vc_dispmanx_element_add (dispman_update,
dispman_display, 0, &dst_rect, 0, &src_rect,
DISPMANX_PROTECTION_NONE, 0, 0, 0);
*window_data = data = g_slice_new0 (RPIWindowData);
data->d = dispman_display;
data->w.element = dispman_element;
data->w.width = width;
data->w.height = height;
vc_dispmanx_update_submit_sync (dispman_update);
return (EGLNativeWindowType) data;
}
gboolean
platform_destroy_native_window (EGLNativeDisplayType display,
EGLNativeWindowType window, gpointer * window_data)
{
DISPMANX_DISPLAY_HANDLE_T dispman_display;
DISPMANX_UPDATE_HANDLE_T dispman_update;
RPIWindowData *data = *window_data;
dispman_display = data->d;
dispman_update = vc_dispmanx_update_start (0);
vc_dispmanx_element_remove (dispman_update, data->w.element);
vc_dispmanx_update_submit_sync (dispman_update);
vc_dispmanx_display_close (dispman_display);
g_slice_free (RPIWindowData, data);
*window_data = NULL;
return TRUE;
}
#endif
#if !defined(USE_EGL_X11) && !defined(USE_EGL_MALI_FB) && !defined(USE_EGL_RPI)
/* Dummy functions for creating a native Window */
EGLNativeWindowType
platform_create_native_window (gint width, gint height, gpointer * window_data)
{
GST_ERROR ("Can't create native window");
return (EGLNativeWindowType) 0;
}
gboolean
platform_destroy_native_window (EGLNativeDisplayType display,
EGLNativeWindowType window, gpointer * window_data)
{
GST_ERROR ("Can't destroy native window");
return TRUE;
}
#endif

View file

@ -1,61 +0,0 @@
/*
* GStreamer Android Video Platform Wrapper
* Copyright (C) 2012 Collabora Ltd.
* @author: Reynaldo H. Verdejo Pinochet <reynaldo@collabora.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Alternatively, the contents of this file may be used under the
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
* which case the following provisions apply instead of the ones
* mentioned above:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* General idea is to have all platform dependent code here for easy
* tweaking and isolation from the main routines
*/
#ifndef __GST_VIDEO_PLATFORM_WRAPPER__
#define __GST_VIDEO_PLATFORM_WRAPPER__
#include <gst/gst.h>
#include <EGL/egl.h>
gboolean platform_wrapper_init (void);
EGLNativeWindowType platform_create_native_window (gint width, gint height, gpointer * window_data);
gboolean platform_destroy_native_window (EGLNativeDisplayType display,
EGLNativeWindowType w, gpointer * window_data);
#endif

View file

@ -1,6 +1,3 @@
if HAVE_EGL
EGL_DIR = egl
endif
if USE_OPENGL
GL_DIR = gl
@ -10,8 +7,8 @@ GL_DIR = gl
endif
SUBDIRS = interfaces basecamerabinsrc codecparsers \
insertbin uridownloader mpegts $(EGL_DIR) $(GL_DIR)
insertbin uridownloader mpegts $(GL_DIR)
noinst_HEADERS = gst-i18n-plugin.h gettext.h glib-compat-private.h
DIST_SUBDIRS = interfaces egl gl basecamerabinsrc codecparsers \
DIST_SUBDIRS = interfaces gl basecamerabinsrc codecparsers \
insertbin uridownloader mpegts

View file

@ -1,95 +0,0 @@
lib_LTLIBRARIES = libgstegl-@GST_API_VERSION@.la
libgstegl_@GST_API_VERSION@_la_SOURCES = egl.c
libgstegl_@GST_API_VERSION@includedir = \
$(includedir)/gstreamer-@GST_API_VERSION@/gst/egl
libgstegl_@GST_API_VERSION@include_HEADERS = egl.h
libgstegl_@GST_API_VERSION@_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_CFLAGS) \
$(EGL_CFLAGS)
libgstegl_@GST_API_VERSION@_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) \
-lgstvideo-@GST_API_VERSION@ \
$(GST_LIBS) \
$(EGL_LIBS)
libgstegl_@GST_API_VERSION@_la_LDFLAGS = \
$(GST_LIB_LDFLAGS) \
$(GST_ALL_LDFLAGS) \
$(GST_LT_LDFLAGS)
if HAVE_INTROSPECTION
BUILT_GIRSOURCES = GstEGL-@GST_API_VERSION@.gir
gir_headers=$(patsubst %,$(srcdir)/%, $(libgstegl_@GST_API_VERSION@include_HEADERS))
gir_headers+=$(patsubst %,$(builddir)/%, $(built_headers))
gir_sources=$(patsubst %,$(srcdir)/%, $(libgstegl_@GST_API_VERSION@_la_SOURCES))
gir_sources+=$(patsubst %,$(builddir)/%, $(built_sources))
GstEGL-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstegl-@GST_API_VERSION@.la
$(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \
GST_PLUGIN_SYSTEM_PATH_1_0="" GST_PLUGIN_PATH_1_0="" GST_REGISTRY_UPDATE=no \
$(INTROSPECTION_SCANNER) -v --namespace GstEGL \
--nsversion=@GST_API_VERSION@ \
--strip-prefix=Gst \
--warn-all \
--c-include "gst/egl/egl.h" \
-I$(top_srcdir)/gst-libs \
-I$(top_builddir)/gst-libs \
--add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \
--add-include-path=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-video-@GST_API_VERSION@` \
--library=libgstegl-@GST_API_VERSION@.la \
--include=Gst-@GST_API_VERSION@ \
--libtool="$(top_builddir)/libtool" \
--pkg gstreamer-@GST_API_VERSION@ \
--pkg gstreamer-video-@GST_API_VERSION@ \
--pkg-export gstreamer-egl-@GST_API_VERSION@ \
--add-init-section="gst_init(NULL,NULL);" \
-DGST_USE_UNSTABLE_API \
--output $@ \
$(gir_headers) \
$(gir_sources)
# INTROSPECTION_GIRDIR/INTROSPECTION_TYPELIBDIR aren't the right place to
# install anything - we need to install inside our prefix.
girdir = $(datadir)/gir-1.0
gir_DATA = $(BUILT_GIRSOURCES)
typelibsdir = $(libdir)/girepository-1.0/
typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
%.typelib: %.gir $(INTROSPECTION_COMPILER)
$(AM_V_GEN)PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" \
$(INTROSPECTION_COMPILER) \
--includedir=$(srcdir) \
--includedir=$(builddir) \
--includedir=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-@GST_API_VERSION@` \
--includedir=`PKG_CONFIG_PATH="$(GST_PKG_CONFIG_PATH)" $(PKG_CONFIG) --variable=girdir gstreamer-base-@GST_API_VERSION@` \
$(INTROSPECTION_COMPILER_OPTS) $< -o $(@F)
CLEANFILES = $(BUILT_GIRSOURCES) $(typelibs_DATA)
endif
Android.mk: $(BUILT_SOURCES) Makefile.am
androgenizer -:PROJECT libgstegl -:STATIC libgstegl-@GST_API_VERSION@ \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstegl_@GST_API_VERSION@_la_SOURCES) \
$(built_sources) \
-:CFLAGS $(DEFS) $(libgstegl_@GST_API_VERSION@_la_CFLAGS) \
-:LDFLAGS $(libgstegl_@GST_API_VERSION@_la_LDFLAGS) \
$(libgstegl@GST_API_VERSION@_la_LIBADD) \
-ldl \
-:HEADER_TARGET gstreamer-@GST_API_VERSION@/gst/egl \
-:HEADERS $(libgsteglinclude_HEADERS) \
$(built_headers) \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
> $@

View file

@ -1,624 +0,0 @@
/*
* GStreamer EGL Library
* Copyright (C) 2012 Collabora Ltd.
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined (USE_EGL_RPI) && defined(__GNUC__)
#ifndef __VCCOREVER__
#define __VCCOREVER__ 0x04000000
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
#pragma GCC optimize ("gnu89-inline")
#endif
#define EGL_EGLEXT_PROTOTYPES
#include <gst/egl/egl.h>
#include <string.h>
#if defined (USE_EGL_RPI) && defined(__GNUC__)
#pragma GCC reset_options
#pragma GCC diagnostic pop
#endif
typedef struct
{
GstMemory parent;
GstEGLDisplay *display;
EGLImageKHR image;
GstVideoGLTextureType type;
GstVideoGLTextureOrientation orientation;
gpointer user_data;
GDestroyNotify user_data_destroy;
} GstEGLImageMemory;
#define GST_EGL_IMAGE_MEMORY(mem) ((GstEGLImageMemory*)(mem))
gboolean
gst_egl_image_memory_is_mappable (void)
{
return FALSE;
}
gboolean
gst_is_egl_image_memory (GstMemory * mem)
{
g_return_val_if_fail (mem != NULL, FALSE);
g_return_val_if_fail (mem->allocator != NULL, FALSE);
return g_strcmp0 (mem->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0;
}
EGLImageKHR
gst_egl_image_memory_get_image (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem), EGL_NO_IMAGE_KHR);
if (mem->parent)
mem = mem->parent;
return GST_EGL_IMAGE_MEMORY (mem)->image;
}
GstEGLDisplay *
gst_egl_image_memory_get_display (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem), NULL);
if (mem->parent)
mem = mem->parent;
return gst_egl_display_ref (GST_EGL_IMAGE_MEMORY (mem)->display);
}
GstVideoGLTextureType
gst_egl_image_memory_get_type (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem), -1);
if (mem->parent)
mem = mem->parent;
return GST_EGL_IMAGE_MEMORY (mem)->type;
}
GstVideoGLTextureOrientation
gst_egl_image_memory_get_orientation (GstMemory * mem)
{
g_return_val_if_fail (gst_is_egl_image_memory (mem),
GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL);
if (mem->parent)
mem = mem->parent;
return GST_EGL_IMAGE_MEMORY (mem)->orientation;
}
void
gst_egl_image_memory_set_orientation (GstMemory * mem,
GstVideoGLTextureOrientation orientation)
{
g_return_if_fail (gst_is_egl_image_memory (mem));
if (mem->parent)
mem = mem->parent;
GST_EGL_IMAGE_MEMORY (mem)->orientation = orientation;
}
static GstMemory *
gst_egl_image_allocator_alloc_vfunc (GstAllocator * allocator, gsize size,
GstAllocationParams * params)
{
g_warning
("Use gst_egl_image_allocator_alloc() to allocate from this allocator");
return NULL;
}
static void
gst_egl_image_allocator_free_vfunc (GstAllocator * allocator, GstMemory * mem)
{
GstEGLImageMemory *emem = (GstEGLImageMemory *) mem;
EGLDisplay display;
g_return_if_fail (gst_is_egl_image_memory (mem));
/* Shared memory should not destroy all the data */
if (!mem->parent) {
display = gst_egl_display_get (emem->display);
eglDestroyImageKHR (display, emem->image);
if (emem->user_data_destroy)
emem->user_data_destroy (emem->user_data);
gst_egl_display_unref (emem->display);
}
g_slice_free (GstEGLImageMemory, emem);
}
static gpointer
gst_egl_image_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
{
return NULL;
}
static void
gst_egl_image_mem_unmap (GstMemory * mem)
{
}
static GstMemory *
gst_egl_image_mem_share (GstMemory * mem, gssize offset, gssize size)
{
GstMemory *sub;
GstMemory *parent;
if (offset != 0)
return NULL;
if (size != -1 && size != mem->size)
return NULL;
/* find the real parent */
if ((parent = mem->parent) == NULL)
parent = (GstMemory *) mem;
if (size == -1)
size = mem->size - offset;
sub = (GstMemory *) g_slice_new (GstEGLImageMemory);
/* the shared memory is always readonly */
gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->allocator, parent,
mem->maxsize, mem->align, mem->offset + offset, size);
return sub;
}
static GstMemory *
gst_egl_image_mem_copy (GstMemory * mem, gssize offset, gssize size)
{
return NULL;
}
static gboolean
gst_egl_image_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
{
return FALSE;
}
typedef GstAllocator GstEGLImageAllocator;
typedef GstAllocatorClass GstEGLImageAllocatorClass;
GType gst_egl_image_allocator_get_type (void);
G_DEFINE_TYPE (GstEGLImageAllocator, gst_egl_image_allocator,
GST_TYPE_ALLOCATOR);
#define GST_TYPE_EGL_IMAGE_ALLOCATOR (gst_egl_image_mem_allocator_get_type())
#define GST_IS_EGL_IMAGE_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EGL_IMAGE_ALLOCATOR))
static void
gst_egl_image_allocator_class_init (GstEGLImageAllocatorClass * klass)
{
GstAllocatorClass *allocator_class = (GstAllocatorClass *) klass;
allocator_class->alloc = gst_egl_image_allocator_alloc_vfunc;
allocator_class->free = gst_egl_image_allocator_free_vfunc;
}
static void
gst_egl_image_allocator_init (GstEGLImageAllocator * allocator)
{
GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
alloc->mem_type = GST_EGL_IMAGE_MEMORY_TYPE;
alloc->mem_map = gst_egl_image_mem_map;
alloc->mem_unmap = gst_egl_image_mem_unmap;
alloc->mem_share = gst_egl_image_mem_share;
alloc->mem_copy = gst_egl_image_mem_copy;
alloc->mem_is_span = gst_egl_image_mem_is_span;
GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
}
static gpointer
gst_egl_image_allocator_init_instance (gpointer data)
{
return g_object_new (gst_egl_image_allocator_get_type (), NULL);
}
GstAllocator *
gst_egl_image_allocator_obtain (void)
{
static GOnce once = G_ONCE_INIT;
g_once (&once, gst_egl_image_allocator_init_instance, NULL);
g_return_val_if_fail (once.retval != NULL, NULL);
return GST_ALLOCATOR (g_object_ref (once.retval));
}
GstMemory *
gst_egl_image_allocator_alloc (GstAllocator * allocator,
GstEGLDisplay * display, GstVideoGLTextureType type, gint width,
gint height, gsize * size)
{
return NULL;
}
GstMemory *
gst_egl_image_allocator_wrap (GstAllocator * allocator,
GstEGLDisplay * display, EGLImageKHR image, GstVideoGLTextureType type,
GstMemoryFlags flags, gsize size, gpointer user_data,
GDestroyNotify user_data_destroy)
{
GstEGLImageMemory *mem;
g_return_val_if_fail (display != NULL, NULL);
g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
if (!allocator) {
allocator = gst_egl_image_allocator_obtain ();
}
mem = g_slice_new (GstEGLImageMemory);
gst_memory_init (GST_MEMORY_CAST (mem), flags,
allocator, NULL, size, 0, 0, size);
mem->display = gst_egl_display_ref (display);
mem->image = image;
mem->type = type;
mem->orientation = GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL;
mem->user_data = user_data;
mem->user_data_destroy = user_data_destroy;
return GST_MEMORY_CAST (mem);
}
GstContext *
gst_context_new_egl_display (GstEGLDisplay * display, gboolean persistent)
{
GstContext *context;
GstStructure *s;
context = gst_context_new (GST_EGL_DISPLAY_CONTEXT_TYPE, persistent);
s = gst_context_writable_structure (context);
gst_structure_set (s, "display", GST_TYPE_EGL_DISPLAY, display, NULL);
return context;
}
gboolean
gst_context_get_egl_display (GstContext * context, GstEGLDisplay ** display)
{
const GstStructure *s;
g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (strcmp (gst_context_get_context_type (context),
GST_EGL_DISPLAY_CONTEXT_TYPE) == 0, FALSE);
s = gst_context_get_structure (context);
return gst_structure_get (s, "display", GST_TYPE_EGL_DISPLAY, display, NULL);
}
struct _GstEGLDisplay
{
EGLDisplay display;
volatile gint refcount;
GDestroyNotify destroy_notify;
};
GstEGLDisplay *
gst_egl_display_new (EGLDisplay display, GDestroyNotify destroy_notify)
{
GstEGLDisplay *gdisplay;
gdisplay = g_slice_new (GstEGLDisplay);
gdisplay->display = display;
gdisplay->refcount = 1;
gdisplay->destroy_notify = destroy_notify;
return gdisplay;
}
GstEGLDisplay *
gst_egl_display_ref (GstEGLDisplay * display)
{
g_return_val_if_fail (display != NULL, NULL);
g_atomic_int_inc (&display->refcount);
return display;
}
void
gst_egl_display_unref (GstEGLDisplay * display)
{
g_return_if_fail (display != NULL);
if (g_atomic_int_dec_and_test (&display->refcount)) {
if (display->destroy_notify)
display->destroy_notify (display->display);
g_slice_free (GstEGLDisplay, display);
}
}
EGLDisplay
gst_egl_display_get (GstEGLDisplay * display)
{
g_return_val_if_fail (display != NULL, EGL_NO_DISPLAY);
return display->display;
}
G_DEFINE_BOXED_TYPE (GstEGLDisplay, gst_egl_display,
(GBoxedCopyFunc) gst_egl_display_ref,
(GBoxedFreeFunc) gst_egl_display_unref);
struct _GstEGLImageBufferPoolPrivate
{
GstAllocator *allocator;
GstAllocationParams params;
GstVideoInfo info;
gboolean add_metavideo;
gboolean want_eglimage;
GstBuffer *last_buffer;
GstEGLImageBufferPoolSendBlockingAllocate send_blocking_allocate_func;
gpointer send_blocking_allocate_data;
GDestroyNotify send_blocking_allocate_destroy;
};
G_DEFINE_TYPE (GstEGLImageBufferPool, gst_egl_image_buffer_pool,
GST_TYPE_VIDEO_BUFFER_POOL);
GstBufferPool *
gst_egl_image_buffer_pool_new (GstEGLImageBufferPoolSendBlockingAllocate
blocking_allocate_func, gpointer blocking_allocate_data,
GDestroyNotify destroy_func)
{
GstEGLImageBufferPool *pool =
g_object_new (GST_TYPE_EGL_IMAGE_BUFFER_POOL, NULL);
GstEGLImageBufferPoolPrivate *priv =
G_TYPE_INSTANCE_GET_PRIVATE (pool, GST_TYPE_EGL_IMAGE_BUFFER_POOL,
GstEGLImageBufferPoolPrivate);
pool->priv = priv;
priv->allocator = NULL;
priv->last_buffer = NULL;
priv->send_blocking_allocate_func = blocking_allocate_func;
priv->send_blocking_allocate_data = blocking_allocate_data;
priv->send_blocking_allocate_destroy = destroy_func;
return (GstBufferPool *) pool;
}
void
gst_egl_image_buffer_pool_replace_last_buffer (GstEGLImageBufferPool * pool,
GstBuffer * buffer)
{
g_return_if_fail (pool != NULL);
gst_buffer_replace (&pool->priv->last_buffer, buffer);
}
static const gchar **
gst_egl_image_buffer_pool_get_options (GstBufferPool * bpool)
{
static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL
};
return options;
}
static gboolean
gst_egl_image_buffer_pool_set_config (GstBufferPool * bpool,
GstStructure * config)
{
GstEGLImageBufferPool *pool = GST_EGL_IMAGE_BUFFER_POOL (bpool);
GstEGLImageBufferPoolPrivate *priv = pool->priv;
GstCaps *caps;
GstVideoInfo info;
if (priv->allocator)
gst_object_unref (priv->allocator);
priv->allocator = NULL;
if (!GST_BUFFER_POOL_CLASS
(gst_egl_image_buffer_pool_parent_class)->set_config (bpool, config))
return FALSE;
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)
|| !caps)
return FALSE;
if (!gst_video_info_from_caps (&info, caps))
return FALSE;
if (!gst_buffer_pool_config_get_allocator (config, &priv->allocator,
&priv->params))
return FALSE;
if (priv->allocator)
gst_object_ref (priv->allocator);
priv->add_metavideo =
gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
priv->want_eglimage = (priv->allocator
&& g_strcmp0 (priv->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0);
priv->info = info;
return TRUE;
}
static GstFlowReturn
gst_egl_image_buffer_pool_alloc_buffer (GstBufferPool * bpool,
GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
{
GstEGLImageBufferPool *pool = GST_EGL_IMAGE_BUFFER_POOL (bpool);
GstEGLImageBufferPoolPrivate *priv = pool->priv;
*buffer = NULL;
if (!priv->add_metavideo || !priv->want_eglimage)
return
GST_BUFFER_POOL_CLASS
(gst_egl_image_buffer_pool_parent_class)->alloc_buffer (bpool,
buffer, params);
if (!priv->allocator)
return GST_FLOW_NOT_NEGOTIATED;
switch (priv->info.finfo->format) {
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:
case GST_VIDEO_FORMAT_RGB16:
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_NV21:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_AYUV:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:{
if (priv->send_blocking_allocate_func)
*buffer = priv->send_blocking_allocate_func (bpool,
priv->send_blocking_allocate_data);
if (!*buffer) {
GST_WARNING ("Fallback memory allocation");
return
GST_BUFFER_POOL_CLASS
(gst_egl_image_buffer_pool_parent_class)->alloc_buffer (bpool,
buffer, params);
}
return GST_FLOW_OK;
break;
}
default:
return
GST_BUFFER_POOL_CLASS
(gst_egl_image_buffer_pool_parent_class)->alloc_buffer (bpool,
buffer, params);
break;
}
return GST_FLOW_ERROR;
}
static GstFlowReturn
gst_egl_image_buffer_pool_acquire_buffer (GstBufferPool * bpool,
GstBuffer ** buffer, GstBufferPoolAcquireParams * params)
{
GstFlowReturn ret;
GstEGLImageBufferPool *pool;
ret =
GST_BUFFER_POOL_CLASS
(gst_egl_image_buffer_pool_parent_class)->acquire_buffer (bpool,
buffer, params);
if (ret != GST_FLOW_OK || !*buffer)
return ret;
pool = GST_EGL_IMAGE_BUFFER_POOL (bpool);
/* XXX: Don't return the memory we just rendered, glEGLImageTargetTexture2DOES()
* keeps the EGLImage unmappable until the next one is uploaded
*/
if (*buffer && *buffer == pool->priv->last_buffer) {
GstBuffer *oldbuf = *buffer;
ret =
GST_BUFFER_POOL_CLASS
(gst_egl_image_buffer_pool_parent_class)->acquire_buffer (bpool,
buffer, params);
gst_object_replace ((GstObject **) & oldbuf->pool, (GstObject *) pool);
gst_buffer_unref (oldbuf);
}
return ret;
}
static void
gst_egl_image_buffer_pool_finalize (GObject * object)
{
GstEGLImageBufferPool *pool = GST_EGL_IMAGE_BUFFER_POOL (object);
GstEGLImageBufferPoolPrivate *priv = pool->priv;
if (priv->allocator)
gst_object_unref (priv->allocator);
priv->allocator = NULL;
gst_egl_image_buffer_pool_replace_last_buffer (pool, NULL);
if (priv->send_blocking_allocate_destroy)
priv->send_blocking_allocate_destroy (priv->send_blocking_allocate_data);
priv->send_blocking_allocate_destroy = NULL;
priv->send_blocking_allocate_data = NULL;
G_OBJECT_CLASS (gst_egl_image_buffer_pool_parent_class)->finalize (object);
}
static void
gst_egl_image_buffer_pool_class_init (GstEGLImageBufferPoolClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
g_type_class_add_private (klass, sizeof (GstEGLImageBufferPoolPrivate));
gobject_class->finalize = gst_egl_image_buffer_pool_finalize;
gstbufferpool_class->get_options = gst_egl_image_buffer_pool_get_options;
gstbufferpool_class->set_config = gst_egl_image_buffer_pool_set_config;
gstbufferpool_class->alloc_buffer = gst_egl_image_buffer_pool_alloc_buffer;
gstbufferpool_class->acquire_buffer =
gst_egl_image_buffer_pool_acquire_buffer;
}
static void
gst_egl_image_buffer_pool_init (GstEGLImageBufferPool * pool)
{
}

View file

@ -1,110 +0,0 @@
/*
* GStreamer EGL Library
* Copyright (C) 2012 Collabora Ltd.
* @author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
* *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_EGL_H__
#define __GST_EGL_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
G_BEGIN_DECLS
#define GST_EGL_IMAGE_MEMORY_TYPE "EGLImage"
#define GST_CAPS_FEATURE_MEMORY_EGL_IMAGE "memory:EGLImage"
typedef struct _GstEGLDisplay GstEGLDisplay;
/* EGLImage GstMemory handling */
gboolean gst_egl_image_memory_is_mappable (void);
gboolean gst_is_egl_image_memory (GstMemory * mem);
EGLImageKHR gst_egl_image_memory_get_image (GstMemory * mem);
GstEGLDisplay *gst_egl_image_memory_get_display (GstMemory * mem);
GstVideoGLTextureType gst_egl_image_memory_get_type (GstMemory * mem);
GstVideoGLTextureOrientation gst_egl_image_memory_get_orientation (GstMemory * mem);
void gst_egl_image_memory_set_orientation (GstMemory * mem,
GstVideoGLTextureOrientation orientation);
/* Generic EGLImage allocator that doesn't support mapping, copying or anything */
GstAllocator *gst_egl_image_allocator_obtain (void);
GstMemory *gst_egl_image_allocator_alloc (GstAllocator * allocator,
GstEGLDisplay * display, GstVideoGLTextureType type, gint width, gint height,
gsize * size);
GstMemory *gst_egl_image_allocator_wrap (GstAllocator * allocator,
GstEGLDisplay * display, EGLImageKHR image, GstVideoGLTextureType type,
GstMemoryFlags flags, gsize size, gpointer user_data,
GDestroyNotify user_data_destroy);
#define GST_EGL_DISPLAY_CONTEXT_TYPE "gst.egl.EGLDisplay"
GstContext * gst_context_new_egl_display (GstEGLDisplay * display, gboolean persistent);
gboolean gst_context_get_egl_display (GstContext * context,
GstEGLDisplay ** display);
/* EGLDisplay wrapper with refcount, connection is closed after last ref is gone */
#define GST_TYPE_EGL_DISPLAY (gst_egl_display_get_type())
GType gst_egl_display_get_type (void);
GstEGLDisplay *gst_egl_display_new (EGLDisplay display, GDestroyNotify destroy_notify);
GstEGLDisplay *gst_egl_display_ref (GstEGLDisplay * display);
void gst_egl_display_unref (GstEGLDisplay * display);
EGLDisplay gst_egl_display_get (GstEGLDisplay * display);
/* EGLImage buffer pool */
#define GST_TYPE_EGL_IMAGE_BUFFER_POOL (gst_egl_image_buffer_pool_get_type())
#define GST_EGL_IMAGE_BUFFER_POOL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_EGL_IMAGE_BUFFER_POOL, GstEGLImageBufferPool))
#define GST_EGL_IMAGE_BUFFER_POOL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_EGL_IMAGE_BUFFER_POOL, GstEGLImageBufferPoolClass))
#define GST_EGL_IS_IMAGE_BUFFER_POOL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_EGL_IMAGE_BUFFER_POOL))
#define GST_EGL_IS_IMAGE_BUFFER_POOL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_EGL_IMAGE_BUFFER_POOL))
#define GST_EGL_IMAGE_BUFFER_POO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_EGL_IMAGE_BUFFER_POOL, GstEGLImageBufferPoolClass))
typedef struct _GstEGLImageBufferPool GstEGLImageBufferPool;
typedef struct _GstEGLImageBufferPoolClass GstEGLImageBufferPoolClass;
typedef struct _GstEGLImageBufferPoolPrivate GstEGLImageBufferPoolPrivate;
struct _GstEGLImageBufferPool {
GstVideoBufferPool parent;
GstEGLImageBufferPoolPrivate *priv;
gpointer _reserved[GST_PADDING];
};
struct _GstEGLImageBufferPoolClass {
GstVideoBufferPoolClass parent_class;
gpointer _reserved[GST_PADDING];
};
GType gst_egl_image_buffer_pool_get_type (void);
typedef GstBuffer *(*GstEGLImageBufferPoolSendBlockingAllocate) (GstBufferPool *
pool, gpointer data);
GstBufferPool *gst_egl_image_buffer_pool_new (
GstEGLImageBufferPoolSendBlockingAllocate blocking_allocate_func,
gpointer blocking_allocate_data, GDestroyNotify destroy_func);
void gst_egl_image_buffer_pool_replace_last_buffer (GstEGLImageBufferPool * pool, GstBuffer * buffer);
G_END_DECLS
#endif /* __GST_EGL_H__ */

View file

@ -12,11 +12,6 @@ pcverfiles_uninstalled = \
gstreamer-insertbin-@GST_API_VERSION@-uninstalled.pc \
gstreamer-mpegts-@GST_API_VERSION@-uninstalled.pc
if HAVE_EGL
pcverfiles += gstreamer-egl-@GST_API_VERSION@.pc
pcverfiles_uninstalled += gstreamer-egl-@GST_API_VERSION@-uninstalled.pc
endif
if HAVE_GST_GL
pcverfiles += gstreamer-gl-@GST_API_VERSION@.pc
pcverfiles_uninstalled += gstreamer-gl-@GST_API_VERSION@-uninstalled.pc
@ -43,7 +38,6 @@ pcinfiles = \
gstreamer-codecparsers.pc.in gstreamer-codecparsers-uninstalled.pc.in \
gstreamer-gl.pc.in gstreamer-gl-uninstalled.pc.in \
gstreamer-insertbin.pc.in gstreamer-insertbin-uninstalled.pc.in \
gstreamer-egl.pc.in gstreamer-egl-uninstalled.pc.in \
gstreamer-mpegts.pc.in gstreamer-mpegts-uninstalled.pc.in
DISTCLEANFILES = $(pcinfiles:.in=)

View file

@ -205,9 +205,6 @@
/* Define to enable DVB Source (used by dvb). */
#undef HAVE_DVB
/* Define to enable eglgles sink (used by eglgles). */
#undef HAVE_EGLGLES
/* Define to enable building of experimental plug-ins. */
#undef HAVE_EXPERIMENTAL