MediaPlayer源码介绍3

Android  源码分析  2023年8月12日 am8:08发布1年前 (2023)更新 城堡大人
131 0 0

前言

我们继续介绍MediaPlayer源码,继《MediaPlayer源码介绍2》和《mediaserver的启动》后,MediaPlayer也进入了MediaPlayerService的接口调用中。

今天我们继续以setDataSource为例,看看其在MediaPlayerService的流程。

涉及代码文件

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
frameworks\av\media\libmediaplayerservice\MediaPlayerFactory.cpp
frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayerDriver.cpp
frameworks\av\media\libstagefright\foundation\ALooper.cpp
frameworks\av\media\libstagefright\foundation\AMessage.cpp
frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayer.cpp
frameworks\av\media\libmediaplayerservice\nuplayer\GenericSource.cpp

正文

MediaPlayer源码介绍3

接上回。这里简单回顾一下mediaplayer.cpp的setDataSource()。

// mediaplayer.cpp 中
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length){
    status_t err = UNKNOWN_ERROR;
    // getMediaPlayerService()获取的是BpMediaPlayerService
    // BpMediaPlayerService的对象service
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        //创建BpMediaPlayer对象player,具体看BpMediaPlayerService中create方法
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            //就是调用BpMediaPlayer->setDataSource();
            (NO_ERROR != player->setDataSource(fd, offset, length))) { 
            player.clear();
        }
        //赋值,mPlayer = plyaer; //BpMediaPlayer在IMediaPlayer.cpp
        err = attachNewPlayer(player);
    }
    return err;
}

我们知道player是BpMediaPlayer,先是简单的回顾一下哈(具体看《MediaPlayer源码介绍2》)。

//其实就是BpMediaPlayer->setDataSource();
player->setDataSource();

//调用的是
remote()->transact(SET_DATA_SOURCE_FD, data, &reply);

//通过Binder通信进入了BnMediaPlayer的onTransact()
BnMediaPlayer.onTransact();

//调用的是setDataSource(),而BnMediaPlayer没有实现,那就看器子类
reply->writeInt32(setDataSource(fd, offset, length));

//BnMediaPlayer继承BnInterface<IMediaPlayer>没有实现其父类接口
//其子类,MediaPlayerService中Client继承BnMediaPlayer
//并实现了setDataSource(),因此进入Client.setDataSource()
MediaPlayerService::Client::setDataSource();

接上回分析,我们进入了

//MediaPlayerService.cpp
MediaPlayerService::Client::setDataSource();

setDataSource()

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length){
    struct stat sb;
    //略
    //获取播放类型
    player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                               fd,
                                                               offset,
                                                               length);
    //根据类型创建createPlayer
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
    if (p == NULL) {
        return NO_INIT;
    }
    return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
}
getPlayerType()
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()

GET_PLAYER_TYPE_IMPL

其实就是查找sFactoryMap中存储的类型。(这个sFactoryMap之前在《mediaserver的启动》中有介绍过),按照之前介绍的,播放类就三种

enum player_type {
    STAGEFRIGHT_PLAYER = 3,
    NU_PLAYER = 4,
    TEST_PLAYER = 5,
};

而我们之前在registerBuiltinFactories()就注册了NU_PLAYER和TEST_PLAYER。一般用这个NU_PLAYER。

#define GET_PLAYER_TYPE_IMPL(a...)                      \
    Mutex::Autolock lock_(&sLock);                      \
    // 默认为STAGEFRIGHT_PLAYER类型
    player_type ret = STAGEFRIGHT_PLAYER;               \
    //最佳播放器得分
    float bestScore = 0.0;                              \
    // 播放器工厂模式实现的缓存注册的已实现的所有播放器集合[sFactoryMap]
    // 进行循环并查找最佳得分的播放器
    for (size_t i = 0; i < sFactoryMap.size(); ++i) {   \
        // 获取该播放器工厂得分,注意此处的参数a是个可变参数,
        // 例如上面是文件流时为4个参数,因此传入给scoreFactory方法的参数即可5个参数
        // 见下面的具体Factory实现分析中      
        IFactory* v = sFactoryMap.valueAt(i);           \
        float thisScore;                                \
        CHECK(v != NULL);                               \
        thisScore = v->scoreFactory(a, bestScore);      \
        // 若当前播放器工厂得分更高则替换旧值
        if (thisScore > bestScore) {                    \
            ret = sFactoryMap.keyAt(i);                 \
            bestScore = thisScore;                      \
        }                                               \
    }                                                   \
    // 若最佳得分为0,则获取默认推荐的播放器类型。
    // getDefaultPlayerType()直接返回的是[NU_PLAYER]播放器类型
    if (0.0 == bestScore) {                             \
        ret = getDefaultPlayerType();                   \
    }                                                   \
    return ret;
setDataSource_pre()

根据playerType,进行获取player

sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
        player_type playerType){
    //根据类型进行获取对应的player
    sp<MediaPlayerBase> p = createPlayer(playerType);
    if (p == NULL) {
        return p;
    }
    sp<IServiceManager> sm = defaultServiceManager();
	//获取媒体解码器
    sp<IBinder> binder = sm->getService(String16("media.extractor"));
    if (binder == NULL) {
        return NULL;
    }
	//解码器死亡监听
    sp<ServiceDeathNotifier> extractorDeathListener =
            new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
    binder->linkToDeath(extractorDeathListener);
	//获取omx
    sp<IOmx> omx = IOmx::getService();
    if (omx == nullptr) {
        return NULL;
    }
	//omx死亡监听
    sp<ServiceDeathNotifier> codecDeathListener =
            new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
    omx->linkToDeath(codecDeathListener, 0);

    Mutex::Autolock lock(mLock);
    clearDeathNotifiers_l();
    mExtractorDeathListener = extractorDeathListener;
    mCodecDeathListener = codecDeathListener;
    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
    }
    return p;
}

我们这里只关注createPlayer哈,其他的暂时忽略。

createPlayer()

先查询已经有的,如果类型不一样,就清除之前的,重新根据类型进行获取

sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType){
	//获取之前使用的player
    sp<MediaPlayerBase> p = getPlayer();
    if ((p != NULL) && (p->playerType() != playerType)) {
		//如果之前的不为null,且类型不一样,清除
        p.clear();
    }
	//重新通过playerType进行创建Player
    if (p == NULL) {
        p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
    }
    if (p != NULL) {
        p->setUID(mUid);
    }
    return p;
}
createPlayer()

进入MediaPlayerFactory::createPlayer()。

sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
        player_type playerType,
        const sp<MediaPlayerBase::Listener> &listener,
        pid_t pid) {
    sp<MediaPlayerBase> p;
    IFactory* factory;
    status_t init_result;
    Mutex::Autolock lock_(&sLock);
    if (sFactoryMap.indexOfKey(playerType) < 0) {
        return p;
    }
    //获取NuPlayerFactory
    factory = sFactoryMap.valueFor(playerType);
    CHECK(NULL != factory);
	// p = new NuPlayerDriver(); factory是之前创建的,从sFactoryMap获取
	//也就是说真正处理的还是进入了NuPlayerDriver,真绕
    p = factory->createPlayer(pid);
    if (p == NULL) {
        return p;
    }
    init_result = p->initCheck();
    if (init_result == NO_ERROR) {
    	//设置监听
        p->setNotifyCallback(listener);
    } else {
        p.clear();
    }
    return p;
}

这里做了三件事(1)从sFactoryMap根据类型获取NuPlayerFactory对象(2)同NuPlayerFactory对象创建NuPlayerDriver(3)对player设置监听。

listener就是赋值的mListener,是MediaPlayerService::Client::Client的变量,这里暂不关心。

从上面的之前sFactoryMap和NuPlayerFactory都稍微介绍过,具体看《mediaserver的启动》。

//获取NuPlayerFactory
factory = sFactoryMap.valueFor(playerType);
//调用NuPlayerFactory.createPlayer()
p = factory->createPlayer(pid);
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
    virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
        return new NuPlayerDriver(pid);
    }
};

也就是创建的p就是NuPlayerDriver对象。

NuPlayerDriver

接上面NuPlayerFactory.createPlayer()。

class NuPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
    virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
        return new NuPlayerDriver(pid);
    }
};

NuPlayerDriver在NuPlayerDriver.cpp中。

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,NuPlayer的对象
      mPlayer(new NuPlayer(pid, mMediaClock)),
      mPlayerFlags(0),
      mAnalyticsItem(NULL),
      mClientUid(-1),
      mAtEOS(false),
      mLooping(false),
      mAutoLoop(false) {
	//mLooper设置名字
    mLooper->setName("NuPlayerDriver Looper");
    mMediaClock->init();
    mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
	//mLooper调用start方法
    mLooper->start(
            false, /* runOnCallingThread */
            true,  /* canCallJava */
            PRIORITY_AUDIO);
	//关联mPlayer
    mLooper->registerHandler(mPlayer);
	//调用mPlayer.init()
    mPlayer->init(this);
}

上面很长,但我们只关注以下几点。

  1. mPlayer的创建

  2. mLooper初始化和启动

  3. mPlayer调用init()

mPlayer初始化

变量初始化时

mPlayer(new NuPlayer(pid, mMediaClock))

这是C++的写法,等于

mPlayer = new NuPlayer(pid, mMediaClock)

也就是mPlayer是NuPlayer的对象。

struct NuPlayer : public AHandler {
}

NuPlayer是AHandler的子类。

后面调用了init()。

init()
mPlayer->init(this);
void NuPlayer::init(const wp<NuPlayerDriver> &driver) {
    //就是NuPlayerDriver
    mDriver = driver;
    //这里初始化了AMessage
    sp<AMessage> notify = new AMessage(kWhatMediaClockNotify, this);
    mMediaClock->setNotificationMessage(notify);
}
mLooper

哈哈看名字是不是很熟悉。没错。就是那个味!

mLooper(new ALooper)
//设置mLooper名字
mLooper->setName("NuPlayerDriver Looper");
//启动looper
mLooper->start(
        false, /* runOnCallingThread */
        true,  /* canCallJava */
        PRIORITY_AUDIO);
//关联mPlayer
mLooper->registerHandler(mPlayer);

暂时对这块不是很理解,只是知道就是ALooper AHandler AMessager组成一个消息循环的。

这部分后续吧,略过。

NuPlayerDriver小结

从上面NuPlayerDriver构造函数可以看出,NuPlayerDriver也是不干活的,真正干活的是NuPlayer,不过这里有一个消息队列。

p->setDataSource()

我们已经知道p就是NuPlayerDriver的对象,就是

NuPlayerDriver->setDataSource();
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
    Mutex::Autolock autoLock(mLock);
    if (mState != STATE_IDLE) {
        return INVALID_OPERATION;
    }
    mState = STATE_SET_DATASOURCE_PENDING;
    //mPlayer是NuPlayer对象
    mPlayer->setDataSourceAsync(fd, offset, length);
    //这里有个循环,会等待mState的变化
    while (mState == STATE_SET_DATASOURCE_PENDING) {
    	//直到mState出现变化,要不然等待
        mCondition.wait(mLock);
    }
    // 这个值会在notifySetDataSourceCompleted()中更新
    return mAsyncResult;
}

mState和mAsyncResult是在notifySetDataSourceCompleted()中更新的,后面会有。

干活的是NuPlayer,进入NuPlayer.cpp

setDataSourceAsync
void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
	//创建Message,消息类型是kWhatSetDataSource和kWhatSourceNotify
    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
    //初始化GenericSource, notify是个Message用于消息通知
    sp<GenericSource> source =
            new GenericSource(notify, mUIDValid, mUID, mMediaClock);
   	//通过source进行setDataSource
    status_t err = source->setDataSource(fd, offset, length);
    if (err != OK) {
        source = NULL;
    }
    //把创建的source附上
    msg->setObject("source", source);
    //发送Message出去
    msg->post();
    mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
}

这里关注GenericSource,这个才是重点GenericSource继承NuPlayer::Source和MediaBufferObserver。

NuPlayer::GenericSource::GenericSource(
        const sp<AMessage> &notify,
        bool uidValid,
        uid_t uid,
        const sp<MediaClock> &mediaClock)
    : Source(notify),//Message用于状态通知
      mAudioTimeUs(0),
      mAudioLastDequeueTimeUs(0),
      mVideoTimeUs(0),
      mVideoLastDequeueTimeUs(0),
      mPrevBufferPercentage(-1),
      mPollBufferingGeneration(0),
      mSentPauseOnBuffering(false),
      mAudioDataGeneration(0),
      mVideoDataGeneration(0),
      mFetchSubtitleDataGeneration(0),
      mFetchTimedTextDataGeneration(0),
      mDurationUs(-1ll),
      mAudioIsVorbis(false),
      mIsSecure(false),
      mIsStreaming(false),
      mUIDValid(uidValid),
      mUID(uid),
      mMediaClock(mediaClock),
      mFd(-1), //文件描述符索引默认值
      mBitrate(-1ll),
      mPendingReadBufferTypes(0) {
    CHECK(mediaClock != NULL);
    mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
    mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
	//重置变量初始状态
    resetDataSource();
}

初始化当前资源进入source,传入了文件描述符索引值和文件长度信息等。

status_t err = source->setDataSource(fd, offset, length);
setDataSource
status_t NuPlayer::GenericSource::setDataSource(
        int fd, int64_t offset, int64_t length) {
    Mutex::Autolock _l(mLock);
	//这里又变量恢复默认状态
    resetDataSource();
	//保存当前文件相关信息
    mFd = dup(fd);
    mOffset = offset;
    mLength = length;
    return OK;
}
onMessageReceived()
msg->post();

消息发送了,消息类型是kWhatSetDataSource,进入了onMessageReceived()

void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatSetDataSource:{
            CHECK(mSource == NULL);
            status_t err = OK;
            sp<RefBase> obj;
            CHECK(msg->findObject("source", &obj));
            if (obj != NULL) {
                Mutex::Autolock autoLock(mSourceLock);
                //mSource赋值,上面setDataSourceAsync()初始化并传入的message中的
                //这里用了静态类型转换
                mSource = static_cast<Source *>(obj.get());
            } else {
                err = UNKNOWN_ERROR;
            }
            CHECK(mDriver != NULL);
            //mDriver是之前传入的NuPlayerDriver对象
            sp<NuPlayerDriver> driver = mDriver.promote();
            if (driver != NULL) {
            	//这里用于回调状态
                driver->notifySetDataSourceCompleted(err);
            }
            break;
        }
		//略
	}
}
notifySetDataSourceCompleted
driver->notifySetDataSourceCompleted(err);

就是

# NuPlayerDriver.cpp
NuPlayerDriver->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通知解锁
    mCondition.broadcast();
}

到此,setDataSource()就差不多了,然后就等setDataSource_post()进行回调状态了。

setDataSource_post()

这个就是抛出p->setDataSource()状态。

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

主要做了如下事情:

  1. 根据p->setDataSource()返回状态进行处理

  2. 把p(也就是NuPlayerDriver对象)赋值给mPlayer(这样不需要重复创建)

参考文章

部分链接丢失

  1. MediaPlayer源码介绍2

  2. mediaserver的启动

  3. Android MediaPlayer整体架构源码分析 -【MediaPlayer多种类型播放器注册和获取创建流程】

  4. Android多媒体框架:GenericSource搭建过程

 历史上的今天

  1. 2020: Android WindowManager弹窗容易出现的问题(0条评论)
  2. 2019: 新井一二三:图书馆的恋人(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

[代码片段]Activity手动设置全屏和非全屏

前言Android开发项目中有些App的部分界面需要全屏,比如视频播放界面,进入时手动全屏,退出时恢复全屏状态。下面记录一下常用的全屏方式。正文当系统全屏时,很多悬浮窗会向上移动一小段距离,原因窗口布局是从状态栏之后开始的,全屏时没有状态栏了,所以会向上移动,给窗口加上,就可以解决。ge...

Android消息机制之二简介(2)

我们通过上一篇《Android消息机制Handler,Looper,Message,MessageQueue关系之一》知道,Android的消息机制必须将Handler,Looper,Message,MessageQueue一起“组织”起来,而且是缺一不可。比如在子线程中使用Handler必须先L...

Android 修改ListView快速滚动条的bar

前言最近需要使用修改ListView快速滚动条的bar,ListView是可以默认支持的,但就是太丑了,需要定制一下。下面就记录一下自己使用的方法。好记性不如烂笔头正文本文并非原创,感谢网友分享。隐藏内容!付费阅读后才能查看!¥2 ¥3多个隐藏块只需支付一次付费阅读

JNI之函数介绍一

前言虽然jni.h中定义了很多函数,但也不是每个都需要用,这个主要是看需求。今天介绍一下常用jni函数,方便自己后续查阅。正文每个个函数可通过JNIEnv指针以固定偏移量进行访问。JNIEnv指针可指向存储全部JNI函数指针的结构。 如果要看全部的函数定义,可以看《NDK中jni.h头文件...

余秋雨:什么是文化?

关于文化的几个“傻问题”文化很重要,这很少有人否认,但是,大家往往躲开了一个起点性的问题,那就是 ——文化到底是什么?文化的定义是什么?对于文化,我们心里一定早就储藏着大量疑问。而且,随着时间的推移,疑问越来越多。普遍人心的最初疑问最重要,但也最难回答。按照民间说法,这样的问题可称为“傻问题...

jaudiotagger解析ID3第二版

前言上一个版本《jaudiotagger解析ID3信息》,功能可以,但性能一般,因此这里之前的基础上优化一个版本。PS:推荐看jaudiotagger源码,我这只是个人流水账。正文导入jaudiotagger.jar导入lib库/libs/jaudiotagger.jarbuil...