ffmpeg是許多音視頻入門書籍都會推薦學習的一套多媒體框架,其集封裝、解封裝、編碼、解碼、播放和濾鏡等多項功能于一身,堪稱音視頻領域的「瑞士軍刀」。
今天,我們将不再遵循常規教程的套路,而是将以表情包界名垂青史的名場面、電影《旺角卡門》中的經典片段——「吔屎啦你」為講解素材,通過GIF表情包創作的場景化教學,來講解FFmpeg命令行工具的實際運用。
若本教程成功地激起了你對FFmpeg命令行工具的探索興趣,記得說聲多謝老舅點贊、收藏、評論三連支持一下。
首先,舉一個最簡單的例子,即,直接把一個任意格式的視頻片段轉為GIF圖像:
ffmpeg -i as_tears_go_by.mp4 as_tears_go_by.gif
-i 選項用于指定任意數量的輸入流,可以是本地文件也可以是網絡文件。
而輸出流也可以是任意數量的,其指定的方式則相對粗暴得多,隻要是命令行中無法解釋為「選項」的内容,都會被FFmpeg命令行工具視為輸出流。
大多數情況下,FFmpeg命令行工具會根據輸入輸出流的擴展名去自動檢測格式,如果需要強制指定輸入或輸出流的格式,可以使用-f 選項,比如:
ffmpeg -i as_tears_go_by.mp4 -f gif as_tears_go_by.gif
效果都是一樣的。
名場面往往就是那幾秒在誕生這些表情包名場面的電影中,你經常會發現有那麼一群“合影黨”,喜歡把播放進度拖動到表情包畫面出現的前後幾秒,然後在公屏上打上“合影留念”的彈幕(說的是不是你?),仿佛一開始就是奔着這幾秒去看這部電影的。
而我們創作表情包的第一步,自然也是先截取出這些全片中最精彩的片段。
要截取視頻中的特定位置與時長的片段,我們可以用以下命令行實現:
ffmpeg -i {input} -ss {position} -t {duration} {output}
其中,
-ss 選項用于定位到指定的視頻位置,可以是「HH:MM:SS」這種格式,也可以是「2.3」這種表示第2.3秒的格式。
-t 選項用于表示截取的視頻時長,也同樣支持以上2種時間格式。
例如,「吔屎啦你」這一名場面發生在上述視頻片段的第11秒,持續時間約為2.3秒,那我們就可以這樣子編寫命令行:
ffmpeg -i as_tears_go_by.mp4 -ss 00:11 -t 2.3 as_tears_go_by-trim.gif
到位了到位了哈!可是有一個問題出現了,盡管經過截取處理,轉出的GIF圖像文件仍有11.6MB,作為一個表情包來講,實在是太大了。
而相同時長的MP4視頻文件大小卻隻有664KB,為什麼兩者能相差這麼大呢?這其實跟二者采用的壓縮算法有關,後面系列文章中會專門講到,這裡就先不展開說了。
鬥圖,講究一個「快」字你肯定有過這樣的經曆,本來和暧昧對象在微信上聊得好好的,不知怎的突然就沒話題了。與其繼續尬聊下去,我們更多會選擇開啟「鬥圖」模式,來緩解和過渡這一尴尬的時刻。
鬥圖除了考驗你表情包彈藥庫的存量之外,表情包連發的“攻速”也很重要。
想象一下,對方的表情包如機關槍般“哒哒哒”密集地發來,而你的表情包卻因為GIF格式下的文件過大,到了對方的聊天面闆還要轉圈下載好一陣,氣勢上就輸了一大截。
因此,壓縮表情包文件的大小,很重要。
壓縮大法第一式——縮放ffprobe是FFmpeg提供的多媒體信息查看工具,我們可以先使用ffprobe來查看上一步中截取了名場面,并轉換了格式後的GIF圖像信息:
ffprobe as_tears_go_by-trim.gif
Input #0, gif, from 'as_tears_go_by-cut.gif':
Duration: 00:00:02.32, start: 0.000000, bitrate: 40101 kb/s
Stream #0:0: Video: gif, bgra, 1920x1080 [SAR 64:64 DAR 16:9], 25 fps, 25 tbr, 100 tbn
可以看到,由于我們是直接将視頻片段轉為GIF圖像的,文件的尺寸大小高達1920x1080!和一般的靜态圖片一樣,GIF格式的文件大小也是受尺寸大小影響的,尺寸越大相應的文件也就越大,但作為表情包我們往往不需要追求如此高清的效果。
因此,我們壓縮工作的第一步,就是縮減GIF文件的尺寸。
可以使用以下命令行來實現:
ffmpeg -i {input} -s {WxH} {output}
可以看到,由于我們是直接将視頻片段轉為GIF圖像的,文件的尺寸大小高達1920x1080!和一般的靜态圖片一樣,GIF格式的文件大小也是受尺寸大小影響的,尺寸越大相應的文件也就越大,但作為表情包我們往往不需要追求如此高清的效果。
【更多音視頻學習資料,點擊下方鍊接免費領取↓↓,先碼住不迷路~】
點擊領取→音視頻開發基礎知識和資料包
因此,我們壓縮工作的第一步,就是縮減GIF文件的尺寸。
可以使用以下命令行來實現:
ffmpeg -i {input} -s {WxH} {output}
-s 選項用于指定輸出文件的尺寸大小,格式上是「寬度(W)x高度(H)」
例如,我們可以拿到前面的GIF圖像文件,将其寬高均縮放至原先的1/6:
ffmpeg -i as_tears_go_by-cut.gif -s 320x180 as_tears_go_by-scale.gif
可以看到,經過縮放後的文件大小已減少至1.6M,約為原先大小的1/7,效果還是比較明顯的。
壓縮大法第二式——抽幀GIF是連續的動态圖像,可以視作是一張一張完整的圖像按一定速率播放,然後利用人眼的視覺殘留效應所形成的效果。每秒鐘依次播放的圖像數量叫做幀率,單位是fps(frame per second,幀每秒)。
前面我們用ffprobe工具查看後可得知,輸出的GIF圖像的幀率是25fps,這是由于我們是直接将視頻片段轉為GIF圖像的,而電影中的常見幀率為24/25幀,因此輸出的GIF圖像也保留了相同的幀率。
幀率越高,GIF圖像的動效相對就越流暢,但相應的要儲存的圖片幀也會更多,可能導緻文件大小直線上升。通過減少幀數,犧牲一點連貫性,可以顯著優化文件的大小。
可以使用以下命令行來實現:
ffmpeg -i {input} -r {fps} {output}
-r 選項用于指定幀率,支持整數和分數格式。
例如,我們可以将上一步幀率為25fps的GIF圖像減少至8fps:
ffmpeg -i as_tears_go_by-scale.gif -r 8 as_tears_go_by-frameextract.gif
幀率減少後的GIF圖像效果如下:
可以看到,經過抽幀處理後的GIF圖像大小得到了進一步的壓縮。
壓縮大法第三式——裁剪裁剪同樣是為了縮減GIF圖像的尺寸,隻不過和單純的縮放相比,裁剪還有去除冗餘元素、突出目标主體的附加效果。
借助FFmpeg命令行工具實現對圖像/視頻的裁剪,我們需要用到Filter(濾鏡、過濾器)模塊。
濾鏡模塊提供了許多音視頻特效處理的功能,比如crop(裁剪)、scale(縮放)、overlay(疊加)、rotate(旋轉),trim(截取)等。可以說,前面幾個步驟提到的功能,都有相應的濾鏡可以實現。
如果要為視頻類型的輸入流指定使用的濾鏡,需要使用-vf 選項。可指定的濾鏡按輸入輸出流的數量和類型可分為「簡單濾鏡」和「複雜濾鏡」兩種。
所謂「簡單濾鏡」,指的是那種剛好隻有一個輸入流、一個輸出流的的濾鏡,且兩者都是同一類型的情況:
相對的,「複雜濾鏡」指的則是那些具有多個輸入流/輸出流,或者輸出流類型與輸入流類型不同的情況:
比如我們現在要實現的裁剪功能,就是一個典型的「簡單濾鏡」:
ffmpeg -i as_tears_go_by-frameextract.gif -vf "crop=180:180:100:0" as_tears_go_by-crop.gif
這條命令行的完整釋義如下:
經過裁剪後輸出的GIF圖像效果如下:
【更多音視頻學習資料,點擊下方鍊接免費領取↓↓,先碼住不迷路~】
點擊領取→C 程序員必看,抓住音視頻開發的大浪潮!沖擊年薪60萬
更騷的操作FFmpeg濾鏡的強大之處,在于它可以通過不同濾鏡的排列組合,實現各種各樣複雜的功能。
FFmpeg濾鏡共包含以下3個層級:
filter -> filterchain -> filtergraph 也即 濾鏡 -> 濾鏡鍊 -> 濾鏡圖
多個濾鏡可以串聯成一條濾鏡鍊,多條濾鏡鍊可以組合成一個濾鏡圖。
我們可以基于FFmpeg的官方示例進行改造,實現“裁剪出視頻的左半部分,并鏡像疊加到視頻的右半部分”的效果,來演示一下三者的關系,以及如何結合使用,流程圖如下:
這個流程使用命令行實現如下:
ffmpeg -i as_tears_go_by-crop.gif -vf "split[main][tmp];[tmp]crop=iw/2:ih:0:0,hflip[flip];[main][flip]overlay=W/2:0" as_tears_go_by-graph.gif
是不是看着這麼多的參數有點懵圈了?不要怕,這個涉及到濾鏡模塊的語法,我們一個一個來解釋:
首先,[main][tmp][flip]是為輸入輸出流所打的标簽,可以任意命名,打标簽是可選的,為了連接其他濾鏡時方便使用。
split、crop、hflip、overlay都是具體使用的濾鏡,濾鏡的各種參數在=号後面指定。
濾鏡的參數之間用冒号:分隔,可以是純值的形式,也可以是“鍵=值”的形式,還可以是二者混用的形式。
比如crop濾鏡的參數也可以這樣指定:crop=w=iw/2:h=ih:x=0:y=0,iw和ih這兩個變量分别指的是輸入幀的寬度和高度。
同一濾鏡鍊内的不同濾鏡之間用逗号,分隔。
比如[tmp]crop=iw/2:ih:0:0,hflip[flip]這一濾鏡鍊中就包含crop和hflip這兩個濾鏡,兩者之間使用逗号,分隔。
同一濾鏡圖内的不同濾鏡鍊之間用分号;分隔。
比如上面的濾鏡圖就包含split;crop,flip;overlay三條濾鏡鍊,彼此之間使用用分号;分隔。
最終輸出的效果如下——忍法·雙頭嘲諷:
嗯......看着有點詭異呢!
表情包的經典二創一個表情包之所以經久不衰,除了表情包本身很有“梗”之外,網友們富有想象力的“二次創作”,也是表情包能再次迸發出生命力的原因之一。
比如讓人忍俊不禁的「欲吔又止」:
這種類似連環畫的表情包叙事感很強,如果采用FFmpeg來創作的話,可以分為以下幾步進行:
視頻截圖手動截圖手動截圖的工作需要先借助前面提到的-ss 選項,定位到視頻片段指定的位置,然後再借助-vframe 選項來輸出指定數量的視頻幀,最後當然還要再對輸出的視頻幀的進行一波同樣的裁剪和縮放。
具體的命令行示例如下:
ffmpeg -i as_tears_go_by.mp4 -ss 00:13 -vframes 1 -vf "crop=ih:ih:iw/4:0" -s 180x180 as_tears_go_by-screenshot.jpg
得到的處理後的視頻截圖如下:
定時截圖
【更多音視頻學習資料,點擊下方鍊接免費領取↓↓,先碼住不迷路~】
點擊領取→音視頻開發基礎知識和資料包
但如果你想偷一下懶,不想一張張手動去截,我們也可以借助fps濾鏡實現來定時截圖,然後再從輸出的圖片集裡找符合預期的截圖即可,命令行如下:
ffmpeg -i as_tears_go_by.mp4 -vf "fps=2,crop=ih:ih:iw/4:0" -s 180x180 screenshot/out%d.jpg
此命令行執行後,每過0.5秒就會生成一張JPG格式的圖片,并進行一波同樣的裁剪和縮放。
從中我們最終挑出以下四張截圖作為素材:
添加文字
添加文字的工作同樣可借助濾鏡功能完成,使用到的濾鏡是「drawtext」濾鏡。
我們先拿前面經過裁剪之後生成的GIF圖像來做下實驗:
ffmpeg -i as_tears_go_by-crop.gif -vf "drawtext=fontsize=30:text='吔屎啦你':fontcolor=white:x=25:y=100:fontfile=JingNanYuanMoTi/KNFONTYUANMO-2.otf" as_tears_go_by-text.gif
添加文字後的效果如下:
fontsize、fontcolor、text等從字面意義就可以知曉其作用的參數我就不再贅述了,這裡需要提到的是,如果默認的字體風格不符合預期,drawtext濾鏡也支持使用「fontfile」參數來指定所采用的字體文件,比如上面的otf文件。
以下是挑選出的4張截圖添加文字後的效果:
多宮格處理
多宮格處理的工作實際就是前面所提到的「複雜濾鏡」的使用場景,我們需要整合多個輸入流(此處是靜态圖),并拼接到一個畫布上輸出。
先丢出處理的命令行:
ffmpeg -i 1.jpg -i 2.jpg -i 3.jpg -i 4.jpg -filter_complex "nullsrc=size=360x360[base];[base][0:v]overlay=0:0[tmp1];[tmp1][1:v]overlay=180:0[tmp2];[tmp2][2:v]overlay=0:180[tmp3];[tmp3][3:v]overlay=180:180" -frames:v 1 output.jpg
命令行很長,但是了解過前面的濾鏡語法以後,相信也不難理解,我們來一步步解釋:
最終産出的效果圖如下:
命令行的優勢
可能有人想說了,我幹嘛要去寫這麼一大串晦澀難懂的命令行呢?要創作表情包,使用有可視化界面的軟件操作不香嗎?
誠然,可視化界面有可視化界面的優勢,像前面添加文字的操作,鼠标或手指點點拖拖就可以完成了。但是别忘了,許多所謂的擁有可視化界面的軟件,其隻不過是在命令行工具上披一層皮而已。
換句話說,隻要熟悉了FFmpeg命令行工具的使用之後,我們就完全可以自己做一個擁有可視化界面,而功能底層使用FFmpeg命令行來實現的軟件。
比如在Android平台上,我們就可以通過手動将FFmpeg源碼編譯成so庫,并抽取ffmpeg編解碼工具的相關文件,借助NDK開發自行封裝成一個FFmpeg命令行工具庫,然後集成到我們的App中去,從而實現一個功能豐富的視頻編輯工具App。(後續文章将講到,敬請關注)。
看到這裡,你還不想打開FFmpeg命令行工具實際操作一番嗎?
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!