1. 程式人生 > >多媒體文件格式(三):M3U8 格式

多媒體文件格式(三):M3U8 格式

我們 文件信息 app 代理服務 width 逗號 適應 ios 作用

一、M3U8 格式標準介紹

M3U8文件是指UTF-8編碼格式的M3U文件。M3U文件是記錄了一個索引純文本文件,打開它時播放軟件並不是播放它,而是根據它的索引找到對應的音視頻文件的網絡地址進行在線播放。

M3U8是一種常見的流媒體格式,主要以文件列表的形式存在,既支持直播又支持點播,尤其在Android、iOS等平臺最為常用。

下面是CCTV6直播播放地址:http://ivi.bupt.edu.cn/hls/cctv6hd.m3u8的M3U8的文件列表:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:35232
#EXT-X-TARGETDURATION:10
#EXTINF:10.000, cctv6hd-1549272376000.ts #EXTINF:10.000, cctv6hd-1549272386000.ts #EXTINF:10.000, cctv6hd-1549272396000.ts #EXTINF:10.000, cctv6hd-1549272406000.ts #EXTINF:10.000, cctv6hd-1549272416000.ts #EXTINF:10.000, cctv6hd-1549272426000.ts

下面我們來分別說明一下相關的幾個字段:

  • EXTM3U:這個是M3U8文件必須包含的標簽,並且必須在文件的第一行,所有的M3U8文件中必須包含這個標簽。
  • EXT-X-VERSION:M3U8文件的版本,常見的是3(目前最高版本應該是7)。
  • EXT-X-TARGETDURATION:該標簽指定了媒體文件持續時間的最大值,播放文件列表中的媒體文件在EXTINF標簽中定義的持續時間必須小於或者等於該標簽指定的持續時間。該標簽在播放列表文件中必須出現一次。
  • EXT-X-MEDIA-SEQUENCE:M3U8直播是的直播切換序列,當播放打開M3U8時,以這個標簽的值作為參考,播放對應的序列號的切片。
  • EXTINF:EXTINF為M3U8列表中每一個分片的duration,如上面例子輸出信息中的第一片的duration為10秒。在EXTINF標簽中,除了duration值,還可以包含可選的描述信息,主要為標註切片信息,使用逗號分隔開。

關於客戶端播放M3U8的標準還有更多的講究,下面我們來介紹一些:

  1. 分片必須是動態改變的,序列不能相同,並且序列必須是增序的。
  2. 當M3U8沒有出現EXT-X-ENDLIST標簽時,無論這個M3U8列表中有多少分片,播放分片都是從倒數第三片開始播放,如果不滿三片則不應該播放。當然如果有些播放器做了特別定制了,則可以不遵照這個原則。
  3. 以播放當前分片的duration時間刷新M3U8列表,然後做對應的加載動作。
  4. 前一片分片和後一片分片有不連續的時候,播放可能會出錯,那麽需要X-DISCONTINUTY標簽來解決這個錯誤。
  5. 如果播放列表在刷新之後與之前的列表相同,那麽在播放當前分片duration一半的時間內在刷新一次。

在上面,我們提到了,一些上面例子沒有出現的一些標簽字段,下面我們針對一些額外的標簽做一些補充說明:

  • EXT-X-ENDLIST:若出現EXT-X-ENDLIST標簽,則表明M3U8文件不會再產生更多的切片,可以理解為該M3U8已停止更新,並且播放分片到這個標簽後結束。M3U8不僅僅是可以作為直播,也可以作為點播存在,在M3U8文件中保存所有切片信息最後使用EXT-X-ENDLIST結尾,這個M3U8即為點播M3U8。EXT-X-ENDLIST標簽可能會出現在播放列表文件的任何地方,但是不能出現兩次或以上。
  • EXT-X-STREAM-INF:EXT-X-STREAM-INF標簽出現在M3U8時,主要是出現在多級M3U8文件中時,例如M3U8中包含子M3U8列表,或者主M3U8中包含多碼率M3U8時;該標簽後需要跟一些屬性,下面就來逐一說明一下這些屬性:
    1. BANDWIDTH:BANDWIDTH的值為最高碼率值,當播放EXT-X-STREAM-INF下對應的M3U8時占用的最大碼率(必要參數)。
    2. AVERAGE-BANDWIDTH:AVERAGE-BANDWIDTH的值為平均碼率值,當播放EXT-X-STREAM-INF下對應的M3U8時占用的平均碼率。(可選參數)。
    3. CODECS:CODECS的值用於聲明EXT-X-STREAM-INF下面對應M3U8裏面的音視頻編碼、視頻編碼的信息(可選參數)。
    4. RESOLUTION:M3U8中視頻的寬高信息描述(可選參數)。
    5. FRAME-RATE:子M3U8中的視頻幀率(可選參數)。

二、HLS 與 M3U8

HLS(全稱:Http Live Streaming)是由Apple公司定義的用於實時流傳輸的協議,HLS基於HTTP協議實現,傳輸內容包括兩部分,一是M3U8描述文件,二是TS媒體文件。

HLS的優勢為:自適應碼率流播(adaptive streaming)。效果就是客戶端會根據網絡狀況自動選擇不同碼率的視頻流,條件允許的情況下使用高碼率,網絡繁忙的時候使用低碼率,並且能夠自動在二者之間隨意切換。這對移動設備網絡狀況不穩定的情況下保障流暢播放非常有幫助。實現方法是服務器端提供多碼率視頻流,並且在列表文件中註明,播放器根據播放進度和下載速度進行自動調整。

為什麽要用 TS 而不是 MP4?這是因為兩個 TS 片段可以無縫拼接,播放器能連續播放,而 MP4 文件由於編碼方式的原因,兩段 MP4 不能無縫拼接,播放器連續播放兩個 MP4 文件會出現破音和畫面間斷,影響用戶體驗。而且如果要在一段長達一小時的視頻中跳轉,如果使用單個 MP4 格式的視頻文件,並且也是用 HTTP 協議,那麽需要代理服務器支持 HTTP range request 獲取大文件中的一部分。這樣的話,對於代理服務器的性能來說要求較高。而 HTTP Live Streaming 則只需要根據列表文件中的時間軸找出對應的 TS 片段下載即可,不需要 range request,對代理服務器的要求小很多。所有代理服務器都支持小文件的高效緩存。

三、FFmpeg轉HLS文件(M3U8)實戰

1. FFmpeg轉MP4為HLS(M3U8)文件

將MP4文件轉換成HLS(M3U8)命令行:

ffmpeg -re -i 好漢歌.mp4 -c copy -f hls -bsf:v h264_mp4toannexb output.m3u8

可以看到生成的M3U8及相應的ts文件:

技術分享圖片

查看一下生成的M3U8文件:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:19
#EXTINF:10.000000,
output19.ts
#EXTINF:10.000000,
output20.ts
#EXTINF:9.280000,
output21.ts
#EXTINF:4.120000,
output22.ts
#EXTINF:2.440000,
output23.ts
#EXT-X-ENDLIST

細心的人可能發現一個問題,就是生成的m3u8文件裏只有最後的五個片段的信息。這是因為ffmpeg 默認的list size 為5,所以只獲得最後的5個片段。為了解決這個問題,需要指定參數-hls_list_size 0,這樣就能包含所有的片段。

下面是優化後的命令行:

ffmpeg -re -i 好漢歌.mp4 -c copy -f hls -hls_list_size 0 -bsf:v h264_mp4toannexb output.m3u8

這時,我們可以看到從output0.ts到output23.ts的文件列表了。

可能有人會發現,無論是優化之前的命令行,還是優化後的命令行都有一個參數-bsf:v h264_mp4toannexb,這個參數的作用是將MP4中的H.264數據轉換成為H.264 AnnexB標準的編碼,AnnexB標準的編碼常見於實時傳輸流中。如果源文件為FLV、TS等可以作為直播傳輸流的視頻,則不需要這個參數。

下面我們逐一介紹下使用FFmpeg生成HLS時還可以配置的其他參數。

四、FFmpeg 轉 HLS (M3U8) 文件命令參數

1. start_number 參數

start_number 參數用於設置M3U8列表中的第一片的序列數。

下面的例子中,我們使用start_number參數設置M3U8中的第一片序列書為100,命令行如下:

ffmpeg -re -i huijia.mp4 -c copy -f hls -start_number 100 -hls_list_size 0 -bsf:v h264_mp4toannexb output.m3u8

輸出的M3U8內容如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:100
#EXTINF:3.000000,
output100.ts
#EXTINF:3.000000,
output101.ts
#EXTINF:3.000000,
output102.ts
#EXTINF:3.000000,
output103.ts
#EXTINF:3.000000,
output104.ts
#EXTINF:3.000000,
output105.ts
#EXTINF:3.000000,
output106.ts
#EXTINF:1.000000,
output107.ts
#EXT-X-ENDLIST

從輸出可以看出,切片的第一片編號是100,上面的命令行參數的-start_number參數已生效。

2. hls_time 參數

hls_time參數用於設置M3U8列表中切片的duration。

下面的例子中,我們使用hls_time參數設置M3U8的TS文件的每一片時長為9秒左右。命令行如下:

ffmpeg -re -i huijia.mp4 -c copy -f hls -hls_time 9 -hls_list_size 0 -bsf:v h264_mp4toannexb output.m3u8 

然後查看輸出的M3U8內容如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:9
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:9.000000,
output0.ts
#EXTINF:9.000000,
output1.ts
#EXTINF:4.000000,
output2.ts
#EXT-X-ENDLIST

可以看到TS的文件每一片的時常都是9秒左右,hls_time參數生效。

( 註意:hls_time設置後效果不一定準確,會受到關鍵幀大小及其他因素影響。)

3. hls_list_size 參數

hls_list_size參數用於為M3U8列表中的TS切片的個數。其中設置為0的時候,將包含所有。

這個命令,我們在第3節優化MP4轉HLS文件的命令行時使用到了。

下面的例子中,我們使用hls_list_size參數設置只保留2片TS切片。命令行如下:

ffmpeg -re -i huijia.mp4 -c copy -f hls -hls_list_size 2 -bsf:v h264_mp4toannexb output.m3u8 

查看輸出的M3U8內容如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:6
#EXTINF:3.000000,
output6.ts
#EXTINF:1.000000,
output7.ts
#EXT-X-ENDLIST

從輸出的M3U8內容可以看出,在M3U8文件中只保留了2片TS的文件信息,可以看出hls_list_size設置生效了。

4. hls_base_url參數

hls_base_url 參數用於為M3U8列表的文件路徑設置前置基本路徑參數,因為在FFmpeg中生成M3U8時寫入的TS切片路徑默認為M3U8生成的路徑相同,但是實際上TS所存儲的路徑既可以為本地絕對路徑,也可以為相對路徑,還可以為網絡路徑,因此使用hls_base_url參數可以達到該效果,命令行如下:

ffmpeg -re -i huijia.mp4 -c copy -f hls -hls_base_url /Users/renhui/Desktop/test/ -bsf:v h264_mp4toannexb output.m3u8

查看輸出的M3U8內容如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:3
#EXTINF:3.000000,
/Users/renhui/Desktop/test/output3.ts
#EXTINF:3.000000,
/Users/renhui/Desktop/test/output4.ts
#EXTINF:3.000000,
/Users/renhui/Desktop/test/output5.ts
#EXTINF:3.000000,
/Users/renhui/Desktop/test/output6.ts
#EXTINF:1.000000,
/Users/renhui/Desktop/test/output7.ts
#EXT-X-ENDLIST

可以看到,TS的路徑變為絕對路徑了,使用ffplay output.m3u8播放,看到播放是能夠正常播放的。這樣就可以說明hls_base_url生效了。

多媒體文件格式(三):M3U8 格式