流的操作(二)如何選擇流?

白狼棧發表於2021-07-13

轉發自白狼棧:檢視原文

流的操作(一)視訊轉音訊引發的血案一文中我們瞭解到,流的選擇,實際有兩種方式,一種是ffmpeg自動選擇,一種是設定引數手動選擇。

對於自動選擇,ffmpeg預設選擇規則如下:

  1. 視訊流:預設選擇解析度最高的流
  2. 音訊流:預設選擇通道最多的流
  3. 字幕流:預設選擇第一個字幕編碼器支援的字幕流

對於視訊流和音訊流,如果解析度相等或者通道相等則以第一個為準,資料流和附件流不支援自動選擇,需要手動選擇。

自動選擇的情況下,ffmpeg每種型別只會選擇一路,舉個例子

ffmpeg -i r3.mp4 -hide_banner 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'r3.mp4': 
... 
Duration: 00:00:58.54, start: 0.000000, bitrate: 1998 kb/s 
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 544x960, 1732 kb/s, 29.83 fps, 29.83 tbr, 11456 tbn, 59.67 tbc (default) 
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 129 kb/s (default) 
Stream #0:2(und): Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)

 

注:Stream #0:0,第一個0表示第一個輸入檔案,第二個0表示第一個輸入檔案的第一路流

如果我們直接對 r3.mp4 轉碼操作,你會發現輸出的視訊只保留了一路視訊和一路音訊。

1、ffmpeg -i r3.mp4 tmp-r3.mp4 
2、ffmpeg -i tmp-r3.mp4 
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 544x960, 1684 kb/s, 29.83 fps, 29.83 tbr, 11456 tbn, 59.67 tbc (default) 
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 129 kb/s (default)

 

這就是ffmpeg自動選擇的結果。

如果想要輸入視訊的Stream #0:2這路音訊流,就只能手動指定了。

流的手動模式,使用 -map 引數操作,-map 非常重要,後面我們還會反覆使用它。它表示我們需要從輸入檔案中選擇哪些流到輸出檔案。

語法規則:

-map [-]input_file_index[:stream_type_specifier][:stream_index]

 

  1. 中括號[]表示可選,input_file_index 之前的 - 表示反選,即可以剔除某一路流。
  2. input_file_index 指的是某個輸入檔案,我們可以用下標0表示第一個輸入檔案,1表示第二個輸入檔案,以此類推;
  3. stream_type_specifier (可選)指的是指定輸入檔案的某路流的型別,我們用 a、v、s、d、t分別表示音訊流、視訊流、字幕流、資料流和附件流;
  4. stream_index(可選)指的是具體的某個型別的某路流。

我們仍然以案例一的素材視訊為例(沒有下載的可以點選這裡下載

如果我們以r1ori.mp4為輸入,想得到r3.mp4的結果,即多了一路音訊流且是mp3格式的,怎麼做?

ffmpeg -i r1ori.mp4 -map 0:v -map 0:a:0 -map 0:a:0 -c:v copy -c:a:0 copy -c:a:1 libmp3lame -y r3.mp4
注意輸出程式碼段Stream mapping這一段
Stream mapping: 
Stream #0:0 -> #0:0 (copy) 
Stream #0:1 -> #0:1 (copy) 
Stream #0:1 -> #0:2 (aac (native) -> mp3 (libmp3lame))

 

簡單分析下

  1. 因為只有一個輸入檔案,所以-map的第一個引數都是0
  2. -map 0:v 表示選擇輸入檔案的所有視訊流(這裡視訊流只有一個)到輸出,-c:v copy表示複製所有的視訊流,即你看到的 Stream #0:0 -> #0:0 (copy)
  3. -map 0:a:0 我們寫了兩遍,第一個表示選擇輸入檔案的第一個音訊流到輸出,第二個仍然表示選擇輸入檔案的第一個音訊流到輸出,相當於輸出了兩路音訊流
  4. -map 0:v -map 0:a:0 -map 0:a:0 連起來也有關係,表示要按照我們選擇的這三路順序輸出
  5. -c:a:0 copy 針對第一個音訊流進行復制,不重新編碼,即 Stream #0:1 -> #0:1 (copy); -c:a:1 libmp3lame 針對第二個音訊流使用libmp3lame編碼器重新編碼,即輸出過程中的 Stream #0:1 -> #0:2 (aac (native) -> mp3 (libmp3lame))

後面我們還會大量使用-map命令,所以上面這段分析,務必要理解清楚。

上面的命令同樣等價於

ffmpeg -i r1ori.mp4 -map 0:0 -map 0:1 -map 0:1 -c:v copy -c:a:0 copy -c:a:1 libmp3lame -y r3.mp4

 

-map 0:v 這裡等價於 -map 0:0,-map 0:a:0 等價於-map 0:1,這是因為在r1ori.mp4中#0:0就是視訊流,#0:1就是音訊流

ffmpeg -i r1ori.mp4 
... 
Stream #0:0(und): Video: h264 
Stream #0:1(und): Audio 
...

 

注意:-map的引數,針對的是輸入流,因為是我們想要從輸入流中選擇流到輸出;-c選項的引數,針對的並不再是輸入流了,-c的引數針對的是-map選擇的流,即輸出流。

除此之外,下面我們再看幾個簡單的例子,你可以在看結果之前嘗試下

1、複製輸入檔案的所有流到輸出,輸出結果可就不止只有兩路流了

ffmpeg -i r3.mp4 -map 0 -c copy output.mp4

 

2、把輸入檔案的三路流分別拆開,輸出三個檔案

ffmpeg -y -i r3.mp4 -map 0:v -c:v copy output-silent.mp4 \
-map 0:a:0 -c:a copy output-audio.aac \
-map 0:a:1 -c:a copy output-audio.mp3

 

我們還可以設定一些選項,比如可以設定r3.mp4的兩路音訊流有不同的位元速率。

ffmpeg -i r3.mp4 -b:a:0 32k -b:a:1 64k -map 0 -y r4.mp4

 

-map 0 是必須的,不然輸出結果並不會輸出兩路音訊流。

對於音視訊流還有很多選項設定,具體你可以查閱官方文件瞭解,你也可以在我們平時練習中多查閱資料,奠定基礎。

最後,我們還有一種最最常見的操作——結合濾鏡使用。

比如把原視訊 r3.mp4 等比例縮放一倍

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

 

我們也可以手動選擇流處理

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

 

上面這兩條命令你可能很難理解,關於濾鏡,大家先有個印象,下面文章我們再作詳細介紹。

流的操作我們就介紹到這裡,大家在練習中碰到各種莫名其妙的問題,儘管留言。

相關文章