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 做了兩件事:
[0:v]colorkey=0x00ff00:0.3:0.2[keyed]:對輸入 0 套用 colorkey,去除綠色(0x00ff00)背景,0.3是相似度容忍度,0.2是邊緣模糊程度,結果存成[keyed]這個帶透明背景的影像流。[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 | 輸出解析度 |
-g | GOP size(關鍵幀間隔),-r 24 -g 240 約等於每 10 秒一個關鍵幀 |
-an | 不處理音訊 |
-f flv | 輸出容器格式 |
-f dshow -i video=OBS-Camera | Windows 上用 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,值得回頭檢查 -g、x264-params 裡的 keyint/min-keyint 是否一致。
常見問題
colorkey 去背邊緣有雜色殘留怎麼辦?
可以調整 colorkey=0x00ff00:0.3:0.2 裡的相似度(第二個數字)和模糊程度(第三個數字)。相似度太低會留下綠邊,太高則會吃掉主體邊緣的細節,通常要來回試個幾次才找到剛好的數值。
為什麼串流延遲還是很高?
先確認推流端有沒有用 -tune:v zerolatency、-preset ultrafast,播放端則檢查 ffplay 是否加了 -fflags nobuffer -flags low_delay -rtmp_buffer 0。中間如果經過額外的 CDN 或轉推服務,那段的緩衝設定也要一併確認,單邊調整不一定看得出效果。
-g 240 這個數字怎麼決定?
GOP size 通常抓 fps 乘上想要的關鍵幀間隔秒數。範例中 24fps、間隔 10 秒,-g 就設 240。間隔越短,隨機跳轉(seek)越流暢但檔案越大;直播場景通常抓 2-10 秒之間。
參考資料
FFmpeg 官方文件,Filters Documentation(drawtext、colorkey、overlay 等濾鏡參數說明),存取日期:2026-08-27。https://ffmpeg.org/ffmpeg-filters.html
延伸閱讀
- 為 SRS6 編譯支援 HTTP-FLV 的 FFmpeg:H.265 over RTMP 推流實作:同樣聚焦 FFmpeg、RTMP,可接著比較不同情境的做法。
- Windows 編譯支援 HTTP-FLV 的 FFmpeg:OBS 虛擬鏡頭推流到 SRS:同樣聚焦 FFmpeg、RTMP,可接著比較不同情境的做法。
- PyAV 如何用 Python 處理 RTMP 串流與透明影片:同樣聚焦 FFmpeg、RTMP,可接著比較不同情境的做法。
關於作者
Claire Chang | 企業 AI 導入與流程轉型顧問。專注於 AI Agent 架構設計、ERP 系統整合與企業 AI 治理。
首次發布:2023-08-23
