鑑於TS包的獨立解碼特性,HLS協議引入了TS格式作為傳輸單元。HLS協議的實現原理是對一個大的媒體分片,並將分片後的檔案路徑記錄於m3u8檔案,客戶端依據該m3u8檔案即可獲取對應的分片列表,再依次播放分片內容。每個TS分片都以SPS與PPS等配置幀開頭,其中指定了影片的規格資訊及其編碼引數,因此每個TS片段都能正常解析播放。關於SPS與PPS的詳細說明參見之前的文章《解析H.264碼流中的SPS幀和PPS幀》。
上述的分片檔案便是一個個以TS格式封裝的影片資源,那麼當直播源來自一個MP4檔案的時候,流媒體伺服器又是怎麼把MP4檔案轉化為一個個TS分片的呢?
以SRS為例,它在組裝TS包時做了特殊處理,在每個TS包的開頭位置,就自動插入SPS與PPS等配置幀。具體程式碼在SRS框架的trunk/src/main/srs_main_ingest_hls.cpp,檢視該原始碼的SrsIngestHlsOutput::on_ts_video函式,找到以下的程式碼片段,可見程式在寫入H.264流時,先寫入SPS幀和PPS幀,再寫入I幀、P幀和B幀。
找到write_h264_sps_pps函式的定義程式碼如下,發現函式內部在封裝序列頭時依次輸入了SPS幀和PPS幀:
進一步跟蹤mux_sequence_header的定義來源,詳細的定義程式碼在SRS框架的trunk/src/protocol/srs_protocol_raw_avc.cpp,檢視該原始碼的SrsRawH264Stream::mux_sequence_header函式,找到以下的程式碼片段,可見程式依據ISO_IEC_14496-15的文件規範,先後寫入了sequenceParameterSet的NAL單元(即SPS幀),以及pictureParameterSet的NAL單元(即PPS幀)。
由此可見,SRS在每個TS包頭都寫入了SPS幀和PPS幀,確保TS包是擁有SPS和PPS的完整H.264分片。只有加上SPS與PPS,客戶端才能正常拉流解析資料,才能正常渲染影片畫面。
更多詳細的FFmpeg開發知識參見