使用 FFmpeg 以 VP9 進行直播編碼

編碼參數

VP9 提供一系列參數,可最佳化直播編碼。如要瞭解這些原則的概略資訊,請參閱「位元率模式」。

FFmpeg VP9 編碼範例

下表說明 VP9 編碼的 ffmpeg 呼叫範例參數。

參數 說明
-quality realtime realtime是直播的必要條件,且適用於高於 5 的速度。
-speed 6 「速度」58 應適用於即時編碼。數字越小 (56) 品質越高,但需要更多 CPU 運算能力。數字越大 (78) 品質越低,但更適合延遲時間較短的用途,以及 CPU 效能較低的裝置 (例如行動裝置)。
-tile-columns 4 分格會將影片分割成矩形區域,以便進行多執行緒編碼和解碼。圖塊數量一律為 2 的乘冪。0 = 1 個圖塊、1 = 2、2 = 4、3 = 8、4 = 16、5 = 32。
-frame-parallel 1 啟用並行解碼功能。
-threads 8 要使用的執行緒數量上限。
-static-thresh 0 動作偵測門檻。
-max-intra-rate 300 最高 I 影格位元率 (百分比)
-deadline realtime -quality realtime 的替代 (舊版) 版本
-lag-in-frames 0 要延遲的影格數量上限
-qmin 4 -qmax 48 量化器的最小值和最大值。這裡的值僅供參考,調整此值會以壓縮效率為代價,提高/降低影片品質。
-row-mt 1 啟用列多執行緒。最多可使用 2 倍的執行緒做為圖塊資料欄。0 = 關閉,1 = 開啟。
-error-resilient 1 啟用錯誤復原功能。

選擇編碼參數

以下資訊使用固定位元率 (CBR) 編碼,進行即時自適應位元率串流 (ABR),其中每個目標速率都會在封裝工具的資訊清單中明確設定。這樣一來,客戶的費率「切換」會更順暢。如果位元率可以更彈性,或編碼正在分塊,您也可以選擇可變位元率 (VBR) 編碼和 CQ 模式Q 模式無法即時編碼,因此不適合用於直播影片。詳情請參閱「位元率模式」。

如要進一步瞭解如何操作 VP9,也建議參閱隨附的 VOD 設定文章,但請以 CBR 為重點。

提示與秘訣

請注意,直播時所有內容都會受到限制,最低即時編碼速度為 1 倍 (FFmpeg 會在編碼過程中回報編碼速度)。如果編碼速度低於 1 倍,編碼程序就無法跟上即時影像的輸入速度,使用者會遇到緩衝問題,傳輸中斷也會導致直播期間無法使用串流 (但封存檔通常可用)。

編碼參數的實際運作範例

下圖顯示在執行 Linux 的四核心 i5 3.6Ghz 桌機上,以 25 FPS 播放各種影格大小的影片時,CPU 使用率:

目標解析度 FFmpeg VP9 參數 CPU / 速度 (範例)
3840x2160 (2160p) -r 30 -g 90 -s 3840x2160 -quality realtime -speed 5 -threads 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k 約 88% 0.39 倍
2560x1440 (1440p) -r 30 -g 90 -s 2560x1440 -quality realtime -speed 5 -threads 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 6000k 約 86% 0.68 倍
1920x1080 (1080p) -r 30 -g 90 -s 1920x1080 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 4500k ~82% 1.04x
1280x720 (720p) -r 30 -g 90 -s 1280x720 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 3000k 約 78% 1.77 倍
854x480 (480p) -r 30 -g 90 -s 854x480 -quality realtime -speed 6 -threads 4 -row-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 1800k ~64% 3.51x
640x360 (360p) -r 30 -g 90 -s 640x360 -quality realtime -speed 7 -threads 4 -row-mt 1 -tile-columns 1 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 730k ~62% 5.27x
426x240 (240p) -r 30 -g 90 -s 426x240 -quality realtime -speed 8 -threads 2 -row-mt 1 -tile-columns 0 -frame-parallel 0 -qmin 4 -qmax 48 -b:v 365k ~66% 8.27x

FFmpeg 範例如下:

ffmpeg -stream_loop 100 -i /home/id3as/Videos/120s_tears_of_steel_1080p.webm \
  -r 30 -g 90 -s 3840x2160 -quality realtime -speed 5 -threads 16 -row-mt 1 \
  -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k -c:v libvpx-vp9 \
  -b:a 128k -c:a libopus -f webm pipe1

提示與秘訣

  • 請注意,我們在這裡輸出至 FIFO 管道 ("pipe1"),執行前應先建立該管道,再執行 FFmpeg 指令。如要這麼做,請在工作目錄中執行 mkfifo pipe1 指令。使用 Shaka Packager 時,系統會將該管道做為指定串流的輸入來源。其他包裝型號可能需要使用不同方法。

  • 如要確保系統能辨識 -row-mt 指令,請使用 FFmpeg 的最新穩定版本 (目前為 3.3.3),網址為 https://www.ffmpeg.org/download.html

自動調整位元率設定範例

視執行 FFmpeg 編碼的電腦效能而定,可能無法同時提供下列所有編碼,因此請從清單中選取適合可用資源和目標對象的子集。

FFmpeg 完整 ABR 設定

在理想情況下,我們會結合前一節中列出的編碼範例,建立單一指令,同時產生所有編碼:

ffmpeg -stream_loop 100 -i lakes1080p.mp4 \
  -y -r 25 -g 75 -s 3840x2160 -quality realtime -speed 5 -threads 8 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 7800k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe1 \
  -y -r 25 -g 75 -s 2560x1440 -quality realtime -speed 5 -threads 8 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 6000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe2 \
  -y -r 25 -g 75 -s 1920x1080 -quality realtime -speed 5 -threads 4 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 4500k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe3 \
  -y -r 25 -g 75 -s 1280x720 -quality realtime -speed 5 -threads 4 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 3000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe4 \
  -y -r 25 -g 75 -s 854x480 -quality realtime -speed 6 -threads 4 \
  -tile-columns 2 -frame-parallel 1 \
  -b:v 2000k -c:v libvpx-vp9 -b:a 196k -c:a libopus -f webm pipe5 \
  -y -r 25 -g 75 -s 640x360 -quality realtime -speed 7 -threads 2 \
  -tile-columns 1 -frame-parallel 0 \
  -b:v 730k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe6 \
  -y -r 25 -g 75 -s 426x240 -quality realtime -speed 8 -threads 2 \
  -tile-columns 1 -frame-parallel 0 \
  -b:v 365k -c:v libvpx-vp9 -b:a 64k -c:a libopus -f webm pipe7

不過,上述完整組合需要非常強大的 CPU,或可能需要硬體 GPU 卸載支援,例如某些晶片組越來越常提供的支援。Intel Kabylake (和後續版本) 具有完整的硬體編碼管道。(請注意,Kabylake GPU 可以進行 8 位元 VP9 編碼,但無法進行 10 位元編碼)。

使用 Shaka Packager 的實用電腦版範例

以常見的桌上型電腦為例,更實用的做法是使用 Shaka Packager。 如要輕鬆設定 Shaka,請使用 Google 的 DockerHub 映像檔,在 Docker 容器中安裝 Shaka。如需操作說明,請參閱:

https://github.com/google/shaka-packager#using-docker-for-testing--development

在本範例中,我們使用的機器具有下列設定:

系統 Host: obs Kernel: 4.4.0-91-lowlatency x86_64 (64 bit)
電腦 Xfce 4.12.3 發行版本:OS:https://ubuntustudio.org/2016/10/ubuntu-studio-16-10-released/
CPU 四核心 Intel Core i5-6500 (-MCP-)
快取:6144 KB
時脈速度:最高:3600 MHz 1:800 MHz 2:800 MHz 3:800 MHz 4:800 MHz
顯示卡 Intel Skylake 整合式顯示卡
記憶體 8 GB RAM

實際上,這部機器可以最佳化產生下列可用的 ABR 編碼範圍,而 FFmpeg 會持續回報 1 倍的編碼速度:

ffmpeg -stream_loop 100 -i 120s_tears_of_steel_1080p.webm \
  -y -r 30 -g 90 -s 1920x1080 -quality realtime -speed 7 -threads 8 \
  -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 \
  -b:v 4500k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe1 \
  -y -r 30 -g 90 -s 1280x720 -quality realtime -speed 8 -threads 6 \
  -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 \
  -b:v 3000k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe2 \
  -y -r 30 -g 90 -s 640x360 -quality realtime -speed 8 -threads 2 \
  -row-mt 1 -tile-columns 1 -frame-parallel 1 -qmin 4 -qmax 48 \
  -b:v 730k -c:v libvpx-vp9 -b:a 128k -c:a libopus -f webm pipe3

請注意,-speed 設定相當高。這些設定是透過實驗建立,因機器而異。

Shaka Packager 負荷

封裝作業並不會特別耗用 CPU 資源。即使 FFmpeg 只傳送部分輸出內容,Shaka Packager 仍可設定為監聽所有輸出內容。以下是在上述電腦上測試的封裝工具設定:

packager \
  in=pipe1,stream=audio,init_segment=livehd-audio-1080.webm,segment_template=livehd-audio-1080-\$Number\$.webm \
  in=pipe1,stream=video,init_segment=livehd-video-1080.webm,template=livehd-video-1080-\$Number\$.webm \
  in=pipe2,stream=audio,init_segment=livehd-audio-720.webm,segment_template=livehd-audio-720-\$Number\$.webm \
  in=pipe2,stream=video,init_segment=livehd-video-720.webm,template=livehd-video-720-\$Number\$.webm \
  in=pipe3,stream=audio,init_segment=livehd-audio-360.webm,segment_template=livehd-audio-360-\$Number\$.webm \
  in=pipe3,stream=video,init_segment=livehd-video-360.webm,template=livehd-video-360-\$Number\$.webm \
  --mpd_output livehd.mpd --dump_stream_info --min_buffer_time=10 --time_shift_buffer_depth=300 \
  --segment_duration=3 --io_block_size 65536