XBMC 使用 Android StageFright 硬件解碼
轉載自:http://blog.csdn.net/mirkerson/article/details/40184803
XBMC 在 Android 平臺上,除了可以通過 Java MediaCodec API 使用硬件解碼功能,還可以直接調用 Android 媒體框架 StageFright 提供的 C++ API 訪問硬件解碼器。
StageFright 是 Android 在 4.0 (level 14) 上的媒體框架(http://source.android.com/devices/media.html),支持 OpenMAX 標準。在該媒體框架下,硬件廠商採用 OMX plugin 方式封裝 libstagefrighthw.so 私有庫,爲系統提供硬件編解碼器。Android 的 MediaPlayer 通過調用 StageFright API 爲 App 提供編解碼功能。
雖然 StageFright API 屬於非正式的 API,爲了較好的視頻播放效果,XBMC 也直接調用 Stagefright API,進行硬件解碼。
## XBMC 調用 StageFright API
XBMC 使用 StageFright 分兩步:首先封裝一個通用類,供程序上層使用統一接口調用;再將與 Android 底層
相關的 StageFright 代碼封裝到一個單獨的動態鏈接庫,並提供自己的 API。隨着 Android 平臺的升級,如果 StageFright API 有改變,只需要更新底層的動態鏈接庫。
### CDVDVideoCodecStageFright 類
支持 StageFright 的 CDVDVideoCodec 爲 CDVDVideoCodecStageFright:
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStageFright.h:
class CDVDVideoCodecStageFright : public CDVDVideoCodec
播放視頻時,XBMC 根據系統和軟件設置,決定是否使用 Codec Factory 創建 StageFright 解碼器
xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp:
CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigned int surfaces, const std::vector& formats)
{
CDVDVideoCodec* pCodec = NULL;
#if defined(HAS_LIBSTAGEFRIGHT)
hwSupport += "libstagefright:yes ";
#elif defined(_LINUX)
hwSupport += "libstagefright:no ";
#endif
#if defined(HAS_LIBSTAGEFRIGHT)
if (!hint.software && CSettings::Get().GetBool("videoplayer.usestagefright"))
{
switch(hint.codec)
{
case CODEC_ID_H264:
case CODEC_ID_MPEG4:
case CODEC_ID_MPEG2VIDEO:
case CODEC_ID_VC1:
case CODEC_ID_WMV3:
case CODEC_ID_VP3:
case CODEC_ID_VP6:
case CODEC_ID_VP6F:
case CODEC_ID_VP8:
if ( (pCodec = OpenCodec(new CDVDVideoCodecStageFright(), hint, options)) ) return pCodec;
break;
default:
break;
}
}
#endif
}
CDVDVideoCodec* CDVDFactoryCodec::OpenCodec(CDVDVideoCodec* pCodec, CDVDStreamInfo &hints, CDVDCodecOptions &options )
{
if( pCodec->Open( hints, options ) )
{
CLog::Log(LOGDEBUG, "FactoryCodec - Video: %s - Opened", pCodec->GetName());
return pCodec;
}
return NULL;
}
在 DVDVideoCodecStageFright 中,加載動態鏈接庫 libXBMCvcodec_stagefrightICS-arm.so
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecStagefright.cpp:
CDVDVideoCodecStageFright::CDVDVideoCodecStageFright()
: CDVDVideoCodec()
, m_convert_bitstream(false), m_converter(NULL)
, m_stf_handle(NULL)
{
if (!m_stf_dll)
m_stf_dll = new DllLibStageFrightCodec;
}
然後調用它提供的接口函數:
bool CDVDVideoCodecStageFright::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
m_stf_handle = m_stf_dll->create_stf(&g_application, &CApplicationMessenger::Get(), &g_Windowing, &g_advancedSettings);
if (!m_stf_dll->stf_Open(m_stf_handle, hints))
{
Dispose();
return false;
}
return true;
}
int CDVDVideoCodecStageFright::Decode(uint8_t *pData, int iSize, double dts, double pts)
{
rtn = m_stf_dll->stf_Decode(m_stf_handle, demuxer_content, demuxer_bytes, dts, pts);
return rtn;
}
### 封裝 StageFright 的動態鏈接庫 libXBMCvcodec_stagefrightICS-arm.so
在它的 Makefile 中,可以看到它依賴 libstagefright.so
LIBS += -landroid -lEGL -lGLESv2 -L${prefix}/opt/android-libs -lstdc++ -lutils -lcutils -lstagefright -lbinder -lui -lgui
該動態鏈接庫中定義了一套自己的接口函數來使用解碼器:
xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterfac.cpp
extern "C"
{
void* create_stf(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings);
void destroy_stf(void*);
bool stf_Open(void*, CDVDStreamInfo &hints);
void stf_Dispose(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);
}
在接口函數實現代碼中,解碼功能又通過 CStageFrightVideo 對象完成。
xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightInterfac.cpp
void* create_stf(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings)
{
return (void*)new CStageFrightVideo(application, applicationMessenger, windowing, advsettings);
}
bool stf_Open(void* stf, CDVDStreamInfo &hints)
{
return ((CStageFrightVideo*)stf)->Open(hints);
}
int stf_Decode(void* stf, uint8_t *pData, int iSize, double dts, double pts)
{
return ((CStageFrightVideo*)stf)->Decode(pData, iSize, dts, pts);
}
最後,所有直接調用 Stagefright API 的操作都被封裝到 CStageFrightVideo 類中。
xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.h
class CStageFrightVideo
{
public:
CStageFrightVideo(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings);
virtual ~CStageFrightVideo();
bool Open(CDVDStreamInfo &hints);
void Dispose(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;
};
通過 StageFright API 使用解碼器也分爲三個步驟:
1. 創建解碼器
主要調用 StageFright 中 OMXClient 的 connect() 和 OMXCodec 的 Create() 函數,同時創建解碼線程。
xbmc/cores/dvdplayer/DVDCodecs/Video/libstagefrightICS/StageFrightVideo.cpp
CStageFrightVideo::CStageFrightVideo(CApplication* application, CApplicationMessenger* applicationMessenger, CWinSystemEGL* windowing, CAdvancedSettings* advsettings)
{
p = new CStageFrightVideoPrivate;
...
}
bool CStageFrightVideo::Open(CDVDStreamInfo &hints)
{
p->source = new CStageFrightMediaSource(p, p->meta);
p->client = new OMXClient;
if (p->client->connect() != OK)
{
return false;
}
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))
{
return false;
}
p->decode_thread = new CStageFrightDecodeThread(p);
p->decode_thread->Create(true );
}
2. 將編碼的數據傳給解碼器
編碼數據由 Decode() 函數複製到 in_queue 中的空閒緩存
int CStageFrightVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
{
Frame *frame;
int demuxer_bytes = iSize;
uint8_t *demuxer_content = pData;
int ret = 0;
if (demuxer_content)
{
frame = (Frame*)malloc(sizeof(Frame));
frame->status = OK;
frame->medbuf = p->getBuffer(demuxer_bytes);
fast_memcpy(frame->medbuf->data(), demuxer_content, demuxer_bytes);
p->in_mutex.lock();
p->in_queue.push_back(frame);
p->in_condition.notify();
p->in_mutex.unlock();
}
}
創建解碼器時傳入的 p->source 對象,其類 CStageFrightMediaSource 提供的 read() 函數,負責將 in_queue 隊列中的緩存取出交給 OMXCodec 解碼器處理。
class CStageFrightMediaSource : public MediaSource
{
virtual status_t read(MediaBuffer **buffer,
const MediaSource::ReadOptions *options)
{
Frame *frame;
status_t ret;
*buffer = NULL;
std::list
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.