美文网首页
Android多媒体框架--05:setDataSource详细

Android多媒体框架--05:setDataSource详细

作者: DarcyZhou | 来源:发表于2023-04-19 08:28 被阅读0次

    "本文转载自:[yanbixing123]的Android MultiMedia框架完全解析 - setDataSource继续分析"

    1.概述

      前面的章节已经涉及到了setDataSource()方法的代码逻辑,这一节将对setDataSource()作一个单独的详细总结。这里从frameworks/av/media/libmedia/mediaplayer.cpp文件中setDataSource()方法开始分析:

    status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
    {
        ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
        status_t err = UNKNOWN_ERROR;
        const sp<IMediaPlayerService> service(getMediaPlayerService());
        if (service != 0) {
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                (NO_ERROR != player->setDataSource(fd, offset, length))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
        return err;
    }
    

      前面章节分析到从服务端返回后,函数的执行流程:

    (NO_ERROR != player->setDataSource(fd, offset, length)))
    

      这里继续执行,从服务端返回后,这个player就对应的是MediaPlayerService::Client,同时需要注意的是,在《Android多媒体框架--03:MediaPlayer的C/S架构与Binder机制实现》中介绍了创建了一个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<MediaPlayerBase> p = setDataSource_pre(playerType);
        if (p == NULL) {
            return NO_INIT;
        }
    
        // now set data source
        // 最后,在这里将数据源设置给真正的播放器
        return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
    }
    

    2.getPlayerType

      继续分析上面的三个主要过程,其中MediaPlayerFactory::getPlayerType代码位于frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp中:

    player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
                                                  int fd,
                                                  int64_t offset,
                                                  int64_t length) {
        GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
    }
    

    GET_PLAYER_TYPE_IMPL是一个宏定义:

    #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和TestPlayer两种播放器,TestPlayer并未正式启用。所以,函数调用返回的是NuPlayer对应的播放器类型NU_PLAYER。

    • MediaPlayerInterface.h
    enum player_type {
        STAGEFRIGHT_PLAYER = 3,
        NU_PLAYER = 4,
        // Test players are available only in the 'test' and 'eng' builds.
        // The shared library with the test player is passed passed as an
        // argument to the 'test:' url in the setDataSource call.
        TEST_PLAYER = 5,
    };
    

    目前只注册了NU_PLAYER和TEST_PLAYER两种播放器。 STAGEFRIGHT_PLAYER实际上指的是AwesomePlayer,在早期的安卓系统使用AwesomePlayer去播放本地视频,用NuPlayer去播放流媒体。后来因为某些原因所以逐渐用弃用了AwesomePlayer,统一使用NuPlayer去播放。在某些过渡版本的安卓系统开发者选项里面还可以选择NuPlayer代替AwesomePlayer,到后期都不用选了,只有一个NuPlayer可以用。

    MediaPlayerService::MediaPlayerService()
    {
        ALOGV("MediaPlayerService created");
        mNextConnId = 1;
    
        MediaPlayerFactory::registerBuiltinFactories();
    }
    

    在MediaPlayerService构造函数中会去调用registerBuiltinFactories()函数注册一些播放器。

    void MediaPlayerFactory::registerBuiltinFactories() {
        Mutex::Autolock lock_(&sLock);
    
        if (sInitComplete)
            return;
    
        IFactory* factory = new NuPlayerFactory();
        if (registerFactory_l(factory, NU_PLAYER) != OK)
            delete factory;
        factory = new TestPlayerFactory();
        if (registerFactory_l(factory, TEST_PLAYER) != OK)
            delete factory;
    
        sInitComplete = true;
    }
    

    分别创建了NuPlayerFactory和TestPlayerFactory,并registerFactory_l函数进行注册,注册成功后会将它们添加到sFactoryMap中,对应宏定义GET_PLAYER_TYPE_IMPL就是sFactoryMap中的Factory,计算每个Factory的得分,最后取最高大分的播放器。

    3.setDataSource_pre

    frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

    sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
            player_type playerType)
    {
        ALOGV("player type = %d", playerType);
    
        // create the right type of player
        sp<MediaPlayerBase> p = createPlayer(playerType);
        if (p == NULL) {
            return p;
        }
    ......
        return p;
    }
    

    来看看createPlayer函数的具体实现:

    sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
    {
        // determine if we have the right player type
        sp<MediaPlayerBase> p = getPlayer();
        if ((p != NULL) && (p->playerType() != playerType)) {
            ALOGV("delete player");
            p.clear();
        }
        if (p == NULL) {
            p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
        }
    
        if (p != NULL) {
            p->setUID(mUid);
        }
    
        return p;
    }
    

    这个函数中,首先确定正确的播放器类型,如果不对,删除旧的,然后就调用MediaPlayerFactory中的createPlayer函数(最终会去调用NuPlayerFactory的createPlayer函数),如下所示:

        virtual sp<MediaPlayerBase> 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),
          mPlayingTimeUs(0),
          mRebufferingTimeUs(0),
          mRebufferingEvents(0),
          mRebufferingAtExit(false),
          mLooper(new ALooper),
          mMediaClock(new MediaClock),
          mPlayer(AVNuFactory::get()->createNuPlayer(pid, mMediaClock)),
          mPlayerFlags(0),
          mAnalyticsItem(NULL),
          mClientUid(-1),
          mAtEOS(false),
          mLooping(false),
          mAutoLoop(false) {
        ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
        mLooper->setName("NuPlayerDriver Looper");
    
        mMediaClock->init();
    
        // set up an analytics record
        mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
    
        mLooper->start(
                false, /* runOnCallingThread */
                true,  /* canCallJava */
                PRIORITY_AUDIO);
    
        mLooper->registerHandler(mPlayer);
    
        mPlayer->init(this);
    }
    

    这里设置了Looper,创建了一个NuPlayer,并且注册NuPlayer的Driver是NuPlayerDriver。

    4.setDataSource_post

    setDataSource_post(p, p->setDataSource(fd, offset, length));
    

      首先在MediaPlayerService::Client::setDataSource_post函数中,只是设置了一下setRetransmitEndpoint,没有做很多的工作,其实这里还有一个函数嵌套,首先需要执行的是:

    p->setDataSource(fd, offset, length)
    

    这里的p就是setDataSource_pre()方法创建的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);
        }
    
        AVNuUtils::get()->printFileName(fd);
        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<AMessage> msg = new AMessage(kWhatSetDataSource, this);
    
        sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
    
        sp<GenericSource> source =
                new GenericSource(notify, mUIDValid, mUID, mMediaClock);
    
        ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
                fd, (long long)offset, (long long)length, source.get());
    
        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();
        mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
    }
    

    这里使用了AMessage-AHandler-Alooper机制,总之,首先声明并设置了GenericSource,在这个类的构造函数中,有个很重要的函数:DataSource::RegisterDefaultSniffers(),这个函数在后面的MediaExtractor中有很大作用,之后调用GenericSource的setDataSource函数,最后发送这个msg,这里先按照这个流程分析,到后面再仔细理解这个过程:

    void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
        switch (msg->what()) {
            case kWhatSetDataSource:
            {
                ALOGV("kWhatSetDataSource");
    
                CHECK(mSource == NULL);
    
                status_t err = OK;
                sp<RefBase> obj;
                CHECK(msg->findObject("source", &obj));
                if (obj != NULL) {
                    Mutex::Autolock autoLock(mSourceLock);
                    mSource = static_cast<Source *>(obj.get());
                } else {
                    err = UNKNOWN_ERROR;
                }
    
                CHECK(mDriver != NULL);
                sp<NuPlayerDriver> 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) {
       Mutex::Autolock _l(mLock);
       ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)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的流程就分析完毕了。

    相关文章

      网友评论

          本文标题:Android多媒体框架--05:setDataSource详细

          本文链接:https://www.haomeiwen.com/subject/qwubddtx.html