FFmpeg 除了轉檔,也能直接用濾鏡疊字、去背合成、推流測試延遲。以下整理幾個實際會用到的指令:疊上即時時鐘文字、把虛擬攝影機畫面推到 RTMP 伺服器、做綠幕去背疊加,以及設定低延遲播放。指令來自 官方下載頁 對應版本的 FFmpeg,在 Windows 環境下用 DirectShow 抓攝影機畫面測試過。
如何用 FFmpeg 疊上即時時鐘文字並推流?
用 `drawtext` 濾鏡搭配 `setpts` 計算時間戳,就能在畫面上疊一個會跳動的時鐘文字,常用來檢查串流延遲:
```bash
ffmpeg -f lavfi -i color=c=0x00ff00:s=800x450 -vf "settb=AVTB, setpts='trunc(PTS/1K)1K+st(1,trunc(RTCTIME/1K))-1Ktrunc(ld(1)/1K)', drawtext=text='STREAM2-%{localtime}.%{eif\:1Mt-1Ktrunc(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:
```bash
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 做極低延遲播放測試?
推流端調整完,播放端也要關掉緩衝才能驗證真實延遲:
```bash
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 編碼輸出:
```bash
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 範例,把常用選項抽成變數方便替換:
```bash
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` 直接看:
```bash
ffprobe -v quiet -show_streams -select_streams v:0 input.flv
```
抓出所有 I-frame(關鍵幀):
```bash
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
延伸閱讀
關於作者 {#author}
Claire Chang | 企業 AI 導入與流程轉型顧問。專注於 AI Agent 架構設計、ERP 系統整合與企業 AI 治理。
首次發布:2023-08-23
