最近做了點關于這倆玩意的東西,記在這。
友提:廢話較多,想看 tl;dr 的按end后往回翻。
首先,這倆東西都是用來處理視頻的,為視頻提供基于HTTP的Streaming方案,除了這倆之外,還有下面的技術:
- Adobe HTTP Dynamic Streaming (HDS)
- Microsoft Smooth Streaming (MSS)
這倆沒接觸,不寫。標題中提到的那倆,也就記下來用到的東西,沒研究過的,比如說直播啥的也不寫。
Overview
先說需求吧,拋開需求談技術就是耍流氓,嗯。
隨著網絡的發展,技術的演進,人們手上的電子垃圾設備也越來越多,碰到的網絡狀況也越來越多,本文的廢話也越來越多。在現實的網絡環境中做媒體分發,以視頻為例,不同的設備所需的大小,碼率都不同,就算在相同的設備上,也需要根據網絡情況的不同選擇合適的碼率來播放。在此基礎上,還需要提供流暢的切換體驗。不難看出,想法很美好,但是現實很復雜。所以,需要有更好的辦法向用戶提供多碼率的媒體分發。
歷史
純廢話,可以無視
N年前在學校的時候就有這些東西了,當時是 RTSP
和 MMS
(暴露年齡了哇~),自己架好后去BBS(又一個暴露年齡的東西)上貼地址,然后傻等著那收聽數帶來的莫名其妙的成就感。好像把這玩意給革命掉的是Flash播放器,在播放的時候可以選擇碼率,不過在切換碼率的時候視頻會停一下(這個后臺具體的實現沒考證過,只描述現象)。慢慢的人們發現,Flash將設備變成曖手寶/電熨斗的功能是如此的顯著,但是這些熱量又不能給電池充電,總不能出門就給手機電腦啥的背尿袋吧,于是又開始鼓搗新玩意了~
HLS
Apple弄的流媒體標準,基于HTTP提供流媒體的功能,在蘋果系的軟件中被原生支持,至于Windows/Linux/Android,不好意思Who are you?
MPEG DASH
在基于HTTP提供流媒體的方面,到目前為止已經看到了三種方案,蘋果的HLS,土坯的HDS和巨硬的MSS,當然,各家用的協議,格式神馬的都不會一樣。于是每次做支持都要來三人份的。看到這三倍工作量,再想想老板不給加工資,碼農們的心都寒了...
MPEG的同志們體察到了這份疾苦,呼吁大家來個標準點的玩意唄,于是就有了MPEG DASH 。這里有一篇綜述,寫的比我好還圖文并茂的,去那看吧~
解決方案
此處是我在項目中的理解,沒查文檔,不保證正確
就接觸到的MPEG DASH和HLS來看,它們的主要想法都是把一個長視頻給切成小塊,然后通過一個個的HTTP請求分別下載。這樣一是每次請求的數據量不是很大,二是當用戶需要換碼率或分辨率時,在下次請求給新的視頻就好。但是兩種方法還是有些不同的,這個會在后面描述。此外,MPEG DASH還支持對于單一的媒體文件按時間戳請求,不過這次用到的不多,只會在后面介紹下生成方法。
在本文中,切片出來的視頻片段被稱為Segments。除了這些Segments外,還有描述這些Segments的文件,一般稱為 Manifest 文件,但是后面也會根據文件擴展名稱為 MPD 文件(MPEG DASH)或 M3U8 文件(HLS)。
進行MPEG DASH切片用的工具是 MP4Box
,而HLS切片的工具是 ffmpeg
需求
終于說到了這次的需求。首先,是個視頻服務提供商,之前的做法就是把mp4丟s3上讓用戶自己去看。不過現在發現一是一個視頻看下來,HTTP長連接受不了,二是如果只想給用戶一段視頻小樣(切片播放),現在的方案沒法實現。找了一圈,決定拿HTTP Streaming來試一試。
在做原型測試的時候,把HLS和DASH都嘗試了下,由于需要支持切片播放,目前的實現方案選擇的是HLS。
一些命令
源視頻為 foo.mp4 ,就是隨便從油管找一段720p的視頻下到本地來用的
MPEG DASH
-
切成 Segments
$ MP4Box -dash-strict 5000 -profile dashavc264:live -rap foo.mp4#video foo.mp4#audio -out index.mpd
命令執行成功后會在當前目錄下生成一個mpd文件,兩個mp4文件和一系列的m4s文件。下面分別說明:
-
index.mpd
: 上面提到的 Manifest 文件,XML格式,包含對視頻的描述。至于完整的Schema介紹,我也沒找到......一點點問G吧。 -
*_init.mp4
: 初始的mp4文件,相當于視頻頭,在這個頭文件中包含了完整的視頻元信息(moov),具體的可以使用MP4Box <init video> -info
查看。 -
*.m4s
: 即上面提到的Segments文件,每個m4s僅包含媒體信息 (moof + mdat),而播放器是不能直接播放這個文件的,需要用支持DASH的播放器從init文件開始播放。
關于video structure的知識,可以參考這個網頁
命令行參數中,
-dash 5000
表示把視頻按5s一段來切,-profile
指定一些預設的配置,-rap
強制Segments的起始位置為random access point,這個我也不清楚具體指什么,就是網上抄的命令。后面列出所有要導入的媒體流,如果有多個碼率,按規則寫即可,最后在-out
后跟上輸出的mpd文件名,m4s文件會存放在和mpd文件同級的目錄中。這個切片基本上相當于把視頻從中間直接分開,沒有重新編碼之類的過程,所以比較快。
注意在切片時把audio和video通過上面的命令分開,因為雖然DASH協議并沒有限制一個m4s中是否可以包含多過一個moof塊,但是目前的瀏覽器如Chrome是只支持在一個 Segment 中只包含一個moof的。
-
-
多碼率支持
DASH中,對多碼率的支持是通過增加
<Representation>
來完成的,具體可以問Google。
-
播放
把生成出來的所有東西放到http服務器的static目錄中,即可通過mpd播放器訪問了。除此之外,也可以使用支持mpd的app來放。
HLS
-
切成 Segments
$ ffmpeg -i foo.mp4 -g 25 -hls_time 1 -hls_list_size 0 index.m3u8
這個命令把視頻按1秒切成Segments。命令執行成功后,會在當前目錄下生成一個m3u8文件和一系列的ts文件。在HLS中,每個Segments都是可以獨立播放的MPEG-2 TS文件,而m3u8的作用就是明確這些ts文件的順序。m3u8文件是純文本格式,可以方便的閱讀修改。命令行參數中,
-g
用來指定按frame切視頻,而-hls_time
指定Segments的長度為1s。這兩個參數可以限定切出來的Segments 基本 符合1s一段的規則。所以在使用-g
時需要先確定源視頻文件的fps后再設定。不過,即便如此,也有一些Segments的長度會有1s以內的偏差,應該是無法避免的了。-hls_list_size
表示最后生成的m3u8中列出的ts文件的數目,默認是5,此處寫0表示把所有的ts文件都列上(這里是項目需求,實際使用中可以適當設置以減少m3u8文件大小)。沒有測過如果最后生成10個ts文件,但是m3u8中只有5個的情況下,能不能把視頻放完。回頭如果試了再補充。
由于這個命令需要使用ffmpeg對源視頻進行重新編碼,所以需要占用比較多的CPU和時間。
-
多碼率支持
HLS中,多碼率的支持是通過
#EXT-X-STREAM-INF
標簽指定的,在此標簽中通過設置BANDWIDTH
參數來指定碼率,然后在接下來的一行中填寫uri來標明此碼率對應的m3u8。 -
播放
如果使用Safari,可以直接把m3u8的地址輸入地址欄,即可直接播放。據稱Android的Chrome也支持,但是桌面的不支持,不過可以通過擴展播放。
播放器
雖然說有些瀏覽器可以內建支持HLS或者DASH,但是對于開發這邊而言,有一個統一的播放器會更方便些。之前查的時候找到了這些播放器,有些是兩者通吃,有些是只能放一個;有些免費,有些收費,按需取用吧~
- http://demo.theoplayer.com/test-hls-mpeg-dash-stream
- http://bitmovin.com/hls-mpeg-dash-test-player/
- http://dash-mse-test.appspot.com/dash-player.html
- http://shaka-player-demo.appspot.com/demo/
- http://dashif.org/reference/players/javascript/1.4.0/samples/dash-if-reference-player/
基本上就是這些了,主要是做項目中查到的東西,整理下以便查閱。如有錯誤,歡迎告知。