(hanchao3c Android開發人員論壇原創,轉載請註明)
本文是《Android的多媒體架構OpenCore(PacketVideo)介紹 》的後續內容,前文請參考:
http://www.androidin.com/bbs/viewthread.php?tid=2585&extra=page%3D1
5.1 Player的組成
OpenCore的Player的編譯檔案是pvplayer/Android.mk,
將產生動態庫檔案libopencoreplayer.so。這個庫包含了兩方面的內容:一方是Player的engine(引擎),一方面是為
Android構件的Player,這實際上是一個適配器(adapter)。engine的路徑是engine/player;adapter的路徑是
android。
5.2 Player Engine部分
OpenCore的Player Engine具有清晰明確的介面。在這個介面之上,不同的系統可一個根據自己的情況實現不同Player。目錄engines中的檔案結構如下所示:
OpenCore的Player Engine具有清晰明確的介面。在這個介面之上,不同的系統可一個根據自己的情況實現不同Player。目錄engines中的檔案結構如下所示:
engines/player/
|-- Android.mk
|-- build
| |-- linux_nj
| |-- make
| `-- makefile.conf
|-- config
| `-- linux_nj
|-- include
| |-- pv_player_datasink.h
| |-- pv_player_datasinkfilename.h
| |-- pv_player_datasinkpvmfnode.h
| |-- pv_player_datasource.h
| |-- pv_player_datasourcepvmfnode.h
| |-- pv_player_datasourceurl.h
| |-- pv_player_events.h
| |-- pv_player_factory.h
| |-- pv_player_interface.h
| |-- pv_player_license_acquisition_interface.h
| |-- pv_player_registry_interface.h
| |-- pv_player_track_selection_interface.h
| `-- pv_player_types.h
|-- sample_app
| |-- Android.mk
| |-- build
| |-- sample_player_app_release.txt
| `-- src
|-- src
| |-- pv_player_datapath.cpp
| |-- pv_player_datapath.h
| |-- pv_player_engine.cpp
| |-- pv_player_engine.h
| |-- pv_player_factory.cpp
| |-- pv_player_node_registry.h
| `-- pv_player_sdkinfo.h
`-- test
|-- Android.mk
|-- build
|-- config
`-- src
其中,engines/player/include目錄中是介面標頭檔,engines/player/src目錄源檔案和私人標頭檔,主要標頭檔的功能如下所示:
pv_player_types.h:定義一些資料結構和枚舉值
pv_player_events.h:定義UUID和一些錯誤值。
pv_player_datasink.h:datasink是媒體資料的輸出,定義類PVPlayerDataSink,這是媒體資料輸出的基類,作為介面使用
pv_player_datasinkfilename.h:定義類PVPlayerDataSinkFilename繼承PVPlayerDataSink。
pv_player_datasinkpvmfnode.h:定義類PVPlayerDataSinkPVMFNode繼承PVPlayerDataSink。
pv_player_datasource.h:datasource是媒體資料的輸入,定義類PVPlayerDataSource,這是媒體資料輸入的基類,作為介面使用。
pv_player_datasourcepvmfnode.h:定義類PVPlayerDataSourcePVMFNode繼承PVPlayerDataSource。
pv_player_datasourceurl.h:定義類PVPlayerDataSourceURL繼承PVPlayerDataSource。
pv_player_interface.h:定義Player的介面PVPlayerInterface,這是一個介面類。
pv_player_factory.h:主要定義工廠類PVPlayerFactory,用於建立和銷毀PVPlayerInterface。
事實上,在engines/player/src目錄中,主要實作類別為pv_player_engine.cpp,其中定義了類PVPlayerEngine,PVPlayerEngine繼承了PVPlayerInterface,這是一個實作類別,在PVPlayerFactory建立PVPlayerInterface介面的時候,實際建立的是PVPlayerEngine。
在Player Engine的實現中,包含了編解碼和流量控制等功能,而輸出的介質需要從外部設定近來。PVPlayerInterface定義的介面基本是按照操作順序的,主要的介面如下所示:
在Player Engine的實現中,包含了編解碼和流量控制等功能,而輸出的介質需要從外部設定近來。PVPlayerInterface定義的介面基本是按照操作順序的,主要的介面如下所示:
PVCommandId AddDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData = NULL);
PVCommandId Init(const OsclAny* aContextData = NULL);
PVCommandId AddDataSink(PVPlayerDataSink& aDataSink, const OsclAny* aContextData = NULL);
PVCommandId Prepare(const OsclAny* aContextData = NULL);
PVCommandId Start(const OsclAny* aContextData = NULL);
PVCommandId Pause(const OsclAny* aContextData = NULL);
PVCommandId Resume(const OsclAny* aContextData = NULL);
PVCommandId Stop(const OsclAny* aContextData = NULL);
PVCommandId RemoveDataSink(PVPlayerDataSink& aDataSink, const OsclAny* aContextData = NULL);
PVCommandId Reset(const OsclAny* aContextData = NULL);
PVCommandId RemoveDataSource(PVPlayerDataSource& aDataSource, const OsclAny* aContextData = NULL);
這裡面的DataSink可能包含Video的輸出和Audio的輸出兩者部分。在pv_player_types.h檔案中,定義了Player的狀態機器,以PVP_STATE_為開頭,如下所示:
typedef enum
{
PVP_STATE_IDLE = 1,
PVP_STATE_INITIALIZED = 2,
PVP_STATE_PREPARED = 3,
PVP_STATE_STARTED = 4,
PVP_STATE_PAUSED = 5,
PVP_STATE_ERROR = 6
} PVPlayerState;
PVPlayerInterface中的各個操作如果成功,可以更改Player的狀態機器:初始化的時候Player是PVP_STATE_IDLE狀
態,調用Init後,進入PVP_STATE_INITIALIZED狀態;調用AddDataSink,進入PVP_STATE_PREPARED狀
態;調用Prepare後,進入PVP_STATE_PREPARED狀態;調用start後進入PVP_STATE_STARTED狀態,之後可以調用
pause進入PVP_STATE_PAUSED狀態。
PVP_STATE_STARTED和PVP_STATE_PAUSED狀態是播放情況下的狀態,可以使用start和pause函數在這兩個狀態中切換。
在播放過程中,調用stop可以返回PVP_STATE_INITIALIZED狀態,在調用RemoveDataSource返回PVP_STATE_IDLE狀態。
5.3 Android Player Adapter
在android目錄中定義為Player的適配器,這個目錄主要包含的檔案如下所示:
android
|-- Android.mk
|-- android_audio_mio.cpp
|-- android_audio_mio.h
|-- android_audio_output.cpp
|-- android_audio_output.h
|-- android_audio_output_threadsafe_callbacks.cpp
|-- android_audio_output_threadsafe_callbacks.h
|-- android_audio_stream.cpp
|-- android_audio_stream.h
|-- android_log_appender.h
|-- android_surface_output.cpp
|-- android_surface_output.h
|-- mediascanner.cpp
|-- metadatadriver.cpp
|-- metadatadriver.h
|-- playerdriver.cpp
|-- playerdriver.h
`-- thread_init.cpp
這個Android的Player的“適配器”需要調用OpenCore的Player
Engine的介面,實現Android的媒體播放器的服務所需要介面,即最終實現一個PVPlayer,而PVPlayer實際上是繼承了
MediaPlayerInterface。
在實現過程中,首先實現了一個PlayerDriver,然後再使用PVPlayer,PVPlayer通過調用PlayerDriver來完成具體的功能。整個實現的結構圖:
對PVPlayerDriver的各種操作使用各種命令來完成,這些命令在playerdriver.h中進行的定義。
enum player_command_type {
PLAYER_QUIT = 1,
PLAYER_SETUP = 2,
PLAYER_SET_DATA_SOURCE = 3,
PLAYER_SET_VIDEO_SURFACE = 4,
PLAYER_SET_AUDIO_SINK = 5,
PLAYER_INIT = 6,
PLAYER_PREPARE = 7,
PLAYER_START = 8,
PLAYER_STOP = 9,
PLAYER_PAUSE = 10,
PLAYER_RESET = 11,
PLAYER_SET_LOOP = 12,
PLAYER_SEEK = 13,
PLAYER_GET_POSITION = 14,
PLAYER_GET_DURATION = 15,
PLAYER_GET_STATUS = 16,
PLAYER_REMOVE_DATA_SOURCE = 17,
PLAYER_CANCEL_ALL_COMMANDS = 18,
};
這些命令一般實現的是PVPlayerInterface各個介面的簡單封裝,例如對於較為簡單的暫停播放這個操作,整個系統執行的過程如下所示:
1.在PVPlayer中的pause函數(在playerdriver.cpp檔案中)
status_t PVPlayer::pause()
{
LOGV("pause");
return mPlayerDriver->enqueueCommand(new PlayerPause(0,0));
}
這時調用其成員mPlayerDriver(PlayerDriver類型)的函數,將一個PlayerPause命令加入了命令序列,具體的各種命令功能在playerdriver.h檔案中。
2.PlayerDriver類的enqueueCommand將間接調用各個以handle為開頭的函數,對於PlayerPause命令,調用的函數是handlePause
void PlayerDriver::handlePause(PlayerPause* ec)
{
LOGV("call pause");
mPlayer->Pause(0);
FinishSyncCommand(ec);
}
這裡的mPlayer是一個PVPlayerInterface類型的指標,使用這個指標調用到了OpenCore的 Player Engine中的PVPlayerEngine類。
在這個播放器適配器的實現中,一個主要的工作是將Android架構中定義的媒體的輸出(包括Audio的輸出和Video的輸出)轉換
成,OpenCore的 Player
Engine需要的形式。在這裡兩個重要的類是android_surface_output.cpp實現的
AndroidSurfaceOutput,android_audio_output.cpp實現的AndroidAudioOutput。
對於Video輸出的設定過程,在類PlayerDriver中定義了3個成員:
PVPlayerDataSink *mVideoSink;
PVMFNodeInterface *mVideoNode;
PvmiMIOControl *mVideoOutputMIO;
這裡的mVideoSink 的類型為PVPlayerDataSink,這是Player
Engine中定義的類介面,mVideoNode的類型為VMFNodeInterface,在pvmi/pvmf/include的
pvmf_node_interface.h中定義,這是所有的PVMF的NODE都需要繼承的統一介面,mVideoOutputMIO的類型為
PvmiMIOControl也在pvmi/pvmf/include中定義,這是媒圖輸出控制的介面類。
1.在PVPlayer的setVideoSurface用以設定一個Video輸出的介面,這裡使用的參數的類型是ISurface指標:
status_t PVPlayer::setVideoSurface(const sp<ISurface>& surface)
{
LOGV("setVideoSurface(%p)", surface.get());
mSurface = surface;
return OK;
}
setVideoSurface函數設定的是PVPlayer中的一個成員mSurface,真正設定Video輸出的介面的功能在run_set_video_surface()函數中實現:
void PVPlayer::run_set_video_surface(status_t s, void *cookie)
{
LOGV("run_set_video_surface s=%d", s);
if (s == NO_ERROR) {
PVPlayer *p = (PVPlayer*)cookie;
if (p->mSurface == NULL) {
run_set_audio_output(s, cookie);
} else {
p->mPlayerDriver->enqueueCommand(new PlayerSetVideoSurface(p->mSurface, run_set_audio_output, cookie));
}
}
}
這時使用的命令是PlayerSetVideoSurface,最終將調用到PlayerDriver中的handleSetVideoSurface函數。
2.handleSetVideoSurface函數的實現如下所示:
void PlayerDriver::handleSetVideoSurface(PlayerSetVideoSurface* ec)
{
int error = 0;
mVideoOutputMIO = new AndroidSurfaceOutput(ec->surface());
mVideoNode = PVMediaOutputNodeFactory::CreateMediaOutputNode(mVideoOutputMIO);
mVideoSink = new PVPlayerDataSinkPVMFNode;
((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkNode(mVideoNode);
((PVPlayerDataSinkPVMFNode *)mVideoSink)->SetDataSinkFormatType(PVMF_YUV420);
OSCL_TRY(error, mPlayer->AddDataSink(*mVideoSink, ec));
OSCL_FIRST_CATCH_ANY(error, commandFailed(ec));
}
在這裡首先建立的建立成員mVideoOutputMIO(類型為PvmiMIOControl),這時建立的類是類
AndroidSurfaceOutput,這個類繼承了PvmiMIOControl,所以可以作為PvmiMIOControl使用。然後調用
PVMediaOutputNodeFactory::CreateMediaOutputNode建立了PVMFNodeInterface
類型的mVideoNode。隨後建立PVPlayerDataSinkPVMFNode類型的
mVideoSink,PVPlayerDataSinkPVMFNode本身繼承了PVPlayerDataSink,因此可以作為
PVPlayerDataSink使用。調用SetDataSinkNode函數將mVideoNode設定為mVideoSink的資料輸出節點。
事實上,對於Video的輸出,基本的功能都是在類AndroidSurfaceOutput中完成的,在這個類當中,主要的工作是將Android的
ISurface輸出作為Player
Engine的輸出。最後調用了AddDataSink將mVideoSink增加為了PVPlayerInterface的輸出。
在android_surface_output.cpp檔案中實現了類AndroidSurfaceOutput,這個類相當於一個OpenCore
Player
Engine的Video輸出和Android輸出的“適配器”。AndroidSurfaceOutput類本身繼承了類
PvmiMIOControl,而其建構函式又以ISurface類型為參數。這個類的實現是使用ISurface實現PvmiMIOControl的各
個介面。