美文网首页
Android多媒体框架:GenericSource搭建过程

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

作者: 像程序那样去思考 | 来源:发表于2023-04-26 22:06 被阅读0次

1.概述

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

image.png

2.NuPlayer::Source

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

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

3.GenericSource创建

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


image.png

主要有两个方面作用:

  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);

相关文章

网友评论

      本文标题:Android多媒体框架:GenericSource搭建过程

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