【FFmpeg筆記】 從零開始之濾鏡

verzqlis發表於2019-05-07

FFmpeg 除了具有強大的封裝/解封裝、編/解碼功能外,還包含了一個非常強大的組建---濾鏡avfilter。avfilter組建經常用於進行多媒體的處理與編輯,FFmpeg中包含多種濾鏡

1.FFmpeg 濾鏡filter的引數排列方式

為了便於理解Filter,下面用最簡單的方式來描述Filter使用時的引數排列方式:
[輸入流或標記名]濾鏡引數[臨時標記名];[輸入流或標記名]濾鏡引數[臨時標記名]...
文字描述的排列方式很明確,接下來列舉一個簡單的例子:輸入兩個檔案,一個視訊input.mp4,一個圖片logo.png,將logo進行縮放,然後放在視訊的左上角
複製程式碼
ffmpeg -i test.mp4 -i logo.png -filter_complex "[1:v]scale=176:144[logo];[0:v][logo]overlay=x=0:y=0" filter.mp4

將logo.png的影像六縮放為176*144解析度,然後定義一個臨時標記名logo,最後將縮放後的影像[logo]鋪在輸入的視訊test.mp4的視訊流[0:v]的左上角

複製程式碼

2.FFmpeg 濾鏡filter時間內建變數

在使用Filter時,經常會用到根據時間軸進行操作的需求,在使用FFmpeg的Filter時可以使用Filter的時間相關的內建變數,下面先來了解下這些相關的變數,如下表,在下面可以使用到

變數 說明
t 時間戳以秒錶示,如果輸入的時間戳時位置的,則是NAN
n 輸入幀的順序編號,從0開始
pos 輸入幀的位置,如果位置則是NAN
w 輸入視訊幀的寬度
h 輸入視訊幀的高度

3.FFmpeg 為視訊新增水印

FFmpeg可以為視訊新增水印,水印可以時文字,也可以時圖片,主要用來標記視訊歸屬

3.1 文字水印

在視訊中增加文字水印需要準備的條件比較多,需要有文字字型檔處理的相關檔案,在編譯FFmpeg時需要支援FreeType、FontConfig、iconv,系統中需要有相關的字型檔,在FFmpeg中增加純字母水印可以使用drawtext濾鏡進行支援,下面就是drawtext的濾鏡引數 
複製程式碼
引數 型別 說明
fontfile 字串 字型檔案
text 字串 文字
textfile 字串 文字檔案
fontcolor 字串 字型顏色
box 字串 文字區域背景框
boxcolor 字串 展示字型顏色的區域快的顏色
fontsize 字串 顯示字型的大小
font 字串 字型名稱(預設為Sans字型)
x 字串 文字顯示的x座標
y 字串 文字顯示的y座標
使用舉例
ffmpeg -i out2.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world ':x=20:y=20" waterfont.mp4
 
執行後即可在視訊左上角增加hello world 文字水印,文字顏色為純黑,為了讓水印更柔和,可以通過drawtext濾鏡的fontcolor引數調節顏色,比如設為綠色

ffmpeg -i out2.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world ':x=20:y=20:fontcolor=green" waterfont.mp4

還可以呼叫一些系統資料,比如水印按當前時間來顯示
ffmpeg -re -i out2.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='%{localtime\:%Y\-%m\-%d %H-%M-%S}':x=20:y=20:fontcolor=green" waterfont4.mp4
複製程式碼

3.2 圖片水印

FFmpeg除了可以向視訊新增文字水印外,還可以向視訊新增圖片水印,視訊跑馬燈等,為視訊新增水印可以使用movie濾鏡,下面就是movie濾鏡的一些引數

引數 型別 說明
filename 字串 輸入的檔名,可以是檔案、協議、裝置
format_name_,f 字串 輸入的封裝格式
stream_index,f 整數 輸入的流索引編號
seek_point,sp 浮點數 Seek輸入流的時間位置
stream,s 字串 輸入的多個流的流資訊
loop 整數 迴圈次數
discontinuity 時間差值 支援跳動的時間戳差值

下面舉例說明,在FFmpeg中加入圖片水印有兩種方式,一是通過movie指定水印檔案路徑,另外一種方式是通filter讀取輸入檔案的流並指定為水印,這裡重點介紹如何讀取movie圖片檔案作為水印

ffmpeg -i out2.mp4 -vf "movie=water_pic.png[wm];[in][wm]overlay=30:10[out]" waterPic.mp4
圖片就會出現在視訊的左上角
也可以用movie與colorkey濾鏡配合做成半透明效果,例如
ffmpeg -i out2.mp4 -vf "movie=water_pic.png,colorkey=black:1.0:1.0 [wm];[in][wm]overlay=30:10[out]" waterPicAlpha.mp4
此時圖片以30%透明度顯示在左上角,[wm]作用為給前面命名
複製程式碼

3.3 overlay的濾鏡用法

overlay又稱視訊疊加技術,overlay視訊技術使用非常廣泛,常見的例子有上面的圖片水印以及下面會提到的畫中畫功能,畫中畫功能值得是在一個大視訊播放視窗中還存在一個小播放視窗,兩個視窗不同的視訊內容同時播放。 overlay 技術中設計兩個視窗,通常把較大的視窗稱為背景視窗,較小的視窗稱為前景視窗,兩者皆可以播放視訊或顯示圖片.

overlay濾鏡說明如下
描述 說明
語法 overlay[=x:y[[:rgb={0, 1}]]引數x和y是可選的,其預設值為0 rgb引數是可選的,其值為0或1
x 從左上角開始的水平座標,預設為0
y 從左上角開始的垂直座標,預設為0
rgb rgb = 0…輸入的顏色空間不改變,預設值rgb = 1…輸入的顏色空間設定為RGB
main_w 或者 W 主輸入(背景視窗)寬度
main_h 或者 H 主輸入(背景視窗)高度
overlay_w 或者 w overlay輸入(前景視窗)寬度
overlay_h或者h overlay輸入(前景視窗)高度
eof_action 遇到eof標誌時的處理方式。預設為重複
repeat(值為0) :重複前一幀
endall(值為1) :停止所有幀
pass(值為2) :保留主圖層
format 設定output的畫素格式。預設為yuv420
yuv420(值為0)
yuv422(值為1)
yuv444(值為2)
rgb(值為3)
shortest 布林值,終止最短視訊時全部終止(預設關閉)
overlay濾鏡用法

使用overlay命令列基本格式如下:

ffmpeg -i input1 -i input2 -filter_complex overlay=x:y output

使用一個簡單例子,將圖片疊在視訊的右上角,效果如下圖
ffmpeg -i test.mp4 -i chenyao.png -filter_complex overlay=W-w:56 -max_muxing_queue_size 1024 overlay.mp4
複製程式碼

效果如圖

3.4 FFmpeg生成畫中畫

除了上述overlay新增圖示在視訊上外,在使用FFmepg處理流媒體檔案時,有時需要使用畫中畫效果。在FFmpeg中,可以通過overlay將多個視訊流、多個多媒體採集裝置、多個視訊檔案合併到一個介面中,生成畫中畫效果。在前面的濾鏡使用中和以後的濾鏡使用中,與視訊操作相關的處理,大多數會與overlay濾鏡配合使用,尤其時用在圖層處理與合併場景中

從上面3.3的引數列表中可以看到,主要引數並不多,但實際上在overlay濾鏡使用中,還有很多組合的引數可以使用,可以使用一些內部變數,例如overlay圖層的寬、高、座標等,下面列舉幾個畫中畫的例子

ffmpeg -re -i out2.mp4 -vf "movie=output.avi,scale = 480*320[test]; [in][test] overlay [out]" -vcodec libx264 videoInvideo.mp4
複製程式碼

兩個老虎視訊

上圖為顯示畫中畫的最基本方式,如果希望子視訊顯示在指定位置,例如顯示在畫面右下角,則需要用到overlay中x座標與y座標的內部變數,如同上面圖片疊加視訊的用法

ffmpeg -re -i out2.mp4 -vf "movie=output.avi,scale = 480*320[test]; [in][test] overlay=x=main_w-500:main_h-500 [out]" -vcodec libx264 videoInvideo.mp4
複製程式碼

出現在視訊的右下角

以上兩種視訊畫中畫的處理均為靜態位置處理,使用overlay還可以配合正規表示式進行跑馬燈進行畫中畫處理

ffmpeg -re -i out2.mp4 -vf "movie=output.avi,scale = 480*320[test]; [in][test] overlay=x='if(gte(t,2),-w+(t-2)*20,NAN)':y=0 [out]" -vcodec libx264 videoInvideo.mp4
圖片就不上了,效果為一個視訊從左到右緩緩移動
複製程式碼

3.4 FFmpeg 濾鏡圖,濾鏡鏈,濾鏡之間的關係

濾鏡圖(filtergraph):跟在 -vf 之後的就是一個濾鏡圖 濾鏡鏈(filterchain):一個濾鏡圖包含多個濾鏡鏈 濾鏡(filter):一個濾鏡鏈包含多個濾鏡 概括來說就是:濾鏡 ∈ 濾鏡鏈 ∈ 濾鏡圖 FFmpeg支援多種濾鏡,檢視全部濾鏡 $ ffmpeg -filters

一個濾鏡圖的例子如下:

ffmpeg -i out2.mp4 -vf [in]scale=640.0:480.0[wm]; movie='logo.png',scale=92.25:30.0[logo]; 
[wm][logo]overlay=main_w-overlay_w-24.0:24.0[out]  output.mp4
複製程式碼

在該示例中,有三個濾鏡鏈:

  • [in]scale=640.0:480.0[wm]
  • movie='logo.png',scale=92.25:30.0[logo]
  • [wm][logo]overlay=main_w-overlay_w-24.0:24.0[out] 可以看到,濾鏡鏈是使用分號 ";" 來分隔,濾鏡鏈中的濾鏡使用逗號 "," 來分隔;濾鏡鏈沒有指定輸入或者輸出,預設使用前面的濾鏡鏈的輸出為輸入,並輸出給後面的濾鏡鏈作為輸入,
簡單濾鏡和複雜濾鏡(Simple filtergraphs 和 Complex filtergraphs)
  • Simple filtergraphs(簡單濾鏡):該濾鏡只有一個輸入和一個輸出,實際就是新增在解碼和編碼步驟之間的操作,如下圖所示。
    簡單濾鏡流程圖

簡單filtergraphs配置了每個流的篩選器選項(與視訊和音訊分別-vf和-af別名)。

  • Complex filtergraphs(複雜濾鏡):複雜filtergraphs是那些不能被描述為簡單的線性處理鏈的濾鏡組。例如,當濾鏡組具有多個輸入和/或輸出,或當輸出流的型別是不同於輸入。它們可以被表示為以下圖:
    複雜濾鏡流程圖
    複雜濾鏡圖使用-filter_complex 選項來表示,與-vf不同在於他有多個輸入。該選項是全域性的, -lavfi 選項等同於 -filter_complex,一個具體的例子就是,overlay 濾鏡,該濾鏡有兩個視訊輸入,一個視訊輸出,輸出視訊是一個輸入視訊覆蓋在另一個視訊之上的結果,音訊有同等的amix濾鏡
-map :-vf、-filter_complex合併

有事會遇到有的使用-vf,有的又必須使用-filter_complex,怎樣將這兩項整合起來呢,下面有幾個示例,總體的思路就是將單輸入輸出的-vf整合到 -filter_complex中去,這時會用到 第三條中的媒體流選擇 -map 示例(該示例我未驗證過)

************************* vf 與 filter_complex結合·示例一 **************************


ffmpeg -i input.mp4 

-vf  "crop='if(gte(iw,ih),ih,iw):if(gte(ih,iw),iw,ih)', scale=720x720"   

-an -c:v libx264 -profile:v high -level 4.1  -preset superfast -crf 20 

output.mp4

========================================


ffmpeg -i input.mp4 -filter_complex \ 
"[0:v]trim=0:4.95,setpts=PTS-STARTPTS[v1]; \
   [0:v]trim=4.95:6.75,setpts=PTS-STARTPTS[v2]; \
 [0:v]trim=6.75:8,setpts=PTS-STARTPTS[v3]; \
   [v2]setpts=PTS/0.1[vslow2]; \
 [v1][vslow2][v3]concat=n=3:v=1:a=0[out]" \
-map [out] -an -c:v libx264 -profile:v high -level 4.1 \
-preset superfast -crf 20 -r 30 output.mp4



=================合成====================


ffmpeg -i input.mp4  -filter_complex \
"[0:v]crop='if(gte(iw,ih),ih,iw):if(gte(ih,iw),iw,ih)',scale=720x720,split=3[1v][2v][3v]; \
   [1v]trim=0:4.95,setpts=PTS-STARTPTS[v1]; \
 [2v]trim=4.95:6.75,setpts=(PTS-STARTPTS)/0.1[v2]; \
   [3v]trim=6.75:8,setpts=PTS-STARTPTS[v3]; \
   [v1][v2][v3]concat=n=3:v=1:a=0[out]" \
-map [out] -an -c:v libx264 -profile:v high -level 4.1 \
-preset superfast -crf 20 -r 30 output.mp4
複製程式碼

參考:

相關文章