ffmpeg入門篇-濾鏡的基本使用

濾鏡

什么是濾鏡盏求?百度百科介紹說“濾鏡主要是用來實(shí)現(xiàn)圖像的各種特殊效果......”滚澜。

我們最早在ffmpeg是如何轉(zhuǎn)碼的一文中了解過濾鏡朽色,來回顧下當(dāng)時(shí)的轉(zhuǎn)碼流程圖胀瞪。

image

從圖中可以看到濾鏡前后畫的是虛線金矛,表示可有可無毙玻,在術(shù)語中秸抚,濾鏡指的是在編碼之前針對(duì)解碼器解碼出來的原始數(shù)據(jù)(即音視頻幀)進(jìn)行處理的動(dòng)作速和,我們還可以稱它為過濾器歹垫。

ffmpeg內(nèi)置了大概近400種濾鏡,我們可以用 ffmpeg -filters 命令查看所有的濾鏡颠放,也可以用命令 ffmpeg -h filter=xxx 或者查看官方文檔了解每一種濾鏡排惨。

實(shí)際在大部分音視頻的處理過程中都離不開濾鏡,所以你應(yīng)該能明白其重要性碰凶。

多個(gè)濾鏡可以結(jié)合在一起使用形成濾鏡鏈或者濾鏡圖暮芭,在每一個(gè)濾鏡中,不僅可以對(duì)輸入源進(jìn)行處理欲低,A濾鏡處理好的結(jié)果還可以作為B濾鏡的輸入?yún)?shù)辕宏,通過B濾鏡繼續(xù)處理。

針對(duì)濾鏡的處理砾莱,ffmpeg提供了兩種處理方式瑞筐,簡單濾鏡和復(fù)雜濾鏡。

簡單濾鏡

簡單濾鏡指的是只有一個(gè)輸入和輸出腊瑟,而且保證輸入和輸出的流類型相同聚假。

比如我們?cè)谏掀恼?a target="_blank">流的操作(二)如何選擇流?末尾提到的把原視頻 r3.mp4 等比例縮放一倍

ffmpeg -i r3.mp4 -vf scale=272:480 -y filter.mp4

-vf 是 -filter:v 的簡寫闰非,類似的我們還可以使用 -filter:a 或者 -af 針對(duì)音頻流做處理膘格。

-filter的語法規(guī)則:-filter[:stream_specifier] filtergraph (output,per-stream)
stream_specifier流的類型我們一般用a表示音頻,v表示視頻财松,filtergraph表示具體的濾鏡瘪贱,這里用的是scale濾鏡

scale濾鏡用于調(diào)整視頻的大小辆毡,比如等比例縮放政敢、等比例放大,不做等比例操作輸出就變形了胚迫,變形結(jié)果我們一般不考慮喷户。

因?yàn)槲覀冎涝曨l r1ori.mp4 的分辨率是 544x960,所以等比例縮放一倍访锻,上面的命令直接指定了 272x480褪尝,scale濾鏡自帶很多參數(shù),我們介紹幾個(gè)常用的期犬。

in_w in_h 或者 iw ih 表示輸入視頻的寬高
out_w out_h 或者 ow oh 表示輸出視頻的寬高

當(dāng)然不一定是視頻河哑,輸入輸出也可以是圖片。

所以原視頻縮放一倍我們還可以這樣寫:

ffmpeg -i r3.mp4 -vf scale=iw/2:ih/2 -y filter.mp4

問題一:如果我們要把原視頻的寬度調(diào)整為300且保持原分辨率龟虎,怎么辦璃谨?

列一個(gè)方程 544/960 = 300/x ,x=300x960/540,很麻煩佳吞,結(jié)果還不一定能整除拱雏,為此我們可以直接指定高度等于-1,它會(huì)自動(dòng)做等比例處理底扳。

ffmpeg -i r1ori.mp4 -vf scale=300:-1 -y filter.mp4

結(jié)果發(fā)現(xiàn)轉(zhuǎn)碼失敗了铸抑,提示

[libx264 @ 0x7ff509053a00] height not divisible by 2 (300x529) 
Error initializing output stream 0:0 -- 
Error while opening encoder for output stream #0:0 - 
maybe incorrect parameters such as bit_rate, rate, width or height [aac @ 0x7ff50904e200] 
Qavg: 28010.410 [aac @ 0x7ff50904e200] 2 frames left in the queue on closing

提示我們 height not divisible by 2 (300x529)即高度529不能被2整除。這是因?yàn)橐恍┚幗獯a器要求很多視頻的寬高必須是n的倍數(shù)(這里n是2)衷模,所以我們寫腳本處理視頻或者圖片寬高的時(shí)候鹊汛,切記不要使用-1,正確的用法是使用-2阱冶。

ffmpeg -i r1ori.mp4 -vf scale=300:-2 -y filter.mp4 輸出結(jié)果視頻的分辨率是 300 × 530

問題二:老板為了刁難你刁憋,提出了一個(gè)新的要求:“我想要所有輸出視頻的分辨率是 300x500且不能變形”,怎么辦木蹬?

我們知道3:5的寬高比是很少見的职祷,現(xiàn)在常見的分辨率是16:9、4:3届囚,也就是說原視頻我們必須要經(jīng)過一番處理才可以滿足老板的變態(tài)需求有梆。

針對(duì)原視頻 r1ori.mp4,如果保證寬度是300意系,等比例縮放后高度是530泥耀,強(qiáng)制設(shè)置高度為500就會(huì)變形,也就是說我們只能讓高度等于500蛔添,盡量縮小寬度試試痰催。

ffmpeg -i r1ori.mp4 -vf scale=-2:500 -y filter.mp4 輸出的結(jié)果視頻的分辨率是284x500
image

如上圖,藍(lán)色框表示視頻的真實(shí)寬高迎瞧,紅色框表示目標(biāo)寬高夸溶,有些像html中的css一樣,可以給空出來的部分填充顏色即內(nèi)邊距不就可以了凶硅?

查閱了文檔我們發(fā)現(xiàn)pad濾鏡可以解決我們的問題缝裁。

pad濾鏡的語法規(guī)則:-pad=width[:height[:x[:y[:color]]]]

1、ffmpeg -i r1ori.mp4 -vf "scale=-2:500,pad=300:500:(300-iw)/2:0" -y filter2.mp4 
2足绅、ffmpeg -i r1ori.mp4 -vf scale=-2:500,pad=300:500:-1:0 -y filter.mp4 
3捷绑、ffmpeg -i r1ori.mp4 -vf scale=-2:500,pad=300:500:-1:0:black -y filter.mp4 
4、ffmpeg -i r1ori.mp4 -vf "scale=-2:500,pad=300:ih:(ow-iw)/2:0:green" -y filter.mp4

上面提供4中寫法氢妈,我們以方法4做個(gè)簡單介紹粹污。

scale=-2:500,指原視頻按照等比例縮放首量,高度等于500壮吩,就是上面大家看到的284x500进苍。

pad=300:ih:(ow-iw)/2:0:green,300:ih即300:500就是紅色框的寬高(ow-iw)/2鸭叙,指的是紅色框和藍(lán)色框差值的一半觉啊,即兩邊各需要填充的范圍;最后一個(gè)參數(shù)表示需要填充的顏色递雀,默認(rèn)是黑色 black,為了調(diào)試方便我們把顏色設(shè)為green蚀浆。

現(xiàn)在我們保證了當(dāng)前視頻一定會(huì)按照300x500的比例輸出且不會(huì)變形缀程,但是請(qǐng)注意老板說的“所有輸出視頻”,也就是說輸入視頻的分辨率可能是200x300市俊、544x960杨凑、500x400、200x800等等各種比例都要保證按照300x500輸出摆昧,很顯然撩满,上面的寫法不完全通用,怎么辦绅你?

現(xiàn)在我們已知原輸入視頻的寬高和想要的寬高伺帘,針對(duì)這種情況,我們制定一套處理規(guī)則即可解決:

  1. 寬高都偏小忌锯,不拉伸伪嫁,不縮放
  2. 寬高都偏大,等比例縮小偶垮,以高度為準(zhǔn)
  3. 寬超出范圍张咳,等比例縮小,以寬為準(zhǔn)
  4. 高超出范圍似舵,等比例縮小脚猾,以高為準(zhǔn)

在實(shí)際的開發(fā)過程中,我們要跟代碼打交道砚哗,平時(shí)在命令行中的實(shí)現(xiàn)都是練習(xí)龙助,所以基于該規(guī)則,我們有了下面一段代碼

<?php
declare(strict_types=1);

class CalculatorService
{
    /**
     * 用戶視頻分辨率轉(zhuǎn)換
     * 規(guī)則:
     *  寬高都偏小蛛芥,不拉伸泌参,不縮放
     *  寬高都偏大,等比例縮小常空,以高度為準(zhǔn)
     *  寬超出范圍沽一,等比例縮小,以寬為準(zhǔn)
     *  高超出范圍漓糙,等比例縮小铣缠,以高為準(zhǔn)
     * @param int $inputWidth 輸入視頻的寬度
     * @param int $inputHeight 輸入視頻的高度
     * @param int $outWidth 輸出視頻的寬高
     * @param int $outHeight 輸出視頻的高度
     * @return string scale
     */
    public function getSize(int $inputWidth, int $inputHeight, int $outWidth, int $outHeight): string
    {
        $scale = "";
        if ($inputWidth <= $outWidth && $inputHeight <= $outHeight) {
            $scale = "scale={$inputWidth}:{$inputHeight},pad={$outWidth}:{$outHeight}:-1:-1:green";
        } elseif (($inputWidth > $outWidth && $inputHeight > $outHeight)
            || ($inputHeight > $outHeight)
        ) {
            $scale = "scale=-2:{$outHeight},pad={$outWidth}:{$outHeight}:-1:0:green";
        } elseif ($inputWidth > $outWidth) {
            $scale = "scale={$outWidth}:-2,pad={$outWidth}:{$outHeight}:0:-1:green";
        }

        return $scale;
    }
}

$calculatorService = new CalculatorService();
var_dump($calculatorService->getSize(200, 300, 300, 500));
var_dump($calculatorService->getSize(544, 960, 300, 500));
var_dump($calculatorService->getSize(500, 400, 300, 500));
var_dump($calculatorService->getSize(200, 600, 300, 500));

// 結(jié)果
string(37) "scale=200:300,pad=300:500:-1:-1:green"
string(35) "scale=-2:500,pad=300:500:-1:0:green"
string(35) "scale=300:-2,pad=300:500:0:-1:green"
string(35) "scale=-2:500,pad=300:500:-1:0:green"

為了方便理解,大家可以參考下面的圖一一對(duì)應(yīng)。

image

復(fù)雜濾鏡

相對(duì)于簡單濾鏡蝗蛙,復(fù)雜濾鏡是可以處理任意數(shù)量輸入和輸出效果的濾鏡圖蝇庭,它幾乎無所不能。

復(fù)雜濾鏡用命令 -filter_complex 表示捡硅,它還有一個(gè)別名 -lavfi哮内。

上篇文章介紹到流和濾鏡結(jié)合是一種最重要、最常用的方法壮韭。依然是將輸入視頻 r3.mp4 等比例縮放一倍北发,我們以手動(dòng)選擇流的方式為例。

ffmpeg -i r3.mp4 -filter_complex "[0]scale=272:480[out]" -map 0:a -map "[out]" -y filter.mp4

簡單分析如下:

  1. 命令 "[0]scale=272:480[out]" 中的[0]表示第一個(gè)輸入的視頻喷屋,因?yàn)橐獙?duì)視頻做處理琳拨,所以也可以用[0:v]表示,如果要對(duì)音頻單獨(dú)處理屯曹,就需要用 [0:a] 了狱庇;
  2. [0] 結(jié)合scale濾鏡,表示的就是把第一個(gè)輸入的視頻作為scale濾鏡的參數(shù)輸入恶耽;
  3. [out] 中括號(hào)是必須要的密任,out是自定義的一個(gè)別名,結(jié)合scale濾鏡偷俭,表示的是把scale濾鏡輸出的結(jié)果命名為[out]批什,但并非是最終輸出的結(jié)果,只能作為中間過程輸出的一個(gè)結(jié)果社搅;
  4. -map "[out]" 就是直接選擇[out] 流作為輸出

我們說過驻债,一個(gè)濾鏡的輸出作為另一個(gè)濾鏡的輸入,這樣就極大的避免了寫多條命令反復(fù)編解碼操作形葬,我們的原則只有一個(gè)合呐,能用一條命令處理的絕不用兩條命令。

有損編解碼器反復(fù)編解碼操作會(huì)降低原視頻質(zhì)量笙以。

比如現(xiàn)在要把原視頻 r1ori.mp4 的中間部分裁剪出來淌实,但仍保持原視頻的分辨率544x960,如何做呢猖腕?

ffmpeg -i r1ori.mp4 -filter_complex "nullsrc=s=544x960[background]; \
crop=iw:(ih/2 - 110):0:250[middle]; \
[background][middle]overlay=shortest=1:x=(main_w-overlay_w)/2:y=(main_h-overlay_h)/2[out]" \
-map "[out]" 
-map 0:a 
-movflags +faststart 
-y fc.mp4

這個(gè)命令就顯得稍微長了一些拆祈,在這條命令中使用了nullsrccrop倘感、overlay三種常見濾鏡放坏。

nullsrc濾鏡用于創(chuàng)建一個(gè)空的視頻,簡單的說就是一個(gè)空的畫布或者說是綠布老玛,因?yàn)槟J(rèn)創(chuàng)建的顏色是綠色的淤年。s用于指定畫布的大小钧敞,默認(rèn)是320x240,這里表示我們創(chuàng)建一個(gè)544x960的畫布麸粮,并命名為background溉苛;

關(guān)于nullsrc還有很多種不同的用戶,比如使用nullsrc和CIQRCodeGenerator創(chuàng)建一個(gè)“白狼椗澹”首頁的二維碼

ffmpeg -f lavfi -i nullsrc=s=200x200,coreimage=filter=CIQRCodeGenerator@inputMessage=\ 
http\\\\\://manks.top/@inputCorrectionLevel=H -frames:v 1 manks.png

crop濾鏡用于裁剪視頻愚战,也就是說視頻的任意區(qū)域任意大小,我們都可以裁剪出來齐遵。crop=iw:(ih/2 - 110):0:250[middle]; 這里我們裁剪原視頻的中間部分并命名為middle寂玲;

overlay濾鏡表示兩個(gè)視頻相互疊加,shortest官網(wǎng)是這么介紹的:“If set to 1, force the output to terminate when the shortest input terminates. Default value is 0.”洛搀,因?yàn)槲覀兪褂胣ullsrc創(chuàng)建了一個(gè)沒有時(shí)間軸的畫布敢茁,所以這里需要以middle的視頻時(shí)間為最終時(shí)間佑淀,故設(shè)置為1留美。main_w和main_h表示主視頻的寬高,overlay_w和overlay_h表示疊加視頻的寬高伸刃。如果要把A視頻疊加到B視頻上谎砾,則main_w和main_h表示B視頻的寬高,overlay_w和overlay_h表示A視頻的寬高捧颅。合起來便是把middle疊加到background之上且置于background的中間(相當(dāng)于有個(gè)疊加層的概念)景图;

最后一個(gè)參數(shù)是-movflags,它跟mp4的元數(shù)據(jù)有關(guān)碉哑,設(shè)為faststart表示會(huì)將moov移動(dòng)到mdat的前面挚币,在線播放的時(shí)候會(huì)稍微快一些。

作業(yè):我們?cè)?a target="_blank">音視頻合成案例一文中介紹了兩個(gè)案例扣典,快去試試你能不能一條命令解決妆毕?

關(guān)于濾鏡的基本介紹我們就介紹到這里,有任何問題可以下方留言贮尖。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笛粘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子湿硝,更是在濱河造成了極大的恐慌薪前,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件关斜,死亡現(xiàn)場(chǎng)離奇詭異示括,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)痢畜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門例诀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來随抠,“玉大人,你說我怎么就攤上這事繁涂」八” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵扔罪,是天一觀的道長秉沼。 經(jīng)常有香客問我,道長矿酵,這世上最難降的妖魔是什么唬复? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮全肮,結(jié)果婚禮上敞咧,老公的妹妹穿的比我還像新娘。我一直安慰自己辜腺,他們只是感情好休建,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著评疗,像睡著了一般测砂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上百匆,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天砌些,我揣著相機(jī)與錄音,去河邊找鬼加匈。 笑死存璃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的雕拼。 我是一名探鬼主播纵东,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼悲没!你這毒婦竟也來了篮迎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤示姿,失蹤者是張志新(化名)和其女友劉穎甜橱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栈戳,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岂傲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了子檀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镊掖。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乃戈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亩进,到底是詐尸還是另有隱情症虑,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布归薛,位于F島的核電站谍憔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏主籍。R本人自食惡果不足惜习贫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望千元。 院中可真熱鬧苫昌,春花似錦、人聲如沸幸海。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涕烧。三九已至月而,卻和暖如春汗洒,著一層夾襖步出監(jiān)牢的瞬間议纯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工溢谤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞻凤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓世杀,卻偏偏與公主長得像阀参,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞻坝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容