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 \
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
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)
$(MAKE) -C pvr-addons
endif
-codecs: papcodecs dvdpcodecs
+codecs: papcodecs dvdpcodecs dvdpextcodecs
libs: libhdhomerun imagelib libexif system/libcpluff-@ARCH@.so $(CMYTH)
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])
XB_ADD_CODEC([LIBAMCODEC], [amcodec])
;;
*libstagefright*)
- LIBS+="-L${prefix}/opt/android-libs -lstdc++ -lutils -lcutils -lstagefright -lbinder -lui -lgui"
XB_ADD_CODEC([LIBSTAGEFRIGHT], [libstagefright])
;;
*)
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"
#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"
#include <EGL/eglext.h>
#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;
}
#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();
namespace Shaders { class BaseYUV2RGBShader; }
namespace Shaders { class BaseVideoFilterShader; }
class COpenMaxVideo;
-class CStageFrightVideo;
+class CDVDVideoCodecStageFright;
class CDVDMediaCodecInfo;
typedef std::vector<int> Features;
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
struct __CVBuffer *cvBufferRef;
#endif
#ifdef HAS_LIBSTAGEFRIGHT
- CStageFrightVideo* stf;
+ CDVDVideoCodecStageFright* stf;
EGLImageKHR eglimg;
#endif
#if defined(TARGET_ANDROID)
class COpenMax;
class COpenMaxVideo;
struct OpenMaxVideoBuffer;
-class CStageFrightVideo;
+class CDVDVideoCodecStageFright;
class CDVDMediaCodecInfo;
typedef void* EGLImageKHR;
};
struct {
- CStageFrightVideo* stf;
+ CDVDVideoCodecStageFright* stf;
EGLImageKHR eglimg;
};
#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()
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;
}
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)
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)
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
#include "DVDVideoCodec.h"
#include "utils/BitstreamConverter.h"
-class CStageFrightVideo;
+class DllLibStageFrightCodec;
+
class CDVDVideoCodecStageFright : public CDVDVideoCodec
{
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
--- /dev/null
+#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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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()
+};
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
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
-
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-/***************************************************************************/
-
-//#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 <EGL/egl.h>
-#include <EGL/eglext.h>
-#include "windowing/egl/EGLWrapper.h"
-
-#include <new>
-
-#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<MetaData> meta)
- {
- p = priv;
- source_meta = meta;
- }
-
- virtual sp<MetaData> 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<int64_t,Frame*>::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<MetaData> 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<MetaData> 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<MetaData> 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<std::pair<EGLImageKHR, int> >::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<EGLImageKHR, int>(*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<MetaData> outFormat;
- int32_t cropLeft, cropTop, cropRight, cropBottom;
- //Vector<String8> 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; i<INBUFCOUNT; ++i)
- {
- p->inbuf[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<int64_t, Frame*>(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<int64_t,Frame*>::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; i<INBUFCOUNT; ++i)
- {
- p->inbuf[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<int64_t,Frame*>::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<std::pair<EGLImageKHR, int> >::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<EGLImageKHR, int>(*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<EGLImageKHR, int>(*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<std::pair<EGLImageKHR, int> >::iterator it = p->busy_queue.begin();
- std::list<std::pair<EGLImageKHR, int> >::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<EGLImageKHR, int>(*itfree));
- p->busy_queue.erase(itfree);
- }
- p->free_mutex.unlock();
-}
+++ /dev/null
-#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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#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
+++ /dev/null
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-/***************************************************************************/
-
-#include "StageFrightVideoPrivate.h"
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#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 (; i<INBUFCOUNT; ++i)
- if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
- break;
- if (i == INBUFCOUNT)
- {
- i = 0;
- for (; i<INBUFCOUNT; ++i)
- if (inbuf[i]->refcount() == 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; i<INBUFCOUNT; ++i)
- if (inbuf[i]->refcount() == 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<NUMFBOTEX; ++i)
- {
- glGenTextures(1, &(slots[i].texid));
- glBindTexture(GL_TEXTURE_2D, slots[i].texid);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, 0);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // This is necessary for non-power-of-two textures
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- slots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(slots[i].texid),imageAttributes);
- free_queue.push_back(std::pair<EGLImageKHR, int>(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; i<NUMFBOTEX; ++i)
- {
- glDeleteTextures(1, &(slots[i].texid));
- eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
- }
-
- if (eglContext != EGL_NO_CONTEXT)
- eglDestroyContext(eglDisplay, eglContext);
- eglContext = EGL_NO_CONTEXT;
-
- if (eglSurface != EGL_NO_SURFACE)
- eglDestroySurface(eglDisplay, eglSurface);
- eglSurface = EGL_NO_SURFACE;
-
- eglInitialized = false;
-}
-
-bool CStageFrightVideoPrivate::InitStagefrightSurface()
-{
- if (mVideoNativeWindow != NULL)
- return true;
-
- JNIEnv* env = xbmc_jnienv();
-
- 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);
-
- mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_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);
-}
-
+++ /dev/null
-#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
- * <http://www.gnu.org/licenses/>.
- *
- */
-/***************************************************************************/
-
-#include "threads/Thread.h"
-#include "xbmc/guilib/FrameBufferObject.h"
-#include "cores/VideoRenderers/RenderFormats.h"
-
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaSource.h>
-
-#include <binder/ProcessState.h>
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <utils/List.h>
-#include <utils/RefBase.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <gui/SurfaceTexture.h>
-
-#include "system_gl.h"
-
-#include <map>
-#include <list>
-
-#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<MediaSource> 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<EGLImageKHR, int> > free_queue;
- std::list< std::pair<EGLImageKHR, int> > busy_queue;
-
- sp<MetaData> meta;
- int64_t framecount;
- std::map<int64_t, Frame*> in_queue;
- std::map<int64_t, Frame*> 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<MediaSource> 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<ANativeWindow> mVideoNativeWindow;
-
- bool InitStagefrightSurface();
- void UninitStagefrightSurface();
- void UpdateStagefrightTexture();
- void GetStagefrightTransformMatrix(float* transformMatrix);
-};
--- /dev/null
+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 \
+
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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);
+}
+
--- /dev/null
+#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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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);
+}
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+/***************************************************************************/
+
+//#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 <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "windowing/egl/EGLWrapper.h"
+#include "windowing/WindowingFactory.h"
+
+#include <new>
+
+#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<MetaData> meta)
+ {
+ p = priv;
+ source_meta = meta;
+ }
+
+ virtual sp<MetaData> 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<int64_t,Frame*>::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<MetaData> 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<MetaData> 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<MetaData> 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<std::pair<EGLImageKHR, int> >::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<EGLImageKHR, int>(*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<MetaData> outFormat;
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
+ //Vector<String8> 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; i<INBUFCOUNT; ++i)
+ {
+ p->inbuf[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<int64_t, Frame*>(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<int64_t,Frame*>::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; i<INBUFCOUNT; ++i)
+ {
+ if (p->inbuf[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<int64_t,Frame*>::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<std::pair<EGLImageKHR, int> >::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<EGLImageKHR, int>(*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<EGLImageKHR, int>(*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<std::pair<EGLImageKHR, int> >::iterator it = p->busy_queue.begin();
+ std::list<std::pair<EGLImageKHR, int> >::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<EGLImageKHR, int>(*itfree));
+ p->busy_queue.erase(itfree);
+ }
+ p->free_mutex.unlock();
+}
--- /dev/null
+#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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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
--- /dev/null
+/*
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+/***************************************************************************/
+
+//#define DEBUG_VERBOSE 1
+
+#include "StageFrightVideoPrivate.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#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; i<INBUFCOUNT; ++i)
+ inbuf[i] = NULL;
+}
+
+void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer)
+{
+}
+
+MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size)
+{
+ int i=0;
+ for (; i<INBUFCOUNT; ++i)
+ if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
+ break;
+ if (i == INBUFCOUNT)
+ {
+ i = 0;
+ for (; i<INBUFCOUNT; ++i)
+ if (inbuf[i]->refcount() == 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; i<INBUFCOUNT; ++i)
+ if (inbuf[i]->refcount() == 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<NUMFBOTEX; ++i)
+ {
+ glGenTextures(1, &(slots[i].texid));
+ glBindTexture(GL_TEXTURE_2D, slots[i].texid);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // This is necessary for non-power-of-two textures
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ slots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(slots[i].texid),imageAttributes);
+ free_queue.push_back(std::pair<EGLImageKHR, int>(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<NUMFBOTEX; ++i)
+ {
+ glDeleteTextures(1, &(slots[i].texid));
+ eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
+ }
+
+ if (eglContext != EGL_NO_CONTEXT)
+ eglDestroyContext(eglDisplay, eglContext);
+ eglContext = EGL_NO_CONTEXT;
+
+ if (eglSurface != EGL_NO_SURFACE)
+ eglDestroySurface(eglDisplay, eglSurface);
+ eglSurface = EGL_NO_SURFACE;
+
+ eglInitialized = false;
+}
+
+bool CStageFrightVideoPrivate::InitStagefrightSurface()
+{
+#if defined(DEBUG_VERBOSE)
+ CLog::Log(LOGDEBUG, "%s: >>> 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);
+}
+
--- /dev/null
+#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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+/***************************************************************************/
+
+#include "threads/Thread.h"
+#include "xbmc/guilib/FrameBufferObject.h"
+#include "cores/VideoRenderers/RenderFormats.h"
+
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaSource.h>
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <gui/SurfaceTexture.h>
+
+#include "system_gl.h"
+
+#include <map>
+#include <list>
+
+#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<MediaSource> 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<EGLImageKHR, int> > free_queue;
+ std::list< std::pair<EGLImageKHR, int> > busy_queue;
+
+ sp<MetaData> meta;
+ int64_t framecount;
+ std::map<int64_t, Frame*> in_queue;
+ std::map<int64_t, Frame*> 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<MediaSource> 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<ANativeWindow> mVideoNativeWindow;
+
+ bool InitStagefrightSurface();
+ void UninitStagefrightSurface();
+ void UpdateStagefrightTexture();
+ void GetStagefrightTransformMatrix(float* transformMatrix);
+};