在上一节中,我们分析到从服务端返回后,函数的执行流程

(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(obj.get());            } else {                err = UNKNOWN_ERROR;            }            CHECK(mDriver != NULL);            sp driver = mDriver.promote();            if (driver != NULL) {                driver->notifySetDataSourceCompleted(err);            }            break;        }

这段代码中大部分都是与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的流程就分析完毕了。

更多相关文章

  1. C语言函数的递归(上)
  2. android 热修复之类加载机制
  3. [android] HttpURLConnection的初步学习
  4. Android布局优化(一),Android渲染机制
  5. Binder框架 -- android AIDL 的使用
  6. Android中JNI编程的那些事儿
  7. Android保存数据的技巧
  8. 《第一行代码 Android(安卓)》学习记录(一)
  9. Android设置铃声分析

随机推荐

  1. 一种粗暴快速的Android全屏幕适配方案
  2. Android应用程序键盘(Keyboard)消息处理机
  3. Android文件存储位置简述
  4. Android(安卓)Button控件 的简单使用(butt
  5. 采用跑马灯形式显示文本
  6. Android(安卓)P 指纹 HAL
  7. 限制EditText输入类型与长度
  8. Android布局中margin,padding,align的用
  9. 【eoe Android特刊】第二十四期 Android(
  10. Android(安卓)CTS 测试研究