Android視頻檔案格式解析相關分析

來源:互聯網
上載者:User

引用:http://blog.csdn.net/wstarx/archive/2008/12/17/3541458.aspx

目錄結構<br />OpenCore的代碼在以下目錄中:external/opencore/。這個目錄是OpenCore的根目錄,其中包含的子目錄如下所示:<br /> * android:這裡面是一個上層的庫,它基於PVPlayer和PVAuthor的SDK實現了一個為Android使用的Player和Author。<br /> * baselibs:包含資料結構和安全執行緒等內容的底層庫<br /> * codecs_v2:這是一個內容較多的庫,主要包含編解碼的實現,以及一個OpenMAX的實現<br /> * engines:包含PVPlayer和PVAuthor引擎的實現<br /> * extern_libs_v2:包含了khronos的OpenMAX的標頭檔<br /> * fileformats:檔案格式的據具體解析(parser)類<br /> * nodes:編解碼和檔案解析的各個node類。<br /> * oscl:作業系統相容庫<br /> * pvmi: 輸入輸出控制的抽象介面<br /> * protocols:主要是與網路相關的RTSP、RTP、HTTP等協議的相關內容<br /> * pvcommon:pvcommon庫檔案的Android.mk檔案,沒有源檔案。<br /> * pvplayer:pvplayer庫檔案的Android.mk檔案,沒有源檔案。<br /> * pvauthor:pvauthor庫檔案的Android.mk檔案,沒有源檔案。<br /> * tools_v2:編譯工具以及一些可註冊的模組。<br />Splitter的定義與初始化<br />以wav的splitter為例,在fileformats目錄下有解析wav檔案格式的pvwavfileparser.cpp檔案,在nodes目錄 下有pvmf_wavffparser_factory.cpp,pvmf_wavffparser_node.h, pvmf_wavffparser_port.h等檔案。<br />我們由底往上看,vwavfileparser.cpp中的PV_Wav_Parser類有InitWavParser(),GetPCMData(),RetrieveFileInfo()等解析wav格式的成員函數,此類應該就是最終的解析類。我們搜尋PV_Wav_Parser類被用到的地方可知,在PVMFWAVFFParserNode類中有PV_Wav_Parser的一個指標成員變數。再搜尋可知,PVMFWAVFFParserNode類是通過PVMFWAVFFParserNodeFactory的CreatePVMFWAVFFParserNode()成員函數產生的。而CreatePVMFWAVFFParserNode()函數是在PVPlayerNodeRegistry::PVPlayerNodeRegistry()類建構函式中通過PVPlayerNodeInfo類被註冊到Oscl_Vector<PVPlayerNodeInfo, OsclMemAllocator> 的vector中,在這個建構函式中,AMR,mp3等node也是同樣被註冊的。<br />由上可知,Opencore中對splitter的管理也是與ffmpeg等類似,都是在架構的初始化時註冊的,只不過Opencore註冊的是每個splitter的factory函數。<br />綜述一下splitter的定義與初始化過程:<br />每個splitter都在fileformats目錄下有個對應的子目錄,其下有各自的解析類。<br />每個splitter都在nodes目錄下有關對應的子目錄,其下有各自的統一介面的node類和node factory類。<br />播放引擎PVPlayerEngine類中有PVPlayerNodeRegistry iPlayerNodeRegistry成員變數。<br />在PVPlayerNodeRegistry的建構函式中,將 AMR, AAC, MP3等splitter的輸入與輸出類型標示和node factory類中的create node與release delete介面通過PVPlayerNodeInfo類push到Oscl_Vector<PVPlayerNodeInfo, OsclMemAllocator> iType成員變數中。<br />當前Splitter的匹配過程<br />PVMFStatus PVPlayerNodeRegistry::QueryRegistry(PVMFFormatType& aInputType, PVMFFormatType& aOutputType, Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids)函數的功能是根據輸入類型和輸出類型,在登入的node vector中尋找是否有匹配的node,有的話傳回其唯一識別標識PVUuid。<br />從QueryRegistry這個函數至底向上搜尋可得到,在android中splitter的匹配過程如下:<br />android_media_MediaPlayer.cpp之中定義了一個JNINativeMethod(JAVA本地調用方法)類型的數組gMethods,供java代碼中調用MultiPlayer類的setDataSource成員函數時找到對應的c++函數<br /> {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},<br />static void android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)<br /> 此函數中先得到當前的MediaPlayer執行個體,然後調用其setDataSource函數,傳入路徑<br />status_t MediaPlayer::setDataSource(const char *url)<br /> 此函數通過調getMediaPlayerService()先得到當前的MediaPlayerService, const sp<IMediaPlayerService>& service(getMediaPlayerService());<br /> 然後建立一個IMediaPlayer變數, sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));<br /> 在sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)中<br /> 調status_t MediaPlayerService::Client::setDataSource(const char *url)函數,Client是MediaPlayerService的一個內部類。<br /> 在MediaPlayerService::Client::setDataSource中,調sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)<br /> 產生一個繼承自MediaPlayerBase的PVPlayer執行個體,<br /> PVPlayer的繼承關係如下:<br /> PVPlayer-->MediaPlayerInterface-->MediaPlayerBase<br /> 最後調PVPlayer的setDataSource()函數<br />status_t PVPlayer::setDataSource(const char *url)<br />status_t PVPlayer::prepare()<br /> 此函數開頭執行ret = mPlayerDriver->enqueueCommand(new PlayerSetDataSource(mDataSourcePath,0,0));<br /> 將PlayerSetDataSource 的command類加入到PlayerDriver的command處理隊列中,<br /> 在void PlayerDriver::Run()函數中處理此command,調用下面的handleSetDataSource函數。<br />void PlayerDriver::handleSetDataSource(PlayerSetDataSource* ec)<br />PVCommandId PVPlayerEngine::AddDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData)<br /> This function allows a player data source to be specified for playback. This function must be called<br />PVMFStatus PVPlayerEngine::DoAddDataSource(PVPlayerEngineCommand& aCmd)<br />PVMFStatus PVPlayerEngine::DoSetupSourceNode(PVCommandId aCmdId, OsclAny* aCmdContext) 

 

以上,是前輩摸索出的一條線索,但是不全面,至少對我現在的工作來說如此.

其以WAV格式為突破口,止步於CreatePVMFWAVFFParserNode().最後這段代碼位置是在 external/opencore/engines/player/config/linux_nj/pv_player_node_registry.cpp中.

 

我們已經知道3gp格式是支援的,但是android代碼中並沒有明確的有關3gp的檔案解析node或者代碼,在PVPlayer的方法中enqueueCommand(),再在playerdriver的Run()中,dequeueCommand()並且根據command->code(),做相應的操作.

其中就有handleSetDataSource(),這個方法看上去與檔案格式解析相關.

 

handleSetDataSource()中會調用pv_player_engine.cpp中的AddDataSource()方法,發出一個Command:“PVP_ENGINE_COMMAND_ADD_DATA_SOURCE”到隊列中,

接著在Run()中的switch(...)語句中,執行DoAddDataSource(),在這裡

if(iSourceFormat=SOURCEFORMAT_UNKNOWN)

{

     retval = DoQuerySourceFormat(...);

}

else

{

      ...

}

 

在DoQuerySourceFormat()中,參數iPlayerRecognizerRegistry閃亮登場,其類型為PVPlayerRecognizerRegistry,通過

iPlayerRecognizerRegistry.QueryFormatType(iDataSource->GetDataSourceURL(), *this, (OsclAny*) context));

在QueryFormatType()中,會使用傳入的檔案路徑建立一個PVMIDataStreamSyncInterfaceRefFactory對象,並強制轉換成PVMFDataStreamFactory*.再使用PVMFRecognizerRegistry::Recognize(iRecSessionId, *iFileDataStreamFactory, NULL, iRecognizerResult, NULL);它會繼續向下調用PVMFRecognizerRegistryImpl::Recognize(...),將參數儲存,再產生一個CMD:PVMFRECREG_COMMAND_RECOGNIZE,再在PVMFRecognizerRegistryImpl::Run()中,通過switch(...)執行doRecognize().

 

可以理解為所有解析的node都儲存在iRecognizerPluginFactoryList中,再在doRecognaize()中遍曆,以獲得合適的node(I am not sure!XD)

 

 

以下可以忽略

/*******************************************************************************************

初始化位置是在PVPlayerEngine::PopulateRecognizerRegistry(...)中,這個函數是被PopulateAllRegistries(...)調用,而PopulateAllRegistries(...)在PlayerEngine的Construct()中調用,並且其在調用PopulateRecognizerRegistry(...)之前,還會調用一個PopulateNodeRegistry(...),暫且把PopulateAllRegistries(...)放下不談,回到PopulateRecognizerRegistry(...)中,首先通過讀取config檔案(/system/etc/pvplayer.conf),將其中與PV_RECOGNIZER_INTERFACE相同Uuid的動態庫載入進來...(這裡為什麼會指定一個Uuid呢?這個Uuid在config檔案中對應的正是 libopencoremp4reg.so,也就是說,格式為UNKNOWN的,都用這個庫來識別?...繼續看). 這個庫本身就是opencore的一個node,產生它的Android.mk位於"external/opencore/tools_v2/build/modules/linux_mp4/node_registry",可以看出,他其實就是nodes/pvmp4ffparsernode,到此,檔案解析的動態庫也已載入.明天來繼續往下看,今天再溫習一下流程,思索下...

*********************************************************************************************/

 

 

好吧,其實android 1.5不支援.MP4的現象是因為我的.mp4檔案的聲音部分是用的aac編碼,而android本身只支援wav的音頻編碼...so,雖然能夠識別出是video/mp4,但是卻會導致播放器die(因為我的播放器沒做錯誤修正)

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.