寫在前面
最近正好有音視訊編輯的需求,雖然之前粗略的瞭解過FFmpeg不過肯定是不夠用的,藉此重新學習下;
基本概念
容器/檔案(Conainer/File):
即特定格式的多媒體檔案,一般來說一個視訊檔案是由視訊,音訊,字幕等按特定的格式/規則組合到一起的,常見如:
mp4
flv
mkv
avi
媒體流(Stream):
表示時間軸上的一段連續資料,如一段聲音資料、一段視訊資料或一段字幕資料,可以是壓縮的,也可以是非壓縮的,壓縮的資料需要關聯特定的編解碼器。
資料幀/資料包(Frame/Packet):
通常,一個媒體流是由大量的資料幀組成的,對於壓縮資料,幀對應著編解碼器的最小處理單元,分屬於不同媒體流的資料幀交錯儲存於容器之中。
一般: Frame對應壓縮前的資料,Packet對應壓縮後的資料。
編解碼器(Codec):
視訊和音訊都需要經過編碼,才能儲存成檔案。編解碼器是指以幀為單位實現壓縮資料和原始資料之間的相互轉換的;
編碼:原始資料->壓縮資料;
解碼:壓縮資料->原始資料;
不同的編碼格式(CODEC),有不同的壓縮率,會導致檔案大小和清晰度的差異。
常用的視訊編碼格式如下:
H.262
H.264
H.265
示例:原始圖形YUV資料用H.264編碼成H264幀
常用的音訊編碼格式如下:
MP3
AAC
示例:原始聲音PCM資料用AAC編碼器編碼成AAC幀(是的音訊也有幀)
複用(mux):
把不同的流按照某種容器的規則放入容器,這種行為叫做複用(mux)
解複用(mux):
把不同的流從某種容器中解析出來,這種行為叫做解複用(demux)
幀率(Frame rate):
n幀率也叫幀頻率,用FPS表示。幀率是視訊檔案中每一秒的幀數,肉眼想看到連續移動影像至少需要15幀。
一般電影的幀率為24;
位元速率(Bit Rate):
位元率(也叫位元速率,資料率)是一個確定整體視訊/音訊質量的引數,秒為單位處理的位數,位元速率和視訊質量成正比,在視訊檔案中中位元率用bps(bit per second)來表達。
位元速率越低,表示壓縮程度越高,畫質越差。
位元速率越高,視訊質量相對越高,視訊檔案也就越大。
FFmpeg
FFmpeg是一個很多的專案,包括很多元件:
- ffmpeg——一個命令列工具,用來對視訊檔案轉換格式,也支援對電視卡即時編碼
- ffserver——一個HTTP多媒體即時廣播流伺服器,支援時光平移
- ffplay——一個簡單的播放器,基於SDL與FFmpeg庫
- libavcodec——包含全部FFmpeg音訊/視訊編解碼庫
- libavformat——包含demuxers和muxer庫
- libavutil——包含一些工具庫
- libpostproc——對於視訊做前處理的庫
- libswscale——對於視訊作縮放的庫
我們一般說的的FFmpeg 是指FFmpeg 的命令列工具;
第一條FFmpeg命令
ffmpeg -y -i input.mp4 -acodec copy -vcodec libx264 -s 720x1280 output.avi
引數解析
-y # 全域性引數,等於npm -y
-i input.mp4 #輸入檔案,FFmpeg命令有位置之分, -i 之前是輸入引數,之後是輸出引數
-acodec copy #輸出檔案引數,複製音訊編碼而不用重新編碼
-vcodec libx26 #輸出檔案引數,重新用libx26編碼(比較慢耗效能)
-s 720x1280 #輸出引數,
output.avi #輸出檔案
可以看到,FFmpeg一般分為這五個部分,大家參考上面命令對號入座
全域性引數
輸入檔案引數
輸入檔案
輸出檔案引數
輸出檔案
所以這條命令的含義是:把視訊input.mp4不修改音訊的情況下用libx26編碼音訊,同時解析度改成720*1280,格式改成avi;
視訊資訊
左:input.mp4 ,右:output.avi
可以看到視訊檔案已經完成了命令操作轉換;
FFmpeg常用引數
-c:指定編碼器
-c copy:直接複製,不經過重新編碼
-c:v:指定視訊編碼器
-c:a:指定音訊編碼器
-i:指定輸入檔案
-an:去除音訊流
-vn: 去除視訊流,不處理視訊
-preset:指定輸出的視訊質量,會影響檔案的生成速度,有以下幾個可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
-y:不經過確認,輸出時直接覆蓋同名檔案。
-s: size 設定幀大小 格式為WXH 預設160X128.下面的簡寫也可以直接使用:Sqcif 128X96 qcif 176X144 cif 252X288 4cif 704X576
-b: bitrate 設定位元率,預設200kb/s
-vcodec: codec 強制使用codec編解碼方式。 如果用copy表示原始編解碼資料直接被拷貝。
-filter: 視訊過濾器,如 -filter:v "crop=w:h:x:y"用過濾器v裁剪視訊
w - 源視訊中裁剪的矩形的寬度
h – 矩形的高度。
x – 我們想自源視訊中裁剪的矩形的 x 座標 。
y – 矩形的 y 座標。
-aspect:設定橫縱比 4:3 16:9 或 1.3333 1.7777
-ss:position 搜尋到指定的時間 [-]hh:mm:ss[.xxx]的格式也支援,比如用來指定剪下開始時間
FFmpeg命令處理流程
我們還是以這條命令為例,分析FFmpeg命令對視訊的處理經過哪些流程
ffmpeg -y -i input.mp4 -acodec copy -vcodec libx264 -s 720x1280 output.avi
我們看圖:
我們看到命令處理一般分成5個步驟
- 解複用:把容器檔案解析成編碼的資料包;
- 解碼:解碼器把資料包解碼成資料幀;
- filter進行幀處理:把1080 * 1920的資料幀處理成720 * 1280
- 重新編碼:編碼器libx264重新把資料幀編碼成編碼的資料包;
- 複用:把資料包按格式avi封裝;
這個簡單流程比較重要,要了然於心;
FFmpeg常用命令
列印視訊基本資訊
$ ffmpeg -i input.mp4 -hide_banner
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42mp41isomavc1
creation_time : 2021-05-29T16:51:47.000000Z
Duration: 00:00:30.61, start: 0.000000, bitrate: 5932 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920, 5672 kb/s, 60 fps, 60 tbr, 60 tbn (default)
Metadata:
creation_time : 2021-05-29T16:51:47.000000Z
handler_name : L-SMASH Video Handler
vendor_id : [0][0][0][0]
encoder : AVC Coding
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 253 kb/s (default)
Metadata:
creation_time : 2021-05-29T16:51:47.000000Z
handler_name : L-SMASH Audio Handler
vendor_id : [0][0][0][0]
At least one output file must be specified
轉換格式修改解析度
ffmpeg -y -i input.mp4 -s 720x1280 output.avi
視訊靜音處理(移除音訊)
ffmpeg -i input.mp4 -an quiet.mp4
從視訊中提取圖片
ffmpeg -i input.mp4 -r 1 -f image2 -ss 00:00:10 -t 2 image-%2d.png
-
-r
– 設定幀速度。即,每秒提取幀到影像的數字。預設值是 25。 -
-f
– 表示輸出格式,即,在我們的例項中是影像。 -
image-%2d.png
– 表明我們如何想命名提取的影像。在這個例項中,命名應該像這樣image-01.png、image-02.png、image-03.png 等等開始。如果你使用%3d
,那麼影像的命名像 image-001.png、image-002.png 等等開始。
新增/修改封面
ffmpeg -y -i input.mp4 -i cover.png -map 0 -map 1 -c copy -disposition:v:1 attached_pic cover_output.mp4
如果需要把視訊第一幀截出來坐封面,那就先提取
ffmpeg -ss 00:00:01 -i input.mp4 -f image2 cover.png
提取視訊裡的音訊檔案
ffmpeg -i input.mp4 -vn -c:a copy output.aac
裁剪視訊
ffmpeg -i input.mp4 -filter:v "crop=640:480:120:240" cut.mp4
-
-filter:v
– 表示視訊過濾器。 -
crop
– 表示裁剪過濾器。 -
w
– 我們想自源視訊中裁剪的矩形的寬度。 -
h
– 矩形的高度。 -
x
– 我們想自源視訊中裁剪的矩形的 x 座標 。 -
y
– 矩形的 y 座標。
視訊擷取
ffmpeg -i input.mp4 -ss 00:00:05 -codec copy -t 10 cutout.mp4
-
-ss
開始時間 -
-t
10,擷取十秒
視訊切割拆分成多個
ffmpeg -i input.mp4 -t 00:00:13 -c copy part1.mp4 -ss 00:00:13 -codec copy part2.mp4
-
-t 00:00:13
表示從視訊的開始到視訊的第 30 秒建立一部分視訊。 -
-ss 00:00:13
為視訊的下一部分顯示開始時間戳。它意味著第 2 部分將從第 30 秒開始,並將持續到原始視訊檔案的結尾。
視訊合併拼接
ffmpeg -i "concat:part1.mp4|part2.mp4" -c:a copy -c:v copy combine.mp4
設定視屏遮蔽寬高
ffmpeg -i input.mp4 -aspect 4:3 4_3.mp4
通常使用的高寬比是:
- 16:9
- 4:3
- 16:10
- 5:4
- 2:21:1
- 2:35:1
- 2:39:1
新增字幕
ffmpeg -i input.mp4 -i subtitle.srt -c copy output.mkv
是字幕檔案,然後這裡選用的是軟字幕方式比較快
總結
根據專案需要,簡單學習了下音視訊的非常基本的概念和FFmpeg的基本使用,留個記錄;
[參考]
https://www.ruanyifeng.com/blog/2020/01/ffmpeg.html
https://zhuanlan.zhihu.com/p/67878761
廖慶富視訊教程