NO IMAGE

ffmpeg / avconv是通用的視訊/音訊編解碼命令列工具。

通用是既指他們可以處理各種各樣的編碼的視訊和音訊,轉換成各種需要的格式,又指他們是跨平臺的工具,可以執行在Linux、Windows、MacOS X等作業系統上。

avconv和ffmpeg的淵源頗深。ffmpeg是FFmpeg專案的命令列編解碼工具;avconv是Libav專案中用來代替ffmpeg的命令列編解碼工具。2012年1月下旬Libav專案決定拋棄掉ffmpeg
完全用avconv代替之,因此Libav專案的命令列編碼器只有avconv。

事實上,avconv和ffmpeg是基本一致的,avconv只是對原 ffmpeg的某些選項做了些微調,並且規範了一些行為。此外,FFmpeg專案也在不斷吸收Libav專案的更新,因此兩者的行為幾乎一樣。具體的差別看這裡我們下面主要用ffmpeg來做例子

特別說明:ffmpeg和avconv的選項經常變化,本文用的是ffmpeg version N-37208-g01fcbdf和avconv version N-32611-gd55b06b。我們使用時需要結合具體版本。也就是說,這個筆記可能會很快過時…

一、獲取

兩個專案都提供了原始碼的映象地址和編譯好的Windows二進位制檔案的下載地址。

FFmpeg:

原始碼 git://git.libav.org/libav.git

Windows編譯版 http://ffmpeg.zeranoe.com/builds/

下載最新版(lastest),可以下載static的build。用到壓縮包裡的bin資料夾裡的ffmpeg.exe。

Libav:

原始碼 git://git.libav.org/libav.git

32位Windows編譯版 http://win32.libav.org/win32/

64位Windows編譯版 http://win32.libav.org/win64/

看日期下載最新版,用到壓縮包裡bin資料夾裡的各種檔案。

 

二、文件和幫助

非常詳細的線上文件

ffmpeg
http://ffmpeg.org/ffmpeg.html

avconv
http://libav.org/avconv.html

例0、列印幫助資訊(以下用ffmpeg作為例子,用美元符號$作為命令列提示符)

在命令列裡輸入

$ffmpeg.exe -h

下面我們去掉.exe,因為linux下的二進位制檔案本來就沒有副檔名,Windows下不寫exe也能呼叫

ffmpeg的幫助非常長,Windows的cmd的緩衝區預設高度甚至裝不下。用重定向符號把幫助輸出到某個txt裡:

$ffmpeg -h > ffmpeghelp.txt

幫助分為基本用法、主要選項(main options)、各種高階選項、各種AVOptions、編譯資訊等部分。

我們看AVCodecContext AVOptions裡有個選項是-bufsize

-bufsize <int> E.VA. set ratecontrol buffer size (in bits)

該行告訴我們,此選項的引數應該是一個整數,單位是bit。注意到E、V和A三個字母,分別代表Encode、Video和Audio,說明這個選項在編碼中有效,對視訊和音訊有效。另外還有D,代表Decode,比如:

-ar <int> ED.A. set audio sampling rate (in Hz)

這個選項對編碼(Encode)、解碼(Decode)起作用,是音訊(Audio)方面的選項。

列出支援的編解碼器

$ffmpeg -codecs

列出支援的濾鏡

$ffmpeg -filters

列出支援的格式

$ffmpeg -formats

返回版本資訊

$ffmpeg -version

 

三、ffmpeg選項基本用法

用法:

$ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

選項 -> 輸入選項 -> 輸入檔案 … -> 輸出選項 -> 輸出檔案 …

我們稱帶橫線-的引數為選項(option),選項的值這裡稱為引數(argument),即 -option argumet。

說明:

(1)輸入檔案用-i指定;輸出檔案無選項,直接指定。

(2)選項-y 輸出檔案直接覆蓋已存在的檔案;-n 不覆蓋已存在檔案。

(3)選項區分先後順序,特別是輸入選項應對應輸入檔案,輸出選項對應輸出檔案;濾鏡呼叫也有順序;-map也是順序相關的。

(4)可以輸入多個檔案,輸出多個檔案。

 

好,用例子體會。

 

四、初步任務

一些簡單的音訊和視訊單獨編碼和轉換封裝

1、編碼音訊

例1、把3po.ac3壓成128Kbps的mp3

$ffmpeg -i 3po.ac3 -acodec libmp3lame -b:a 128000 3po_enc.mp3

說明:

(1)使用選項-acodec指定音訊編碼,如果用引數copy是直接複製相應的流。

(2)選項-b:a指定音訊位元速率,單位是bits/s;使用-aq指定音訊質量,具體數值和編碼有關。

 

2、視訊編碼

例2、把只有視訊的、編碼為xvid的obi-wan.avi壓成編碼為H264、封裝為mkv的視訊

$ffmpeg -i obi-wan.avi -vcodec libx264 -crf 22 -preset medium -tune film -deblock 1:1 -refs 4 -bf 8 -psy-rd 0.6:0.2 -subq 6 obi-wan_enc.mkv

說明:

(1)使用選項-vcodec指定音訊編碼,如果用引數copy是直接複製相應的流。引數指定libx264就是呼叫編譯在ffmpeg中的libx264。

(2) 這裡例子中的很多選項和直接使用x264是很像的,其中-crf、-preset、-tune、-deblock、-psy-rd等都是對應的,而 -refs對應x264的–ref,-subq對應–subme,-bf對應–bframes。寫法基本一致,具體可以參考幫助的libx264 AVOptions部分,但有些選項是在AVCodecContext AVOptions部分的。

(3)我們指定的輸出檔案為obi-wan.mkv,ffmpeg會根據副檔名用相應的封裝格式。

(4)編碼過程中按q停止。

例3、呼叫libx264 2 pass編碼,輸入檔案還是沒有音訊的obi-wan.avi

#1pass:
$ffmpeg -i obi-wan.avi -vcodec libx264 -preset medium -tune film -pass 1 -passlogfile 1pass.stats -crf 20 -f null obi-wan1p.mkv
 
#2pass:
$ffmpeg -i obi-wan.avi -vcodec libx264 -preset medium -tune film -pass 2 -passlogfile 1pass.stats -b:v 400000 obi-wan2p.mkv

說明:

(1)-pass指定某個pass,我們看到用ffmpeg編碼時1pass也可以用crf模式;用-passlogfile指定stats檔案。

(2)用-b:v指定位元速率,單位是bits/s。

(3)-f null不輸出檔案,其實後面輸出檔案的名字隨便,但至少要指定一個輸出;passlogfile還是會正常輸出的。

例4、改變視訊的解析度,這次是有音訊的r2d2.mkv,但是我們要把音訊去掉

$ffmpeg -i r2d2.mkv -an -vcodec libx264 -filter scale=480:204 r2d2_small.mkv

說明:

(1)用scale濾鏡調整解析度,用法是 -filter scale=out_w:out_h,寬:高。

(2)用選項-an去掉所有音訊流;-vn去掉所有視訊流;-sn去掉所有字幕流。流(stream)會在下面講。

(3)ffmpeg會根據輸入視訊流的DAR自動調整縮放後視訊的SAR,以保證DAR不變。

 

3、轉換封裝(remux),但不重編碼

例5、例子是有音訊的r2d2.mkv,轉換成mp4封裝

$ffmpeg -i r2d2.mkv -codec:v copy -codec:a copy r2d2_remux.mp4

說明:

(1) -codec:v copy表示不重編碼視訊, -codec:a copy表示不重編碼音訊

(2)這個例子再次說明了ffmpeg會根據副檔名選擇封裝

(3)因為只有音訊流和視訊流,因此可以用”-codec copy”代替”-codec:v copy -codec:a copy”

 

五、複雜一點的例子和為某些裝置編碼

1、更多濾鏡的例子

例6、對有音訊的r2d2.mkv先切邊(crop),再縮小(resize)

$ffmpeg -i r2d2.mkv -filter crop=1240:544:20:0,scale=464:204 -sws_flags lanczos r2d2_smaller.mp4

說明:

(1)crop 的用法是 -filter crop=out_w:out_h:x:y,寬:高:x座標:y座標。座標原點在左上角,往右x增加,往下y增加。因此 crop=1240:544:20:0代表在座標(20,0)處框出一個1240×544的框,框內部的畫面保留。

(2)濾鏡之間用逗號(,)分開。濾鏡有先後順序。

(3)這個例子中使用了選項-sws_flags指定縮放演算法,這裡指定了lanczos。

(4)我們沒有指定編碼,ffmpeg會自動使用輸入檔案的編碼壓一遍。

例7、把字幕嵌進視訊,視訊是r2d2.mkv,字幕是r2d2.ass

$ffmpeg -i r2d2.mkv -filter ass=r2d2.ass -codec:a copy r2d2_sub.mkv

說明:

(1)需要configure時有–enable-libass的ffmpeg

(2)這裡-codec:a等於-acodec;類似的,-codec:v等於-vcodec

 

2、為裝置編碼

例8、給iPhone 4壓片,源是解析度為1280×720的darth_vader.mkv,有1條2.0的音軌

我們知道,iPhone 4的解析度是960×640,因此片子解析度不需要那麼大。iPhone 4支援H264 level小於或等於3.1,音訊需要2.0聲道AAC,封裝是mp4。

我們先算好,960/(1280/720)=540,因此應該縮小到960/540。

$ffmpeg -i darth_vader.mkv -filter scale=960:540 -codec:v libx264 -f ipod -level 3 -preset slow -tune film -crf 20 -codec:a aac -b:a 160k darth_vader_iphone.mp4

說明:

如果懶得算解析度,就用 scale=960:-1,ffmpeg會自動按照比例調整。或者連原視訊的解析度都不需要知道,用scale=’min(960, iw):-1′,如果小於寬度960,就不動解析度,如果寬度大於960就縮小到960。scale的用法很靈活,具體參考
http://ffmpeg.org/ffmpeg.html#Video-Filters

 

3、只壓一部分

-ss 指定開始時間(s)

-t 指定視訊/音訊長度(s)

-fs 檔案到指定大小編碼結束,單位byte

-timelimit 指定ffmepg最大執行時間(s)

-frames 指定編碼幀數

例9、只編碼前500幀,用有一個視訊流和音訊流的padme.mkv作為例子

$ffmpeg -i padme.mkv -frames:v 500 padme_trim1.mkv

說明:

用-frames:v指定編碼視訊的幀數。

例10、從5分33.145秒開始到8分20.073秒結束

$ffmpeg -i padme.mkv -ss 00:05:33.145 -t 00:02:46.928 padme_trim2.mkv

說明:

(1)用-ss指定開始時間,用hh:mm:ss[.ms]格式,或者換算成用秒計。

(2)用-t指定長度,和-ss的格式一樣,用hh:mm:ss[.ms]格式,或者換算成用秒計。

(3)如果-ss放在-i之前,就會成為輸入選項,會先跳轉過去。如果-i放在輸出檔案前面,則會成為輸出選項,ffmpeg會先解碼到給定時間,再開始編碼行為,這樣做會比較慢,但更精確。

(4)如果想用這個方法無損分割(用-codec copy),是不一定能切準的。

 

六、更復雜的用法和pipe

1、流對映(stream mapping)選項-map

ffmpeg把輸入檔案的軌道稱為stream,如果我們只輸入darth_vader.mkv但不指定輸出

$ffmpeg -i darth_vader.mkv

會看到以下返回資訊

Input #0, matroska,webm, from 'darth_vader.mkv':

Duration: 00:22:52.09, start: 0.000000, bitrate: 2753 kb/s

Stream #0:0: Video: h264 (High), yuv420p, 1280×720, SAR 1:1 DAR 16:9, 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)

Stream #0:1: Audio: aac, 48000 Hz, stereo, s16 (default)

第一個輸入檔案的第一個流叫stream #0:0,編號是從0開始的,如果有兩個輸入,第二個輸入檔案的第一個流則是stream #1:0,依次類推。

音訊流、視訊流、字幕流的地位平等。

ffmpeg預設不調整流的順序,也不去掉任何流,如果想調整流的順序,或把不同檔案的流mux起來,需要用-map強制順序。ffmpeg會根據-map的先後順序調整輸出檔案中流的順序。

例11、把r2d2.mkv的視訊和darth_vader.mkv的音訊合成一個檔案

$ffmpeg -i r2d2.mkv -i darth_vader.mkv -map 0:0 -map 1:1 -c:v copy -c:a copy r2d2_remux.mkv

說明:

(1)這裡有兩個-i,輸入了兩個檔案。

(2)-c代表-codec。-c:v copy表示對所有的視訊流做copy;-c:a copy表示對所有的音訊流做copy。

 

2、多輸出

ffmpeg實際可以指定多個輸出檔案。把選項和輸出檔案按照順序寫下來即可。

例12、把yoda.m2ts的視訊remux成mkv格式,音訊壓成flac

$ffmpeg -i yoda.m2ts -map 0:0 -c:v copy yoda_v.mkv -map 0:1 -c:a flac yoda_a.flac

說明:

(1)第一個-map配合-c:v copy,輸出了第一個檔案yoda_v.mkv

(2)第二個-map配合-c:a flac,編碼了第二個輸出檔案yoda_a.flac

 

3、pipe

這個技巧經常用在32位avs配合64位x264上。ffmpeg可以輸出rawyuv或yuv4mpeg,pipe給x264

例13、用兩種方法把解析度為1280×720、fps為23.976的count_dooku.avs pipe給x264

$ffmpeg -i count_dooku.avs -f rawvideo - | x264 --input-res 1280x720 --fps 24000/1001 -o count_dooku_rawyuv.mkv -

$ffmpeg -i count_dooku.avs -f yuv4mpegpipe pipe: | x264 --demuxer y4m -o count_dooku_y4m.mkv -

說明:

(1)pipe時,ffmpeg的輸出用-或pipe:,x264的輸入用-,兩個程式用|分開

(2)前一個例子pipe rawyuv,需要為x264指定–input-res、–input-csp和–fps。由於兩者預設色彩空間相同,因此–input-csp可以省掉;指定–fps是為了更準的位元速率控制

(3)後一個例子pipe yuv4mpeg,不需要為x264指定解析度等格式。

例14、一邊pipe給x264做1pass,一邊壓出ffv1,以count_dooku.avs作為例子

$ffmpeg -i count_dooku.avs -vcodec ffv1 count_dooku_ffv1.mkv -f yuv4mpegpipe - | x264 --demuxer y4m -o count_dooku_1p.mkv -p 1 --stats 1p.stats -

說明:

純蛋疼

 

4、其他

例15、隔行掃描視訊luke.m2ts,先用yadif反交錯並縮小,再用libx264壓

$ffmpeg -i luke.m2ts -filter yadif:scale=1280:-1 -v:c libx264 -c:a copy luke_deint.mkv

說明:

yadif是反交錯濾鏡,縮放應在反交錯之後。

例16、把視訊darth_sidious.mkv的每一幀輸出成png

$ffmpeg -i darth_sidious.mkv darth_sidious%03d.png

說明:

(1)會浪費大量硬碟空間。

(2)%03d的行為和C語言的格式化字元一樣。

 

七、總結

ffmpeg和avconv是通用的編解碼工具,可以勝任絕大多數編碼的任務。雖然上面的例子幾乎都可以用專門性更強的工具解決,但像ffmpeg和 avconv功能如此多、用起來如此方便的工具的是找不到第四個的(因為還有mencoder,但已經很久不開發了,在mplayer2中甚至被拿掉 了)。

-vcodec和-acodec是選擇編碼的核心選項。但這是原來的寫法,面向未來,這兩個選項統一成了-codec,通過選 擇stream指定,即-codec:v和-codec:a,或者簡寫成-c:v和-c:a。ffmpeg和avconv有越來越多選項可以選擇 stream,比如-filter、-frames、-q。應該多使用-codec:v這種形式的寫法。

 

參考

http://ffmpeg.org/ffmpeg.html

http://libav.org/documentation.html

http://howto-pages.org/ffmpeg/