就像數位照片整理多了,用過各式軟體,最後還是得擁抱 ExifTool。
最近數位影片也漸漸整理多了,是時候學習以前嫌複雜的 ffmpeg了。
在巴哈姆特找到神級推廣文,萬一以後找不到怎麼辦?請務必讓我複製一份備查!
作者:晴空和聲
簡介
ffmpeg是一款開放原始碼的編碼器工具,由command line介面操作,更詳細的歷史之類不是本篇重點,可以去維基百科看。
功能上可以做影音的編碼、解碼,配合參數可以做到很多事情,這篇文章會以常用的應用場合來簡介,如果用到成精,基本上可以用ffmpeg剪片都沒問題。
為什麼是ffmpeg
如果說要合併兩個影片,就去載了一個來路不明的Mp4ConcaterFree;要抽取音訊再去載一個來路不明的BestMp4ToMp3;要剪裁影片再去找一個FreeVideoCropper;然後檔案太大了就再去裝一個SuperMp4Compresser,雖然上面這些名字都是隨手想的,可能不一定存在,但如果照著這種情況來電腦沒兩下子就會變成養蠱場,一個影片從這個工具丟到那個工具一條龍下來畫質音質都直接變渣,這顯然是很不OK的作法。
如果說有一個工具可以搞定上面說的那些情況,那不就好了,有些人可能會說「那格式工廠呢?」,問題就在那些軟體大多來源都很不明,這個載點加點料,那個載點再參點毒,就是電腦變成養蠱場的開端。
這時候就是要介紹ffmpeg,是開放原始碼的編碼器工具,基本上所有人都可以維護這個工具,也可以檢視原始碼,安全性是由公開的大眾監督,含有惡意功能的機會微乎其微,ffmpeg會收錄很多開放授權的影音格式編解碼器,基本上要用到的都會有,論實用性與安全性遠大於上面提到的那些來路不明的東西。
安裝方式
這篇文章以Windows為主,相信用linux的人都會自己clone下來make了。
首先去ffmpeg官網的下載頁面,下面選自己系統對應的可執行檔,以Windows為例,有兩家社群會定期編譯Windows的ffmpeg,分別是gyan.dev跟BtbN,個人是推BtbN這家的,編譯週期比較勤。
進去對應的GitHub Release頁面之後會看到玲瑯滿目的Assets,基本上照著自己系統的版本選就好了,Windows的部分有兩個,分別是ffmpeg-master-latest-win64-gpl-shared跟ffmpeg-master-latest-win64-gpl。
這兩個版本的差異在編碼器的授權問題,簡單來說gpl授權的專案的衍生專案也需要依照gpl公開,gpl-shared授權下的衍生專案中,引入其他外部非gpl專案的部分不需要照gpl授權公開,所以gpl-shared版中不會包含gpl授權的編碼器。
總結簡單來說如果如果只是要個人使用,不會對ffmpeg進行再製的話建議用gpl授權的,內容比較多。
下載之後解壓縮,會有一個資料夾bin,裡面會有三個執行檔,就是ffmpeg的三個部分,為了方便使用建議加入環境變數:
先將bin資料夾放到一個適合永久存放的地方,像是C:\ProgramFiles\ffmpeg\bin之類,自己決定就好,我自己是習慣在D槽放一個資料夾專門放portable軟體,接下來按Win+Pause/Break打開系統資訊,然後找到進階系統設定,然後按環境變數,然後在系統變數中找到Path後按編輯,然後新增,再來貼上bin資料夾的完整路徑,然後一路按確定關掉那些視窗,基本上就算完成了。
如果設定環境變數還是有問題,這邊借用java官網的設定教學提供參考。
測試的話可以開啟一個新的命令提示字元,注意要新開啟的才會反應剛才環境變數的設定,然後輸入ffmpeg -version來確定環境變數有正常設定,如果成功會看到ffmpeg的版本資訊。
工具簡介
bin資料夾中剛才有看到三個可執行檔,分別為以下功能:
ffmpeg:本體,編解碼之類都是本體完成
ffplay:簡易的播放器,經常是測試用
ffprobe:檢視媒體資訊用的
ffmpeg最基本的語法如下:
| ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}… |
最基本的範例如下:
| ffmpeg -i input.mp4 output.mp4 |
-i參數是輸入,最後一個位置參數是輸出,以這個為例就是將input.mp4輸入並重新編碼之後輸出到output.mp4,編碼器的話如果不指定會用副檔名來預設判斷,mp4容器中預設的影像會用H.264、音訊會用AAC。
如果要手動指定編碼器的話可以用-codec或簡稱-c參數指定,-c:v指定影像、-c:a指定音訊。
| ffmpeg -i input.mp4 -c:v libx265 -c:a Opus output.mp4 |
這樣的話會指定影像用H.265格式,音訊用Opus格式,如果要看ffmpeg支援那些編碼器的話可以打:
| ffmpeg -codecs |
就會列出支援的格式與編碼器,以及支援的屬性跟動作如解碼、編碼、影音類型、破壞性、非破壞性等,以某段輸出為例來解釋:
| Codecs: D..... = Decoding supported .E.... = Encoding supported ..V... = Video codec ..A... = Audio codec ..S... = Subtitle codec ..D... = Data codec ..T... = Attachment codec ...I.. = Intra frame-only codec ....L. = Lossy compression .....S = Lossless compression ------- DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_qsv libopenh264 h264_cuvid ) (encoders: libx264 libx264rgb libopenh264 h264_amf h264_mf h264_nvenc h264_qsv ) D.VIL. hap Vidvox Hap DEVIL. hdr HDR (Radiance RGBE format) image DEV.L. hevc H.265 / HEVC (High Efficiency Video Coding) (decoders: hevc hevc_qsv hevc_cuvid ) (encoders: libx265 hevc_amf hevc_mf hevc_nvenc hevc_qsv ) |
前面的DEV.LS代表支援編碼、解碼,類型為影像、可以是破壞性壓縮或非破壞性壓縮。
以h264為例,h264是格式的名稱,要在-c中指定的是編碼器,後方就有寫這個格式有哪些編解碼器能用,像是編碼器最常用的是libx264,h264_nvenc是用NVIDIA的硬體加速、h264_qsv是用intel內顯的硬體加速。
如果-c指定copy的話,代表不重新編碼,要有一個觀念是破壞性壓縮的話每編碼一次就會損失一次品質,如果只是想要合併/拆分影音但不想要轉換格式那當然是不要重新編碼,不然從h264解碼再編成h264也會損失一次品質。
保持良好習慣,不要重新編碼的地方就不要重新編碼,節省效能跟時間,也保持品質。
簡單前置觀念
要不要看自己決定,就是一些小細節。
mp4(MPEG-4)其實是一種容器,不是一種影像格式,mp4中可以裝的影像舉幾個大家常見的:
- H.264/AVC
- H.265/HEVC
- VP9
- VP8
- AV1
音訊的話也舉幾個常見的:
- AAC(Advanced Audio Coding)
- MP3
- Opus
- FLAC
完整的支援格式列表更長,有興趣自己查。
所謂容器就是裡面可以裝多個串流,像是影像串流、音訊串流、外掛字幕串流等等,當然一種串流也可以不只一條,可以有像是不同語言地區就有不同的音訊跟字幕。
還有一些真的比較不重要的觀念,跳過沒關係,就是很多人會用mp3稱音訊,像是什麼youtube下載mp3等等的工具,其實youtube原生並不會提供mp3格式,那些奇奇怪怪的網站跟工具如果是提供mp3,而且還號稱什麼高音質的話絕對都在唬爛,如果要下載youtube內容的話請考慮yt-dlp,也是開放原始碼的cli工具,直接從youtube android API撈原始檔資訊,那些奇奇怪怪網站的核心八成也是基於youtube-dl或是yt-dlp做的,然後再把Opus編碼成mp3然後用最高的位元率320kbps唬爛你說那是無損高音質。
還有一點,其實在音訊界說mp3是會被唾棄的,至少我是,在相同位元率下的mp3跟AAC,雖然兩者都是破壞性壓縮,但AAC可以有更高的品質,如果是從yt下載的話條件允許還是會選Opus,相對的品質會比AAC更好。
論品質轉換的話基本上:
- 破壞性壓縮互轉會損失品質
- 轉換至非破壞性壓縮或是不壓縮(RAW)不會損失品質
- 如果能不轉換就不轉換,保持良好習慣
ffmpeg的實用狀況
分離影音
以最簡單的影片為例,一個mp4容器,只有一個H.264視訊軌道跟一個AAC音訊軌道:
| ffmpeg -i input.mp4 -c copy -an output.mp4 |
-an代表不要輸出聲音,這樣輸出的檔案就只會有影像,而且指定-c copy代表不重新編碼,速度上等同於複製檔案,品質也不會損失。
| ffmpeg -i input.mp4 -c copy -vn output.aac |
-vn相對的就是不要輸出影像,輸出檔案就只會有AAC音訊,也不會重新編碼。
分離字幕串流
特別注意,這裡指的字幕是指獨立一條字幕軌道,而非已經編碼進影像的硬字幕。
| ffmpeg -i input.mp4 -map 0:s:0 subtitle.srt |
-map是選取特定軌道至輸出,詳細用法後面會提到,這個範例會將第0個字幕軌道輸出。
如果字幕是已經壓製到影像裡面的話,就要找工具OCR出來了,中文的話目前準確度普遍上不太好。
合併影像與聲音
如果是最基本的一個影像跟一個聲音要合併成一個檔案同時有影像跟聲音:
| ffmpeg -i video.mp4 -i audio.aac -c copy output.mp4 |
這樣就會把影像跟聲音合併成一個檔案,因為影像跟聲音都只有一個,所以合併的時候就不用指定誰是影像誰是聲音。
如果輸入有多個影像跟聲音,那就要用-map指定哪個影像哪個聲音去第幾個軌道。
例如如果有一個影片input1.mp4要提供影像,影片input2.mp4要提供聲音,那可以考慮以下的指令:
| ffmpeg -i input1.mp4 -i input2.mp4 -map 0:0 -map 1:1 -c copy output.mp4 |
這樣子的-map 0:0會指定選擇第0個輸入檔案(即為input1.mp4)的第0個串流(通常為影像);和-map 1:1選取的第1個輸入檔案(input2.mp4)的第1個串流(通常是音訊)來做合併,檔案編號會照輸入順序排列,例如第一個-i input1.mp4參數就是第0個檔案(基本上這些東西都是從0開始編號,以下用阿拉伯數字跟國字區分),輸出的串流編號會依照map出現的順序排列,如這個例子中的影像仍然會在第0個串流;音訊在第1個串流。
如果輸入檔案有多個影像或音訊,但沒有用-map指定選取哪個的話,預設只會選取影音各一個串流,選擇方式是會預設選取品質最好的,詳細自動選取規則可以去看官方文件。
關於map語法的簡單介紹,這邊總結一下,其實官方文件也寫得簡單易懂,如果英文可以建議直接看官方的說明。
簡單來說借用官方的圖片說明:
第幾個-i就是第幾個輸入檔案編號,每個檔案可以有多個軌道,-map的語法如下:
| -map 輸入檔案編號:串流類型:串流編號 |
- 輸入檔案編號是選取第幾個-i,預設是全部。
- 串流類型是可選填的,v代表影像、a代表音訊,還有其他字幕等等的,不指定就是預設全部。
- 串流編號也是可選填,是選取的輸入內的指定串流類型的第幾個串流,不指定就是預設全部。
例如-map 1:v:0就是選取第二個-i的第一個影像串流。
另外一個語法是在輸入檔案編號前面加上-,代表反向選取,例如-map 0 -map -0:v:1就是選取第一個輸入的全部,再排除第一個輸入的第二個影像串流。
剪裁長度
可以用-ss參數指定來源開始讀取的位置、-sseof從結尾往回算開始讀取的位置、-t參數指定讀取的長度、-to指定到哪個時間點結束,例如:
| ffmpeg -i input.mp4 -c copy -ss 1:2.3 -to 2:0 output.mp4 |
會把input.mp4從一分零二點三秒到兩分零秒之間的內容輸出到output.mp4,不重新編碼,但因為H.264等常見的影像壓縮方式是用Differential Encoding,意思是用兩個畫面之間的差異來儲存,如果直接從連續影像中間切下去而不重新編碼的話,前面幾個影格就會失去參考畫面而出現解碼異常,通常反應是黑色畫面,這點就是在剪裁的時候要自己考量的了。
轉換編碼
可以用-codec或是簡寫-c參數指定要轉換的編碼,可以用-c:v指定影像編碼器、-c:a指定音訊編碼器,如果有多個影像串流或是音訊串流的話可以加上編號,例如-c:v:0是第0個影像,這些編號是對應輸出的串流編號,主要要注意的是輸出的容器能裝哪些格式,如果mp4裝不下的話可以直接無腦用mkv,基本上大多數的格式都可以裝進mkv裡面:
| ffmpeg -i input.mp4 -c:v libvpx-vp9 -c:a libopus output.mkv |
壓縮影音
某些破壞性壓縮的編碼器有參數-b可以指定位元率,位元率直接影響輸出大小跟品質,如果有些平台有限制檔案大小的話可以透過降低位元率來壓縮檔案大小:
| ffmpeg -i input.mp4 -b:v 1M -c:a copy output.mp4 |
基本上改變位元率就是在重新編碼成較低品質的資料,所以複製格式只指定音訊,而-b也可以分成-b:v指定影像、-b:a指定音訊,當然要編碼器支援才行,1M代表1Mbps的位元率。
銜接影片
不同格式、解析度
如果輸入是不同格式與解析度的話,銜接必定需要重新編碼,可以考慮以下這樣:
| ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex "[0:v] [0:a] [1:v] [1:a] concat=n=2:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" -c:v libx264 -c:a aac output.mp4 |
這個指令假設 input1.mp4 和 input2.mp4 的影像和音訊格式不同,在合併之後指定用H.264影像、AAC音訊。
至於這裡用到的-filter_complex語法在後面會有詳細解釋。
相同格式、解析度,串流等級
基本上用於相同格式、解析度,但是來源不是分割檔案的情況,基本上大多數人要合併的都屬於這種狀況。
首先建立一個文字檔案,裡面列出要銜接的檔案列表,假設名字叫做list.txt,格式如下:
| file 'path\to\input1.mp4' file 'path\to\input2.mp4' |
後面的檔案路徑換成自己要合併的,Windows中路徑分隔字元是反斜線,Unix系是正斜線,雖然有些情況下支援混用,但是就自己評估,在這個檔案中的反斜線不用跳脫。
列表產生完之後,用ffmpeg來合併:
| ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4 |
-safe 0是取消掉ffmpeg對於路徑的檢查,只要你確保你的路徑不會寫入到一些不該寫的地方就可以關掉,不然如果檔案路徑包含相對路徑的話,沒有-safe 0會被阻擋。
如果要在Windows中自動產生檔案列表的話,可以用cmd的迴圈來做,例如以下這個指令可以把目錄下的所有.mp4檔案作成列表:
| for %f in (*.mp4) do @echo file '%f' >> list.txt |
相同格式、解析度,檔案層級
通常用於.ts檔案,這種檔案的規格允許檔案直接被分割,不用在分割的時候加額外的資訊,所以合併的時候直接將檔案二進位內容連接即可,用cmd的copy /b 1.ts+2.ts concat.ts也可以,但這邊講個用ffmpeg的例子:
| ffmpeg -i "concat:1.ts|2.ts|3.ts" -c copy output.ts |
基本上這個行為與上面的方法相同。
附加:m3u播放清單的合併
.ts檔也常用在hls中,例如巴哈的卡通瘋也是用hls來傳輸影片的,通常這種檔案都會有一個清單為.m3u或是.m3u8(utf-8格式),ffmpeg也可以直接照著這個檔案的清單來合併.ts,甚至是下載遠端的.ts來合併,以下用niconico的hls模式來舉例(當然niconico可以用http模式直接下載整部影片,但這邊是教學用途,所以用hls):
例如這是一段niconico某影片的playlist.m3u8的網址:
直接用ffmpeg來下載合併:
如果仔細看那個m3u8會發現內容是相對位址,只是下載的來源為只跟m3u8的資料夾相同,所以可以直接下載。
如果是在本機上面的m3u指向網路上的資源,就需要用-protocol_whitelist將網路有關的通訊協定加入白名單才可以使用,這是ffmpeg基於安全目的設定的限制,假設playlist.m3u8是一個本機上面的m3u,裡面的.ts來源都是網址:
| ffmpeg -protocol_whitelist file,crypto,data,https,tls,tcp -i playlist.m3u8 -c copy video.mp4 |
當然相同的m3u播放清單也適用於本機的檔案,只要確定路徑是正確的就可以使用ffmpeg來合併,至於有些播放清單的.ts會加密,只要金鑰檔案在m3u中有指定出位置,ffmpeg在合併的時候也會一併解密。
影格序列拆分
| ffmpeg -i video.mp4 frames%04d.png |
這樣會將輸入檔案的每個影格匯出成png,檔名中的%04d代表用0填滿空位的4位數數字。
影格序列合併
| ffmpeg -r 30 frames%04d.png -c:v libx264 -pix_fmt yuv420p video.mp4 |
這樣會把frames%04d.png這個序列用30fps讀進來,然後用H.264格式跟yuv420p的色彩格式輸出成影片,-r這個參數加在-i前面是指定讀取的fps,只對RAW來源有效。
yuv420p是H.264壓縮的時候的色彩分量跟量度分量的比例,420是最常見的比例。
%04d會從0000開始找0填補的四位數字,如果影像序列不是從0開始的話,可以用-start_number參數指定從幾號開始讀,例如如果序列是frames1001.png到frames1100.png,那可以用以下這個寫法:
| ffmpeg -r 30 -start_number 1001 frames%04d.png -c:v libx264 -pix_fmt yuv420p video.mp4 |
關於影像序列可以參考官方文件。
濾鏡(濾鏡圖,filtergraph)
ffmpeg中的濾鏡參數的概念是一張濾鏡圖,一個濾鏡圖中可以包含很多個濾鏡組合而成,從外界看濾鏡圖就是一個複合濾鏡,濾鏡圖可以有一個輸出跟輸入或是多個輸出跟輸入,對應到的參數名稱分別是-filter跟-filter_complex,-filter的限制是濾鏡圖只能有一個輸入跟一個輸出,-filter_complex的濾鏡圖可以有多個輸入跟多個輸出,所以-filter_complex可以向下相容於-filter,所有-filter中使用的濾鏡在-filter_complex中都可以使用。
濾鏡圖是由濾鏡鏈組成,一條濾鏡鏈是由濾鏡串接而成,濾鏡鏈中不同濾鏡之間用半形逗號分隔、濾鏡鏈之間用半形分號分隔。
濾鏡語法
一個濾鏡的語法如下:
| [輸入1]...[輸入N]濾鏡名稱@id=參數[輸出1]...[輸出N] |
其中[輸入N]可以是前面寫的串流選擇器如[0:v:0]或是另一條濾鏡鏈的輸出,[輸出N]則是可以為這個濾鏡鏈的輸出命名,作為在後面需要指定這個輸出串流的時候可以用的辨識代號。
參數
參數的話有幾種表示方法,一種是關鍵字參數,之間用半形冒號分隔,例如如果有一個濾鏡第一個參數是x、第二個參數是y,用關鍵字參數表示可以寫成這樣:
| x=100:y=20 |
也可以用位置參數,就是只寫參數的值,然後一個位子會對應到一個參數名稱,用位置參數表示就可以寫成:
| 100:20 |
也可以用混和參數,前面是用位置參數表示,後面用關鍵字參數,可以節省打字量又可以跳過一些不指定的參數,例如:
| 100:y=20 |
上方這幾種表示方式都是相同的。
另外,如果參數內有包含[]=;,的字元的話,需要進行跳脫,這在後面會詳細說明。
參數還有另一種語法,可以在參數名稱前面加上/,代表參數值是一個檔案路徑,就可以用檔案內容當作參數值,例如以下這樣:
| ffmpeg -i video.mp4 -vf "drawtext=/text=/path/to/textfile.txt" output.mp4 |
這樣參數內容就可以從/path/to/textfile.txt中讀取。
濾鏡鏈(filterchain)
兩個濾鏡如果前面輸出串流數跟後面輸入串流數一樣,可以直接用逗號銜接,串成一個濾鏡鏈,在兩個濾鏡之間就不用為暫存結果命名,否則如果濾鏡鏈的頭尾不是濾鏡圖的最前及最後端,就需要指定輸入串流跟為輸出串流命名。
多條濾鏡鏈之間用分號分隔,例如以下這個-filter的範例:
| ffmpeg -i video.mp4 -vf "split=2[v0][v1];[v0]scale=200:300,drawtext=text=foobar:x=10:y=10[v0_filtered];[v1][v0_filtered]overlay=10:10" output.mp4 |
以圖形化來看,可以畫出這一個濾鏡圖:
| ._____ ____ _____________ __________ | | split | | scale drawtext | | overlay | | |input| --------> | v0 | ---------> ------------> | v0_filtered | -----------> | output | |_____| \ |____| |_____________| / |__________| \ ______ / \ | | / \----> | v1 | -------------------------------------/ |______| |
這個濾鏡圖的作用是先用split濾鏡將影像複製成兩份並命名成v0跟v1,然後v0先用scale調整大小,然後再用drawtext在上面繪製文字,在這條鏈的最後命名成v0_filtered,然後再用overlay把v1上面蓋上v0_filtered。
如果把每一條濾鏡鏈拆開來畫的畫會是這樣:
| ._______ ______ | | split | | | input | --------> | v0 | |_______| \ |______| \ ______ \ | | \----> | v1 | |______| .______ _______________ | | scale drawtext | | | v0 | ---------> ------------> | v0_filtered | |______| |_______________| ._______________ __________ | | overlay | | | v0_filtered | -----------> | output | |_______________| / |__________| .______ / | | / | v1 | -------/ |______| |
這是一個輸入一個輸出的-filter,濾鏡圖的頭尾不用加上串流選擇跟輸出名稱,因為輸出跟輸入必定只有一個串流。
再舉一個例子是-filter_complex的,將輸入1的影像半透明蓋在輸入0的影像上面:
| ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[1:v]format=rgba,colorchannelmixer=aa=0.5[overlay];[0:v][overlay]overlay[v_out]" -map "[v_out]" output.mp4 |
| ._______ ___________ ________ | | format colorchannelmixer | | overlay | | | 1:v | ----------> ---------------------> | overlay | -----------> | vout | |_______| |___________| / |________| _______ / | | / | 0:v | ---/ |_______| |
這個濾鏡圖的輸入是直接用選擇器挑選串流輸入,輸出命名為v_out,在後面輸出檔案的時候用-map指定影像串流來源是濾鏡圖中的v_out串流。
濾鏡參數中的跳脫字元
在濾鏡中如果有要使用到特殊字元,例如繪製文字時要繪製’:或是參數中包含[],;需要進行跳脫動作,在一般情況下分為三層需要跳脫,分別是第一層為濾鏡參數字串、第二層為濾鏡圖參數、第三層為shell,以跟官方說明中一樣的繪製文字舉例:
如果要在畫面上繪製以下文字:
| this is a 'string': may contain one, or more, special characters |
在寫進濾鏡參數的時候就要跳脫’:這兩個字元:
| text=this is a \'string\'\: may contain one, or more, special characters |
下一層濾鏡圖參數需要跳脫[],;\’,如以下範例:
| drawtext=text=this is a \\\'string\\\'\\: may contain one\, or more\, special characters |
其中\\為跳脫\字元,讓text參數可以讀取到\,’跟,也是第二層需要跳脫的字元。
再下一層就是shell需要跳脫的字元,普遍來說只有\需要跳脫,因此整個-vf參數會變成以下這樣:
| -vf "drawtext=text=this is a \\\\\\'string\\\\\\'\\\\: may contain one\\, or more\\, special characters" |
基本上就是因為\需要跳脫,所以\數量會直接翻倍。
這點需要提醒常常被遺忘的是Windows環境中路徑分隔符號也是\,所以如果在參數中有用到路徑名稱的,例如subtitle濾鏡的檔案路徑,裡面的分隔符號\就需要加上位於第二層的跳脫字元,至於第三層shell的話,Windows的cmd的引號範圍中不用跳脫\,只要注意跳脫”即可(但注意Windows cmd中其他特殊字元需要用^來跳脫,那個屬於cmd語法的部分,這些東西可以去wiki看詳細資料)。
濾鏡的實際應用
濾鏡的官方說明在這,這篇只舉幾個可能大家比較常會用到的來舉例。
快轉/放慢
這邊用的濾鏡叫做setpts,就是改變影格出現的時間點,如果每個影格出現的時間點都是之前時間點的一半,那就相當於快轉兩倍;聲音的話是用atempo設定倍率:
| ffmpeg -i video.mp4 -vf "setpts=PTS/2" -af "atempo=2" output.mp4 |
以上這種方法會重新編碼,在相同fps的情況下將影像跟聲音快轉兩倍,應該是快轉普遍最常用的方法。
也可以透過把影片輸出成RAW,然後再用指定的fps讀取RAW,在不重新編碼的情況下透過調整影片的fps來達成看似快轉的效果,但這種作法比較少用,因為這只是調整了影片的fps而已,總影格數還是相同。
以30fps、H.264轉到60fps為例:
| ffmpeg -i input.mp4 -map 0:v -c:v copy -f h264 - | ffmpeg -fflags +genpts -r 60 -i - -i input.mp4 -c:v copy -map 0:v -map 1:a -af atempo=2 output.mp4 |
這樣就是只取出輸入的影像軌道,然後用H.264 RAW的格式輸出到pipe,後面的ffmpeg從pipe讀取RAW跟原始影片的音訊,然後用-fflags +genpts來強制重新生成pts,用60fps讀取來源,這樣的話兩者影像都不會重新編碼,但是輸出的時候重新生成了pts跟指定了fps,就會反映在播放上面,聲音的話用atempo濾鏡調快兩倍再並進輸出。
要注意的是atempo要自己算來源的fps到輸出的fps之間加速了幾倍。
另外這跟fps濾鏡不一樣,fps濾鏡是透過丟棄影格來讓播放速度不變的情況下達到指定的fps。
剪裁
剪裁可以用crop濾鏡來把畫面中一塊裁出來,例如以下:
| ffmpeg -i video.mp4 -vf "crop=x=100:y=50:w=200:h=300" output.mp4 |
這樣就會把影像中從x=100、y=50的地方裁出一塊寬200、高300的影像。
硬字幕
subtitles濾鏡可以把一個字幕檔壓製到影像上面,例如以下這個例子:
| ffmpeg -i video.mp4 -vf "subtitles=sub.srt" -c:a copy output.mp4 |
就會把sub.srt這個字幕檔壓在影片的影像上面。
ffplay跟ffprobe
ffplay
基本上ffplay用法就當作是輸出到螢幕或是喇叭的ffmpeg,但是不支援-filter_complex,大概就這樣,我自己是常常拿來初步檢測檔案的編碼是不是正常。
ffprobe
在用ffmpeg的時候會發現,每次輸出的時候都會列出來源檔案的資訊,像是大小、位元率、編碼、flags、fps等等,如果只是要看這些資訊的話可以用ffprobe工具來看,把檔名傳進參數就行了。
使用技巧
如果你已經對ffmpeg有一定程度的熟悉了,可以用chatgpt加速編寫濾鏡或是一些操作的流程,像是以下這樣:
記得檔名什麼的要自己替換,然後就可以得到這樣的東西:
如果生成出來的結果是錯的,可以用文字繼續敘述或是自己debug,總之這樣真的省了很多以前要查的時間,但缺點就是會生出更多自己能力之外的bug,所以如果要從基礎了解的話還是建議看文件跟stackoverflow的前例會比較好,像是chatgpt一直認為-vf可以跟-c:v copy共存,但實際上影像濾鏡跟不重新編碼本身邏輯上就有衝突了。
總而言之,不要再去用那些奇奇怪怪可疑的轉檔軟體了,銜接影片不要再去威力導演了,就這樣。
沒有留言:
張貼留言