圖為:芒果TV CDN研發總監劉維
芒果TV CDN研發主要負責芒果TV點播、直播CDN的建設。現在主流的直播平臺主要包括互動性平臺,對業務的要求是低延時和流暢性,在保障這兩個前提的基礎上再去強調清晰度。芒果TV主要有兩大需求方向:一個是對于電視臺類的傳統節目類的頻道直播,還有一個就是大型的活動性直播,包括綜藝、晚會等。
目前直播平臺面臨很多技術挑戰,首先是視頻編碼,264是為了覆蓋兼容性,265各個平臺基本也都在使用,265主要是為了解決清晰度和節約帶寬的問題,在音頻上AAC是比較主流的,芒果TV也使用了EAC3,是為了解決多聲道和高品質的問題,因為像《歌手》類唱歌型比賽對音頻的要求比較高,封裝一般主流網站是FLV流和HLS,但是芒果TV多了一個MPEG-TS,因此負載比較大,從視頻編碼格式、音頻編碼格式再乘以封裝格式,所輸出的并發流的路數非常多,終端覆蓋,基本上移動端、網頁端,PC端,芒果TV多一個重點的就是電視端,電視端帶來的問題,就是它有很多的7×24頻道直播,頻道直播會對保障要求更過,頻道直播還要求時移和回看功能,在直播平臺,包括點播功能,從上面來看,整體的技術需求還是比較復雜的。
面對這些技術需求,芒果TV實行一些關鍵技術,來解決這些問題,一是高可用網站,還有無縫切流,最后一個是邊緣同步切片。高可用源站,整個信號的流程是從信源開始,信源包括衛星,主要用衛星接收,用網絡來做備份,不同的信源下面接的是不同的編碼器組,通過組播的方式把信源編碼以后傳遞給下面的分發源站,分發源站用組播的方式有一個好處,就是可以平滑地、無縫地去擴容分發源站,但是這個好處也帶來一個問題,分發源站有很多的服務器,這些服務器如何同步地執行切換流的指令是目前需要面對的問題。針對這個問題引入了Redis元數據的概念,通過控制所有源站的控制指令,通過后臺對Redis元數據控制,實現所有源站在發現信源或者是編碼器組故障,或者有業務需求要切流的時候,一致性地推動所有的分發源站做切換動作。
接下來是無縫切流,做過CDN的人都有所了解,如果源站出了問題可能會導致全網故障,所以保障源站的可用性是比較大的問題。源站從信源到編碼器,一直到分發源站都是多備份的,在多備份的情況下如何平滑地在多備份之間進行切換,這就帶來了一個技術挑戰。一個是用戶的體驗(流暢性),一個是競品網站的清晰度,產品和運營PK最后的結論就是讓技術解決。
編碼器1、編碼器2是相互備份的關系,提供同樣的清晰度,編碼器1提供三檔清晰度,編碼器2也提供同樣三檔清晰度,源站集群向一級、二級邊緣下發,如果產品要求拼播,會把第二檔的清晰度作為默認清晰度下發,當發現用戶卡頓比較高、流暢性比較差的情況下,把默認清晰度動態切換到碼流比較低的狀態,用戶體驗可以比較高,編碼器第一組掛了,可以快速地切換到編碼器第二組,用了清晰度3,如果流暢性比較好,嘗試讓用戶切換到更清晰的程度,在同平臺的競爭中我們也有一定的優勢。
這是技術細節,視頻編碼分三類幀,一類是I幀、關鍵幀,還有就是B幀,是通過I幀的相對運算集散出來的,壓縮比可以達到50%左右,壓縮效率更高。還有B幀,B幀要通過P幀或者I幀做演算,壓縮率會更高,因為極度壓縮,里面產生了很多片斷的狀態,有些B幀需要前后幀結算,所以在切流的時候,從第一路流切到第二路流,第一路流沒有到關鍵幀就切的話,前面的幀是解析不了的,所以必須在第一路流的I幀播放完以后馬上切到第二路流,第一套方案上線后出現一些問題,切到第二路流的時候,只追求了一個時效性,非常快速地切過去,但是因為編碼器之間時效性、準確性對得不是很齊,會產生不能解析的問題,因為它是P幀,缺少前面的關鍵幀,所以導致P幀不能解析,甚至B幀也不能解析,所以這塊會產生一個花屏,時間非常短,用戶會發現突然花一下,后面等I幀到了以后會繼續流暢地往下播。目前芒果TV的改進方案就是解決這個問題。
最后是全網邊緣的同步切片,芒果TV目前封裝方式很多,編碼器到分發源之間是用RTMT組播,組播之后進行封裝,因為需要HLS格式,如果同時把這些路往下傳,以后可能還有更多路,剛才說264、265、AAC等等這么多路同時往下傳的話,會員帶寬和成本是扛不住的。因此采用一路流直接傳到邊緣,在邊緣做轉封裝,這樣的好處是成本可以大幅下降,而且壓力比較輕。
但是碰到邊緣A站看直播流的時候,突然邊緣A站宕掉或者有什么意外的情況需要重試,通過調度到邊緣B站,到邊緣B站再獲取同樣時間點片的時候,由于每個邊緣到源站的時延是不一樣的,包括跳過幾級路由也不一樣,可能經過其他中間層的傳輸,所以它到邊緣的時候時延是不一樣的,雖然系統時間一樣,但是流的時間是不一樣的,中間就產生了差,因為播放器都是有緩存的,播放器緩存如果網突然有問題了,拿不到緩存,去后臺做重試,去邊緣B站,去繼續拿流,但是因為兩邊產生的內容差,就發現拿流的時候,會出現重復情況,有的時候時延情況更嚴重,給用戶帶來的體驗比較差,要解決這個問題必須在內容上去做標記,來實現切片的時候是內容對齊的,所以就考慮了在剛才說的I幀、P幀、B幀中間插一些注示幀、SEI幀,自定義一些信息,把拿到FLV流做封裝的時候,讀到這些信息的時候就知道在什么位置做切片,這樣全網所有的切片都是一致的,從A邊緣跳到B邊緣、C邊緣中間都是非常流暢的。