24/7 不間斷串流,影片之間不重新連線:透過管道餵給單一 ffmpeg

影片

全天候播放成品影片的直播頻道有兩種簡單設計,但兩者都有缺陷。每支影片重啟 ffmpeg 會在每次切換時中斷 RTMP 連線。串接播放清單僅在啟動時讀取一次,因此新影片必須等到下次重啟才會播放。

設計方案

每支影片僅轉換一次為符合串流尺寸與幀率的 MPEG-TS;直式影片置於自身模糊副本之上,而非黑邊。單一 ffmpeg 程序從標準輸入讀取 MPEG-TS,以固定位元率編碼,每兩秒一個關鍵幀,符合直播接收端的預期。小型餵送器按實時節奏將預備好的檔案逐一寫入該管道,並在每次切換時選擇下一個檔案:優先播放從未播放過的影片,其次播放最久未播放的影片。ffmpeg 的 MPEG-TS 讀取器會發現每個檔案的時間戳記重新開始,並自動偏移,使輸出串流不間斷地持續運行。

細節一:從首個位元組開始計時

我們的第一版在 ffmpeg 啟動時開始計時。準備第一個檔案花了九秒,因此餵送器認為自己落後了九秒,便一次性全部發送。改為在寫入首個位元組時啟動計時器後問題解決:執行 53 秒即產生 53 秒的串流。

細節二:接縫處的音訊

在切換時,下一個檔案的音訊比前一個檔案的音訊結束早 17 毫秒開始。編碼器警告其輸入「時間倒退」,多工器則修補了時間戳記。使用 aresample=async=1:min_hard_comp=0.01:first_pts=0 進行重採樣,可在編碼器看到之前修剪或填補這類重疊。在略超過一分鐘、包含五次切換的執行中,接收串流中的所有音訊與影片時間戳記均遞增,且串流解碼時無任何錯誤。

細節三:部分警告屬正常現象

每個檔案都會重置其 MPEG-TS 計數器與時鐘,因此 ffmpeg 會在每次切換時回報「Packet corrupt」與「timestamp discontinuity」。這些訊息屬預期之內,我們將其從日誌中排除,以便突顯真正的錯誤。

守護程序

如果 ffmpeg 結束執行,或其進度停止一分鐘,串流便會以逐漸延長的間隔重新啟動,並在多次失敗後發送訊息。在我們的測試中,我們手動終止了編碼器;串流在七秒後恢復,而中途新增的影片無需重新連線便加入了輪播。重新啟動只是一次短暫的重新連線,因此請將 YouTube 直播設定為自動開始且不要自動停止。串流金鑰在所有日誌行中都會被遮罩,包括 ffmpeg 自身的日誌。Studio 將此直播頻道作為 systemd 服務提供。

已更新: