使用 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-Frame 位元率上限 (pct)
-deadline realtime -quality realtime 的替代 (舊版) 版本
-lag-in-frames 0 要延遲的畫格數量上限
-qmin 4 -qmax 48 量化器的最小值和最大值。這裡的值只是用來提供建議及調整後的結果,有助於提高/降低影片畫質,但必須達到壓縮效率。
-row-mt 1 啟用資料列多執行緒。最多可使用 2 倍執行緒做為圖塊欄。0 = 關閉,1 = 開啟。
-error-resilient 1 啟用錯誤應變功能。

選擇編碼參數

以下資訊使用即時位元率 (CBR) 編碼來進行即時自動調整位元率串流 (ABR),其中每個目標費率都是在 Packager 的資訊清單中明確設定。這樣會導致用戶端的速率「清除」更加簡潔。如果位元率較有彈性,或是編碼已被分割,則可以使用變數位元率 (VBR) 編碼和 CQ 模式。「即時模式」會經過即時直播的即時編碼處理。詳情請參閱位元率模式

要進一步瞭解如何操控 VP9,也別忘了參考 VOD 設定中的相關文章,但請考慮 CC 的重點。

提示與秘訣

請記住,在直播過程中,所有內容都受到最低 1 倍的即時編碼速度限制 (FFmpeg 會不斷在進行編碼時回報速度)。 如果您的編碼速度降到 1 倍以下,編碼程序將不會跟上即時影像的輸入,使用者將等待緩衝處理,而在傳輸過程中發生中斷,將導致直播在直播期間無法使用 (雖然可正常使用封存)。

編碼參數實際運作的範例

下圖顯示執行中 Linux 的四核心 i5 3.6Ghz 桌上型電腦中各種影格大小的 CPU 使用率 (每秒 25 個畫格):

目標解析度 FFmpeg VP9 參數 CPU / 速度 (範例)
3840x2160 (2160p) -r 30 -g 90 -s 3840x2160 - 質量實時 - 速度 5 - 螺紋 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 7800k ~88% 0.39x
2560x1440 (1440p) -r 30 -g 90 -s 2560x1440 - 質量實時 - 速度 5 - 螺紋 16 -row-mt 1 -tile-columns 3 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 6000k ~86% 0.68x
1920x1080 (1080p) -r 30 -g 90 -s 1920x1080 - 質量實時 - 速度 5 - 螺紋 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 - 數量實時 - 速度 5 - 螺紋 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 3000k ~78% 1.77x
854x480 (480p) -r 30 -g 90 -s 854x480 - 質量實時 - 速度 6 - 螺紋 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 - 質量實時 - 速度 7 -螺紋 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 - 數量實時 - 速度 8 -螺紋 2 -row-mt 1 -瓷盤柱 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 vp9 \
  -b:a 128k -c:a libopus -f webm pipe1

提示與秘訣

  • 請注意,這裡將輸出至 FIFO 管道 (「pipe1」),您應在執行前,先執行此函式,然後再執行 FFmpeg 指令。方法是在工作目錄中提供 mkfifo pipe1 指令。使用 Shaka Packager 時,該指令會監聽該管道為輸入串流的輸入來源。其他包裝包裝可能需要不同的方法。

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

自動調整位元率組合範例

視執行 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 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 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 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 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 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 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 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 容器中。相關操作步驟請參閱:

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

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

系統 主機:obs 內核:4.4.0-91-low 低延遲 x86_64(64 位)
Desktop 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 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 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 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