ffmpeg第7篇:資料流選擇神器-map指令

愉快程式設計發表於2021-11-04

自動選擇規則

ffmpeg在處理視訊時,如果只提供了輸入和輸出引數,ffmpeg會自動地去選擇相應的視訊流和音訊流來合成檔案

自動選擇的方式根據如下規則:

  • 視訊流:選解析度最高的,比如有兩個視訊,一個是1080,一個是720,會選擇1080的作為預設的視訊流
  • 音訊流:選通道數最多的,比如兩個視訊,一個無聲音,一個有聲音,會自動選擇有聲音的音訊流作為最終的輸出,如果A視訊是1080無聲音,B視訊是720有聲音,那麼最終輸出的檔案畫面是A視訊的,聲音是B視訊的
  • 字幕:選第一個被檢索到的字幕流,如果兩個視訊都有字幕,那就是第一個輸入的第一個字幕流,其它的忽視

為了驗證上面的規則,來做個測試:

現有兩個視訊檔案noaudio.mp4和normal.mp4

其中noaudio.mp4是720解析度,沒有聲音, normal.mp4是360解析度,有聲音
執行如下命令:

ffmpeg -v quiet -i noaudio.mp4 -i normal.mp4 out.mp4

結果:out的畫面是noaudio.mp4的,而聲音是normal.mp4的

map指令

ffmpeg的自動選擇規則,顯然並不能總是符合需求,所以有了map指令

官方文件描述如下:

When -map is used, only user-mapped streams are included in that output file(只有被使用者選擇的流才會被用到輸出檔案中)

同樣拿上面的兩個檔案,做以下測試

ffmpeg -i noaudio.mp4 -i normal.mp4 -map 1:a -acodec copy out.mp4
-map 1:a的意思是:輸出檔案的音訊使用第二個檔案的音訊,這次,在out.mp4中,雖然是mp4格式檔案,但是只有聲音,沒有畫面

再做個測試

ffmpeg -i noaudio.mp4 -i normal.mp4 -map 1:a -acodec copy -vcodec copy out.mp4

這次指定了視訊的編碼方式,使用原視訊編碼方式不重新編碼,然而out檔案依然只有聲音

再做測試

ffmpeg -i noaudio.mp4 -i normal.mp4 -map 1:a -map 0:v -acodec copy -vcodec copy out.mp4
這次用0:v來指定輸出檔案使用第一個檔案的視訊,這次out是第一個檔案的畫面,第二個檔案的聲音

那現在再考慮一個問題:如果指定使用第一個檔案(noaudio.mp4)的音訊會如何呢

繼續測試:

ffmpeg -i noaudio.mp4 -i normal.mp4 -map 0:a -map 1:v -acodec copy -vcodec copy out.mp4 -y

執行時出錯了,提示如下:

Stream map '0:a' matches no streams.
To ignore this, add a trailling '?' to the map

意思是指定的音訊沒有匹配到,但是可以加個問題忽略這個map,那加上"?"嘗試一下:

ffmpeg -i noaudio.mp4 -i normal.mp4 -map 0:a? -map 1:v -acodec copy -vcodec copy out.mp4 -y

這次成功執行,但是out中只有畫面,沒有聲音,說明問號的功能僅僅是忽視這個map,並不會重新選擇新的音訊

未命名濾鏡如何處理

現在有兩個檔案:ftwo.mp4是720解析度,scale.mp4是360解析度。

overlay是水印濾鏡,我們們之前的文章中已經講過了,如果不清楚可以去看。

執行下面命令:

ffmpeg -i ftwo.mp4 -i scale.mp4 -filter_complex "overlay" out.mp4 -y

out.mp4檔案中,scale.mp4覆蓋到ftwo.mp4的左上角,聲音用的是scale.mp4的

把兩個檔案的輸入順序顛倒一下試試:

ffmpeg -i scale.mp4 -i ftwo.mp4 -filter_complex "overlay" out.mp4 -y

這次是ftwo.mp4覆蓋住了scale.mp4,由於scale.mp4解析度小,所以scale.mp4被完全覆蓋住,畫面也只截了ftwo.mp4左上角640*360的畫面,而不是1280*720。

但是聲音依然用的是scale的聲音,因為scale.mp4時長是是10s,而ftwo.mp4時長是17秒,在合成時ffmpeg會預設用時長較短的那個檔案作為輸出檔案的時長,對應的音訊也用這個,所以上面兩個輸出檔案的時長都是10s,ftwo後面的視訊就被截斷了。

有命名的濾鏡如何處理

看這個命令:

ffmpeg -i ftwo.mp4 -i three_scale.mp4 -i oness_scale.mp4 \
-filter_complex "[1:v]hue=s=0[out];overlay;aresample" \
-map '[out]' -an out1.mp4

這裡有個命名的濾鏡:out,它將第二個輸入檔案的顏色飽和度s設定為0。

還有兩個未命名的濾鏡:overlay、aresample

命令執行完,發現out1.mp4是ftwo.mp4的畫面和聲音。

為什麼會這樣呢?map和an指令沒起作用。

根據官方文件解釋,因為有兩個未命名濾鏡,所以ffmpeg會把這兩個未命名的濾鏡結果直接輸出給第一個輸出檔案,也就是out1,這時會忽略map指令。

至於an指令,這個指令只作用於自動選擇音訊流時或手動指定了音訊流,對於濾鏡輸出的流是不起作用的,所以這裡也會忽視掉an。

基於以上解釋,這裡雖然用了out濾鏡,但是其並沒起作用,第二個輸入檔案也等於沒用。

我們們改一下命令再試試:

ffmpeg -i ftwo.mp4 -i three_scale.mp4 -i oness_scale.mp4 \
-filter_complex "[1:v]hue=s=0[out];overlay;aresample" \
-map '[out]' -an out1.mp4 out2.mp4

結果out1與上面一樣,out2是第一個輸入檔案的畫面,第二個輸入檔案的聲音。

這是因為out2前面沒有map,所以觸發了ffmpeg的自動選擇規則,預設用第一個檔案的畫面,由於第二個檔案的時長短,所以將第一個檔案截斷了,且用的第二個檔案的聲音。

再改一下命令,既然map和an沒用,就去掉

ffmpeg -i ftwo.mp4 -i three_scale.mp4 -i oness_scale.mp4 \
-filter_complex "[1:v]hue=s=0[out];overlay;aresample" \
out1.mp4 out2.mp4

然而這次出錯了:
Filter hue has an unconnected output

錯誤意思是:out濾鏡沒有指定輸出檔案。

這說明一旦指定了命名濾鏡,就必須用上

再改下命令

ffmpeg -i ftwo.mp4 -i three_scale.mp4 -i oness_scale.mp4 \
-filter_complex "[1:v]hue=s=0[out];overlay;aresample" \
-map '[out]' -an out1.mp4 out2.mp4 \
-map '[out]' -map 0:a:0 out2.mp4

這次將濾鏡用了兩次,再次報錯:
Output with label 'out' does not exist in any defined filter graph,or was already used elsewhere.

意思是濾鏡沒用過或者已經用過了,這說明一個濾鏡只能使用一次,且必須使用一次

既然如此,我們們只能將濾鏡分開了,修改命令如下:

ffmpeg -i ftwo.mp4 -i three_scale.mp4 -i oness_scale.mp4 \
-filter_complex "[1:v]hue=s=0,split=[out1][out2];overlay;aresample" \
-map '[out1]' -an out1.mp4 \
-map '[out2]' -map 0:a:0 out2.mp4

這次用split將同一個濾鏡分成了兩個,分別使用,第一個上面已經分析過,不起作用。

第二個濾鏡起作用了,且根據後面的map,使用了第一個輸入檔案的第一個音訊,所以out2是二個檔案的畫面,第一個檔案的音訊,這下怎麼用清楚了嗎?。

ffmpeg系列文章目錄

ffmpeg第1篇:日誌級別控制、儲存日誌到指定檔案、處理進度查詢
ffmpeg第2篇:簡單濾鏡與複雜濾鏡的區別
ffmpeg第3篇:為視訊新增靜態水印
ffmpeg第4篇:為視訊新增動態水印
ffmpeg第5篇:讓水印圖片旋轉起來
ffmpeg第6篇:濾鏡語法
ffmpeg第7篇:資料流選擇神器-map指令

番外篇

ffmpeg番外篇:聽說這款水印曾經在某音很火?辦它!

有問題請留言溝通,歡迎轉載,轉載請註明出處

更多精彩內容,歡迎點選個人部落格地址:愉快程式設計

相關文章