Android多媒体框架:GenericSource创建过程

1.概述

MediaPlayer播放视频时,先通过setDataSource接口设置视频源,然后再开始播放。而对于NuPlayer来说,拿到数据只是第一步,后续需要经过解复用,解码,渲染和音视频同步等一系列复杂的过程,最终完成视频的播放。过程如下图所示:

2.NuPlayer::Source

NuPlayer拿到setDataSource设置的数据后首先去解封装,解封装模块的重要作用是将封装好的音视频源文件,通过不同的封装协议,解析成码流后,送到解码器解码。NuPlayer中和解封装相关的类有:

  • NuPlayer::Source:解封装模块的基类,定义了解封装的基本接口。
  • GenericSource:本地文件相关。
  • HTTPLiveSource:HLS流媒体使用的解封装类。
  • RTSPSource:SDP协议媒体流使用的解封装类。
  • StreamingSource:流媒体使用的解封装类。

3.GenericSource创建

对于不同类型的数据源,在通过setDataSource()方法设置数据后,会创建对应的Source。这里只分析本地文件对应创建的GenericSource。setDataSource()到创建GenericSource的代码流程如下:

主要有两个方面作用:

  1. 将一些媒体资源文件相关索引(值),以及解析器状态重置为默认状态。
  2. 停止使用让BufferingMonitor停止循环监听buffer。

下面再看一下涉及到的主要的方法:
(1)setDataSourceAsync()

void NuPlayer::setDataSourceAsync(const sp<DataSource> &dataSource) {
    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
    // 创建GenericSource
    sp<GenericSource> source = new GenericSource(notify, mUIDValid, mUID);
    status_t err = source->setDataSource(dataSource);

    if (err != OK) {
        ALOGE("Failed to set data source!");
        source = NULL;
    }

    msg->setObject("source", source);
    msg->post();
    mDataSourceType = DATA_SOURCE_TYPE_MEDIA;
}

本地音视频设置到这里,先是创建一个GenericSource,然后将数据设置到该对象中。

(2)new GenericSource()

NuPlayer::GenericSource::GenericSource(
        const sp<AMessage> &notify,
        bool uidValid,
        uid_t uid)
    : Source(notify),//将一个AMessage对象存放在父类Source的mNotify字段中,这是个通用操作,用来通知调用者,当前资源状态的。
      mAudioTimeUs(0),
      mAudioLastDequeueTimeUs(0),
      mVideoTimeUs(0),
      mVideoLastDequeueTimeUs(0),
      mFetchSubtitleDataGeneration(0),
      mFetchTimedTextDataGeneration(0),
      mDurationUs(-1ll),
      mAudioIsVorbis(false),
      mIsByteMode(false),
      mIsSecure(false),
      mIsStreaming(false),
      mUIDValid(uidValid),
      mUID(uid),
      mFd(-1),// 文件句柄
      mBitrate(-1ll),
      mPendingReadBufferTypes(0) {
    ALOGV("GenericSource");

    mBufferingMonitor = new BufferingMonitor(notify);// 新建一个BufferingMonitor实例
    resetDataSource();// 重置一些DataSource数据到初始状态。
}

从构造函数默认初始化列表中的字段含义来看,GenericSource包含了除了Buffer以外几乎所有的解封装相关数据,如文件句柄(mFd)、媒体时长(mDurationUs)等。而关于Buffer状态的管理和监听使用的是BufferingMonitor类来实现。

BufferingMonitor:协助监控Buffer的状态,每秒轮询一次,必要时会将Buffer的状态通过AMessage通知Player。

struct BufferingMonitor : public AHandler {
public:
    explicit BufferingMonitor(const sp<AMessage> &notify);

    void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
    status_t setBufferingSettings(const BufferingSettings &buffering);

    // 更新状态
    void prepare(const sp<NuCachedSource2> &cachedSource,
            int64_t durationUs,
            int64_t bitrate,
            bool isStreaming);
    // 停止并重置监听器
    void stop();
    // 取消当前的任务
    void cancelPollBuffering();
    // 重启监听任务
    void restartPollBuffering();
    // 停止缓冲任务并发送相应的事件
    void stopBufferingIfNecessary();
    // 确保数据源正在获取数据
    void ensureCacheIsFetching();
    // 更新从DataSource刚刚提取的缓冲区的媒体时间。
    void updateQueuedTime(bool isAudio, int64_t timeUs);

    // Set the offload mode.
    void setOffloadAudio(bool offload);
    // 更新发送到解码器的最后出队缓冲区的媒体时间。
    void updateDequeuedBufferTime(int64_t mediaUs);

protected:
    virtual ~BufferingMonitor();
    virtual void onMessageReceived(const sp<AMessage> &msg);

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值