1.概述
MediaPlayer播放視頻時球切,先通過setDataSource接口設(shè)置視頻源叭喜,然后再開始播放囚聚。而對于NuPlayer來說靖榕,拿到數(shù)據(jù)只是第一步,后續(xù)需要經(jīng)過解復(fù)用顽铸,解碼茁计,渲染和音視頻同步等一系列復(fù)雜的過程,最終完成視頻的播放。過程如下圖所示:
2.NuPlayer::Source
NuPlayer拿到setDataSource設(shè)置的數(shù)據(jù)后首先去解封裝星压,解封裝模塊的重要作用是將封裝好的音視頻源文件践剂,通過不同的封裝協(xié)議,解析成碼流后娜膘,送到解碼器解碼逊脯。NuPlayer中和解封裝相關(guān)的類有:
- NuPlayer::Source:解封裝模塊的基類,定義了解封裝的基本接口竣贪。
- GenericSource:本地文件相關(guān)军洼。
- HTTPLiveSource:HLS流媒體使用的解封裝類。
- RTSPSource:SDP協(xié)議媒體流使用的解封裝類演怎。
- StreamingSource:流媒體使用的解封裝類匕争。
3.GenericSource創(chuàng)建
對于不同類型的數(shù)據(jù)源,在通過setDataSource()方法設(shè)置數(shù)據(jù)后爷耀,會創(chuàng)建對應(yīng)的Source甘桑。這里只分析本地文件對應(yīng)創(chuàng)建的GenericSource。setDataSource()到創(chuàng)建GenericSource的代碼流程如下:
主要有兩個方面作用:
- 將一些媒體資源文件相關(guān)索引(值)歹叮,以及解析器狀態(tài)重置為默認(rèn)狀態(tài)跑杭。
- 停止使用讓BufferingMonitor停止循環(huán)監(jiān)聽buffer。
下面再看一下涉及到的主要的方法: (1)setDataSourceAsync()
void NuPlayer::setDataSourceAsync(const sp<DataSource> &dataSource) {
sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
// 創(chuàng)建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;
}
復(fù)制代碼
本地音視頻設(shè)置到這里咆耿,先是創(chuàng)建一個GenericSource德谅,然后將數(shù)據(jù)設(shè)置到該對象中。
(2)new GenericSource()
NuPlayer::GenericSource::GenericSource(
const sp<AMessage> ¬ify,
bool uidValid,
uid_t uid)
: Source(notify),//將一個AMessage對象存放在父類Source的mNotify字段中票灰,這是個通用操作女阀,用來通知調(diào)用者,當(dāng)前資源狀態(tài)的屑迂。
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數(shù)據(jù)到初始狀態(tài)浸策。
}
復(fù)制代碼
從構(gòu)造函數(shù)默認(rèn)初始化列表中的字段含義來看,GenericSource包含了除了Buffer以外幾乎所有的解封裝相關(guān)數(shù)據(jù)惹盼,如文件句柄(mFd)庸汗、媒體時長(mDurationUs)等。而關(guān)于Buffer狀態(tài)的管理和監(jiān)聽使用的是BufferingMonitor類來實現(xiàn)手报。
BufferingMonitor:協(xié)助監(jiān)控Buffer的狀態(tài)蚯舱,每秒輪詢一次,必要時會將Buffer的狀態(tài)通過AMessage通知Player掩蛤。
struct BufferingMonitor : public AHandler {
public:
explicit BufferingMonitor(const sp<AMessage> ¬ify);
void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */);
status_t setBufferingSettings(const BufferingSettings &buffering);
// 更新狀態(tài)
void prepare(const sp<NuCachedSource2> &cachedSource,
int64_t durationUs,
int64_t bitrate,
bool isStreaming);
// 停止并重置監(jiān)聽器
void stop();
// 取消當(dāng)前的任務(wù)
void cancelPollBuffering();
// 重啟監(jiān)聽任務(wù)
void restartPollBuffering();
// 停止緩沖任務(wù)并發(fā)送相應(yīng)的事件
void stopBufferingIfNecessary();
// 確保數(shù)據(jù)源正在獲取數(shù)據(jù)
void ensureCacheIsFetching();
// 更新從DataSource剛剛提取的緩沖區(qū)的媒體時間枉昏。
void updateQueuedTime(bool isAudio, int64_t timeUs);
// Set the offload mode.
void setOffloadAudio(bool offload);
// 更新發(fā)送到解碼器的最后出隊緩沖區(qū)的媒體時間。
void updateDequeuedBufferTime(int64_t mediaUs);
protected:
virtual ~BufferingMonitor();
virtual void onMessageReceived(const sp<AMessage> &msg);