Android多媒體框架:GenericSource搭建過程

1.概述

MediaPlayer播放視頻時球切,先通過setDataSource接口設(shè)置視頻源叭喜,然后再開始播放囚聚。而對于NuPlayer來說靖榕,拿到數(shù)據(jù)只是第一步,后續(xù)需要經(jīng)過解復(fù)用顽铸,解碼茁计,渲染和音視頻同步等一系列復(fù)雜的過程,最終完成視頻的播放。過程如下圖所示:

image.png

2.NuPlayer::Source

NuPlayer拿到setDataSource設(shè)置的數(shù)據(jù)后首先去解封裝星压,解封裝模塊的重要作用是將封裝好的音視頻源文件践剂,通過不同的封裝協(xié)議,解析成碼流后娜膘,送到解碼器解碼逊脯。NuPlayer中和解封裝相關(guān)的類有:

  • NuPlayer::Source:解封裝模塊的基類,定義了解封裝的基本接口竣贪。
  • GenericSource:本地文件相關(guān)军洼。
  • HTTPLiveSource:HLS流媒體使用的解封裝類。
  • RTSPSource:SDP協(xié)議媒體流使用的解封裝類演怎。
  • StreamingSource:流媒體使用的解封裝類匕争。
image.png

3.GenericSource創(chuàng)建

對于不同類型的數(shù)據(jù)源,在通過setDataSource()方法設(shè)置數(shù)據(jù)后爷耀,會創(chuàng)建對應(yīng)的Source甘桑。這里只分析本地文件對應(yīng)創(chuàng)建的GenericSource。setDataSource()到創(chuàng)建GenericSource的代碼流程如下:


image.png

主要有兩個方面作用:

  1. 將一些媒體資源文件相關(guān)索引(值)歹叮,以及解析器狀態(tài)重置為默認(rèn)狀態(tài)跑杭。
  2. 停止使用讓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> &notify,
        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> &notify);

    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);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揍鸟,一起剝皮案震驚了整個濱河市兄裂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖晰奖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谈撒,死亡現(xiàn)場離奇詭異,居然都是意外死亡匾南,警方通過查閱死者的電腦和手機啃匿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛆楞,“玉大人溯乒,你說我怎么就攤上這事‰叮” “怎么了橙数?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長帅戒。 經(jīng)常有香客問我,道長崖技,這世上最難降的妖魔是什么逻住? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮迎献,結(jié)果婚禮上瞎访,老公的妹妹穿的比我還像新娘。我一直安慰自己吁恍,他們只是感情好扒秸,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冀瓦,像睡著了一般伴奥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翼闽,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天拾徙,我揣著相機與錄音,去河邊找鬼感局。 笑死尼啡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的询微。 我是一名探鬼主播崖瞭,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼撑毛!你這毒婦竟也來了书聚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寺惫,沒想到半個月后疹吃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡西雀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年萨驶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艇肴。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡腔呜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出再悼,到底是詐尸還是另有隱情核畴,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布冲九,位于F島的核電站谤草,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏莺奸。R本人自食惡果不足惜丑孩,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灭贷。 院中可真熱鬧温学,春花似錦、人聲如沸甚疟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽览妖。三九已至轧拄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間黄痪,已是汗流浹背紧帕。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留桅打,地道東北人是嗜。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像挺尾,于是被迫代替她去往敵國和親鹅搪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容