1. 程式人生 > >FFmpeg filter簡介 --正則表示式

FFmpeg filter簡介 --正則表示式

1. 引言及示例

FFmpeg中的libavfilter提供了一整套的基於filter的機制。filter本身是一個外掛的形式,可以快速的組裝需要的效果。 比如下面的filter,可以實現視訊的水平映象效果。 ffplay.exe sample.rmvb -vf hflip

FFmpeg為什麼重新定義filter API?

FFmpeg定義的libavcodec介面已經成為在編解碼領域的事實上的行業標準。但音視訊filter並沒有類似的標準,多個不同的多媒體專案(比如MPlayer、Xine、GStreamer等)都實現了自定義的filter系統。為了統一filter庫API介面,FFmpeg提出了參考DirectDraw實現了高質量、高效、靈活的音視訊filter介面。詳細的文件資料可以參考

FFmpeg filter

傳統概念上filter是什麼?

本部分資料參考filter-def filter可以翻譯成過濾器,濾波器。物理概念上,常見的過濾器跟淨化器概念重複,比如濾水器、空氣淨化器等。

  • 在計算機程式中,filter是指一段程式碼,可用於檢查輸入或者輸出,按照預定的規則處理並傳遞這些資料。換種說法,filter是一種傳遞(pass-through)程式碼塊,將輸入資料做特定的變換並輸出。通常filter自身不做任何輸入/輸出。舉個例子,linux下的grep可以認為是一個filter,按照正則表示式匹配選擇,從輸入中選擇輸出資料。
  • 在電信工程領域,filter通常指的用於訊號處理的裝置,比如音訊處理比較典型的低通濾波器、高通濾波器、帶通濾波器、去噪濾波器等。

filter的分類

按照處理資料的型別,通常多媒體的filter分為:

  • 音訊filter
  • 視訊filter
  • 字幕filter

另一種按照處於編解碼器的位置劃分:

  • prefilters: used before encoding
  • intrafilters: used while encoding (and are thus an integral part of a video codec)
  • postfilters: used after decoding

FFmpeg中filter分為:

  • source filter (只有輸出)
  • audio filter
  • video filter
  • Multimedia filter
  • sink filter (只有輸入)

除了source和sink filter,其他filter都至少有一個輸入、至少一個輸出。

介紹了這麼多,下面也是一個例子,使用filter實現寬高減半顯示:

ffplay.exe sample.rmvb -vf scale=iw/2:ih/2

下面是使用mptestsrc的source filter作為ffplay輸入,直接顯示:

ffplay -f lavfi mptestsrc=t=dc_luma ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_color=#00ff00,scale=1200:800:flags=16

2. 基本原理

FFmpeg filter可以認為是一些預定義的正規化,可以實現類似積木的多種功能的自由組合。每個filter都有固定數目的輸入和輸出,而且實際使用中不允許有空懸的輸入輸出端。使用文字描述時我們可以通過識別符號指定輸入和輸出埠,將不同filter串聯起來,構成更復雜的filter。這就形成了巢狀的filter。當然每個filter可以通過ffmpeg/ffplay命令列實現,但通常filter更方便。

ffmpeg.exe、ffplay.exe能夠通過filter處理原始的音視訊資料。ffmpeg將filtergraph分為simple filtergraph和complex filtergraph。通常simple filtergraph只有一個輸入和輸出,ffmpeg命令列中使用-vf-af識別,基本原理圖如下:

     _________                        ______________
    |         |                      |              |
    | decoded |                      | encoded data |
    | frames  |\                   _ | packets      |
    |_________| \                  /||______________|
                 \   __________   /
      simple     _\||          | /  encoder
      filtergraph   | filtered |/
                    | frames   |
                    |__________|

complex filtergraph,通常是具有多個輸入輸出檔案,並有多條執行路徑;ffmpeg命令列中使用-lavfi-filter_complex,基本原理圖如下:

 _________
|         |
| input 0 |\                    __________
|_________| \                  |          |
             \   _________    /| output 0 |
              \ |         |  / |__________|
 _________     \| complex | /
|         |     |         |/
| input 1 |---->| filter  |\
|_________|     |         | \   __________
               /| graph   |  \ |          |
              / |         |   \| output 1 |
 _________   /  |_________|    |__________|
|         | /
| input 2 |/
|_________|

第三部分會介紹filtergraph的基本語法和構成。

在libavfilter, 一個filter可以包含多個輸入、多個輸出。下圖是一個filtergraph的示例:

                [main]
input --> split ---------------------> overlay --> output
            |                             ^
            |[tmp]                  [flip]|
            +-----> crop --> vflip -------+

上圖中filtergraph將輸入流分成兩個流,其中一個通過crop filter和vflip filter,然後通過overlay filter將這兩個流合成一個流輸出。這個filtergraph可以用下面命令列表示:

ffmpeg -i INPUT -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT

3. 語法識別

FFmpeg中filter包含三個層次,filter->filterchain->filtergraph。具體可以參考下圖:

filter syntax

filter是ffmpeg的libavfilter提供的基礎單元。在同一個線性鏈中的filter使用逗號分隔,在不同線性鏈中的filter使用分號隔開,比如下面的例子:

ffmpeg -i INPUT -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT

這裡crop、vflip處於同一個線性鏈,split、overlay位於另一個線性鏈。二者連線通過命名的label實現(位於中括號中的是label的名字)。在上例中split filter有兩個輸出,依次命名為[main]和[tmp];[tmp]作為crop filter輸入,之後通過vflip filter輸出[flip];overlay的輸入是[main]和[flilp]。如果filter需要輸入引數,多個引數使用冒號分割。 對於沒有音訊、視訊輸入的filter稱為source filter,沒有音訊、視訊輸出的filter稱為sink filter。

4. 經典的filter

FFmpeg支援的所有filter可以通過filters檢視。 這裡選幾個相對經典的filter。

音訊filter

  • adelay filter 實現不同聲道的延時處理。使用引數如下adelay=1500|0|500,這個例子中實現第一個聲道的延遲1.5s,第三個聲道延遲0.5s,第二個聲道不做調整。
  • aecho filter 實現回聲效果,具體參考http://ffmpeg.org/ffmpeg-filters.html#aecho。
  • amerge filter 將多個音訊流合併成一個多聲道音訊流。具體參考http://ffmpeg.org/ffmpeg-filters.html#amerge-1。
  • ashowinfo filter 顯示每一個audio frame的資訊,比如時間戳、位置、取樣格式、取樣率、取樣點數等。具體參考http://ffmpeg.org/ffmpeg-filters.html#ashowinfo。
  • panfilter 特定聲道處理,比如立體聲變為單聲道,或者通過特定引數修改聲道或交換聲道。主要有兩大類: 混音處理,比如下面的例子pan=1c|c0=0.9*c0+0.1*c1,實現立體聲到單聲道的變換; 聲道變換,比如5.1聲道順序調整,pan="5.1| c0=c1 | c1=c0 | c2=c2 | c3=c3 | c4=c4 | c5=c5"
  • silencedetectsilenceremove filter 根據特定引數檢測靜音和移除靜音。
  • volumevolumedetect filter 這兩個filter分別實現音量調整和音量檢測。
  • audio source filteraevalsrc filter按照特定表示式生成音訊訊號。anullsrc filter生成特定的原始音訊資料,用於模板或測試。anoisesrc filter生成噪聲音訊訊號。sine filter生成正弦波音訊訊號。
  • audio sink filterabuffersink filter和anullsink filter,這些filter只是用於特定情況下結束filter chain。

視訊filter

  • blendtblend filter 將兩幀視訊合併為一幀。具體引數參考http://ffmpeg.org/ffmpeg-filters.html#blend_002c-tblend。
  • crop filter 按照特定解析度裁剪輸入視訊,具體引數參考http://ffmpeg.org/ffmpeg-filters.html#crop。
  • drawboxdrawgriddrawtext filter 繪製box(對話方塊)、grid(表格)、text(文字)。
  • edgedetect filter 邊緣檢測filter。
  • fps filter 按照指定幀率輸出視訊幀(丟幀或者複製)。具體參考http://ffmpeg.org/ffmpeg-filters.html#fps-1。
  • hflipvflip filter 水平和垂直映象。
  • histogram filter 生成每幀的各顏色分量的直方圖。
  • noise filter 在輸入視訊幀中新增白噪聲。
  • overlay filter 視訊疊加。具體參考http://ffmpeg.org/ffmpeg-filters.html#overlay-1。
  • pad filter 視訊邊界填充。具體參考http://ffmpeg.org/ffmpeg-filters.html#pad-1。
  • rotate filter 視訊任意角度旋轉。具體參考http://ffmpeg.org/ffmpeg-filters.html#rotate。
  • scale filter 使用libswscale庫完成視訊縮放的filter。
  • showinfo filter 顯示視訊幀的引數資訊,比如時間戳、取樣格式、幀型別等。
  • subtitles filter 使用libass庫繪製subtitle(字幕)。
  • thumbnail filter 提取縮圖的filter。
  • transpose filter 影象轉置的filter。引數參考http://ffmpeg.org/ffmpeg-filters.html#transpose。
  • source filter 主要有cellatuocoreimagesrcmptestsrclife等filter,具體效果建議參考ffmpeg使用者手冊。
  • source sink 主要有buffersinknullsink兩個filter。

多媒體filter

  • ahistogram filter 將音訊轉化為視訊輸出,並顯示為音量的直方圖。
  • concat filter 將音訊流、視訊流拼接成一個。具體參考http://ffmpeg.org/ffmpeg-filters.html#concat。
  • metadataametadata filter 操作metadata資訊。
  • setptsasetpts filter 改變輸入音訊幀或視訊幀的pts。
  • showfreqsshowspectrumshowspertrumpicshowvolumeshowwaves filter 將輸入音訊轉換為視訊顯示,並顯示頻譜、音量等資訊
  • splitasplit filter 將輸入切分為多個相同的輸出。
  • source filter 主要是movieamovie filter。從movie容器中讀取音訊或者視訊幀。

5. 例項demo

FFmpeg提供了很多有趣的filter例項,詳見Fancy Filtering Examples。 我們這裡先從幾個簡單的例項開始。

例項一:縮放scale

將輸入縮小寬度縮小一半,並保持寬高比。

ffmpeg -i input.jpg -vf scale=iw/2:-1 output.jpg

例項二:filter、filterchain和filtergraph的使用

先將輸入去交織,然後減半顯示。 以下三個命令是等價的。

# 2 chains form, one filter per chain, chains linked by the [middle] pad ffmpeg -i input -vf [in]yadif=0:0:0[middle];[middle]scale=iw/2:-1[out] output

# 1 chain form, with 2 filters in the chain, linking implied ffmpeg -i input -vf [in]yadif=0:0:0,scale=iw/2:-1[out] output

# the input and output are implied without ambiguity ffmpeg -i input -vf yadif=0:0:0,scale=iw/2:-1 output

例項三:2x2佈局畫面拼接

這個例項主要說明下filtergraph使用。命令列如下:

./ffmpeg -f lavfi -i testsrc -f lavfi -i testsrc -f lavfi -i testsrc -f lavfi -i testsrc -filter_complex \
"[0:v]pad=iw*2:ih*2[a]; \
 [1:v]negate[b]; \
 [2:v]hflip[c]; \
 [3:v]edgedetect[d]; \
 [a][b]overlay=w[x]; \
 [x][c]overlay=0:h[y]; \
 [y][d]overlay=w:h[out]" -map "[out]" -c:v ffv1 -t 5 multiple_input_grid.avi

6. 參考資料