当前位置: 首页>前端>正文

openldap 启动 关闭 opencore关闭启动代码

本文从代码的角度来分析Android多媒体框架中mediaplay是如何调用opencore的。
一.摘要:
对于Android 多媒体框架,Google 在 Android 2.2中就已经实现了stagefright,但还是保留了opencore;
在新推出的2.3版本中,正式抛弃了opencore,而采用stagefright。网上关于Android opencore架构的文章有很多,例如下面的链接:
http://www.360doc.com/content/10/0207/22/155970_15398760.shtml。 但大都是基于框架的,而没有更加细致的给出代码的实现过程,
本文从MediaPlayer::setDataSource开始,分析一下整个opcncore的初始化过程。

二. 引子:
在播放一个视频文件的时候,往往会这样做:
第一步,创建一个MediaPlayer对象;
第二步,依次调用MediaPlayer的setDataSource,prepare,start函数;

本文仅仅分析setDataSource(opencore的初始化就是在这个函数中完成的)。
三. 代码分析:
1.  MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length):
当我们在java层调用setDataSource函数时,最终,它会通过jni调用到C++层的MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)函数。它的实现如下:

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) ;
   1).getMediaPlayerService()  
         1.1   getService(String16("media.player")
   2).  service->create(getpid(), this, fd, offset, length)
         2.1  c = new Client, //这是一个MediaPlayerService::Client对象,参考MediaPlayerService类图
         2.2  c->setDataSource(fd, offset, length)
                getPlayerType
                sp<MediaPlayerBase> p = createPlayer(playerType);  // 真正的是实例PVPlayer, MidiFile or VorbisPlayer
                    android::createPlayer(playerType, this, notify)
                         sp<MediaPlayerBase> p;
                         case 1: p = new PVPlayer();  // defined media/PVPlayer.h
                         case 2: p = new MidiFile();   // defined libmediaplayerservice/PVPlayer.h
                         case 3: p = new VorbisPlayer();// same as MidiFile                        case 4: p = new stagefright;   // 2.2开始加入的,2.3中就彻底用它了。
     3). setDataSource(player):保存player的引用到MediaPlayer中.



以上三步,简要分析如下:
首先. 得到MediaPlayerService;
其次. 通过MediaPlayerService这个service来创建Client,再通过Client去创建Player(即调用createPlayer函数),事实上,创建的真正的是实例PVPlayer, MidiFile or VorbisPlayer,这就是opencore于mediaplayer的真正的唯一的桥梁。
最后. 通过调用setDataSource(这个是MediaPlayer类的函数)就创建的适配层的实例保存在MediaPlayer类的成员对象mPlayer中(详见setDataSource函数)。

 

2. PVPlayer的初始化:

  1)相关文件分布:
     既然createPlayer(playerType)函数中最创建PVPlayer(即调用new PVPlayer()),那么,就有必要看一下PVPlayer的构造的实现:
     PVPlayer的头文件是PVPlayer.h,路径为:base/include/media,而实现是在Playerdriver.cpp中,路径为:opencore/android.
     从这个小小的文件分布来看,也能得出PVPlayer是衔接C++层的mediaserver与opencore的桥梁。
  2)然而,为什么头文件和实现不是相同的前缀名呢?
     答:看Playerdriver.cpp的代码就知道,原来,最终的与opencore打交道的任务都落在了Playerdriver这个类上,
     而它也是PVPlayer类的一个数据成员。所以,为了与上层的MediaPlayer(要注意,PVPlayer类是MediaPlayer类的数据成员->其实是sp<IMediaPlayer>       mPlayer,这里,因为PVPlayer继承了sp<IMediaPlayer>)衔接,头文件取名为PVPlayer; 另外,真正与opencore 打交道的是Playerdriver,所以,实现的Cpp文件就是Playerdriver.cpp了。笔者认为,为了更加代码更加清晰,完全可以写一个PVPlayer.cpp,将PVPlayer.cpp相关代码写在这个PVPlayer.cpp中,尽管代码不是特别多。
  3) 是该看一下PVPlayer的初始化过程了:
    看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的定义与理解:

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

 

对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中继续使用。不过对于上层应用来说,不用管这些,因为接口没有变化。

 

 


https://www.xamrdz.com/web/2hr1942510.html

相关文章: