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的代码流程如下:
主要有两个方面作用:
- 将一些媒体资源文件相关索引(值),以及解析器状态重置为默认状态。
- 停止使用让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> ¬ify,
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> ¬ify);
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);