mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
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:
parent
d93ed2b870
commit
09116bf10d
20 changed files with 70 additions and 6544 deletions
269
configure.ac
269
configure.ac
|
@ -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
|
dnl Needed by plugins that use g_module_*() API
|
||||||
PKG_CHECK_MODULES(GMODULE_NO_EXPORT, gmodule-no-export-2.0)
|
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
|
HAVE_X11=NO
|
||||||
PKG_CHECK_MODULES(X11, x11, HAVE_X11=yes, HAVE_X11=no)
|
PKG_CHECK_MODULES(X11, x11, HAVE_X11=yes, HAVE_X11=no)
|
||||||
AC_SUBST(X11_LIBS)
|
AC_SUBST(X11_LIBS)
|
||||||
|
@ -458,163 +458,6 @@ else
|
||||||
AG_GST_DISABLE_PLUGIN(dccp)
|
AG_GST_DISABLE_PLUGIN(dccp)
|
||||||
fi
|
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 ***
|
dnl *** opengl ***
|
||||||
AC_ARG_ENABLE([opengl],
|
AC_ARG_ENABLE([opengl],
|
||||||
[ --enable-opengl Enable Desktop OpenGL support @<:@default=auto@:>@],
|
[ --enable-opengl Enable Desktop OpenGL support @<:@default=auto@:>@],
|
||||||
|
@ -707,10 +550,7 @@ HAVE_GLU=no
|
||||||
HAVE_GNUSTEP_COCOA=no
|
HAVE_GNUSTEP_COCOA=no
|
||||||
HAVE_WAYLAND_EGL=no
|
HAVE_WAYLAND_EGL=no
|
||||||
|
|
||||||
HAVE_EGL_RPI="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
|
|
||||||
|
|
||||||
case $host in
|
case $host in
|
||||||
*-mingw32* )
|
*-mingw32* )
|
||||||
|
@ -729,6 +569,70 @@ case $host in
|
||||||
AG_GST_CHECK_LIBHEADER(GLU, GLU, gluSphere,, GL/glu.h)
|
AG_GST_CHECK_LIBHEADER(GLU, GLU, gluSphere,, GL/glu.h)
|
||||||
AG_GST_CHECK_LIBHEADER(GLES2, GLESv2, glTexImage2D,, GLES2/gl2.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)
|
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
|
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_EGL=no
|
||||||
USE_WGL=no
|
USE_WGL=no
|
||||||
USE_COCOA=no
|
USE_COCOA=no
|
||||||
|
USE_EGL_MALI=no
|
||||||
USE_EGL_RPI=no
|
USE_EGL_RPI=no
|
||||||
USE_EAGL=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_EGL, test "x$USE_EGL" = "xyes")
|
||||||
AM_CONDITIONAL(USE_WGL, test "x$USE_WGL" = "xyes")
|
AM_CONDITIONAL(USE_WGL, test "x$USE_WGL" = "xyes")
|
||||||
AM_CONDITIONAL(USE_COCOA, test "x$USE_COCOA" = "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_EGL_RPI, test "x$USE_EGL_RPI" = "xyes")
|
||||||
AM_CONDITIONAL(USE_EAGL, test "x$USE_EAGL" = "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)
|
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 ***
|
dnl *** gl ***
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_GL, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_GL, true)
|
||||||
AG_GST_CHECK_FEATURE(GL, [gl elements], gl, [
|
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_OPENNI2, false)
|
||||||
AM_CONDITIONAL(USE_OPUS, false)
|
AM_CONDITIONAL(USE_OPUS, false)
|
||||||
AM_CONDITIONAL(USE_PVR, false)
|
AM_CONDITIONAL(USE_PVR, false)
|
||||||
AM_CONDITIONAL(USE_RSVG, false)
|
|
||||||
AM_CONDITIONAL(USE_EGLGLES, false)
|
|
||||||
AM_CONDITIONAL(USE_LIBVISUAL, false)
|
AM_CONDITIONAL(USE_LIBVISUAL, false)
|
||||||
AM_CONDITIONAL(USE_TIMIDITY, false)
|
AM_CONDITIONAL(USE_TIMIDITY, false)
|
||||||
AM_CONDITIONAL(USE_WILDMIDI, false)
|
AM_CONDITIONAL(USE_WILDMIDI, false)
|
||||||
|
@ -3237,7 +3108,6 @@ gst/yadif/Makefile
|
||||||
gst-libs/Makefile
|
gst-libs/Makefile
|
||||||
gst-libs/gst/Makefile
|
gst-libs/gst/Makefile
|
||||||
gst-libs/gst/basecamerabinsrc/Makefile
|
gst-libs/gst/basecamerabinsrc/Makefile
|
||||||
gst-libs/gst/egl/Makefile
|
|
||||||
gst-libs/gst/gl/Makefile
|
gst-libs/gst/gl/Makefile
|
||||||
gst-libs/gst/gl/android/Makefile
|
gst-libs/gst/gl/android/Makefile
|
||||||
gst-libs/gst/gl/cocoa/Makefile
|
gst-libs/gst/gl/cocoa/Makefile
|
||||||
|
@ -3308,7 +3178,6 @@ ext/directfb/Makefile
|
||||||
ext/wayland/Makefile
|
ext/wayland/Makefile
|
||||||
ext/daala/Makefile
|
ext/daala/Makefile
|
||||||
ext/dts/Makefile
|
ext/dts/Makefile
|
||||||
ext/eglgles/Makefile
|
|
||||||
ext/gl/Makefile
|
ext/gl/Makefile
|
||||||
ext/faac/Makefile
|
ext/faac/Makefile
|
||||||
ext/faad/Makefile
|
ext/faad/Makefile
|
||||||
|
@ -3371,8 +3240,6 @@ pkgconfig/gstreamer-codecparsers.pc
|
||||||
pkgconfig/gstreamer-codecparsers-uninstalled.pc
|
pkgconfig/gstreamer-codecparsers-uninstalled.pc
|
||||||
pkgconfig/gstreamer-insertbin.pc
|
pkgconfig/gstreamer-insertbin.pc
|
||||||
pkgconfig/gstreamer-insertbin-uninstalled.pc
|
pkgconfig/gstreamer-insertbin-uninstalled.pc
|
||||||
pkgconfig/gstreamer-egl.pc
|
|
||||||
pkgconfig/gstreamer-egl-uninstalled.pc
|
|
||||||
pkgconfig/gstreamer-gl.pc
|
pkgconfig/gstreamer-gl.pc
|
||||||
pkgconfig/gstreamer-gl-uninstalled.pc
|
pkgconfig/gstreamer-gl-uninstalled.pc
|
||||||
pkgconfig/gstreamer-mpegts.pc
|
pkgconfig/gstreamer-mpegts.pc
|
||||||
|
|
|
@ -72,7 +72,6 @@ EXTRA_HFILES = \
|
||||||
$(top_srcdir)/ext/dc1394/gstdc1394.h \
|
$(top_srcdir)/ext/dc1394/gstdc1394.h \
|
||||||
$(top_srcdir)/ext/directfb/dfbvideosink.h \
|
$(top_srcdir)/ext/directfb/dfbvideosink.h \
|
||||||
$(top_srcdir)/ext/dts/gstdtsdec.h \
|
$(top_srcdir)/ext/dts/gstdtsdec.h \
|
||||||
$(top_srcdir)/ext/eglgles/gsteglglessink.h \
|
|
||||||
$(top_srcdir)/ext/faac/gstfaac.h \
|
$(top_srcdir)/ext/faac/gstfaac.h \
|
||||||
$(top_srcdir)/ext/faad/gstfaad.h \
|
$(top_srcdir)/ext/faad/gstfaad.h \
|
||||||
$(top_srcdir)/ext/kate/gstkateenc.h \
|
$(top_srcdir)/ext/kate/gstkateenc.h \
|
||||||
|
|
|
@ -76,12 +76,6 @@ else
|
||||||
DTS_DIR=
|
DTS_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if USE_EGLGLES
|
|
||||||
EGLGLES_DIR=eglgles
|
|
||||||
else
|
|
||||||
EGLGLES_DIR=
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_GL
|
if USE_GL
|
||||||
GL_DIR=gl
|
GL_DIR=gl
|
||||||
else
|
else
|
||||||
|
@ -416,7 +410,6 @@ SUBDIRS=\
|
||||||
$(DAALA_DIR) \
|
$(DAALA_DIR) \
|
||||||
$(DTS_DIR) \
|
$(DTS_DIR) \
|
||||||
$(RESINDVD_DIR) \
|
$(RESINDVD_DIR) \
|
||||||
$(EGLGLES_DIR) \
|
|
||||||
$(GL_DIR) \
|
$(GL_DIR) \
|
||||||
$(FAAC_DIR) \
|
$(FAAC_DIR) \
|
||||||
$(FAAD_DIR) \
|
$(FAAD_DIR) \
|
||||||
|
@ -492,7 +485,6 @@ DIST_SUBDIRS = \
|
||||||
lv2 \
|
lv2 \
|
||||||
daala \
|
daala \
|
||||||
dts \
|
dts \
|
||||||
eglgles \
|
|
||||||
gl \
|
gl \
|
||||||
modplug \
|
modplug \
|
||||||
mimic \
|
mimic \
|
||||||
|
|
|
@ -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
|
|
|
@ -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)
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
@ -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__ */
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -1,6 +1,3 @@
|
||||||
if HAVE_EGL
|
|
||||||
EGL_DIR = egl
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USE_OPENGL
|
if USE_OPENGL
|
||||||
GL_DIR = gl
|
GL_DIR = gl
|
||||||
|
@ -10,8 +7,8 @@ GL_DIR = gl
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS = interfaces basecamerabinsrc codecparsers \
|
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
|
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
|
insertbin uridownloader mpegts
|
||||||
|
|
|
@ -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 \
|
|
||||||
> $@
|
|
|
@ -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)
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -12,11 +12,6 @@ pcverfiles_uninstalled = \
|
||||||
gstreamer-insertbin-@GST_API_VERSION@-uninstalled.pc \
|
gstreamer-insertbin-@GST_API_VERSION@-uninstalled.pc \
|
||||||
gstreamer-mpegts-@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
|
if HAVE_GST_GL
|
||||||
pcverfiles += gstreamer-gl-@GST_API_VERSION@.pc
|
pcverfiles += gstreamer-gl-@GST_API_VERSION@.pc
|
||||||
pcverfiles_uninstalled += gstreamer-gl-@GST_API_VERSION@-uninstalled.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-codecparsers.pc.in gstreamer-codecparsers-uninstalled.pc.in \
|
||||||
gstreamer-gl.pc.in gstreamer-gl-uninstalled.pc.in \
|
gstreamer-gl.pc.in gstreamer-gl-uninstalled.pc.in \
|
||||||
gstreamer-insertbin.pc.in gstreamer-insertbin-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
|
gstreamer-mpegts.pc.in gstreamer-mpegts-uninstalled.pc.in
|
||||||
|
|
||||||
DISTCLEANFILES = $(pcinfiles:.in=)
|
DISTCLEANFILES = $(pcinfiles:.in=)
|
||||||
|
|
|
@ -205,9 +205,6 @@
|
||||||
/* Define to enable DVB Source (used by dvb). */
|
/* Define to enable DVB Source (used by dvb). */
|
||||||
#undef HAVE_DVB
|
#undef HAVE_DVB
|
||||||
|
|
||||||
/* Define to enable eglgles sink (used by eglgles). */
|
|
||||||
#undef HAVE_EGLGLES
|
|
||||||
|
|
||||||
/* Define to enable building of experimental plug-ins. */
|
/* Define to enable building of experimental plug-ins. */
|
||||||
#undef HAVE_EXPERIMENTAL
|
#undef HAVE_EXPERIMENTAL
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue