媒體播放引擎
v 在opencore中由PVPlayerEngine負(fù)責(zé)媒體播放功能的實現(xiàn);
v 在PVPlayerEngine中負(fù)責(zé)創(chuàng)建各個節(jié)點來完成媒體文件格式解析(SourceNode)、媒體數(shù)據(jù)編解碼(DecodeNode/EncNode)以及媒體數(shù)據(jù)的輸出(MediaOutputNode);
v 由PlayerDriver負(fù)責(zé)opencore與android媒體框架的適配;
v 由AndroidAudioOutput負(fù)責(zé)音頻數(shù)據(jù)輸出到android-audioflinger服務(wù)輸出,由AndroidSurfaceOutput來負(fù)責(zé)將視頻數(shù)據(jù)輸出到android-surfaceflinger服務(wù)輸出;
媒體播放引擎-驅(qū)動層
v 驅(qū)動層包括:PVPlayer和PlayerDriver組成;
v PVPlayer負(fù)責(zé)將上層應(yīng)用的命令轉(zhuǎn)換成PlayerDriver可以內(nèi)部命令加入到其命令隊列中,由PlayerDriver負(fù)責(zé)執(zhí)行,并負(fù)責(zé)將命令執(zhí)行的結(jié)果回送給上層媒體框架以及JAVA程序;
v 在PlayerDriver中有一個消息循環(huán)負(fù)責(zé)處理PVPlayer發(fā)送過來的命令,調(diào)用PVPlayerEngine相應(yīng)的接口來完成媒體控制;
v 在創(chuàng)建PlayerDriver對象時會生成opencore主線程,并調(diào)用OsclExecScheduler.StartScheduler來開始opencore主線程循環(huán);
v 源碼文件:
v android/playerdriver.cpp
v android/playerdriver.h
媒體播放引擎-文件格式識別
v 在opencore中由PVPlayerRecognizerRegistry負(fù)責(zé)文件格式識別,并將結(jié)果返回給PVPlayerEngine;
v PVPlayerEngine根據(jù)類型來創(chuàng)建對應(yīng)的文件解析節(jié)點ParseNode;
v opencore中對文件格式的識別時通過讀取文件頭的方式進(jìn)行的,而不是根據(jù)文件擴(kuò)展名;
v opencore中通過向系統(tǒng)中注冊文件識別插件的方式來提供文件格式識別的功能,系統(tǒng)通過循環(huán)調(diào)用每個注冊插件的Recognize()函數(shù)來進(jìn)行格式識別;
v 在創(chuàng)建媒體播放引擎的時候會通過PVPlayerRegistryPopulator::Populate()函數(shù)來注冊所有的文件識別插件到系統(tǒng)中
v 源碼文件:
v pvmi/recognizer/src/pvmf_recognizer_registry.cpp
v pvmi/recognizer/src/pvmf_recognizer_registry_impl.cpp
v pvmi/recognizer/plugins/目錄下所有的子目錄中存放著文件識別插件的代碼;
媒體播放引擎-文件格式解析節(jié)點
v 在opencore中通過文件解析節(jié)點(ParseNode)來完成音視頻文件格式的解析,并將文件中的音頻、視頻數(shù)據(jù)送到對應(yīng)的解碼節(jié)點進(jìn)行解碼;
v PVPlayerEngine通過PVMFNodeInterface接口來完成對ParseNode的操作;ParseNode通過提供擴(kuò)展接口來實現(xiàn)通用Node接口不能實現(xiàn)的功能;
v 常用的擴(kuò)展接口如:PvmiCapabilityAndConfig;
v opencore中通過注冊的方式向系統(tǒng)中注冊文件格式解析節(jié)點
媒體播放引擎-節(jié)點注冊
v 1、每個節(jié)點都有一個對應(yīng)的PVMFXXXXFactrory來負(fù)責(zé)創(chuàng)建;
v 2、系統(tǒng)中通過PVPlayerRegistryPopulator. RegisterAllNodes()來注冊所有支持的節(jié)點;
v 3、opencore首先調(diào)用PVPlayerNodeRegistry-> QueryRegistry()函數(shù)查詢對于指定的輸入&輸出格式的Node的UUID,然后通過PVPlayerNodeRegistry-> CreateNode ()創(chuàng)建指定的Node。
v 4、PVPlayerEngine就是通過文件格式識別插件返回的媒體類型來創(chuàng)建對應(yīng)的文件解析節(jié)點的
void PVMFMP4FFParserNode::Run()
{
//Process commands.
if (!iInputCommands.empty())
{
ProcessCommand();
}
while (!iPortActivityQueue.empty() && (iInterfaceState ==EPVMFNodeStarted || FlushPending()))
{
ProcessPortActivity();
}
if (iInterfaceState == EPVMFNodeStarted && !FlushPending())
{
HandleTrackState();
}
//Check for completion of a flush command...
if (FlushPending() && iPortActivityQueue.empty())
{
//Flush is complete.
CommandComplete(iCurrentCommand,iCurrentCommand.front(), PVMFSuccess);
}
}
voidPVMFMP4FFParserNode::HandleTrackState()
{
for (uint32 i = 0; i < iNodeTrackPortList.size(); ++i)
{
switch (iNodeTrackPortList[i].iState)
{
casePVMP4FFNodeTrackPortInfo::TRACKSTATE_UNINITIALIZED:
……
case PVMP4FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_GETDATA:
……
if(!RetrieveTrackData(iNodeTrackPortList[i]))
{
……
}
……
case PVMP4FFNodeTrackPortInfo::TRACKSTATE_TRANSMITTING_SENDDATA:
if(SendTrackData(iNodeTrackPortList[i]))
{
……
}
break;
……
}
}
}
媒體播放引擎-解碼節(jié)點
v opencore中由DecNode節(jié)點負(fù)責(zé)媒體數(shù)據(jù)的解碼工作;
v DecNode通過調(diào)用底層的opencoreMAX通用接口實現(xiàn)媒體數(shù)據(jù)的解碼;
v 對于一個普通的視頻文件,存在2個解碼節(jié)點:音頻解碼節(jié)點和視頻解碼節(jié)點;
boolPVMFOMXBaseDecNode::SendInputBufferToOMXComponent()
{
……
OMX_EmptyThisBuffer(iOMXDecoder, input_buf->pBufHdr);
……
}
PVMFOMXBaseDecNode::SendOutputBufferToOMXComponent()
{
……
OMX_FillThisBuffer(iOMXDecoder, output_buf->pBufHdr);
……
}
OMX_ERRORTYPE PVMFOMXBaseDecNode::EmptyBufferDoneProcessing(OMX_OUTOMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
……
}
OMX_ERRORTYPEPVMFOMXBaseDecNode::FillBufferDoneProcessing(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT OMX_PTR aAppData,
OMX_OUT OMX_BUFFERHEADERTYPE* aBuffer)
{
……
}
v 源碼文件:
v nodes/pvomxbasedecnode/
v nodes/pvomxvideodecnode/
v codecs_v2/omx/
媒體播放引擎-媒體輸出節(jié)點
v MediaOutputNode負(fù)責(zé)接收DecNode的解碼后數(shù)據(jù),并將數(shù)據(jù)輸出到MIO;同時在輸出前作視頻的同步;
v MIO負(fù)責(zé)將數(shù)據(jù)輸出到surfaceFlinger和AudioFlinger;
v 視頻數(shù)據(jù)在輸出前需要做顏色空間的轉(zhuǎn)換(YUV->RGB)和縮放,這部分的工作也在MIO中完成;
v 節(jié)點源碼:
v nodes/pvmediaoutputnode/
v MIO源碼:
v android/android_surface_output.cpp
v android/android_audio_output.cpp
v android/android_audio_mio.cpp
v http://zhaixishan.cublog.cn
附錄:
具體的代碼閱讀:
此函數(shù)中先得到當(dāng)前的MediaPlayer實例,然后調(diào)用其setDataSource函數(shù),傳入路徑
此函數(shù)通過調(diào)getMediaPlayerService()先得到當(dāng)前的MediaPlayerService, const sp<IMediaPlayerService>& service(getMediaPlayerService());
然后新建一個IMediaPlayer變量, sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
在sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)中
調(diào)status_t MediaPlayerService::Client::setDataSource(const char *url)函數(shù),Client是MediaPlayerService的一個內(nèi)部類。
在MediaPlayerService::Client::setDataSource中,調(diào)sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
生成一個繼承自MediaPlayerBase的PVPlayer實例,
PVPlayer的繼承關(guān)系如下:
PVPlayer-->MediaPlayerInterface-->MediaPlayerBase
最后調(diào)PVPlayer的setDataSource()函數(shù)
此函數(shù)開頭執(zhí)行ret = mPlayerDriver->enqueueCommand(new PlayerSetDataSource(mDataSourcePath,0,0));
將PlayerSetDataSource 的command類加入到PlayerDriver的command處理隊列中,
在void PlayerDriver::Run()函數(shù)中處理此command,調(diào)用下面的handleSetDataSource函數(shù)。
This function allows a player data source to be specified for playback. This function must be called