影片剪輯軟體的時間軸畫面,顯示多軌影片與音訊片段

← INSIGHTS & PERSPECTIVES | 後端開發

使用 FFmpeg 濾鏡功能做影片合成

用 FFmpeg 疊字、綠幕去背合成與低延遲推流的實際指令範例,附參數逐項解說。

FFmpeg 除了轉檔,也能直接用濾鏡疊字、去背合成、推流測試延遲。以下整理幾個實際會用到的指令:疊上即時時鐘文字、把虛擬攝影機畫面推到 RTMP 伺服器、做綠幕去背疊加,以及設定低延遲播放。指令來自 官方下載頁 對應版本的 FFmpeg,在 Windows 環境下用 DirectShow 抓攝影機畫面測試過。

如何用 FFmpeg 疊上即時時鐘文字並推流?

drawtext 濾鏡搭配 setpts 計算時間戳,就能在畫面上疊一個會跳動的時鐘文字,常用來檢查串流延遲:

ffmpeg -f lavfi -i color=c=0x00ff00:s=800x450 -vf "settb=AVTB, setpts='trunc(PTS/1K)*1K+st(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K)', drawtext=text='STREAM2-%{localtime}.%{eif\:1M*t-1K*trunc(t*1K)\:d}':x=100:y=100:fontsize=32:fontcolor=white" -c:v libx264 -f flv rtmp://192.168.189.11/live/test2

逐段拆解:

  • -f lavfi -i color=c=0x00ff00:s=800x450:用 lavfi 產生一個純色輸入源,c=0x00ff00 是綠色填充,s=800x450 是解析度。
  • settb=AVTB, setpts=...:設定時間基準並重新計算時間戳,依 PTS(顯示時間戳)與 RTCTIME(實際時鐘時間)換算,讓疊字反映真實時間而不是影格編號。
  • drawtext=text='STREAM2-%{localtime}...':在畫面 (100,100) 位置畫出白色文字,%{localtime} 帶入本地時間,%{eif:...} 補上格式化後的毫秒數。
  • -c:v libx264:以 H.264 編碼。
  • -f flv rtmp://...:輸出為 FLV 格式並推到指定 RTMP 位址。

這種畫面常拿來做端到端延遲量測——比較畫面上的時鐘文字和播放端實際看到的時間差。

如何把虛擬攝影機畫面推流到 RTMP?

Windows 下用 DirectShow 抓 OBS 虛擬攝影機的畫面,編碼後推到 RTMP:

ffmpeg -f dshow -rtbufsize 200M -i video=OBS-Camera -pix_fmt yuv420p -c:v libx264 -profile:v baseline -level:v 3.1 -preset:v ultrafast -s 480x270 -g 240 -an -f flv -y rtmp://172.16.46.89/live/0101_dealerPC1

參數重點:

參數用途
-f dshow -rtbufsize 200M -i video=OBS-Camera用 DirectShow 抓 "OBS-Camera" 這個裝置,緩衝區設 200MB 避免掉幀
-pix_fmt yuv420p輸出像素格式為 4:2:0,相容性最好
-profile:v baseline -level:v 3.1串流用的保守 profile/level 組合,播放器相容性較高
-preset:v ultrafast編碼速度優先,犧牲一點壓縮率換取低延遲
-g 240每 240 幀插一個關鍵幀(GOP size),24fps 時約等於 10 秒一個 I 幀
-an不擷取音訊
-y直接覆蓋已存在的輸出檔案

如何用 FFplay 做極低延遲播放測試?

推流端調整完,播放端也要關掉緩衝才能驗證真實延遲:

ffplay -fflags nobuffer -flags low_delay -rtmp_buffer 0 -rtmp_live live -framedrop -infbuf %desc%
  • -fflags nobuffer-infbuf:都是關閉輸入緩衝,減少排隊等待的時間。
  • -flags low_delay:啟用低延遲解碼模式。
  • -rtmp_buffer 0-rtmp_live live:RTMP 緩衝設為 0,並告知這是即時直播流而非點播。
  • -framedrop:解碼跟不上時主動丟幀,避免畫面越拖越慢。
  • %desc%:換成實際的串流網址或占位變數。

如何用 FFmpeg 把虛擬攝影機和線上串流做綠幕合成?

這是本文的重點案例:把本機虛擬攝影機畫面去背(colorkey)之後,疊加到另一路 RTMP 串流上,再用 GPU 編碼輸出:

ffmpeg -f dshow -rtbufsize 1M -i video="OBS Virtual Camera" -f flv -i rtmp://172.17.22.89/live/test1 -filter_complex "[0:v]colorkey=0x00ff00:0.3:0.2[keyed];[1:v][keyed]overlay[o]" -map "[o]" -c:v h264_nvenc -f flv rtmp://127.0.0.1/live/test3

這裡有兩個輸入源:[0:v] 是本機虛擬攝影機,[1:v] 是另一路 RTMP 串流。-filter_complex 做了兩件事:

  1. [0:v]colorkey=0x00ff00:0.3:0.2[keyed]:對輸入 0 套用 colorkey,去除綠色(0x00ff00)背景,0.3 是相似度容忍度,0.2 是邊緣模糊程度,結果存成 [keyed] 這個帶透明背景的影像流。
  2. [1:v][keyed]overlay[o]:把 [keyed](去背後的虛擬攝影機畫面)疊在輸入 1(線上串流)之上,輸出成 [o]

再用 -map "[o]" 指定要輸出的是合成後的畫面,-c:v h264_nvenc 則交給 NVIDIA GPU 硬體編碼,減輕 CPU 負擔,最後推到 rtmp://127.0.0.1/live/test3

這個做法適合把講者去背後疊加在簡報畫面或另一路遠端串流上,不需要額外的合成軟體。

串流參數速查

實務上常需要動態調整編碼參數,以下是一份 Windows batch 範例,把常用選項抽成變數方便替換:

set ffmpegBin=C:\apps\ffmpeg\
set PATH=%PATH%;%ffmpegBin%

set camName="OBS Virtual Camera"
set camBufferSize=1000
set desc=rtmp://127.0.0.1:1935/live/demo

set codec=libx264
set fps=24
set /a "keyint=%fps%*5"
set x264opts=keyint=120:min-keyint=%fps%:scenecut=0
set preset=medium
set profile=baseline
set level=3.1
set resolution=800x450
set bitrate=700

:: publish stream
ffmpeg -f dshow -rtbufsize %camBufferSize%M -i video=%camName% ^
       -vf format=yuv420p ^
       -vcodec %codec% -x264-params %x264opts% ^
       -preset %preset% -profile:v %profile% -level:v %level% ^
       -tune:v zerolatency ^
       -s %resolution% ^
       -r %fps% ^
       -b:v %bitrate%k -minrate %bitrate%k -maxrate %bitrate%k -bufsize %bitrate%k ^
       -an ^
       -f flv %desc%

常用參數對照:

參數說明
-r輸出 fps
-y覆蓋既有輸出檔案,不詢問
-i輸入來源
-c:v影片編碼器
-profile:v編碼 profile,串流建議用 baseline
-level:v編碼 level,串流建議用 3.1
-preset:v編碼速度,串流建議用 ultrafast
-b:v目標 bitrate,例如 700k
-s輸出解析度
-gGOP size(關鍵幀間隔),-r 24 -g 240 約等於每 10 秒一個關鍵幀
-an不處理音訊
-f flv輸出容器格式
-f dshow -i video=OBS-CameraWindows 上用 DirectShow 抓攝影機畫面
-rtbufsize 200M加大輸入緩衝,避免掉幀
-re依原始檔案的 frame rate 讀取,會拖慢即時轉發,不需要延遲時應拿掉

FFREPORT 環境變數設定後,FFmpeg 會依設定自動存 log,方便事後排查問題。更完整的 restream 設定可參考 Wowza 的官方文件

如何檢查 FFmpeg 輸出的關鍵幀分佈是否正確?

推完流之後,想確認關鍵幀間隔有沒有照設定跑,可以用 ffprobe 直接看:

ffprobe -v quiet -show_streams -select_streams v:0 input.flv

抓出所有 I-frame(關鍵幀):

ffprobe -show_frames input.flv | grep pict_type | grep -n I

例如設定 24fps、關鍵幀間隔 10 秒(-g 240),理想狀況下輸出會是:

1:pict_type=I
241:pict_type=I
481:pict_type=I
721:pict_type=I
961:pict_type=I
1201:pict_type=I

每 240 幀出現一次 I-frame,跟 -g 240 的設定吻合。如果間隔亂掉,通常代表編碼器參數或串流服務端有重新協商過 GOP,值得回頭檢查 -gx264-params 裡的 keyint/min-keyint 是否一致。

常見問題

Qcolorkey 去背邊緣有雜色殘留怎麼辦?

可以調整 colorkey=0x00ff00:0.3:0.2 裡的相似度(第二個數字)和模糊程度(第三個數字)。相似度太低會留下綠邊,太高則會吃掉主體邊緣的細節,通常要來回試個幾次才找到剛好的數值。

Q為什麼串流延遲還是很高?

先確認推流端有沒有用 -tune:v zerolatency-preset ultrafast,播放端則檢查 ffplay 是否加了 -fflags nobuffer -flags low_delay -rtmp_buffer 0。中間如果經過額外的 CDN 或轉推服務,那段的緩衝設定也要一併確認,單邊調整不一定看得出效果。

Q-g 240 這個數字怎麼決定?

GOP size 通常抓 fps 乘上想要的關鍵幀間隔秒數。範例中 24fps、間隔 10 秒,-g 就設 240。間隔越短,隨機跳轉(seek)越流暢但檔案越大;直播場景通常抓 2-10 秒之間。

參考資料

FFmpeg 官方文件,Filters Documentation(drawtextcolorkeyoverlay 等濾鏡參數說明),存取日期:2026-08-27。https://ffmpeg.org/ffmpeg-filters.html

延伸閱讀

關於作者

Claire Chang | 企業 AI 導入與流程轉型顧問。專注於 AI Agent 架構設計、ERP 系統整合與企業 AI 治理。

首次發布:2023-08-23