MediaPlayer源码介绍3

Android  源码分析  2023年8月12日 am8:08发布1年前 (2023)更新 91es.com站长
96 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、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

陈独秀:人生的真义

人生在世,究竟为的甚么?究竟应该怎样?这两句话实在难得回答的很,我们若是不能回答这两句话,糊糊涂涂过了一生,岂不是太无意识吗?自古以来,说明这个道理的人也算不少,大概约有数种:第一是宗教家,像那佛教家说:世界本来是个幻象,人生本来无生;“真如”本性为“无明”所迷,才现出一切生灭幻象;一旦“无明”灭,...

nginx服务器开启Gzip

前言启用Gzip压缩功能, 可以使网站的css、js 等资源在传输时进行压缩,尽管这样会消耗一定的cpu资源,但是会节约大量的出口带宽来提高访问速度。记录一下,方便自己查阅。正文我这用的是Nginx,因此以这个为例,如果是Apache,可以看参考链接一。找到nginx.conf文件# ...

Vim查找命令

前言简单记录Vim查找命令正文/string 查找字符串查找后还可以使用如下命令n 继续查找N 反向查找参考文章

Android 换肤setFactory2时出现No field mFactorySet in class问题解决

前言Android换肤插件开发时,需要依赖LayoutInflater.Factory类,在Android P和 之前版本都测试ok,但放在Android Q(10)上测试就失效了。本文记录一下失效的原因和解决的方法。正文在Android Q之前版本,通过如下代码可以设置的 try {...

朱湘:海外寄霓君(节选)

一霓妹,我的爱妻:你从般若庵十二月初五写的“第一封”信我收到了。我后天就要搬家,你的信可以寄到憩轩四兄第一次替你打的信封那里。我在芝加哥城里过得好些,身体也好,望你不要记挂。我到今天总共收到你八封信。你信内并不曾提到岳母大人同憩轩四兄的病,想必是都好了。你的奶水不够,务必要请奶妈子。照我如今这般...

[摘]Android IO流读写文件实例

继前文摘抄,此篇是Android IO读写的实例操作。案例0功能:1、创建文件夹、文件 2、遍历文件夹下面的所有文件public class Test1 {      public static void main(String[] args) {          // TOD...