3. Android(安卓)MultiMedia框架完全解析 - setDataSource继续分析
在上一节中,我们分析到从服务端返回后,函数的执行流程
(NO_ERROR != player->setDataSource(fd, offset, length)))
这里继续执行,从服务端返回后,这个player就对应的是MediaPlayerService::Client,同时需要注意的是,在《Android中C/S架构以及C++层调用步骤分析》中介绍了创建了一个IMediaPlayer的匿名Binder server,这时候,首先会调用到的是IMediaPlayer.cpp中的setDataSource函数,这是Bp端,再传送到Bn端,最终调用到MediaPlayerService中Client对应的setDataSource函数。
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length){.........//这里获取播放器的类型 player_type playerType = MediaPlayerFactory::getPlayerType(this, fd, offset, length);//这里会根据上面选择的播放器类型去创建相应的播放器 sp p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } // now set data source//最后,在这里将数据源设置给真正的播放器 setDataSource_post(p, p->setDataSource(fd, offset, length)); return mStatus;}
这里有3个知识点,下面就来一个一个分析
1) MediaPlayerFactory::getPlayerType
代码位于frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp中:
player_type MediaPlayerFactory::getPlayerType(const sp& client, const char* url) { GET_PLAYER_TYPE_IMPL(client, url);}
这里是一个宏定义
#define GET_PLAYER_TYPE_IMPL(a...) \ Mutex::Autolock lock_(&sLock); \ \ player_type ret = STAGEFRIGHT_PLAYER; \ float bestScore = 0.0; \ \ for (size_t i = 0; i < sFactoryMap.size(); ++i) { \ \ IFactory* v = sFactoryMap.valueAt(i); \ float thisScore; \ CHECK(v != NULL); \ thisScore = v->scoreFactory(a, bestScore); \ if (thisScore > bestScore) { \ ret = sFactoryMap.keyAt(i); \ bestScore = thisScore; \ } \ } \ \ if (0.0 == bestScore) { \ ret = getDefaultPlayerType(); \ } \ \ return ret;
这里定义了一个宏来选择播放器类型,里面的for循环也很简单,就是查询注册进来的播放器map中的score得分,谁的得分最高,这里最终选择了得分最高的NuPlayer。
(在这个步骤中,很多厂商都会选择自己定制Player,比如FSL定制的OMXPlayer,在下一篇文章中讲解。)
2) setDataSource_pre(playerType)
sp MediaPlayerService::Client::setDataSource_pre( player_type playerType){ ALOGV("player type = %d", playerType); // create the right type of player sp p = createPlayer(playerType); if (p == NULL) { return p; } if (!p->hardwareOutput()) { Mutex::Autolock l(mLock); mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(), mPid, mAudioAttributes); static_cast(p.get())->setAudioSink(mAudioOutput); } return p;}
来看看createPlayer函数的具体实现:
sp MediaPlayerService::Client::createPlayer(player_type playerType){ // determine if we have the right player type sp p = mPlayer; if ((p != NULL) && (p->playerType() != playerType)) { ALOGV("delete player"); p.clear(); } if (p == NULL) { p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid); } if (p != NULL) { p->setUID(mUID); } return p;}
这个函数中,首先确定正确的播放器类型,如果不对,删除旧的,然后就调用MediaPlayerFactory中的createPlayer函数,如下所示:
virtual sp createPlayer(pid_t pid) { ALOGV(" create NuPlayer"); return new NuPlayerDriver(pid); }
这里只是new了一个NuPlayerDriver,NuPlayerDriver可以看作NuPlayer的一个wrapper,看看它的构造函数:
NuPlayerDriver::NuPlayerDriver(pid_t pid) : mState(STATE_IDLE), mIsAsyncPrepare(false), mAsyncResult(UNKNOWN_ERROR), mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), mSeekInProgress(false), mLooper(new ALooper), mPlayerFlags(0), mAtEOS(false), mLooping(false), mAutoLoop(false), mStartupSeekTimeUs(-1) { ALOGV("NuPlayerDriver(%p)", this); mLooper->setName("NuPlayerDriver Looper"); mLooper->start( false, /* runOnCallingThread */ true, /* canCallJava */ PRIORITY_AUDIO); mPlayer = new NuPlayer(pid); mLooper->registerHandler(mPlayer); mPlayer->setDriver(this);}
这里设置了Looper,创建了一个NuPlayer,并且注册NuPlayer的Driver是NuPlayerDriver。
2.3 setDataSource_post(p, p->setDataSource(fd, offset, length));
首先在MediaPlayerService::Client::setDataSource_post函数中,只是设置了一下setRetransmitEndpoint,没有做很多的工作,其实这里还有一个函数嵌套,首先需要执行的是:
p->setDataSource(fd, offset, length)
这时,有个问题,这个p究竟是什么?把2.2的过程仔细再捋一遍,就发现这个p是NuPlayerDriver,而不是NuPlayer,不要想当然,代码位于:frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp中:
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { ALOGV("setDataSource(%p) file(%d)", this, fd); Mutex::Autolock autoLock(mLock); if (mState != STATE_IDLE) { return INVALID_OPERATION; } mState = STATE_SET_DATASOURCE_PENDING; mPlayer->setDataSourceAsync(fd, offset, length); while (mState == STATE_SET_DATASOURCE_PENDING) { mCondition.wait(mLock); } return mAsyncResult;}
首先把mState设置成 STATE_SET_DATASOURCE_PENDING,在NuPlayerDriver的构造函数中,把mPlayer设置成了NuPlayer,所以这里就会调用到NuPlayer的setDataSourceAsync函数。注意这里有个while循环,它会一直等待mState发生改变,所以在setDataSourceAsync函数中理应会去改变这个mState,代码位于NuPlayer.cpp中:
void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { sp msg = new AMessage(kWhatSetDataSource, this); sp notify = new AMessage(kWhatSourceNotify, this); sp source = new GenericSource(notify, mUIDValid, mUID); status_t err = source->setDataSource(fd, offset, length); if (err != OK) { ALOGE("Failed to set data source!"); source = NULL; } msg->setObject("source", source); msg->post();}
这里使用了AMessage-AHandler-Alooper机制(这个机制在后面的《7. Android MultiMedia框架完全解析 - ALooper-AHandler-AMessage机制分析》中详细讲解),总之,首先声明并设置了GenericSource,在这个类的构造函数中,有个很重要的函数:DataSource::RegisterDefaultSniffers(),这个函数在后面的MediaExtractor中有很大作用,后面再分析这个,之后调用GenericSource的setDataSource函数,最后发送这个msg,去msg的处理函数中看看(具体怎么找到msg对应的处理函数,同样在后面的《7. Android MultiMedia框架完全解析 - ALooper-AHandler-AMessage机制分析》中分析,这里先按照这个流程分析,到后面再仔细理解这个过程):
void NuPlayer::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatSetDataSource: { ALOGV("kWhatSetDataSource"); CHECK(mSource == NULL); status_t err = OK; sp obj; CHECK(msg->findObject("source", &obj)); if (obj != NULL) { mSource = static_cast
这段代码中大部分都是与msg相关的,然后通过mDriver获得NuPlayer上面的Driver,比较重要的函数就是driver->notifySetDataSourceCompleted(err)了:
void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { Mutex::Autolock autoLock(mLock); CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING); mAsyncResult = err; mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE; mCondition.broadcast();}
发现这个函数中,就是根据GenericSource的设置结果,来设置mState,然后广播条件变量,记得上面NuPlayerDriver::setDataSource函数中的while循环了没?它就是在等着这个广播的。
既然执行完了setDataSource_post(p, p->setDataSource(fd, offset, length));里面嵌套的p->setDataSource(fd, offset, length),那么接下来就是执行外层的setDataSource_post函数,这个函数中并没有执行太多的东西,但是有一点,这里设置了MediaPlayerService中的成员变量mPlayer为NuPlayerDriver。这里有个混淆的概念,在MediaPlayerService中,有个成员变量mPlayer,而在NuPlayerDriver中,同样有一个成员变量为mPlayer。第一个mPlayer为NuPlayerDriver,而第二个mPlayer为NuPlayer,这里需要根据调用者所在的文件来确定mPlayer到底为哪个。
这时候,把整个过程捋下来,发现,其实虽然层层叠加,但是最终是完成了NuPlayer的创建,设置DataSource也只是最终设置到GenericSource里面,我的理解就是把文件描述符fd传过去,以后打开文件知道打开哪个文件就行,除此之外就是设置状态——mState。
下面,就讲讲GenericSource的作用
status_t NuPlayer::GenericSource::setDataSource( int fd, int64_t offset, int64_t length) { resetDataSource(); mFd = dup(fd); mOffset = offset; mLength = length; // delay data source creation to prepareAsync() to avoid blocking // the calling thread in setDataSource for any significant time. return OK;}
看这个NuPlayer::GenericSource::setDataSource函数,就是通过dup这个指令来复制fd描述符。
同时,GenericSource 的继承关系如下:
struct NuPlayer::GenericSource : public NuPlayer::Source
至此,setDataSource的流程就分析完毕了。
更多相关文章
- C语言函数的递归(上)
- android 热修复之类加载机制
- [android] HttpURLConnection的初步学习
- Android布局优化(一),Android渲染机制
- Binder框架 -- android AIDL 的使用
- Android中JNI编程的那些事儿
- Android保存数据的技巧
- 《第一行代码 Android(安卓)》学习记录(一)
- Android设置铃声分析