您的位置:首页 > 移动开发 > Android开发

Android的PVPlayer介绍

2013-10-15 15:27 309 查看
1 Player的组成

  OpenCore的Player的编译文件是pvplayer/Android.mk,将生成动态库文件 libopencoreplayer.so。这个库包含了两方面的内容:一方是Player的engine(引擎),一方面是为 Android构件的Player,这实际上是一个适配器(adapter)。engine的路径是engine/player;adapter的路径是 android。

  



2 Player Engine部分



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状态。

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的各 个接口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: