看PVPlayer的构造函数,最主要的就就创建了Playerdriver对象( mPlayerDriver = new PlayerDriver(this);),所以,PlayerDriver的构造才是核心。
3. PlayerDriver的构造
在 PlayerDriver 的构造过程中,最主要做了 3 件事情: 1) Semaphore(信号量)的创建: mSyncSem = new OsclSemaphore(); mSyncSem->Create();2) load libopencorehw.so: mLibHandle = ::dlopen(MIO_LIBRARY_NAME, RTLD_NOW); //MIO_LIBRARY_NAME = "libopencorehw.so";3) 开始 player thread createThreadEtc(PlayerDriver::startPlayerThread , this, "PV player"); 4. PlayerDriver::playerThread的实现startPlayerThread会call playerThread,playerThread是真正创建PV thread的函数。
int PlayerDriver::playerThread() { int error; LOGV("InitializeForThread"); if (!InitializeForThread()) { LOGV("InitializeForThread fail"); mPlayer = NULL; mSyncSem->Signal(); return -1; } LOGV("OMX_MasterInit"); OMX_MasterInit(); LOGV("OsclScheduler::Init"); OsclScheduler::Init("AndroidPVWrapper"); LOGV("CreatePlayer"); OSCL_TRY(error, mPlayer = PVPlayerFactory::CreatePlayer(this, this, this)); if (error) { // Just crash the first time someone tries to use it for now? mPlayer = NULL; mSyncSem->Signal(); return -1; } LOGV("AddToScheduler"); AddToScheduler(); LOGV("PendForExec"); PendForExec(); LOGV("OsclActiveScheduler::Current"); OsclExecScheduler *sched = OsclExecScheduler::Current(); LOGV("StartScheduler"); error = OsclErrNone; OSCL_TRY(error, sched->StartScheduler(mSyncSem)); OSCL_FIRST_CATCH_ANY(error, // Some AO did a leave, log it LOGE("Player Engine AO did a leave, error=%d", error) ); LOGV("DeletePlayer"); PVPlayerFactory::DeletePlayer(mPlayer); delete mDownloadContextData; mDownloadContextData = NULL; delete mDataSource; mDataSource = NULL; delete mAudioSink; PVMediaOutputNodeFactory::DeleteMediaOutputNode(mAudioNode); delete mAudioOutputMIO; delete mVideoSink; if (mVideoNode) { PVMediaOutputNodeFactory::DeleteMediaOutputNode(mVideoNode); delete mVideoOutputMIO; } mSyncStatus = OK; mSyncSem->Signal(); // note that we only signal mSyncSem. Deleting it is handled // in enqueueCommand(). This is done because waiting for an // already-deleted OsclSemaphore doesn't work (it blocks), // and it's entirely possible for this thread to exit before // enqueueCommand() gets around to waiting for the semaphore. // do some of destructor's work here // goodbye cruel world delete this; //Moved after the delete this, as Oscl cleanup should be done in the end. //delete this was cleaning up OsclSemaphore objects, eventually causing a crash OsclScheduler::Cleanup(); LOGV("OsclScheduler::Cleanup"); OMX_MasterDeinit(); UninitializeForThread(); return 0; }简析: 1) OMX_MasterInit 的调用,这正好是OMX协议定义中规定的要调用的第一个函数。 2) OsclScheduler::Init("AndroidPVWrapper"); 3) OSCL_TRY(error, mPlayer = PVPlayerFactory::CreatePlayer(this, this, this)); 通过Factory模式来创建Player. 在pv_player_factory.cpp中,有: OSCL_EXPORT_REF PVPlayerInterface *PVPlayerFactory::CreatePlayer(PVCommandStatusObserver* aCmdStatusObserver, PVErrorEventObserver *aErrorEventObserver, PVInformationalEventObserver *aInfoEventObserver, bool aHwAccelerated) { return PVPlayerEngine::New(aCmdStatusObserver, aErrorEventObserver, aInfoEventObserver, aHwAccelerated); // 会创建PVPlayerEngine的实例。 }4) AddToScheduler(); 5) PendForExec(); 6) OSCL_TRY(error, sched->StartScheduler(mSyncSem)); StartScheduler的实现: (1) call BlockingLoopL A. call CallRunExec(pvactive); // PVActiveBase *pvactive, 真正的对象是PlayerDriver实例。 a. call pvactive->Run() // 调用PlayerDriver的run. 分析:在PlayerDriver的run函数中,根据command的命令来执行相应的handle函数。 7) 可以看到,与OSCl层的调用,创建Engine的代码,具体,请读者自己看源码来理解吧。 5 PVPlayerDriver中command的定义与理解 对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, PLAYER_CHECK_LIVE_STREAMING = 19 }; 这些命令一般实现的是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 的类型为PVMFNodeInterface,在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 的数据输出节点。结语:再次说一下,opencore将在2.3版本中彻底消失,但是OMX还会在stagefright中继续使用。不过对于上层应用来说,不用管这些,因为接口没有变化。
在mk文件,没有看到具体的连接库的代码。如libmediaplayerservice的mk只看到链libopencore_player这个,
而opencore/android目录下mk文件写这个模块编译生成的是libandroidpv。在opencore/Android.mk中,有: include $(PV_TOP)/build_config/opencore_dynamic/Android_opencore_common.mk include $(PV_TOP)/build_config/opencore_dynamic/Android_opencore_author.mk include $(PV_TOP)/build_config/opencore_dynamic/Android_opencore_player.mk 在第三个mk文件,即文件opencore/build_config/opencore_dynamic/Android_opencore_player.mk中,有 LOCAL_MODULE := libopencore_player。 在libmediaplayerservice中用的,正是上面这个mk文件编译出来的libopencore_player.so。