一 摘要
对于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();
- mLibHandle = ::dlopen(MIO_LIBRARY_NAME, RTLD_NOW); //MIO_LIBRARY_NAME = "libopencorehw.so";
- createThreadEtc(PlayerDriver::startPlayerThread , this, "PV player");
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的实例。
- }
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
- };
(1) 在PVPlayer中的pause 函数(在playerdriver.cpp 文件中)
- status_t PVPlayer::pause()
- {
- LOGV("pause");
- return mPlayerDriver->enqueueCommand(new PlayerPause(0,0));
- }
(2) PlayerDriver 类的enqueueCommand 将间接调用各个以handle 为开头的函数,对于PlayerPause 命令,调用的函数是handlePause
- void PlayerDriver::handlePause(PlayerPause* ec)
- {
- LOGV("call pause");
- mPlayer->Pause(0);
- FinishSyncCommand(ec);
- }
在这个播放器适配器的实现中,一个主要的工作是将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;
(1) 在PVPlayer 的setVideoSurface 用以设置一个Video 输出的界面,这里使用的参数的类型是ISurface指针:
- status_t PVPlayer::setVideoSurface(const sp<ISurface>& surface)
- {
- LOGV("setVideoSurface(%p)", surface.get());
- mSurface = surface;
- return OK;
- }
- 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));
- }
- }
- }
(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));
- }
结语:再次说一下,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。