From 4d2ff16b2353dce6688ee5a135fe2d2fc2643617 Mon Sep 17 00:00:00 2001 From: "Chris \"koying\" Browet" Date: Sat, 27 Jul 2013 11:44:00 +0200 Subject: [PATCH] FIX: [stagefright] dyload the whole codec to prevent potential future api breakage --- Makefile.in | 18 +- configure.in | 6 +- xbmc/DllPaths_generated_android.h.in | 1 + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 4 +- xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 +- .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 4 +- .../DVDCodecs/Video/DVDVideoCodecStageFright.cpp | 64 +- .../DVDCodecs/Video/DVDVideoCodecStageFright.h | 11 +- .../DVDCodecs/Video/DllLibStageFrightCodec.h | 83 ++ xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 19 +- .../dvdplayer/DVDCodecs/Video/StageFrightVideo.cpp | 967 -------------------- .../dvdplayer/DVDCodecs/Video/StageFrightVideo.h | 54 -- .../DVDCodecs/Video/StageFrightVideoPrivate.cpp | 356 -------- .../DVDCodecs/Video/StageFrightVideoPrivate.h | 160 ---- .../DVDCodecs/Video/libstagefrightICS/Makefile.in | 49 ++ .../libstagefrightICS/StageFrightInterface.cpp | 86 ++ .../Video/libstagefrightICS/StageFrightInterface.h | 45 + .../Video/libstagefrightICS/StageFrightVideo.cpp | 969 +++++++++++++++++++++ .../Video/libstagefrightICS/StageFrightVideo.h | 56 ++ .../libstagefrightICS/StageFrightVideoPrivate.cpp | 385 ++++++++ .../libstagefrightICS/StageFrightVideoPrivate.h | 165 ++++ 21 files changed, 1918 insertions(+), 1590 deletions(-) create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/DllLibStageFrightCodec.h delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.cpp delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.h delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.cpp delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.h create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile.in create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.cpp create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.h create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.cpp create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.h create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.cpp create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.h diff --git a/Makefile.in b/Makefile.in index 72acd89..76d6396 100644 --- a/Makefile.in +++ b/Makefile.in @@ -14,7 +14,11 @@ XBMCTEX_DIRS= \ DVDPCODECS_DIRS= \ lib \ - lib/libdvd + lib/libdvd + +ifeq (@USE_LIBSTAGEFRIGHT@,1) +DVDPCODECS_DIRS += xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS +endif DVDPLAYER_ARCHIVES=xbmc/cores/dvdplayer/DVDPlayer.a \ xbmc/cores/dvdplayer/DVDCodecs/DVDCodecs.a \ @@ -329,7 +333,7 @@ all : $(FINAL_TARGETS) include Makefile.include .PHONY : dllloader exports visualizations screensavers eventclients papcodecs \ - dvdpcodecs imagelib codecs externals force skins libaddon check \ + dvdpcodecs dvdpextcodecs imagelib codecs externals force skins libaddon check \ testframework testsuite # hack targets to keep build system up to date @@ -402,6 +406,14 @@ libaddon: exports dvdpcodecs: dllloader $(MAKE) -C lib $(MAKE) -C lib/libdvd + +ifeq (@USE_LIBSTAGEFRIGHT@,1) +dvdpextcodecs: libxbmc.so + $(MAKE) -C xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS +else +dvdpextcodecs: +endif + eventclients: ifeq ($(findstring osx,@ARCH@), osx) ifneq ($(findstring arm,@ARCH@), arm) @@ -442,7 +454,7 @@ ifeq (@USE_PVR_ADDONS@,1) $(MAKE) -C pvr-addons endif -codecs: papcodecs dvdpcodecs +codecs: papcodecs dvdpcodecs dvdpextcodecs libs: libhdhomerun imagelib libexif system/libcpluff-@ARCH@.so $(CMYTH) diff --git a/configure.in b/configure.in index 9b7c7dc..8af09f9 100644 --- a/configure.in +++ b/configure.in @@ -39,6 +39,7 @@ AC_DEFUN([XB_ADD_CODEC], AC_MSG_CHECKING([for $2]) case $add_codecs in *$2*) + use_codec_$2="yes" AC_SUBST([USE_$1], 1) AC_DEFINE([HAS_$1], 1, [using $2]) AC_MSG_RESULT([enabling $2]) @@ -1966,7 +1967,6 @@ case $add_codecs in XB_ADD_CODEC([LIBAMCODEC], [amcodec]) ;; *libstagefright*) - LIBS+="-L${prefix}/opt/android-libs -lstdc++ -lutils -lcutils -lstagefright -lbinder -lui -lgui" XB_ADD_CODEC([LIBSTAGEFRIGHT], [libstagefright]) ;; *) @@ -2564,6 +2564,10 @@ if test "$use_skin_touched" = "yes"; then OUTPUT_FILES="$OUTPUT_FILES addons/skin.touched/media/Makefile" fi +if test "$use_codec_libstagefright" = "yes"; then +OUTPUT_FILES="$OUTPUT_FILES xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile" +fi + OUTPUT_FILES="$OUTPUT_FILES \ xbmc/interfaces/python/Makefile \ xbmc/interfaces/python/test/Makefile" diff --git a/xbmc/DllPaths_generated_android.h.in b/xbmc/DllPaths_generated_android.h.in index 4754b5e..e77c1bc 100644 --- a/xbmc/DllPaths_generated_android.h.in +++ b/xbmc/DllPaths_generated_android.h.in @@ -73,6 +73,7 @@ #define DLL_PATH_LIBDVDNAV "libdvdnav-@ARCH@.so" #define DLL_PATH_LIBMPEG2 "@MPEG2_SONAME@" #define DLL_PATH_LIBMAD "@MAD_SONAME@" +#define DLL_PATH_LIBSTAGEFRIGHTICS "libXBMCvcodec_stagefrightICS-@ARCH@.so" /* ffmpeg */ #define DLL_PATH_LIBAVCODEC "libavcodec-54-@ARCH@.so" diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp index 196e460..46f4442 100644 --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp @@ -68,7 +68,7 @@ #include #include "windowing/egl/EGLWrapper.h" #include "android/activity/XBMCApp.h" -#include "DVDCodecs/Video/StageFrightVideo.h" +#include "DVDCodecs/Video/DVDVideoCodecStageFright.h" // EGL extension functions static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; @@ -2605,7 +2605,7 @@ void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) } #endif #ifdef HAS_LIBSTAGEFRIGHT -void CLinuxRendererGLES::AddProcessor(CStageFrightVideo* stf, EGLImageKHR eglimg, int index) +void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index) { #ifdef DEBUG_VERBOSE unsigned int time = XbmcThreads::SystemClockMillis(); diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h index 687b7c9..15f7d7b 100644 --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h @@ -40,7 +40,7 @@ class CBaseTexture; namespace Shaders { class BaseYUV2RGBShader; } namespace Shaders { class BaseVideoFilterShader; } class COpenMaxVideo; -class CStageFrightVideo; +class CDVDVideoCodecStageFright; class CDVDMediaCodecInfo; typedef std::vector Features; @@ -167,7 +167,7 @@ public: virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); #endif #ifdef HAS_LIBSTAGEFRIGHT - virtual void AddProcessor(CStageFrightVideo* stf, EGLImageKHR eglimg, int index); + virtual void AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index); #endif #if defined(TARGET_ANDROID) // mediaCodec @@ -278,7 +278,7 @@ protected: struct __CVBuffer *cvBufferRef; #endif #ifdef HAS_LIBSTAGEFRIGHT - CStageFrightVideo* stf; + CDVDVideoCodecStageFright* stf; EGLImageKHR eglimg; #endif #if defined(TARGET_ANDROID) diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h index baee6e0..b78f779 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h @@ -38,7 +38,7 @@ namespace VDPAU { class CVdpauRenderPicture; } class COpenMax; class COpenMaxVideo; struct OpenMaxVideoBuffer; -class CStageFrightVideo; +class CDVDVideoCodecStageFright; class CDVDMediaCodecInfo; typedef void* EGLImageKHR; @@ -75,7 +75,7 @@ struct DVDVideoPicture }; struct { - CStageFrightVideo* stf; + CDVDVideoCodecStageFright* stf; EGLImageKHR eglimg; }; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.cpp index a5d9b17..ee7fbe0 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.cpp @@ -31,17 +31,27 @@ #include "settings/Settings.h" #include "DVDStreamInfo.h" #include "DVDVideoCodecStageFright.h" -#include "StageFrightVideo.h" #include "utils/log.h" +#include "windowing/WindowingFactory.h" +#include "settings/AdvancedSettings.h" + +#include "DllLibStageFrightCodec.h" #define CLASSNAME "CDVDVideoCodecStageFright" //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// + +DllLibStageFrightCodec* CDVDVideoCodecStageFright::m_stf_dll = NULL; + CDVDVideoCodecStageFright::CDVDVideoCodecStageFright() : CDVDVideoCodec() - , m_stf_decoder(NULL), m_converter(NULL), m_convert_bitstream(false) + , m_convert_bitstream(false), m_converter(NULL) + , m_stf_handle(NULL) { m_pFormatName = "stf-xxxx"; + + if (!m_stf_dll) + m_stf_dll = new DllLibStageFrightCodec; } CDVDVideoCodecStageFright::~CDVDVideoCodecStageFright() @@ -94,21 +104,18 @@ bool CDVDVideoCodecStageFright::Open(CDVDStreamInfo &hints, CDVDCodecOptions &op break; } - m_stf_decoder = new CStageFrightVideo; - if (!m_stf_decoder->Open(hints)) + if (!(m_stf_dll && m_stf_dll->Load())) + return false; + m_stf_dll->EnableDelayedUnload(false); + + m_stf_handle = m_stf_dll->create_stf(&g_Windowing, &g_advancedSettings); + + if (!m_stf_dll->stf_Open(m_stf_handle, hints)) { CLog::Log(LOGERROR, "%s::%s - failed to open, codec(%d), profile(%d), level(%d)", CLASSNAME, __func__, hints.codec, hints.profile, hints.level); - delete m_stf_decoder; - m_stf_decoder = NULL; - - if (m_converter) - { - m_converter->Close(); - delete m_converter; - m_converter = NULL; - } + Dispose(); return false; } @@ -126,17 +133,17 @@ void CDVDVideoCodecStageFright::Dispose() delete m_converter; m_converter = NULL; } - if (m_stf_decoder) + if (m_stf_handle) { - m_stf_decoder->Close(); - delete m_stf_decoder; - m_stf_decoder = NULL; + m_stf_dll->stf_Close(m_stf_handle); + m_stf_dll->destroy_stf(m_stf_handle); + m_stf_handle = NULL; } } void CDVDVideoCodecStageFright::SetDropState(bool bDrop) { - m_stf_decoder->SetDropState(bDrop); + m_stf_dll->stf_SetDropState(m_stf_handle, bDrop); } int CDVDVideoCodecStageFright::Decode(uint8_t *pData, int iSize, double dts, double pts) @@ -163,29 +170,30 @@ int CDVDVideoCodecStageFright::Decode(uint8_t *pData, int iSize, double dts, dou CLog::Log(LOGDEBUG, ">>> decode conversion - tm:%d\n", XbmcThreads::SystemClockMillis() - time); #endif - rtn = m_stf_decoder->Decode(demuxer_content, demuxer_bytes, dts, pts); + rtn = m_stf_dll->stf_Decode(m_stf_handle, demuxer_content, demuxer_bytes, dts, pts); return rtn; } void CDVDVideoCodecStageFright::Reset(void) { - m_stf_decoder->Reset(); + m_stf_dll->stf_Reset(m_stf_handle); } bool CDVDVideoCodecStageFright::GetPicture(DVDVideoPicture* pDvdVideoPicture) { - return m_stf_decoder->GetPicture(pDvdVideoPicture); + pDvdVideoPicture->stf = this; + return m_stf_dll->stf_GetPicture(m_stf_handle, pDvdVideoPicture); } bool CDVDVideoCodecStageFright::ClearPicture(DVDVideoPicture* pDvdVideoPicture) { - return m_stf_decoder->ClearPicture(pDvdVideoPicture); + return m_stf_dll->stf_ClearPicture(m_stf_handle, pDvdVideoPicture); } void CDVDVideoCodecStageFright::SetSpeed(int iSpeed) { - m_stf_decoder->SetSpeed(iSpeed); + m_stf_dll->stf_SetSpeed(m_stf_handle, iSpeed); } int CDVDVideoCodecStageFright::GetDataSize(void) @@ -198,4 +206,14 @@ double CDVDVideoCodecStageFright::GetTimeSize(void) return 0; } +void CDVDVideoCodecStageFright::LockBuffer(EGLImageKHR eglimg) +{ + m_stf_dll->stf_LockBuffer(m_stf_handle, eglimg); +} + +void CDVDVideoCodecStageFright::ReleaseBuffer(EGLImageKHR eglimg) +{ + m_stf_dll->stf_ReleaseBuffer(m_stf_handle, eglimg); +} + #endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.h index 95e32c6..5289651 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.h @@ -24,7 +24,8 @@ #include "DVDVideoCodec.h" #include "utils/BitstreamConverter.h" -class CStageFrightVideo; +class DllLibStageFrightCodec; + class CDVDVideoCodecStageFright : public CDVDVideoCodec { public: @@ -45,12 +46,16 @@ public: virtual int GetDataSize(void); virtual double GetTimeSize(void); + virtual void LockBuffer(EGLImageKHR eglimg); + virtual void ReleaseBuffer(EGLImageKHR eglimg); + protected: const char *m_pFormatName; - CStageFrightVideo *m_stf_decoder; - bool m_convert_bitstream; CBitstreamConverter *m_converter; + + static DllLibStageFrightCodec* m_stf_dll; + void * m_stf_handle; }; #endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DllLibStageFrightCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DllLibStageFrightCodec.h new file mode 100644 index 0000000..442746b --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DllLibStageFrightCodec.h @@ -0,0 +1,83 @@ +#pragma once + +/* + * Copyright (C) 2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS) +#include "config.h" +#endif + +#include "DynamicDll.h" +#include "DVDVideoCodec.h" + +class CWinSystemEGL; +class CAdvancedSettings; + +class DllLibStageFrightCodecInterface +{ +public: + virtual ~DllLibStageFrightCodecInterface() {} + + virtual void* create_stf(CWinSystemEGL* windowing, CAdvancedSettings* advsettings)=0; + virtual void destroy_stf(void*)=0; + + virtual bool stf_Open(void*, CDVDStreamInfo &hints) = 0; + virtual void stf_Close(void*) = 0; + virtual int stf_Decode(void*, uint8_t *pData, int iSize, double dts, double pts) = 0; + virtual void stf_Reset(void*) = 0; + virtual bool stf_GetPicture(void*, DVDVideoPicture *pDvdVideoPicture) = 0; + virtual bool stf_ClearPicture(void*, DVDVideoPicture* pDvdVideoPicture) = 0; + virtual void stf_SetDropState(void*, bool bDrop) = 0; + virtual void stf_SetSpeed(void*, int iSpeed) = 0; + + virtual void stf_LockBuffer(void*, EGLImageKHR eglimg) = 0; + virtual void stf_ReleaseBuffer(void*, EGLImageKHR eglimg) = 0; +}; + +class DllLibStageFrightCodec : public DllDynamic, DllLibStageFrightCodecInterface +{ + DECLARE_DLL_WRAPPER(DllLibStageFrightCodec, DLL_PATH_LIBSTAGEFRIGHTICS) + DEFINE_METHOD2(void*, create_stf, (CWinSystemEGL* p1, CAdvancedSettings* p2)) + DEFINE_METHOD1(void, destroy_stf, (void* p1)) + DEFINE_METHOD2(bool, stf_Open, (void* p1, CDVDStreamInfo &p2)) + DEFINE_METHOD1(void, stf_Close, (void* p1)) + DEFINE_METHOD5(int, stf_Decode, (void* p1, uint8_t *p2, int p3, double p4, double p5)) + DEFINE_METHOD1(void, stf_Reset, (void* p1)) + DEFINE_METHOD2(bool, stf_GetPicture, (void* p1, DVDVideoPicture * p2)) + DEFINE_METHOD2(bool, stf_ClearPicture, (void* p1, DVDVideoPicture * p2)) + DEFINE_METHOD2(void, stf_SetDropState, (void* p1, bool p2)) + DEFINE_METHOD2(void, stf_SetSpeed, (void* p1, int p2)) + DEFINE_METHOD2(void, stf_LockBuffer, (void* p1, EGLImageKHR p2)) + DEFINE_METHOD2(void, stf_ReleaseBuffer, (void* p1, EGLImageKHR p2)) + BEGIN_METHOD_RESOLVE() + RESOLVE_METHOD(create_stf) + RESOLVE_METHOD(destroy_stf) + RESOLVE_METHOD(stf_Open) + RESOLVE_METHOD(stf_Close) + RESOLVE_METHOD(stf_Decode) + RESOLVE_METHOD(stf_Reset) + RESOLVE_METHOD(stf_GetPicture) + RESOLVE_METHOD(stf_ClearPicture) + RESOLVE_METHOD(stf_SetDropState) + RESOLVE_METHOD(stf_SetSpeed) + RESOLVE_METHOD(stf_LockBuffer) + RESOLVE_METHOD(stf_ReleaseBuffer) + END_METHOD_RESOLVE() +}; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in index b0819a8..23261f1 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in @@ -22,18 +22,6 @@ SRCS += OpenMax.cpp SRCS += OpenMaxVideo.cpp SRCS += DVDVideoCodecOpenMax.cpp endif -ifeq (@USE_LIBSTAGEFRIGHT@,1) -SRCS += StageFrightVideo.cpp -SRCS += StageFrightVideoPrivate.cpp -SRCS += DVDVideoCodecStageFright.cpp -INCLUDES += -I${prefix}/opt/android-source/frameworks/base/include -INCLUDES += -I${prefix}/opt/android-source/frameworks/base/native/include -INCLUDES += -I${prefix}/opt/android-source/frameworks/base/include/media/stagefright -INCLUDES += -I${prefix}/opt/android-source/frameworks/base/include/media/stagefright/openmax -INCLUDES += -I${prefix}/opt/android-source/system/core/include -INCLUDES += -I${prefix}/opt/android-source/libhardware/include -endif - ifeq (@USE_LIBAMCODEC@,1) SRCS += AMLCodec.cpp SRCS += DVDVideoCodecAmlogic.cpp @@ -44,13 +32,12 @@ endif ifeq (@USE_ANDROID@,1) SRCS += DVDVideoCodecAndroidMediaCodec.cpp endif +ifeq (@USE_LIBSTAGEFRIGHT@,1) +SRCS += DVDVideoCodecStageFright.cpp +endif LIB=Video.a include @abs_top_srcdir@/Makefile.include -include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) -ifeq (@USE_LIBSTAGEFRIGHT@,1) -CXXFLAGS += -Wno-multichar -fno-rtti -endif - diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.cpp deleted file mode 100644 index 4060f3b..0000000 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.cpp +++ /dev/null @@ -1,967 +0,0 @@ -/* - * Copyright (C) 2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ -/***************************************************************************/ - -//#define DEBUG_VERBOSE 1 - -#include "system.h" -#include "system_gl.h" - -#include "StageFrightVideo.h" -#include "StageFrightVideoPrivate.h" - -#include "guilib/GraphicContext.h" -#include "DVDClock.h" -#include "utils/log.h" -#include "utils/fastmemcpy.h" -#include "threads/Thread.h" -#include "threads/Event.h" -#include "settings/AdvancedSettings.h" - -#include "xbmc/guilib/FrameBufferObject.h" - -#include -#include -#include "windowing/egl/EGLWrapper.h" - -#include - -#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00 -#define OMX_TI_COLOR_FormatYUV420PackedSemiPlanar 0x7F000100 - -#define CLASSNAME "CStageFrightVideo" - -#define EGL_NATIVE_BUFFER_ANDROID 0x3140 -#define EGL_IMAGE_PRESERVED_KHR 0x30D2 - -const char *MEDIA_MIMETYPE_VIDEO_WMV = "video/x-ms-wmv"; - -using namespace android; - -static int64_t pts_dtoi(double pts) -{ - return (int64_t)(pts); -} - -static double pts_itod(int64_t pts) -{ - return (double)pts; -} - -/***********************************************************/ - -class CStageFrightMediaSource : public MediaSource -{ -public: - CStageFrightMediaSource(CStageFrightVideoPrivate *priv, sp meta) - { - p = priv; - source_meta = meta; - } - - virtual sp getFormat() - { - return source_meta; - } - - virtual status_t start(MetaData *params) - { - return OK; - } - - virtual status_t stop() - { - return OK; - } - - virtual status_t read(MediaBuffer **buffer, - const MediaSource::ReadOptions *options) - { - Frame *frame; - status_t ret; - *buffer = NULL; - int64_t time_us = -1; - MediaSource::ReadOptions::SeekMode mode; - - if (options && options->getSeekTo(&time_us, &mode)) - { -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s: reading source(%d): seek:%llu\n", CLASSNAME,p->in_queue.size(), time_us); -#endif - } - else - { -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s: reading source(%d)\n", CLASSNAME,p->in_queue.size()); -#endif - } - - p->in_mutex.lock(); - while (p->in_queue.empty() && p->decode_thread) - p->in_condition.wait(p->in_mutex); - - if (p->in_queue.empty()) - { - p->in_mutex.unlock(); - return VC_ERROR; - } - - std::map::iterator it = p->in_queue.begin(); - frame = it->second; - ret = frame->status; - *buffer = frame->medbuf; - - p->in_queue.erase(it); - p->in_mutex.unlock(); - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>> exiting reading source(%d); pts:%llu\n", p->in_queue.size(),frame->pts); -#endif - - free(frame); - - return ret; - } - -private: - sp source_meta; - CStageFrightVideoPrivate *p; -}; - -/********************************************/ - -class CStageFrightDecodeThread : public CThread -{ -protected: - CStageFrightVideoPrivate *p; - -public: - CStageFrightDecodeThread(CStageFrightVideoPrivate *priv) - : CThread("CStageFrightDecodeThread") - , p(priv) - {} - - void OnStartup() - { - #if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s: entering decode thread\n", CLASSNAME); - #endif - } - - void OnExit() - { - #if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s: exited decode thread\n", CLASSNAME); - #endif - } - - void Process() - { - Frame* frame; - int32_t w, h, dw, dh; - int decode_done = 0; - int32_t keyframe = 0; - int32_t unreadable = 0; - MediaSource::ReadOptions readopt; - // GLuint texid; - - //SetPriority(THREAD_PRIORITY_ABOVE_NORMAL); - do - { - #if defined(DEBUG_VERBOSE) - unsigned int time = XbmcThreads::SystemClockMillis(); - CLog::Log(LOGDEBUG, "%s: >>> Handling frame\n", CLASSNAME); - #endif - p->cur_frame = NULL; - frame = (Frame*)malloc(sizeof(Frame)); - if (!frame) - { - decode_done = 1; - continue; - } - - frame->eglimg = EGL_NO_IMAGE_KHR; - frame->medbuf = NULL; - if (p->resetting) - { - readopt.setSeekTo(0); - p->resetting = false; - } - frame->status = p->decoder->read(&frame->medbuf, &readopt); - readopt.clearSeekTo(); - - if (frame->status == OK) - { - if (!frame->medbuf->graphicBuffer().get()) // hw buffers - { - if (frame->medbuf->range_length() == 0) - { - CLog::Log(LOGERROR, "%s - Invalid buffer\n", CLASSNAME); - frame->status = VC_ERROR; - decode_done = 1; - frame->medbuf->release(); - frame->medbuf = NULL; - } - else - frame->format = RENDER_FMT_YUV420P; - } - else - frame->format = RENDER_FMT_EGLIMG; - } - - if (frame->status == OK) - { - sp outFormat = p->decoder->getFormat(); - outFormat->findInt32(kKeyWidth , &w); - outFormat->findInt32(kKeyHeight, &h); - - if (!outFormat->findInt32(kKeyDisplayWidth , &dw)) - dw = w; - if (!outFormat->findInt32(kKeyDisplayHeight, &dh)) - dh = h; - - if (!outFormat->findInt32(kKeyIsSyncFrame, &keyframe)) - keyframe = 0; - if (!outFormat->findInt32(kKeyIsUnreadable, &unreadable)) - unreadable = 0; - - frame->pts = 0; - - // The OMX.SEC decoder doesn't signal the modified width/height - if (p->decoder_component && !strncmp(p->decoder_component, "OMX.SEC", 7) && - (w & 15 || h & 15)) - { - if (((w + 15)&~15) * ((h + 15)&~15) * 3/2 == frame->medbuf->range_length()) - { - w = (w + 15)&~15; - h = (h + 15)&~15; - } - } - frame->width = w; - frame->height = h; - frame->medbuf->meta_data()->findInt64(kKeyTime, &(frame->pts)); - } - else if (frame->status == INFO_FORMAT_CHANGED) - { - int32_t cropLeft, cropTop, cropRight, cropBottom; - sp outFormat = p->decoder->getFormat(); - - outFormat->findInt32(kKeyWidth , &p->width); - outFormat->findInt32(kKeyHeight, &p->height); - - cropLeft = cropTop = cropRight = cropBottom = 0; - if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) - { - p->x = 0; - p->y = 0; - } - else - { - p->x = cropLeft; - p->y = cropTop; - p->width = cropRight - cropLeft + 1; - p->height = cropBottom - cropTop + 1; - } - outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat); - if (!outFormat->findInt32(kKeyStride, &p->videoStride)) - p->videoStride = p->width; - if (!outFormat->findInt32(kKeySliceHeight, &p->videoSliceHeight)) - p->videoSliceHeight = p->height; - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>> new format col:%d, w:%d, h:%d, sw:%d, sh:%d, ctl:%d,%d; cbr:%d,%d\n", p->videoColorFormat, p->width, p->height, p->videoStride, p->videoSliceHeight, cropTop, cropLeft, cropBottom, cropRight); -#endif - - if (frame->medbuf) - frame->medbuf->release(); - frame->medbuf = NULL; - free(frame); - continue; - } - else - { - CLog::Log(LOGERROR, "%s - decoding error (%d)\n", CLASSNAME,frame->status); - if (frame->medbuf) - frame->medbuf->release(); - frame->medbuf = NULL; - free(frame); - continue; - } - - if (frame->format == RENDER_FMT_EGLIMG) - { - if (!p->eglInitialized) - { - p->InitializeEGL(frame->width, frame->height); - } - else if (p->texwidth != frame->width || p->texheight != frame->height) - { - p->UninitializeEGL(); - p->InitializeEGL(frame->width, frame->height); - } - - if (p->free_queue.empty()) - { - CLog::Log(LOGERROR, "%s::%s - Error: No free output buffers\n", CLASSNAME, __func__); - if (frame->medbuf) - frame->medbuf->release(); - free(frame); - continue; - } - - ANativeWindowBuffer* graphicBuffer = frame->medbuf->graphicBuffer()->getNativeBuffer(); - native_window_set_buffers_timestamp(p->mVideoNativeWindow.get(), frame->pts * 1000); - int err = p->mVideoNativeWindow.get()->queueBuffer(p->mVideoNativeWindow.get(), graphicBuffer); - if (err == 0) - frame->medbuf->meta_data()->setInt32(kKeyRendered, 1); - frame->medbuf->release(); - frame->medbuf = NULL; - p->UpdateStagefrightTexture(); - - if (!p->drop_state) - { - p->free_mutex.lock(); - while (!p->free_queue.size()) - usleep(10000); - std::list >::iterator itfree = p->free_queue.begin(); - int cur_slot = itfree->second; - p->fbo.BindToTexture(GL_TEXTURE_2D, p->slots[cur_slot].texid); - p->fbo.BeginRender(); - - glDisable(GL_DEPTH_TEST); - //glClear(GL_COLOR_BUFFER_BIT); - - const GLfloat triangleVertices[] = { - -1.0f, 1.0f, - -1.0f, -1.0f, - 1.0f, -1.0f, - 1.0f, 1.0f, - }; - - glVertexAttribPointer(p->mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); - glEnableVertexAttribArray(p->mPositionHandle); - - glUseProgram(p->mPgm); - glUniform1i(p->mTexSamplerHandle, 0); - - glBindTexture(GL_TEXTURE_EXTERNAL_OES, p->mVideoTextureId); - - GLfloat texMatrix[16]; - // const GLfloat texMatrix[] = { - // 1, 0, 0, 0, - // 0, -1, 0, 0, - // 0, 0, 1, 0, - // 0, 1, 0, 1 - // }; - p->GetStagefrightTransformMatrix(texMatrix); - glUniformMatrix4fv(p->mTexMatrixHandle, 1, GL_FALSE, texMatrix); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - // glDeleteTextures(1, &texid); - // eglDestroyImageKHR(p->eglDisplay, img); - p->fbo.EndRender(); - - glBindTexture(GL_TEXTURE_2D, 0); - - frame->eglimg = p->slots[cur_slot].eglimg; - p->busy_queue.push_back(std::pair(*itfree)); - p->free_queue.erase(itfree); - p->free_mutex.unlock(); - } - } - - #if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s: >>> pushed OUT frame; w:%d, h:%d, dw:%d, dh:%d, kf:%d, ur:%d, img:%p, tm:%d\n", CLASSNAME, frame->width, frame->height, dw, dh, keyframe, unreadable, frame->eglimg, XbmcThreads::SystemClockMillis() - time); - #endif - - p->out_mutex.lock(); - p->cur_frame = frame; - while (p->cur_frame) - p->out_condition.wait(p->out_mutex); - p->out_mutex.unlock(); - } - while (!decode_done && !m_bStop); - - if (p->eglInitialized) - p->UninitializeEGL(); - - } -}; - -/***********************************************************/ - -bool CStageFrightVideo::Open(CDVDStreamInfo &hints) -{ -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::Open\n", CLASSNAME); -#endif - - CSingleLock lock(g_graphicsContext); - - // stagefright crashes with null size. Trap this... - if (!hints.width || !hints.height) - { - CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"null size, cannot handle"); - return false; - } - - p = new CStageFrightVideoPrivate; - p->width = hints.width; - p->height = hints.height; - - if (g_advancedSettings.m_stagefrightConfig.useSwRenderer) - p->quirks |= QuirkSWRender; - - sp outFormat; - int32_t cropLeft, cropTop, cropRight, cropBottom; - //Vector matchingCodecs; - - p->meta = new MetaData; - if (p->meta == NULL) - { - goto fail; - } - - const char* mimetype; - switch (hints.codec) - { - case CODEC_ID_H264: - if (g_advancedSettings.m_stagefrightConfig.useAVCcodec == 0) - return false; - mimetype = MEDIA_MIMETYPE_VIDEO_AVC; - if ( *(char*)hints.extradata == 1 ) - p->meta->setData(kKeyAVCC, kTypeAVCC, hints.extradata, hints.extrasize); - break; - case CODEC_ID_MPEG4: - if (g_advancedSettings.m_stagefrightConfig.useMP4codec == 0) - return false; - mimetype = MEDIA_MIMETYPE_VIDEO_MPEG4; - break; - case CODEC_ID_MPEG2VIDEO: - if (g_advancedSettings.m_stagefrightConfig.useMPEG2codec == 0) - return false; - mimetype = MEDIA_MIMETYPE_VIDEO_MPEG2; - break; - case CODEC_ID_VP3: - case CODEC_ID_VP6: - case CODEC_ID_VP6F: - case CODEC_ID_VP8: - if (g_advancedSettings.m_stagefrightConfig.useVPXcodec == 0) - return false; - mimetype = MEDIA_MIMETYPE_VIDEO_VPX; - break; - case CODEC_ID_VC1: - case CODEC_ID_WMV3: - if (g_advancedSettings.m_stagefrightConfig.useVC1codec == 0) - return false; - mimetype = MEDIA_MIMETYPE_VIDEO_WMV; - break; - default: - return false; - break; - } - - p->meta->setCString(kKeyMIMEType, mimetype); - p->meta->setInt32(kKeyWidth, p->width); - p->meta->setInt32(kKeyHeight, p->height); - - android::ProcessState::self()->startThreadPool(); - - p->source = new CStageFrightMediaSource(p, p->meta); - p->client = new OMXClient; - - if (p->source == NULL || p->client == NULL) - { - goto fail; - } - - if (p->client->connect() != OK) - { - delete p->client; - p->client = NULL; - CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot connect OMX client"); - goto fail; - } - - if ((p->quirks & QuirkSWRender) == 0) - p->InitStagefrightSurface(); - - p->decoder = OMXCodec::Create(p->client->interface(), p->meta, - false, p->source, NULL, - OMXCodec::kHardwareCodecsOnly | (p->quirks & QuirkSWRender ? OMXCodec::kClientNeedsFramebuffer : 0), - p->mVideoNativeWindow - ); - - if (!(p->decoder != NULL && p->decoder->start() == OK)) - { - p->decoder = NULL; - goto fail; - } - - outFormat = p->decoder->getFormat(); - - if (!outFormat->findInt32(kKeyWidth, &p->width) || !outFormat->findInt32(kKeyHeight, &p->height) - || !outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat)) - goto fail; - - const char *component; - if (outFormat->findCString(kKeyDecoderComponent, &component)) - { - CLog::Log(LOGDEBUG, "%s::%s - component: %s\n", CLASSNAME, __func__, component); - - //Blacklist - if (!strncmp(component, "OMX.google", 10)) - { - // On some platforms, software decoders are returned anyway - CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (software)"); - goto fail; - } - else if (!strncmp(component, "OMX.Nvidia.mp4.decode", 21) && g_advancedSettings.m_stagefrightConfig.useMP4codec != 1) - { - // Has issues with some XVID encoded MP4. Only fails after actual decoding starts... - CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (MP4)"); - goto fail; - } - } - - cropLeft = cropTop = cropRight = cropBottom = 0; - if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) - { - p->x = 0; - p->y = 0; - } - else - { - p->x = cropLeft; - p->y = cropTop; - p->width = cropRight - cropLeft + 1; - p->height = cropBottom - cropTop + 1; - } - - if (!outFormat->findInt32(kKeyStride, &p->videoStride)) - p->videoStride = p->width; - if (!outFormat->findInt32(kKeySliceHeight, &p->videoSliceHeight)) - p->videoSliceHeight = p->height; - - for (int i=0; iinbuf[i] = new MediaBuffer(300000); - p->inbuf[i]->setObserver(p); - } - - p->decode_thread = new CStageFrightDecodeThread(p); - p->decode_thread->Create(true /*autodelete*/); - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>> format col:%d, w:%d, h:%d, sw:%d, sh:%d, ctl:%d,%d; cbr:%d,%d\n", p->videoColorFormat, p->width, p->height, p->videoStride, p->videoSliceHeight, cropTop, cropLeft, cropBottom, cropRight); -#endif - - return true; - -fail: - if (p->decoder != 0) - p->decoder->stop(); - if (p->client) - { - p->client->disconnect(); - delete p->client; - } - if (p->decoder_component) - free(&p->decoder_component); - if ((p->quirks & QuirkSWRender) == 0) - p->UninitStagefrightSurface(); - return false; -} - -/*** Decode ***/ -int CStageFrightVideo::Decode(uint8_t *pData, int iSize, double dts, double pts) -{ -#if defined(DEBUG_VERBOSE) - unsigned int time = XbmcThreads::SystemClockMillis(); - CLog::Log(LOGDEBUG, "%s::Decode - d:%p; s:%d; dts:%f; pts:%f\n", CLASSNAME, pData, iSize, dts, pts); -#endif - - Frame *frame; - int demuxer_bytes = iSize; - uint8_t *demuxer_content = pData; - int ret = 0; - - if (demuxer_content) - { - frame = (Frame*)malloc(sizeof(Frame)); - if (!frame) - return VC_ERROR; - - frame->status = OK; - if (g_advancedSettings.m_stagefrightConfig.useInputDTS) - frame->pts = (dts != DVD_NOPTS_VALUE) ? pts_dtoi(dts) : ((pts != DVD_NOPTS_VALUE) ? pts_dtoi(pts) : 0); - else - frame->pts = (pts != DVD_NOPTS_VALUE) ? pts_dtoi(pts) : ((dts != DVD_NOPTS_VALUE) ? pts_dtoi(dts) : 0); - - // No valid pts? libstagefright asserts on this. - if (frame->pts < 0) - { - free(frame); - return ret; - } - - frame->medbuf = p->getBuffer(demuxer_bytes); - if (!frame->medbuf) - { - free(frame); - return VC_ERROR; - } - - fast_memcpy(frame->medbuf->data(), demuxer_content, demuxer_bytes); - frame->medbuf->meta_data()->clear(); - frame->medbuf->meta_data()->setInt64(kKeyTime, frame->pts); - - p->in_mutex.lock(); - p->framecount++; - p->in_queue.insert(std::pair(p->framecount, frame)); - p->in_condition.notify(); - p->in_mutex.unlock(); - } - - if (p->inputBufferAvailable() && p->in_queue.size() < INBUFCOUNT) - ret |= VC_BUFFER; - else - usleep(1000); - if (p->cur_frame != NULL) - ret |= VC_PICTURE; -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::Decode: pushed IN frame (%d); tm:%d\n", CLASSNAME,p->in_queue.size(), XbmcThreads::SystemClockMillis() - time); -#endif - - return ret; -} - -bool CStageFrightVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture) -{ - #if defined(DEBUG_VERBOSE) - unsigned int time = XbmcThreads::SystemClockMillis(); -#endif - if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG && pDvdVideoPicture->eglimg != EGL_NO_IMAGE_KHR) - ReleaseBuffer(pDvdVideoPicture->eglimg); - - if (p->prev_frame) { - if (p->prev_frame->medbuf) - p->prev_frame->medbuf->release(); - free(p->prev_frame); - p->prev_frame = NULL; - } -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::ClearPicture (%d)\n", CLASSNAME, XbmcThreads::SystemClockMillis() - time); -#endif - - return true; -} - -bool CStageFrightVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) -{ -#if defined(DEBUG_VERBOSE) - unsigned int time = XbmcThreads::SystemClockMillis(); - CLog::Log(LOGDEBUG, "%s::GetPicture\n", CLASSNAME); - if (p->cycle_time != 0) - CLog::Log(LOGDEBUG, ">>> cycle dur:%d\n", XbmcThreads::SystemClockMillis() - p->cycle_time); - p->cycle_time = time; -#endif - - status_t status; - - p->out_mutex.lock(); - if (!p->cur_frame) - { - CLog::Log(LOGERROR, "%s::%s - Error getting frame\n", CLASSNAME, __func__); - p->out_condition.notify(); - p->out_mutex.unlock(); - return false; - } - - Frame *frame = p->cur_frame; - status = frame->status; - - pDvdVideoPicture->format = frame->format; - pDvdVideoPicture->dts = DVD_NOPTS_VALUE; - pDvdVideoPicture->pts = frame->pts; - pDvdVideoPicture->iWidth = frame->width; - pDvdVideoPicture->iHeight = frame->height; - pDvdVideoPicture->iDisplayWidth = frame->width; - pDvdVideoPicture->iDisplayHeight = frame->height; - pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; - pDvdVideoPicture->stf = this; - pDvdVideoPicture->eglimg = EGL_NO_IMAGE_KHR; - - if (status != OK) - { - CLog::Log(LOGERROR, "%s::%s - Error getting picture from frame(%d)\n", CLASSNAME, __func__,status); - if (frame->medbuf) { - frame->medbuf->release(); - } - free(frame); - p->cur_frame = NULL; - p->out_condition.notify(); - p->out_mutex.unlock(); - return false; - } - - if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG) - { - pDvdVideoPicture->eglimg = frame->eglimg; - #if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>> pic dts:%f, pts:%llu, img:%p, tm:%d\n", pDvdVideoPicture->dts, frame->pts, pDvdVideoPicture->eglimg, XbmcThreads::SystemClockMillis() - time); - #endif - } - else if (pDvdVideoPicture->format == RENDER_FMT_YUV420P) - { - pDvdVideoPicture->color_range = 0; - pDvdVideoPicture->color_matrix = 4; - - unsigned int luma_pixels = frame->width * frame->height; - unsigned int chroma_pixels = luma_pixels/4; - uint8_t* data = NULL; - if (frame->medbuf && !p->drop_state) - { - data = (uint8_t*)((long)frame->medbuf->data() + frame->medbuf->range_offset()); - } - switch (p->videoColorFormat) - { - case OMX_COLOR_FormatYUV420Planar: - pDvdVideoPicture->iLineSize[0] = frame->width; - pDvdVideoPicture->iLineSize[1] = frame->width / 2; - pDvdVideoPicture->iLineSize[2] = frame->width / 2; - pDvdVideoPicture->iLineSize[3] = 0; - pDvdVideoPicture->data[0] = data; - pDvdVideoPicture->data[1] = pDvdVideoPicture->data[0] + luma_pixels; - pDvdVideoPicture->data[2] = pDvdVideoPicture->data[1] + chroma_pixels; - pDvdVideoPicture->data[3] = 0; - break; - case OMX_COLOR_FormatYUV420SemiPlanar: - case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: - case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: - pDvdVideoPicture->iLineSize[0] = frame->width; - pDvdVideoPicture->iLineSize[1] = frame->width; - pDvdVideoPicture->iLineSize[2] = 0; - pDvdVideoPicture->iLineSize[3] = 0; - pDvdVideoPicture->data[0] = data; - pDvdVideoPicture->data[1] = pDvdVideoPicture->data[0] + luma_pixels; - pDvdVideoPicture->data[2] = pDvdVideoPicture->data[1] + chroma_pixels; - pDvdVideoPicture->data[3] = 0; - break; - default: - CLog::Log(LOGERROR, "%s::%s - Unsupported color format(%d)\n", CLASSNAME, __func__,p->videoColorFormat); - } - #if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>> pic pts:%f, data:%p, col:%d, w:%d, h:%d, tm:%d\n", pDvdVideoPicture->pts, data, p->videoColorFormat, frame->width, frame->height, XbmcThreads::SystemClockMillis() - time); - #endif - } - - if (p->drop_state) - pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; - - p->prev_frame = p->cur_frame; - p->cur_frame = NULL; - p->out_condition.notify(); - p->out_mutex.unlock(); - - return true; -} - -void CStageFrightVideo::Close() -{ -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::Close\n", CLASSNAME); -#endif - - Frame *frame; - - if (p->decode_thread && p->decode_thread->IsRunning()) - p->decode_thread->StopThread(false); - p->decode_thread = NULL; - p->in_condition.notify(); - - // Give decoder_thread time to process EOS, if stuck on reading - usleep(50000); - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "Cleaning OUT\n"); -#endif - p->out_mutex.lock(); - if (p->cur_frame) - { - if (p->cur_frame->medbuf) - p->cur_frame->medbuf->release(); - free(p->cur_frame); - p->cur_frame = NULL; - } - p->out_condition.notify(); - p->out_mutex.unlock(); - - if (p->prev_frame) - { - if (p->prev_frame->medbuf) - p->prev_frame->medbuf->release(); - free(p->prev_frame); - p->prev_frame = NULL; - } - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "Stopping omxcodec\n"); -#endif - p->decoder->stop(); - p->client->disconnect(); - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "Cleaning IN(%d)\n", p->in_queue.size()); -#endif - std::map::iterator it; - while (!p->in_queue.empty()) - { - it = p->in_queue.begin(); - frame = it->second; - p->in_queue.erase(it); - if (frame->medbuf) - frame->medbuf->release(); - free(frame); - } - - if (p->decoder_component) - free(&p->decoder_component); - - delete p->client; - - if ((p->quirks & QuirkSWRender) == 0) - p->UninitStagefrightSurface(); - - for (int i=0; iinbuf[i]->setObserver(NULL); - p->inbuf[i]->release(); - } - - delete p; -} - -void CStageFrightVideo::Reset(void) -{ -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::Reset\n", CLASSNAME); -#endif - Frame* frame; - p->in_mutex.lock(); - std::map::iterator it; - while (!p->in_queue.empty()) - { - it = p->in_queue.begin(); - frame = it->second; - p->in_queue.erase(it); - if (frame->medbuf) - frame->medbuf->release(); - free(frame); - } - p->resetting = true; - p->framecount = 0; - - p->in_mutex.unlock(); -} - -void CStageFrightVideo::SetDropState(bool bDrop) -{ - if (bDrop == p->drop_state) - return; - -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::SetDropState (%d->%d)\n", CLASSNAME,p->drop_state,bDrop); -#endif - - p->drop_state = bDrop; -} - -void CStageFrightVideo::SetSpeed(int iSpeed) -{ -} - -/***************/ - -void CStageFrightVideo::LockBuffer(EGLImageKHR eglimg) -{ - #if defined(DEBUG_VERBOSE) - unsigned int time = XbmcThreads::SystemClockMillis(); -#endif - p->free_mutex.lock(); - std::list >::iterator it = p->free_queue.begin(); - for(;it != p->free_queue.end(); ++it) - { - if ((*it).first == eglimg) - break; - } - if (it == p->free_queue.end()) - { - p->busy_queue.push_back(std::pair(*it)); - p->free_mutex.unlock(); - return; - } -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "Locking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time); -#endif - - p->busy_queue.push_back(std::pair(*it)); - p->free_queue.erase(it); - p->free_mutex.unlock(); -} - -void CStageFrightVideo::ReleaseBuffer(EGLImageKHR eglimg) -{ - #if defined(DEBUG_VERBOSE) - unsigned int time = XbmcThreads::SystemClockMillis(); -#endif - p->free_mutex.lock(); - int cnt = 0; - std::list >::iterator it = p->busy_queue.begin(); - std::list >::iterator itfree; - for(;it != p->busy_queue.end(); ++it) - { - if ((*it).first == eglimg) - { - cnt++; - if (cnt==1) - itfree = it; - else - break; - } - } - if (it == p->busy_queue.end() && !cnt) - { - p->free_mutex.unlock(); - return; - } -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "Unlocking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time); -#endif - - if (cnt==1) - { - p->free_queue.push_back(std::pair(*itfree)); - p->busy_queue.erase(itfree); - } - p->free_mutex.unlock(); -} diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.h deleted file mode 100644 index 7e3cfd5..0000000 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideo.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -/* - * Copyright (C) 2010-2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ - -#if defined(HAS_LIBSTAGEFRIGHT) - -#include "cores/dvdplayer/DVDStreamInfo.h" -#include "DVDVideoCodec.h" - -class CStageFrightVideoPrivate; - -namespace android { class MediaBuffer; } - -class CStageFrightVideo -{ -public: - CStageFrightVideo() {}; - virtual ~CStageFrightVideo() {}; - - bool Open(CDVDStreamInfo &hints); - void Close(void); - int Decode(uint8_t *pData, int iSize, double dts, double pts); - void Reset(void); - bool GetPicture(DVDVideoPicture *pDvdVideoPicture); - bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); - void SetDropState(bool bDrop); - virtual void SetSpeed(int iSpeed); - - void LockBuffer(EGLImageKHR eglimg); - void ReleaseBuffer(EGLImageKHR eglimg); - -private: - CStageFrightVideoPrivate* p; -}; - -// defined(HAS_LIBSTAGEFRIGHT) -#endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.cpp deleted file mode 100644 index 996a38d..0000000 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (C) 2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ -/***************************************************************************/ - -#include "StageFrightVideoPrivate.h" - -#include -#include -#include -#include -#include "windowing/egl/EGLWrapper.h" -#include "windowing/WindowingFactory.h" -#include "utils/log.h" - -#include "android/jni/Surface.h" -#include "android/jni/SurfaceTexture.h" - -GLint glerror; -#define CheckEglError(x) while((glerror = eglGetError()) != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",x, glerror); -#define CheckGlError(x) while((glerror = glGetError()) != GL_NO_ERROR) CLog::Log(LOGERROR, "GL error in %s: %x",x, glerror); - -// EGL extension functions -static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; -static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; -static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; - -int NP2( unsigned x ) { - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return ++x; -} - -CStageFrightVideoPrivate::CStageFrightVideoPrivate() - : decode_thread(NULL), source(NULL) - , eglDisplay(EGL_NO_DISPLAY), eglSurface(EGL_NO_SURFACE), eglContext(EGL_NO_CONTEXT) - , eglInitialized(false) - , framecount(0) - , quirks(QuirkNone), cur_frame(NULL), prev_frame(NULL) - , width(-1), height(-1) - , texwidth(-1), texheight(-1) - , client(NULL), decoder(NULL), decoder_component(NULL) - , drop_state(false), resetting(false) - , mVideoNativeWindow(NULL) -{ - if (!eglCreateImageKHR) - eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR"); - if (!eglDestroyImageKHR) - eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR"); - if (!glEGLImageTargetTexture2DOES) - glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES"); -} - -void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer) -{ -} - -MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size) -{ - int i=0; - for (; irefcount() == 0 && inbuf[i]->size() >= size) - break; - if (i == INBUFCOUNT) - { - i = 0; - for (; irefcount() == 0) - break; - if (i == INBUFCOUNT) - return NULL; - inbuf[i]->setObserver(NULL); - inbuf[i]->release(); - inbuf[i] = new MediaBuffer(size); - inbuf[i]->setObserver(this); - } - - inbuf[i]->add_ref(); - inbuf[i]->set_range(0, size); - return inbuf[i]; -} - -bool CStageFrightVideoPrivate::inputBufferAvailable() -{ - for (int i=0; irefcount() == 0) - return true; - - return false; -} - -void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader) -{ -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>loadOESShader\n"); -#endif - - GLuint shader = glCreateShader(shaderType); - CheckGlError("loadOESShader"); - if (shader) { - glShaderSource(shader, 1, &pSource, NULL); - glCompileShader(shader); - GLint compiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLen = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen) { - char* buf = (char*) malloc(infoLen); - if (buf) { - glGetShaderInfoLog(shader, infoLen, NULL, buf); - printf("Shader compile log:\n%s\n", buf); - free(buf); - } - } else { - char* buf = (char*) malloc(0x1000); - if (buf) { - glGetShaderInfoLog(shader, 0x1000, NULL, buf); - printf("Shader compile log:\n%s\n", buf); - free(buf); - } - } - glDeleteShader(shader); - shader = 0; - } - } - *outShader = shader; -} - -void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm) -{ -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>createOESProgram\n"); -#endif - GLuint vertexShader, fragmentShader; - { - loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader); - } - { - loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader); - } - - GLuint program = glCreateProgram(); - if (program) { - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - GLint linkStatus = GL_FALSE; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - if (linkStatus != GL_TRUE) { - GLint bufLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); - if (bufLength) { - char* buf = (char*) malloc(bufLength); - if (buf) { - glGetProgramInfoLog(program, bufLength, NULL, buf); - printf("Program link log:\n%s\n", buf); - free(buf); - } - } - glDeleteProgram(program); - program = 0; - } - } - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - *outPgm = program; -} - -void CStageFrightVideoPrivate::OES_shader_setUp() -{ - - const char vsrc[] = - "attribute vec4 vPosition;\n" - "varying vec2 texCoords;\n" - "uniform mat4 texMatrix;\n" - "void main() {\n" - " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n" - " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n" - " gl_Position = vPosition;\n" - "}\n"; - - const char fsrc[] = - "#extension GL_OES_EGL_image_external : require\n" - "precision mediump float;\n" - "uniform samplerExternalOES texSampler;\n" - "varying vec2 texCoords;\n" - "void main() {\n" - " gl_FragColor = texture2D(texSampler, texCoords);\n" - "}\n"; - - { - #if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n"); - #endif - CheckGlError("OES_shader_setUp"); - createOESProgram(vsrc, fsrc, &mPgm); - } - - mPositionHandle = glGetAttribLocation(mPgm, "vPosition"); - mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler"); - mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix"); -} - -void CStageFrightVideoPrivate::InitializeEGL(int w, int h) -{ - texwidth = w; - texheight = h; - if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT")) - { - texwidth = NP2(texwidth); - texheight = NP2(texheight); - } - - eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglBindAPI(EGL_OPENGL_ES_API); - EGLint contextAttributes[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - eglContext = eglCreateContext(eglDisplay, g_Windowing.GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes); - EGLint pbufferAttribs[] = { - EGL_WIDTH, texwidth, - EGL_HEIGHT, texheight, - EGL_NONE - }; - eglSurface = eglCreatePbufferSurface(eglDisplay, g_Windowing.GetEGLConfig(), pbufferAttribs); - eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); - CheckGlError("stf init"); - - static const EGLint imageAttributes[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, - EGL_GL_TEXTURE_LEVEL_KHR, 0, - EGL_NONE - }; - - for (int i=0; i(slots[i].eglimg, i)); - - } - glBindTexture(GL_TEXTURE_2D, 0); - - fbo.Initialize(); - OES_shader_setUp(); - - eglInitialized = true; -#if defined(DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s: >>> Initialized EGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight); -#endif -} - -void CStageFrightVideoPrivate::UninitializeEGL() -{ - fbo.Cleanup(); - for (int i=0; iget_raw()); - native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA); - - return true; -} - -void CStageFrightVideoPrivate::UninitStagefrightSurface() -{ - if (mVideoNativeWindow == NULL) - return; - - native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA); - ANativeWindow_release(mVideoNativeWindow.get()); - mVideoNativeWindow = NULL; - - delete mSurface; - delete mSurfTexture; - - glDeleteTextures(1, &mVideoTextureId); -} - -void CStageFrightVideoPrivate::UpdateStagefrightTexture() -{ - mSurfTexture->updateTexImage(); -} - -void CStageFrightVideoPrivate::GetStagefrightTransformMatrix(float* transformMatrix) -{ - mSurfTexture->getTransformMatrix(transformMatrix); -} - diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.h deleted file mode 100644 index 2f9886f..0000000 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/StageFrightVideoPrivate.h +++ /dev/null @@ -1,160 +0,0 @@ -#pragma once -/* - * Copyright (C) 2013 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ -/***************************************************************************/ - -#include "threads/Thread.h" -#include "xbmc/guilib/FrameBufferObject.h" -#include "cores/VideoRenderers/RenderFormats.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "system_gl.h" - -#include -#include - -#define NUMFBOTEX 4 -#define INBUFCOUNT 16 - -class CStageFrightDecodeThread; -class CJNISurface; -class CJNISurfaceTexture; - -using namespace android; - -struct tex_slot -{ - GLuint texid; - EGLImageKHR eglimg; -}; - -struct Frame -{ - status_t status; - int32_t width, height; - int64_t pts; - ERenderFormat format; - EGLImageKHR eglimg; - MediaBuffer* medbuf; -}; - -enum StageFrightQuirks -{ - QuirkNone = 0, - QuirkSWRender = 0x01, -}; - -class CStageFrightVideoPrivate : public MediaBufferObserver -{ -public: - CStageFrightVideoPrivate(); - - virtual void signalBufferReturned(MediaBuffer *buffer); - - MediaBuffer* getBuffer(size_t size); - bool inputBufferAvailable(); - - void loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader); - void createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm); - void OES_shader_setUp(); - void InitializeEGL(int w, int h); - void UninitializeEGL(); - -public: - CStageFrightDecodeThread* decode_thread; - - sp source; - - MediaBuffer* inbuf[INBUFCOUNT]; - - GLuint mPgm; - GLint mPositionHandle; - GLint mTexSamplerHandle; - GLint mTexMatrixHandle; - - CFrameBufferObject fbo; - EGLDisplay eglDisplay; - EGLSurface eglSurface; - EGLContext eglContext; - bool eglInitialized; - - tex_slot slots[NUMFBOTEX]; - std::list< std::pair > free_queue; - std::list< std::pair > busy_queue; - - sp meta; - int64_t framecount; - std::map in_queue; - std::map out_queue; - CCriticalSection in_mutex; - CCriticalSection out_mutex; - CCriticalSection free_mutex; - XbmcThreads::ConditionVariable in_condition; - XbmcThreads::ConditionVariable out_condition; - - int quirks; - Frame *cur_frame; - Frame *prev_frame; - bool source_done; - int x, y; - int width, height; - int texwidth, texheight; - - OMXClient *client; - sp decoder; - const char *decoder_component; - int videoColorFormat; - int videoStride; - int videoSliceHeight; - - bool drop_state; - bool resetting; -#if defined(DEBUG_VERBOSE) - unsigned int cycle_time; -#endif - - unsigned int mVideoTextureId; - CJNISurfaceTexture* mSurfTexture; - CJNISurface* mSurface; - sp mVideoNativeWindow; - - bool InitStagefrightSurface(); - void UninitStagefrightSurface(); - void UpdateStagefrightTexture(); - void GetStagefrightTransformMatrix(float* transformMatrix); -}; diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile.in new file mode 100644 index 0000000..81d7b6e --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/Makefile.in @@ -0,0 +1,49 @@ +ARCH=@ARCH@ + +INCLUDES+=-I@abs_top_srcdir@/xbmc/cores/dvdplayer +INCLUDES+=-I.. + +SRCS += StageFrightInterface.cpp +SRCS += StageFrightVideo.cpp +SRCS += StageFrightVideoPrivate.cpp +INCLUDES += -I${prefix}/opt/android-source/frameworks/base/include +INCLUDES += -I${prefix}/opt/android-source/frameworks/base/native/include +INCLUDES += -I${prefix}/opt/android-source/frameworks/base/include/media/stagefright +INCLUDES += -I${prefix}/opt/android-source/frameworks/base/include/media/stagefright/openmax +INCLUDES += -I${prefix}/opt/android-source/system/core/include +INCLUDES += -I${prefix}/opt/android-source/libhardware/include + +LIBNAME=libXBMCvcodec_stagefrightICS +LIB_SHARED=@abs_top_srcdir@/system/players/dvdplayer/$(LIBNAME)-$(ARCH).so + +LIBS += -landroid -lEGL -lGLESv2 -L${prefix}/opt/android-libs -lstdc++ -lutils -lcutils -lstagefright -lbinder -lui -lgui -L@abs_top_srcdir@ -lxbmc + +all: $(LIB_SHARED) + +include @abs_top_srcdir@/Makefile.include +-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) + +JNICXXFLAGS = $(CXXFLAGS) -std=gnu++0x -Wextra +STFCXXFLAGS = $(CXXFLAGS) -Wno-multichar -fno-rtti -fPIC + +$(LIB_SHARED): $(OBJS) + $(CXX) $(STFCXXFLAGS) $(LDFLAGS) -shared -Wl,-no-undefined -g -o $(LIB_SHARED) $(OBJS) $(LIBS) + +StageFrightVideo.o: StageFrightVideo.cpp + $(CXX) -MF $*.d -MD -c $(STFCXXFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ + +StageFrightVideoPrivate.o: StageFrightVideoPrivate.cpp + $(CXX) -MF $*.d -MD -c $(STFCXXFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ + +Surface.o: Surface.cpp + $(CXX) -MF $*.d -MD -c $(JNICXXFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ + +SurfaceTexture.o: SurfaceTexture.cpp + $(CXX) -MF $*.d -MD -c $(JNICXXFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ + +CLEAN_FILES = \ + $(LIB_SHARED) \ + +DISTCLEAN_FILES= \ + Makefile \ + diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.cpp new file mode 100644 index 0000000..b2305d7 --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistfribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distfributed 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "StageFrightInterface.h" +#include "StageFrightVideo.h" + +#include "windowing/WindowingFactory.h" +#include "settings/AdvancedSettings.h" + +void* create_stf(CWinSystemEGL* windowing, CAdvancedSettings* advsettings) +{ + return (void*)new CStageFrightVideo(windowing, advsettings); +} + +void destroy_stf(void* stf) +{ + delete (CStageFrightVideo*)stf; +} + +bool stf_Open(void* stf, CDVDStreamInfo &hints) +{ + return ((CStageFrightVideo*)stf)->Open(hints); +} + +void stf_Close(void* stf) +{ + ((CStageFrightVideo*)stf)->Close(); +} + +int stf_Decode(void* stf, uint8_t *pData, int iSize, double dts, double pts) +{ + return ((CStageFrightVideo*)stf)->Decode(pData, iSize, dts, pts); +} + +void stf_Reset(void* stf) +{ + ((CStageFrightVideo*)stf)->Reset(); +} + +bool stf_GetPicture(void* stf, DVDVideoPicture *pDvdVideoPicture) +{ + return ((CStageFrightVideo*)stf)->GetPicture(pDvdVideoPicture); +} + +bool stf_ClearPicture(void* stf, DVDVideoPicture* pDvdVideoPicture) +{ + return ((CStageFrightVideo*)stf)->ClearPicture(pDvdVideoPicture); +} + +void stf_SetDropState(void* stf, bool bDrop) +{ + ((CStageFrightVideo*)stf)->SetDropState(bDrop); +} + +void stf_SetSpeed(void* stf, int iSpeed) +{ + ((CStageFrightVideo*)stf)->SetSpeed(iSpeed); +} + +void stf_LockBuffer(void* stf, EGLImageKHR eglimg) +{ + ((CStageFrightVideo*)stf)->LockBuffer(eglimg); +} + +void stf_ReleaseBuffer(void* stf, EGLImageKHR eglimg) +{ + ((CStageFrightVideo*)stf)->ReleaseBuffer(eglimg); +} + diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.h new file mode 100644 index 0000000..6c4eebf --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterface.h @@ -0,0 +1,45 @@ +#pragma once + +/* + * Copyright (C) 2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "DVDVideoCodec.h" + +class CStageFrightVideo; +class CWinSystemEGL; +class CAdvancedSettings; + +extern "C" +{ + void* create_stf(CWinSystemEGL* windowing, CAdvancedSettings* advsettings); + void destroy_stf(void*); + + bool stf_Open(void*, CDVDStreamInfo &hints); + void stf_Close(void*); + int stf_Decode(void*, uint8_t *pData, int iSize, double dts, double pts); + void stf_Reset(void*); + bool stf_GetPicture(void*, DVDVideoPicture *pDvdVideoPicture); + bool stf_ClearPicture(void*, DVDVideoPicture* pDvdVideoPicture); + void stf_SetDropState(void*, bool bDrop); + void stf_SetSpeed(void*, int iSpeed); + + void stf_LockBuffer(void*, EGLImageKHR eglimg); + void stf_ReleaseBuffer(void*, EGLImageKHR eglimg); +} diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.cpp new file mode 100644 index 0000000..1165525 --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.cpp @@ -0,0 +1,969 @@ +/* + * Copyright (C) 2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ +/***************************************************************************/ + +//#define DEBUG_VERBOSE 1 + +#include "system.h" +#include "system_gl.h" + +#include "StageFrightVideo.h" +#include "StageFrightVideoPrivate.h" + +#include "guilib/GraphicContext.h" +#include "DVDClock.h" +#include "utils/log.h" +#include "utils/fastmemcpy.h" +#include "threads/Thread.h" +#include "threads/Event.h" +#include "settings/AdvancedSettings.h" + +#include "xbmc/guilib/FrameBufferObject.h" + +#include +#include +#include "windowing/egl/EGLWrapper.h" +#include "windowing/WindowingFactory.h" + +#include + +#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00 +#define OMX_TI_COLOR_FormatYUV420PackedSemiPlanar 0x7F000100 + +#define CLASSNAME "CStageFrightVideo" + +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 + +const char *MEDIA_MIMETYPE_VIDEO_WMV = "video/x-ms-wmv"; + +using namespace android; + +static int64_t pts_dtoi(double pts) +{ + return (int64_t)(pts); +} + +static double pts_itod(int64_t pts) +{ + return (double)pts; +} + +/***********************************************************/ + +class CStageFrightMediaSource : public MediaSource +{ +public: + CStageFrightMediaSource(CStageFrightVideoPrivate *priv, sp meta) + { + p = priv; + source_meta = meta; + } + + virtual sp getFormat() + { + return source_meta; + } + + virtual status_t start(MetaData *params) + { + return OK; + } + + virtual status_t stop() + { + return OK; + } + + virtual status_t read(MediaBuffer **buffer, + const MediaSource::ReadOptions *options) + { + Frame *frame; + status_t ret; + *buffer = NULL; + int64_t time_us = -1; + MediaSource::ReadOptions::SeekMode mode; + + if (options && options->getSeekTo(&time_us, &mode)) + { +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: reading source(%d): seek:%llu\n", CLASSNAME,p->in_queue.size(), time_us); +#endif + } + else + { +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: reading source(%d)\n", CLASSNAME,p->in_queue.size()); +#endif + } + + p->in_mutex.lock(); + while (p->in_queue.empty() && p->decode_thread) + p->in_condition.wait(p->in_mutex); + + if (p->in_queue.empty()) + { + p->in_mutex.unlock(); + return VC_ERROR; + } + + std::map::iterator it = p->in_queue.begin(); + frame = it->second; + ret = frame->status; + *buffer = frame->medbuf; + + p->in_queue.erase(it); + p->in_mutex.unlock(); + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> exiting reading source(%d); pts:%llu\n", p->in_queue.size(),frame->pts); +#endif + + free(frame); + + return ret; + } + +private: + sp source_meta; + CStageFrightVideoPrivate *p; +}; + +/********************************************/ + +class CStageFrightDecodeThread : public CThread +{ +protected: + CStageFrightVideoPrivate *p; + +public: + CStageFrightDecodeThread(CStageFrightVideoPrivate *priv) + : CThread("CStageFrightDecodeThread") + , p(priv) + {} + + void OnStartup() + { + #if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: entering decode thread\n", CLASSNAME); + #endif + } + + void OnExit() + { + #if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: exited decode thread\n", CLASSNAME); + #endif + } + + void Process() + { + Frame* frame; + int32_t w, h, dw, dh; + int decode_done = 0; + int32_t keyframe = 0; + int32_t unreadable = 0; + MediaSource::ReadOptions readopt; + // GLuint texid; + + //SetPriority(THREAD_PRIORITY_ABOVE_NORMAL); + do + { + #if defined(DEBUG_VERBOSE) + unsigned int time = XbmcThreads::SystemClockMillis(); + CLog::Log(LOGDEBUG, "%s: >>> Handling frame\n", CLASSNAME); + #endif + p->cur_frame = NULL; + frame = (Frame*)malloc(sizeof(Frame)); + if (!frame) + { + decode_done = 1; + continue; + } + + frame->eglimg = EGL_NO_IMAGE_KHR; + frame->medbuf = NULL; + if (p->resetting) + { + readopt.setSeekTo(0); + p->resetting = false; + } + frame->status = p->decoder->read(&frame->medbuf, &readopt); + readopt.clearSeekTo(); + + if (frame->status == OK) + { + if (!frame->medbuf->graphicBuffer().get()) // hw buffers + { + if (frame->medbuf->range_length() == 0) + { + CLog::Log(LOGERROR, "%s - Invalid buffer\n", CLASSNAME); + frame->status = VC_ERROR; + decode_done = 1; + frame->medbuf->release(); + frame->medbuf = NULL; + } + else + frame->format = RENDER_FMT_YUV420P; + } + else + frame->format = RENDER_FMT_EGLIMG; + } + + if (frame->status == OK) + { + frame->width = p->width; + frame->height = p->height; + frame->pts = 0; + + sp outFormat = p->decoder->getFormat(); + outFormat->findInt32(kKeyWidth , &w); + outFormat->findInt32(kKeyHeight, &h); + + // The OMX.SEC decoder doesn't signal the modified width/height + if (p->decoder_component && (w & 15 || h & 15) && !strncmp(p->decoder_component, "OMX.SEC", 7)) + { + if (((w + 15)&~15) * ((h + 15)&~15) * 3/2 == frame->medbuf->range_length()) + { + w = (w + 15)&~15; + h = (h + 15)&~15; + frame->width = w; + frame->height = h; + } + } + frame->medbuf->meta_data()->findInt64(kKeyTime, &(frame->pts)); + } + else if (frame->status == INFO_FORMAT_CHANGED) + { + int32_t cropLeft, cropTop, cropRight, cropBottom; + sp outFormat = p->decoder->getFormat(); + + outFormat->findInt32(kKeyWidth , &p->width); + outFormat->findInt32(kKeyHeight, &p->height); + + cropLeft = cropTop = cropRight = cropBottom = 0; + if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) + { + p->x = 0; + p->y = 0; + } + else + { + p->x = cropLeft; + p->y = cropTop; + p->width = cropRight - cropLeft + 1; + p->height = cropBottom - cropTop + 1; + } + outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat); + if (!outFormat->findInt32(kKeyStride, &p->videoStride)) + p->videoStride = p->width; + if (!outFormat->findInt32(kKeySliceHeight, &p->videoSliceHeight)) + p->videoSliceHeight = p->height; + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> new format col:%d, w:%d, h:%d, sw:%d, sh:%d, ctl:%d,%d; cbr:%d,%d\n", p->videoColorFormat, p->width, p->height, p->videoStride, p->videoSliceHeight, cropTop, cropLeft, cropBottom, cropRight); +#endif + + if (frame->medbuf) + frame->medbuf->release(); + frame->medbuf = NULL; + free(frame); + continue; + } + else + { + CLog::Log(LOGERROR, "%s - decoding error (%d)\n", CLASSNAME,frame->status); + if (frame->medbuf) + frame->medbuf->release(); + frame->medbuf = NULL; + free(frame); + continue; + } + + if (frame->format == RENDER_FMT_EGLIMG) + { + if (!p->eglInitialized) + { + p->InitializeEGL(frame->width, frame->height); + } + else if (p->texwidth != frame->width || p->texheight != frame->height) + { + p->UninitializeEGL(); + p->InitializeEGL(frame->width, frame->height); + } + + if (p->free_queue.empty()) + { + CLog::Log(LOGERROR, "%s::%s - Error: No free output buffers\n", CLASSNAME, __func__); + if (frame->medbuf) + frame->medbuf->release(); + free(frame); + continue; + } + + ANativeWindowBuffer* graphicBuffer = frame->medbuf->graphicBuffer()->getNativeBuffer(); + native_window_set_buffers_timestamp(p->mVideoNativeWindow.get(), frame->pts * 1000); + int err = p->mVideoNativeWindow.get()->queueBuffer(p->mVideoNativeWindow.get(), graphicBuffer); + if (err == 0) + frame->medbuf->meta_data()->setInt32(kKeyRendered, 1); + frame->medbuf->release(); + frame->medbuf = NULL; + p->UpdateStagefrightTexture(); + + if (!p->drop_state) + { + p->free_mutex.lock(); + while (!p->free_queue.size()) + usleep(10000); + std::list >::iterator itfree = p->free_queue.begin(); + int cur_slot = itfree->second; + p->fbo.BindToTexture(GL_TEXTURE_2D, p->slots[cur_slot].texid); + p->fbo.BeginRender(); + + glDisable(GL_DEPTH_TEST); + //glClear(GL_COLOR_BUFFER_BIT); + + const GLfloat triangleVertices[] = { + -1.0f, 1.0f, + -1.0f, -1.0f, + 1.0f, -1.0f, + 1.0f, 1.0f, + }; + + glVertexAttribPointer(p->mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); + glEnableVertexAttribArray(p->mPositionHandle); + + glUseProgram(p->mPgm); + glUniform1i(p->mTexSamplerHandle, 0); + + glBindTexture(GL_TEXTURE_EXTERNAL_OES, p->mVideoTextureId); + + GLfloat texMatrix[16]; + // const GLfloat texMatrix[] = { + // 1, 0, 0, 0, + // 0, -1, 0, 0, + // 0, 0, 1, 0, + // 0, 1, 0, 1 + // }; + p->GetStagefrightTransformMatrix(texMatrix); + glUniformMatrix4fv(p->mTexMatrixHandle, 1, GL_FALSE, texMatrix); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); + // glDeleteTextures(1, &texid); + // eglDestroyImageKHR(p->eglDisplay, img); + p->fbo.EndRender(); + + glBindTexture(GL_TEXTURE_2D, 0); + + frame->eglimg = p->slots[cur_slot].eglimg; + p->busy_queue.push_back(std::pair(*itfree)); + p->free_queue.erase(itfree); + p->free_mutex.unlock(); + } + } + + #if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: >>> pushed OUT frame; w:%d, h:%d, dw:%d, dh:%d, kf:%d, ur:%d, img:%p, tm:%d\n", CLASSNAME, frame->width, frame->height, dw, dh, keyframe, unreadable, frame->eglimg, XbmcThreads::SystemClockMillis() - time); + #endif + + p->out_mutex.lock(); + p->cur_frame = frame; + while (p->cur_frame) + p->out_condition.wait(p->out_mutex); + p->out_mutex.unlock(); + } + while (!decode_done && !m_bStop); + + if (p->eglInitialized) + p->UninitializeEGL(); + + } +}; + +/***********************************************************/ + +CStageFrightVideo::CStageFrightVideo(CWinSystemEGL* windowing, CAdvancedSettings* advsettings) +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::ctor: %d\n", CLASSNAME, sizeof(CStageFrightVideo)); +#endif + p = new CStageFrightVideoPrivate; + p->m_g_Windowing = windowing; + p->m_g_advancedSettings = advsettings; +} + +CStageFrightVideo::~CStageFrightVideo() +{ + delete p; +} + +bool CStageFrightVideo::Open(CDVDStreamInfo &hints) +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::Open\n", CLASSNAME); +#endif + + CSingleLock lock(g_graphicsContext); + + // stagefright crashes with null size. Trap this... + if (!hints.width || !hints.height) + { + CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"null size, cannot handle"); + return false; + } + p->width = hints.width; + p->height = hints.height; + + if (p->m_g_advancedSettings->m_stagefrightConfig.useSwRenderer) + p->quirks |= QuirkSWRender; + + sp outFormat; + int32_t cropLeft, cropTop, cropRight, cropBottom; + //Vector matchingCodecs; + + p->meta = new MetaData; + if (p->meta == NULL) + { + CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"cannot allocate MetaData"); + return false; + } + + const char* mimetype; + switch (hints.codec) + { + case CODEC_ID_H264: + if (p->m_g_advancedSettings->m_stagefrightConfig.useAVCcodec == 0) + return false; + mimetype = MEDIA_MIMETYPE_VIDEO_AVC; + if ( *(char*)hints.extradata == 1 ) + p->meta->setData(kKeyAVCC, kTypeAVCC, hints.extradata, hints.extrasize); + break; + case CODEC_ID_MPEG4: + if (p->m_g_advancedSettings->m_stagefrightConfig.useMP4codec == 0) + return false; + mimetype = MEDIA_MIMETYPE_VIDEO_MPEG4; + break; + case CODEC_ID_MPEG2VIDEO: + if (p->m_g_advancedSettings->m_stagefrightConfig.useMPEG2codec == 0) + return false; + mimetype = MEDIA_MIMETYPE_VIDEO_MPEG2; + break; + case CODEC_ID_VP3: + case CODEC_ID_VP6: + case CODEC_ID_VP6F: + case CODEC_ID_VP8: + if (p->m_g_advancedSettings->m_stagefrightConfig.useVPXcodec == 0) + return false; + mimetype = MEDIA_MIMETYPE_VIDEO_VPX; + break; + case CODEC_ID_VC1: + case CODEC_ID_WMV3: + if (p->m_g_advancedSettings->m_stagefrightConfig.useVC1codec == 0) + return false; + mimetype = MEDIA_MIMETYPE_VIDEO_WMV; + break; + default: + return false; + break; + } + + p->meta->setCString(kKeyMIMEType, mimetype); + p->meta->setInt32(kKeyWidth, p->width); + p->meta->setInt32(kKeyHeight, p->height); + + android::ProcessState::self()->startThreadPool(); + + p->source = new CStageFrightMediaSource(p, p->meta); + p->client = new OMXClient; + + if (p->source == NULL || p->client == NULL) + { + CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot obtain source / client"); + return false; + } + + if (p->client->connect() != OK) + { + delete p->client; + p->client = NULL; + CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot connect OMX client"); + return false; + } + + if ((p->quirks & QuirkSWRender) == 0) + p->InitStagefrightSurface(); + + p->decoder = OMXCodec::Create(p->client->interface(), p->meta, + false, p->source, NULL, + OMXCodec::kHardwareCodecsOnly | (p->quirks & QuirkSWRender ? OMXCodec::kClientNeedsFramebuffer : 0), + p->mVideoNativeWindow + ); + + if (!(p->decoder != NULL && p->decoder->start() == OK)) + { + p->decoder = NULL; + return false; + } + + outFormat = p->decoder->getFormat(); + + if (!outFormat->findInt32(kKeyWidth, &p->width) || !outFormat->findInt32(kKeyHeight, &p->height) + || !outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat)) + return false; + + const char *component; + if (outFormat->findCString(kKeyDecoderComponent, &component)) + { + CLog::Log(LOGDEBUG, "%s::%s - component: %s\n", CLASSNAME, __func__, component); + + //Blacklist + if (!strncmp(component, "OMX.google", 10)) + { + // On some platforms, software decoders are returned anyway + CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (software)"); + return false; + } + else if (!strncmp(component, "OMX.Nvidia.mp4.decode", 21) && p->m_g_advancedSettings->m_stagefrightConfig.useMP4codec != 1) + { + // Has issues with some XVID encoded MP4. Only fails after actual decoding starts... + CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (MP4)"); + return false; + } + } + + cropLeft = cropTop = cropRight = cropBottom = 0; + if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) + { + p->x = 0; + p->y = 0; + } + else + { + p->x = cropLeft; + p->y = cropTop; + p->width = cropRight - cropLeft + 1; + p->height = cropBottom - cropTop + 1; + } + + if (!outFormat->findInt32(kKeyStride, &p->videoStride)) + p->videoStride = p->width; + if (!outFormat->findInt32(kKeySliceHeight, &p->videoSliceHeight)) + p->videoSliceHeight = p->height; + + for (int i=0; iinbuf[i] = new MediaBuffer(300000); + p->inbuf[i]->setObserver(p); + } + + p->decode_thread = new CStageFrightDecodeThread(p); + p->decode_thread->Create(true /*autodelete*/); + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> format col:%d, w:%d, h:%d, sw:%d, sh:%d, ctl:%d,%d; cbr:%d,%d\n", p->videoColorFormat, p->width, p->height, p->videoStride, p->videoSliceHeight, cropTop, cropLeft, cropBottom, cropRight); +#endif + + return true; +} + +/*** Decode ***/ +int CStageFrightVideo::Decode(uint8_t *pData, int iSize, double dts, double pts) +{ +#if defined(DEBUG_VERBOSE) + unsigned int time = XbmcThreads::SystemClockMillis(); + CLog::Log(LOGDEBUG, "%s::Decode - d:%p; s:%d; dts:%f; pts:%f\n", CLASSNAME, pData, iSize, dts, pts); +#endif + + Frame *frame; + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; + int ret = 0; + + if (demuxer_content) + { + frame = (Frame*)malloc(sizeof(Frame)); + if (!frame) + return VC_ERROR; + + frame->status = OK; + if (p->m_g_advancedSettings->m_stagefrightConfig.useInputDTS) + frame->pts = (dts != DVD_NOPTS_VALUE) ? pts_dtoi(dts) : ((pts != DVD_NOPTS_VALUE) ? pts_dtoi(pts) : 0); + else + frame->pts = (pts != DVD_NOPTS_VALUE) ? pts_dtoi(pts) : ((dts != DVD_NOPTS_VALUE) ? pts_dtoi(dts) : 0); + + // No valid pts? libstagefright asserts on this. + if (frame->pts < 0) + { + free(frame); + return ret; + } + + frame->medbuf = p->getBuffer(demuxer_bytes); + if (!frame->medbuf) + { + free(frame); + return VC_ERROR; + } + + fast_memcpy(frame->medbuf->data(), demuxer_content, demuxer_bytes); + frame->medbuf->meta_data()->clear(); + frame->medbuf->meta_data()->setInt64(kKeyTime, frame->pts); + + p->in_mutex.lock(); + p->framecount++; + p->in_queue.insert(std::pair(p->framecount, frame)); + p->in_condition.notify(); + p->in_mutex.unlock(); + } + + if (p->inputBufferAvailable() && p->in_queue.size() < INBUFCOUNT) + ret |= VC_BUFFER; + else + usleep(1000); + if (p->cur_frame != NULL) + ret |= VC_PICTURE; +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::Decode: pushed IN frame (%d); tm:%d\n", CLASSNAME,p->in_queue.size(), XbmcThreads::SystemClockMillis() - time); +#endif + + return ret; +} + +bool CStageFrightVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture) +{ + #if defined(DEBUG_VERBOSE) + unsigned int time = XbmcThreads::SystemClockMillis(); +#endif + if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG && pDvdVideoPicture->eglimg != EGL_NO_IMAGE_KHR) + ReleaseBuffer(pDvdVideoPicture->eglimg); + + if (p->prev_frame) { + if (p->prev_frame->medbuf) + p->prev_frame->medbuf->release(); + free(p->prev_frame); + p->prev_frame = NULL; + } +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::ClearPicture (%d)\n", CLASSNAME, XbmcThreads::SystemClockMillis() - time); +#endif + + return true; +} + +bool CStageFrightVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) +{ +#if defined(DEBUG_VERBOSE) + unsigned int time = XbmcThreads::SystemClockMillis(); + CLog::Log(LOGDEBUG, "%s::GetPicture\n", CLASSNAME); + if (p->cycle_time != 0) + CLog::Log(LOGDEBUG, ">>> cycle dur:%d\n", XbmcThreads::SystemClockMillis() - p->cycle_time); + p->cycle_time = time; +#endif + + status_t status; + + p->out_mutex.lock(); + if (!p->cur_frame) + { + CLog::Log(LOGERROR, "%s::%s - Error getting frame\n", CLASSNAME, __func__); + p->out_condition.notify(); + p->out_mutex.unlock(); + return false; + } + + Frame *frame = p->cur_frame; + status = frame->status; + + pDvdVideoPicture->format = frame->format; + pDvdVideoPicture->dts = DVD_NOPTS_VALUE; + pDvdVideoPicture->pts = frame->pts; + pDvdVideoPicture->iWidth = frame->width; + pDvdVideoPicture->iHeight = frame->height; + pDvdVideoPicture->iDisplayWidth = frame->width; + pDvdVideoPicture->iDisplayHeight = frame->height; + pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; + pDvdVideoPicture->eglimg = EGL_NO_IMAGE_KHR; + + if (status != OK) + { + CLog::Log(LOGERROR, "%s::%s - Error getting picture from frame(%d)\n", CLASSNAME, __func__,status); + if (frame->medbuf) { + frame->medbuf->release(); + } + free(frame); + p->cur_frame = NULL; + p->out_condition.notify(); + p->out_mutex.unlock(); + return false; + } + + if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG) + { + pDvdVideoPicture->eglimg = frame->eglimg; + #if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> pic dts:%f, pts:%llu, img:%p, tm:%d\n", pDvdVideoPicture->dts, frame->pts, pDvdVideoPicture->eglimg, XbmcThreads::SystemClockMillis() - time); + #endif + } + else if (pDvdVideoPicture->format == RENDER_FMT_YUV420P) + { + pDvdVideoPicture->color_range = 0; + pDvdVideoPicture->color_matrix = 4; + + unsigned int luma_pixels = frame->width * frame->height; + unsigned int chroma_pixels = luma_pixels/4; + uint8_t* data = NULL; + if (frame->medbuf && !p->drop_state) + { + data = (uint8_t*)((long)frame->medbuf->data() + frame->medbuf->range_offset()); + } + switch (p->videoColorFormat) + { + case OMX_COLOR_FormatYUV420Planar: + pDvdVideoPicture->iLineSize[0] = frame->width; + pDvdVideoPicture->iLineSize[1] = frame->width / 2; + pDvdVideoPicture->iLineSize[2] = frame->width / 2; + pDvdVideoPicture->iLineSize[3] = 0; + pDvdVideoPicture->data[0] = data; + pDvdVideoPicture->data[1] = pDvdVideoPicture->data[0] + luma_pixels; + pDvdVideoPicture->data[2] = pDvdVideoPicture->data[1] + chroma_pixels; + pDvdVideoPicture->data[3] = 0; + break; + case OMX_COLOR_FormatYUV420SemiPlanar: + case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: + case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: + pDvdVideoPicture->iLineSize[0] = frame->width; + pDvdVideoPicture->iLineSize[1] = frame->width; + pDvdVideoPicture->iLineSize[2] = 0; + pDvdVideoPicture->iLineSize[3] = 0; + pDvdVideoPicture->data[0] = data; + pDvdVideoPicture->data[1] = pDvdVideoPicture->data[0] + luma_pixels; + pDvdVideoPicture->data[2] = pDvdVideoPicture->data[1] + chroma_pixels; + pDvdVideoPicture->data[3] = 0; + break; + default: + CLog::Log(LOGERROR, "%s::%s - Unsupported color format(%d)\n", CLASSNAME, __func__,p->videoColorFormat); + } + #if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>> pic pts:%f, data:%p, col:%d, w:%d, h:%d, tm:%d\n", pDvdVideoPicture->pts, data, p->videoColorFormat, frame->width, frame->height, XbmcThreads::SystemClockMillis() - time); + #endif + } + + if (p->drop_state) + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; + + p->prev_frame = p->cur_frame; + p->cur_frame = NULL; + p->out_condition.notify(); + p->out_mutex.unlock(); + + return true; +} + +void CStageFrightVideo::Close() +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::Close\n", CLASSNAME); +#endif + + Frame *frame; + + if (p->decode_thread && p->decode_thread->IsRunning()) + p->decode_thread->StopThread(false); + p->decode_thread = NULL; + p->in_condition.notify(); + + // Give decoder_thread time to process EOS, if stuck on reading + usleep(50000); + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Cleaning OUT\n"); +#endif + p->out_mutex.lock(); + if (p->cur_frame) + { + if (p->cur_frame->medbuf) + p->cur_frame->medbuf->release(); + free(p->cur_frame); + p->cur_frame = NULL; + } + p->out_condition.notify(); + p->out_mutex.unlock(); + + if (p->prev_frame) + { + if (p->prev_frame->medbuf) + p->prev_frame->medbuf->release(); + free(p->prev_frame); + p->prev_frame = NULL; + } + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Stopping omxcodec\n"); +#endif + if (p->decoder != NULL) + p->decoder->stop(); + if (p->client) + p->client->disconnect(); + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Cleaning IN(%d)\n", p->in_queue.size()); +#endif + std::map::iterator it; + while (!p->in_queue.empty()) + { + it = p->in_queue.begin(); + frame = it->second; + p->in_queue.erase(it); + if (frame->medbuf) + frame->medbuf->release(); + free(frame); + } + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Cleaning libstagefright\n", p->in_queue.size()); +#endif + if ((p->quirks & QuirkSWRender) == 0) + p->UninitStagefrightSurface(); + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Final Cleaning\n", p->in_queue.size()); +#endif + if (p->decoder_component) + free(&p->decoder_component); + + delete p->client; + + for (int i=0; iinbuf[i]) + { + p->inbuf[i]->setObserver(NULL); + p->inbuf[i]->release(); + p->inbuf[i] = NULL; + } + } +} + +void CStageFrightVideo::Reset(void) +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::Reset\n", CLASSNAME); +#endif + Frame* frame; + p->in_mutex.lock(); + std::map::iterator it; + while (!p->in_queue.empty()) + { + it = p->in_queue.begin(); + frame = it->second; + p->in_queue.erase(it); + if (frame->medbuf) + frame->medbuf->release(); + free(frame); + } + p->resetting = true; + p->framecount = 0; + + p->in_mutex.unlock(); +} + +void CStageFrightVideo::SetDropState(bool bDrop) +{ + if (bDrop == p->drop_state) + return; + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s::SetDropState (%d->%d)\n", CLASSNAME,p->drop_state,bDrop); +#endif + + p->drop_state = bDrop; +} + +void CStageFrightVideo::SetSpeed(int iSpeed) +{ +} + +/***************/ + +void CStageFrightVideo::LockBuffer(EGLImageKHR eglimg) +{ + #if defined(DEBUG_VERBOSE) + unsigned int time = XbmcThreads::SystemClockMillis(); +#endif + p->free_mutex.lock(); + std::list >::iterator it = p->free_queue.begin(); + for(;it != p->free_queue.end(); ++it) + { + if ((*it).first == eglimg) + break; + } + if (it == p->free_queue.end()) + { + p->busy_queue.push_back(std::pair(*it)); + p->free_mutex.unlock(); + return; + } +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Locking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time); +#endif + + p->busy_queue.push_back(std::pair(*it)); + p->free_queue.erase(it); + p->free_mutex.unlock(); +} + +void CStageFrightVideo::ReleaseBuffer(EGLImageKHR eglimg) +{ + #if defined(DEBUG_VERBOSE) + unsigned int time = XbmcThreads::SystemClockMillis(); +#endif + p->free_mutex.lock(); + int cnt = 0; + std::list >::iterator it = p->busy_queue.begin(); + std::list >::iterator itfree; + for(;it != p->busy_queue.end(); ++it) + { + if ((*it).first == eglimg) + { + cnt++; + if (cnt==1) + itfree = it; + else + break; + } + } + if (it == p->busy_queue.end() && !cnt) + { + p->free_mutex.unlock(); + return; + } +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "Unlocking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time); +#endif + + if (cnt==1) + { + p->free_queue.push_back(std::pair(*itfree)); + p->busy_queue.erase(itfree); + } + p->free_mutex.unlock(); +} diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.h new file mode 100644 index 0000000..4ddc310 --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.h @@ -0,0 +1,56 @@ +#pragma once +/* + * Copyright (C) 2010-2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#if defined(HAS_LIBSTAGEFRIGHT) + +#include "cores/dvdplayer/DVDStreamInfo.h" +#include "DVDVideoCodec.h" + +class CWinSystemEGL; +class CAdvancedSettings; +class CStageFrightVideoPrivate; + +namespace android { class MediaBuffer; } + +class CStageFrightVideo +{ +public: + CStageFrightVideo(CWinSystemEGL* windowing, CAdvancedSettings* advsettings); + virtual ~CStageFrightVideo(); + + bool Open(CDVDStreamInfo &hints); + void Close(void); + int Decode(uint8_t *pData, int iSize, double dts, double pts); + void Reset(void); + bool GetPicture(DVDVideoPicture *pDvdVideoPicture); + bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); + void SetDropState(bool bDrop); + virtual void SetSpeed(int iSpeed); + + void LockBuffer(EGLImageKHR eglimg); + void ReleaseBuffer(EGLImageKHR eglimg); + +private: + CStageFrightVideoPrivate* p; +}; + +// defined(HAS_LIBSTAGEFRIGHT) +#endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.cpp new file mode 100644 index 0000000..ab638a0 --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.cpp @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ +/***************************************************************************/ + +//#define DEBUG_VERBOSE 1 + +#include "StageFrightVideoPrivate.h" + +#include +#include +#include +#include +#include "windowing/egl/EGLWrapper.h" +#include "windowing/WindowingFactory.h" +#include "settings/AdvancedSettings.h" +#include "utils/log.h" + +#include "android/jni/Surface.h" +#include "android/jni/SurfaceTexture.h" + +#define CLASSNAME "CStageFrightVideoPrivate" + +GLint glerror; +#define CheckEglError(x) while((glerror = eglGetError()) != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",x, glerror); +#define CheckGlError(x) while((glerror = glGetError()) != GL_NO_ERROR) CLog::Log(LOGERROR, "GL error in %s: %x",x, glerror); + +// EGL extension functions +static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; +static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; +static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + +int NP2( unsigned x ) { + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + +CStageFrightVideoPrivate::CStageFrightVideoPrivate() + : decode_thread(NULL), source(NULL) + , eglDisplay(EGL_NO_DISPLAY), eglSurface(EGL_NO_SURFACE), eglContext(EGL_NO_CONTEXT) + , eglInitialized(false) + , framecount(0) + , quirks(QuirkNone), cur_frame(NULL), prev_frame(NULL) + , width(-1), height(-1) + , texwidth(-1), texheight(-1) + , client(NULL), decoder(NULL), decoder_component(NULL) + , drop_state(false), resetting(false) +{ + if (!eglCreateImageKHR) + eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR"); + if (!eglDestroyImageKHR) + eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR"); + if (!glEGLImageTargetTexture2DOES) + glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES"); + + for (int i=0; irefcount() == 0 && inbuf[i]->size() >= size) + break; + if (i == INBUFCOUNT) + { + i = 0; + for (; irefcount() == 0) + break; + if (i == INBUFCOUNT) + return NULL; + inbuf[i]->setObserver(NULL); + inbuf[i]->release(); + inbuf[i] = new MediaBuffer(size); + inbuf[i]->setObserver(this); + } + + inbuf[i]->add_ref(); + inbuf[i]->set_range(0, size); + return inbuf[i]; +} + +bool CStageFrightVideoPrivate::inputBufferAvailable() +{ + for (int i=0; irefcount() == 0) + return true; + + return false; +} + +void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader) +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>loadOESShader\n"); +#endif + + GLuint shader = glCreateShader(shaderType); + CheckGlError("loadOESShader"); + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + printf("Shader compile log:\n%s\n", buf); + free(buf); + } + } else { + char* buf = (char*) malloc(0x1000); + if (buf) { + glGetShaderInfoLog(shader, 0x1000, NULL, buf); + printf("Shader compile log:\n%s\n", buf); + free(buf); + } + } + glDeleteShader(shader); + shader = 0; + } + } + *outShader = shader; +} + +void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm) +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>createOESProgram\n"); +#endif + GLuint vertexShader, fragmentShader; + { + loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader); + } + { + loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader); + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + glAttachShader(program, fragmentShader); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + printf("Program link log:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + *outPgm = program; +} + +void CStageFrightVideoPrivate::OES_shader_setUp() +{ + + const char vsrc[] = + "attribute vec4 vPosition;\n" + "varying vec2 texCoords;\n" + "uniform mat4 texMatrix;\n" + "void main() {\n" + " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n" + " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n" + " gl_Position = vPosition;\n" + "}\n"; + + const char fsrc[] = + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES texSampler;\n" + "varying vec2 texCoords;\n" + "void main() {\n" + " gl_FragColor = texture2D(texSampler, texCoords);\n" + "}\n"; + + { + #if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n"); + #endif + CheckGlError("OES_shader_setUp"); + createOESProgram(vsrc, fsrc, &mPgm); + } + + mPositionHandle = glGetAttribLocation(mPgm, "vPosition"); + mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler"); + mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix"); +} + +void CStageFrightVideoPrivate::InitializeEGL(int w, int h) +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: >>> InitializeEGL: w:%d; h:%d\n", CLASSNAME, w, h); +#endif + texwidth = w; + texheight = h; + if (!m_g_Windowing->IsExtSupported("GL_TEXTURE_NPOT")) + { + texwidth = NP2(texwidth); + texheight = NP2(texheight); + } + + eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == EGL_NO_DISPLAY) + CLog::Log(LOGERROR, "%s: InitializeEGL: no display\n", CLASSNAME); + eglBindAPI(EGL_OPENGL_ES_API); + EGLint contextAttributes[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + eglContext = eglCreateContext(eglDisplay, m_g_Windowing->GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes); + EGLint pbufferAttribs[] = { + EGL_WIDTH, texwidth, + EGL_HEIGHT, texheight, + EGL_NONE + }; + eglSurface = eglCreatePbufferSurface(eglDisplay, m_g_Windowing->GetEGLConfig(), pbufferAttribs); + eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + CheckGlError("stf init"); + + static const EGLint imageAttributes[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, + EGL_GL_TEXTURE_LEVEL_KHR, 0, + EGL_NONE + }; + + for (int i=0; i(slots[i].eglimg, i)); + + } + glBindTexture(GL_TEXTURE_2D, 0); + + fbo.Initialize(); + OES_shader_setUp(); + + eglInitialized = true; +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: <<< InitializeEGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight); +#endif +} + +void CStageFrightVideoPrivate::UninitializeEGL() +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: >>> UninitializeEGL\n", CLASSNAME); +#endif + fbo.Cleanup(); + for (int i=0; i>> InitStagefrightSurface\n", CLASSNAME); +#endif + if (mVideoNativeWindow != NULL) + return true; + + mVideoTextureId = -1; + + glGenTextures(1, &mVideoTextureId); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, mVideoTextureId); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); + + mSurfTexture = new CJNISurfaceTexture(mVideoTextureId); + mSurface = new CJNISurface(*mSurfTexture); + + JNIEnv* env = xbmc_jnienv(); + mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw()); + native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA); + +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: <<< InitStagefrightSurface\n", CLASSNAME); +#endif + return true; +} + +void CStageFrightVideoPrivate::UninitStagefrightSurface() +{ +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: >>> UninitStagefrightSurface\n", CLASSNAME); +#endif + if (mVideoNativeWindow == NULL) + return; + + native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA); + ANativeWindow_release(mVideoNativeWindow.get()); + mVideoNativeWindow = NULL; + + mSurface->release(); + mSurfTexture->release(); + + delete mSurface; + delete mSurfTexture; + + glDeleteTextures(1, &mVideoTextureId); +#if defined(DEBUG_VERBOSE) + CLog::Log(LOGDEBUG, "%s: <<< UninitStagefrightSurface\n", CLASSNAME); +#endif +} + +void CStageFrightVideoPrivate::UpdateStagefrightTexture() +{ + mSurfTexture->updateTexImage(); +} + +void CStageFrightVideoPrivate::GetStagefrightTransformMatrix(float* transformMatrix) +{ + mSurfTexture->getTransformMatrix(transformMatrix); +} + diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.h new file mode 100644 index 0000000..d10ef41 --- /dev/null +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideoPrivate.h @@ -0,0 +1,165 @@ +#pragma once +/* + * Copyright (C) 2013 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ +/***************************************************************************/ + +#include "threads/Thread.h" +#include "xbmc/guilib/FrameBufferObject.h" +#include "cores/VideoRenderers/RenderFormats.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "system_gl.h" + +#include +#include + +#define NUMFBOTEX 4 +#define INBUFCOUNT 16 + +class CStageFrightDecodeThread; +class CJNISurface; +class CJNISurfaceTexture; +class CWinSystemEGL; +class CAdvancedSettings; + +using namespace android; + +struct tex_slot +{ + GLuint texid; + EGLImageKHR eglimg; +}; + +struct Frame +{ + status_t status; + int32_t width, height; + int64_t pts; + ERenderFormat format; + EGLImageKHR eglimg; + MediaBuffer* medbuf; +}; + +enum StageFrightQuirks +{ + QuirkNone = 0, + QuirkSWRender = 0x01, +}; + +class CStageFrightVideoPrivate : public MediaBufferObserver +{ +public: + CStageFrightVideoPrivate(); + + virtual void signalBufferReturned(MediaBuffer *buffer); + + MediaBuffer* getBuffer(size_t size); + bool inputBufferAvailable(); + + void loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader); + void createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm); + void OES_shader_setUp(); + void InitializeEGL(int w, int h); + void UninitializeEGL(); + +public: + CStageFrightDecodeThread* decode_thread; + + sp source; + + MediaBuffer* inbuf[INBUFCOUNT]; + + GLuint mPgm; + GLint mPositionHandle; + GLint mTexSamplerHandle; + GLint mTexMatrixHandle; + + CWinSystemEGL* m_g_Windowing; + CAdvancedSettings* m_g_advancedSettings; + + CFrameBufferObject fbo; + EGLDisplay eglDisplay; + EGLSurface eglSurface; + EGLContext eglContext; + bool eglInitialized; + + tex_slot slots[NUMFBOTEX]; + std::list< std::pair > free_queue; + std::list< std::pair > busy_queue; + + sp meta; + int64_t framecount; + std::map in_queue; + std::map out_queue; + CCriticalSection in_mutex; + CCriticalSection out_mutex; + CCriticalSection free_mutex; + XbmcThreads::ConditionVariable in_condition; + XbmcThreads::ConditionVariable out_condition; + + int quirks; + Frame *cur_frame; + Frame *prev_frame; + bool source_done; + int x, y; + int width, height; + int texwidth, texheight; + + OMXClient *client; + sp decoder; + const char *decoder_component; + int videoColorFormat; + int videoStride; + int videoSliceHeight; + + bool drop_state; + bool resetting; +#if defined(DEBUG_VERBOSE) + unsigned int cycle_time; +#endif + + unsigned int mVideoTextureId; + CJNISurfaceTexture* mSurfTexture; + CJNISurface* mSurface; + sp mVideoNativeWindow; + + bool InitStagefrightSurface(); + void UninitStagefrightSurface(); + void UpdateStagefrightTexture(); + void GetStagefrightTransformMatrix(float* transformMatrix); +}; -- 2.7.4