這是播放端的實現(xiàn)框圖,中間少畫了一個地方。這就是個傳統(tǒng)的播放器框圖,沒有體現(xiàn)出我們的核心的技術點,數(shù)據(jù)從網(wǎng)絡接收進來之后,經(jīng)過RTMP的Demux之后,我們是有一個模塊的,這個模塊會去判斷當前視頻是否需要被丟棄,這個原則也和我們接收緩存有關系,我們緩存配的是兩秒,如果超過兩秒,或者超過某一個其他的閾值的話,我們會開啟丟棄的模式。
這個丟棄有多種策略,有的是直接丟掉幀,有的是快進。如果做過播放器就會知道,傳統(tǒng)的視頻追趕一般都是在視頻解碼之后來做追趕。解碼就意味著會耗CPU,尤其是現(xiàn)在如果我想播720的視頻,光是解碼就基本上勉強實時的話,根本就沒有什么追趕的余地了。
所以我們在算法上做了一些優(yōu)化,我們拿到這個視頻的時候會先去判斷它是不是一個可以丟的,如果它是可以丟的,在解碼之前我們就丟,但是這樣丟會出問題,因為解碼器會內部不連續(xù),一旦解碼器內部不連續(xù)了,它可能會產(chǎn)生黑屏,所以我們即使要丟,也是在解碼器里邊做了一些定制化的開發(fā),還是把要丟的視頻傳進去,讓它自己來丟,它不去解,這樣就能達到更快速的把這個視頻丟掉,趕上現(xiàn)在的實際主播的進度。
這樣的話,如果我們網(wǎng)絡狀況很好,不擔心以后抖動的話,我們能做到從推流到觀看是2秒的延遲,但是一般我們都控制在4秒,就是為了防止抖動產(chǎn)生。
剛才說的是丟的這種邏輯,如果想快進,類似斗魚那種,在一點進去之后,開始畫面是很快過去的,但是沒有音頻,我們現(xiàn)在在做有音頻的方式,視頻在快進,音頻也在快進,這樣的話聲音會變調,因為采樣率變了。以前在做端的經(jīng)驗的時候,也做過這種變速不變調的算法,很多開源的,改改其實效果都能不錯,這種算法只要做好逆向優(yōu)化,放進來之后,音頻也能保證不變調。
日志收集,可能日志收集不是所有的開發(fā)者都愿意接受的,但是有的開發(fā)者是逼著我們要我們做,因為他們需要這個數(shù)據(jù)來定位問題,就像我剛才說的,經(jīng)常有人會問,是不是又卡了,這個問題被問多了之后,大家都希望知道為什么卡,端上的日志不收集上來是沒有辦法定位出這個問題的。我們現(xiàn)在有日志收集的策略在用戶同意的情況下,會定期可能幾百條打成一個ZIP包發(fā)上來,這個數(shù)據(jù)是我們和用戶共享的。
播放器其實我們也趟過坑,最開始我們基于VLC做,因為最開始我們做媒體云是做點播的業(yè)務,VLC是個挺好的架構,但是用VLC做追趕這個邏輯就能把人坑死,特別難改。因為它里頭一層一層耦合的很重,即使到最后改完了,聲音也有卡的情況。后來還是用更簡單的框架,自己來寫上層的所有控制。所以在移動端的直播場景和點播場景還是有很大區(qū)別的,這也就是為什么最近突然又出現(xiàn)了很多在視頻語音業(yè)務上的門檻。
這頁我剛才已經(jīng)陸陸續(xù)續(xù)都提到了,就是我們如何來定位問題,如何滿足播放器的兼容,還有追趕的各種體驗,發(fā)包的時候,我們會注意APP的大小。因為我們是一個采集和播放都是由我們提供的端到端的方案,有很多庫是可以復用的,如果都用我們的話,我們可以把其中一些庫做合并,最大程度節(jié)省我們提供的壓縮包的大小。