一次用ffmpeg實(shí)現(xiàn)圖片+音頻合成視頻的開發(fā)

一、需求

用戶針對(duì)一個(gè)PPT的每一頁圖片,進(jìn)行語音錄制,輸出多段音頻文件,將用戶每段音頻和對(duì)應(yīng)的PPT圖片拼接起來,最后輸出成一整段MP4視頻,作為教學(xué)視頻播放

二、方案選擇

針對(duì)需求,最開始提出了幾個(gè)主要的方案

方案 優(yōu)點(diǎn) 缺點(diǎn)
方案一:直播推流錄制 使用現(xiàn)成直播方案,上手成本小 業(yè)務(wù)邏輯要和直播業(yè)務(wù)切割隔離,重新弄一套,不合適,而且感覺殺雞用牛刀
方案二:客戶端處理圖片、音頻合成,視頻拼接等多媒體操作 1、后端業(yè)務(wù)簡單;
2、大多數(shù)視頻處理類APP都是如此,方案成熟
1、前端要新嵌入七牛多媒體處理SDK,對(duì)包穩(wěn)定性有影響
2、APP處理視頻,可能比較耗費(fèi)手機(jī)性能,如果APP受眾用戶是中老年用戶,可能手機(jī)性能扛不住
方案三:服務(wù)端統(tǒng)一處理圖片、音頻合成,視頻拼接等多媒體操作 1、客戶端無需再嵌入SDK
2、對(duì)用戶手機(jī)性能的要求降到最低
服務(wù)端交互邏輯變復(fù)雜,并且要處理耗時(shí)的多媒體合成任務(wù)

最終定了方案三,原因是該功能的受眾是老年用戶,手機(jī)性能可能很差,耗時(shí)的操作交給服務(wù)端來比較合適

三、方案執(zhí)行

3.1 初版方案

查詢了一下,對(duì)應(yīng)圖片+音頻合成視頻,這樣的音畫合成的操作,七牛并沒有提供API~
所以只能服務(wù)端采用萬能的多媒體處理工具:ffmpeg 了,整體方案如下


ppt錄制ffmpeg處理方案流程.png

可以看到上述方案,有兩個(gè)關(guān)鍵操作:

關(guān)鍵操作 描述 如何觸發(fā)
音畫合成 圖片+音頻合成視頻 客戶端接口觸發(fā),用戶每錄一段語音,則服務(wù)端立馬調(diào)異步任務(wù)進(jìn)行音畫合成
視頻mp4拼接 不同的視頻片段拼接成一整段視頻 客戶端接口觸發(fā),用戶點(diǎn)擊預(yù)覽或提交審核,服務(wù)端檢查所有語音片段是否音畫合成完畢,條件符合則進(jìn)行視頻mp4拼接

注意,七牛提供了視頻mp4拼接的接口,但是經(jīng)過實(shí)踐,用ffmpeg進(jìn)行本地視頻mp4拼接沒有任何問題,并且速度很快,所以這里所有操作都用 本地 ffmpeg 來進(jìn)行

ffmpeg 不具體介紹,詳情可自行g(shù)oogle:

官網(wǎng):https://ffmpeg.org/

參數(shù)詳解:https://zhuanlan.zhihu.com/p/31674583

具體ffmpeg的命令執(zhí)行操作,第一版的執(zhí)行如下:

關(guān)鍵操作 描述 ffmpeg操作和參考
音畫合成 圖片+音頻合成視頻 ffmpeg -i 1976.aac -i mulan.jpg -acodec aac -strict -2 -vcodec libx264 -ar 22050 -ab 128k -ac 2 -pix_fmt yuvj420p -y conf_liutao_test1.mp4
參考來源:https://blog.51cto.com/cjxkaka/1569109
視頻mp4拼接 不同的視頻片段拼接成一整段視頻 如下
$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat 
-i mylist.txt 
-c copy output

不同的視頻片段拼接成一整段視頻
參考來源:我是Stack Overflow鏈接
參考上面 Stack Overflow回答中”Jack Miller“ 的回答

3.2 遇到的問題和優(yōu)化

問題1. 音畫合成的視頻,在有些瀏覽器中無法拖動(dòng)進(jìn)度條

咨詢了人森導(dǎo)師手哥,他給我介紹了一個(gè)工具:mediainfo,該工具可以查看視頻詳情,如音軌(Audio)和畫面(Video)的時(shí)長,通過該工具可以看到通過第一版操作音畫合成的視頻,畫面時(shí)長只有40ms,然而音軌時(shí)長卻有7s,這里存在嚴(yán)重的不同步,因此在有些瀏覽器(safari)中并不能正常拖動(dòng)進(jìn)度條播放:


quiz_audioD_videoD.png

問題1的解決辦法

參考:Combine one image + one audio file to make one video using FFmpeg

中"community wiki"的回答,使用如下ffmpeg命令可以正常生成Video_Duration和Audio_Duration接近的視頻

ffmpeg -loop 1 -i xuanwu.jpg 
-i 1.aac 
-c:v libx264 -tune stillimage 
-c:a aac -b:a 192k -pix_fmt yuvj420p 
-shortest liutao_test_2.mp4

問題2:將不同的音畫合成后的視頻片段拼接起來后生成的 最終課程錄制視頻,會(huì)有音畫不同步的問題

現(xiàn)象是明明是第一個(gè)PPT的錄音,畫面已經(jīng)翻到PPT第二頁了,錄音還在播放第一頁P(yáng)PT尾段的錄制語音

原因:通過 mediainfo 查看最后生成的 最終拼接視頻,發(fā)現(xiàn)還是存在 Video_Duration和Audio_Duration 不一致的問題

應(yīng)該是第一步音畫合成的視頻片段本身就有 Video_Duration和Audio_Duration 不完全一致,將他們拼接起來后,是音軌和畫面軌道分別拼接,最后兩條軸出現(xiàn)了不一致的問題。

因此,我們需要在第一步音畫合成的時(shí)候做處理,讓 Video_Duration和Audio_Duration 保持嚴(yán)格一致或盡量接近

問題2的解決辦法

在音畫合成后,多一步操作,對(duì)合成的視頻片段,進(jìn)行人為剪裁~讓視頻的 Video_Duration和Audio_Duration 保持一致:

ffmpeg -i input.mp4 
-ss 00:00:00 
-t 00:00:11.72 
-acodec aac -vcodec h264 
-strict -2 cut_output.mp4

如此生成的視頻 Video_Duration和Audio_Duration 不會(huì)有太大差距。

問題3:安卓端的播放器,播放合成的課程視頻,依然無法拖動(dòng)視頻的進(jìn)度條

和安卓端同學(xué)溝通后,定位問題是視頻缺少關(guān)鍵幀,需要為視頻加入關(guān)鍵幀

問題3的解決辦法

參考:https://codeday.me/bug/20180927/259812.html

在音畫合成截?cái)啵歪槍?duì)視頻插入關(guān)鍵幀,關(guān)鍵命令:

ffmpeg -x264-params keyint=1:scenecut=0

上面的keyint=1表示每隔1幀插入設(shè)置一個(gè)關(guān)鍵幀

問題4:音畫合成的速度特別慢,音畫合成生成的文件也特別的大

首先觀察現(xiàn)象,發(fā)現(xiàn) 圖片大小為 212k,音頻 .aac 文件大小為 132k,生成的視頻文件居然會(huì)是540k

懷疑是幀率問題,google了一下,ffmpeg指令如果不人為設(shè)定幀率,默認(rèn)幀率為25,而我們音畫合成的視頻就是一張圖片,并不需要太高的幀率,這個(gè)地方應(yīng)該可以優(yōu)化下

問題4的解決辦法

參考:https://zhuanlan.zhihu.com/p/31674583

經(jīng)過人為設(shè)置幀率為1,生成文件大小優(yōu)化為356k

人為設(shè)置幀率為1的關(guān)鍵指令如下:

ffmpeg -r 1

同時(shí),寫了個(gè)小腳本,做了下實(shí)驗(yàn)驗(yàn)證,人為設(shè)置幀率,也大大降低了處理速度:

實(shí)驗(yàn):對(duì)比使用 -r 2 設(shè)置幀率(fps) 來對(duì)靜態(tài)圖的mp4處理速度和大小進(jìn)行優(yōu)化
第一組:幀率使用默認(rèn)值為25的處理:
Array
(
    [command] => ffmpeg -loop 1 -i mulan.jpg -i 1_min.aac -c:v libx264 -c:a aac -b:a 64k -pix_fmt yuvj420p -shortest liutao_test_1min_64k.mp4
    [spend] => 46401.793956757ms
)
第二組:幀率認(rèn)為設(shè)定為2的處理(使用 命令參數(shù) -r 2 認(rèn)為指定幀率為2):
Array
(
    [command] => ffmpeg -loop 1 -i mulan.jpg -i 1_min.aac -r 2 -c:v libx264 -c:a aac -b:a 64k -pix_fmt yuvj420p -shortest liutao_test_1min_64k_r2.mp4
    [spend] => 21741.201877594ms
)
生成文件大小的對(duì)比
[med@qa liutao]$ du -ak liutao_test_1min_64k.mp4 liutao_test_1min_64k_r2.mp4
1404    liutao_test_1min_64k.mp4
548 liutao_test_1min_64k_r2.mp4

從上面的實(shí)驗(yàn)看起來,針對(duì)1分鐘的音頻,人為設(shè)置幀率為2使得處理耗時(shí)降低了至少50%,生成文件大小降低了近60%

問題5:音畫合成后的視頻,截?cái)嗪笥謥G失了關(guān)鍵幀

音畫合成后的視頻,是帶有關(guān)鍵幀信息的,為何截?cái)嗪笥謥G失了關(guān)鍵幀?

經(jīng)過仔細(xì)對(duì)比,發(fā)現(xiàn)音畫合成和截?cái)嗟拿睿兄?xì)微差距

1,音畫合成:
ffmpeg -loop 1 
-i mulan.jpg 
-i 2191.aac 
-r 1 
-c:v libx264 -x264-params keyint=1:scenecut=0 
-c:a aac 
-b:a 32k -pix_fmt yuvj420p  
-shortest 
liutao_test_2191_mulan_r1_key1.mp4
2,截?cái)啵?ffmpeg -i output1.mp4 
-ss 00:00:00 
-t 00:00:06.80 
-acodec aac 
-vcodec h264 
-strict -2 output1_cut.mp4

仔細(xì)觀察上面兩個(gè)命令,經(jīng)過google,發(fā)現(xiàn) 【-c:a】和【-acodec】是一個(gè)意思,表示音頻編碼方式,【-c:v】和【-vcodec】是一個(gè)意思,表示視頻編碼方式

這里兩個(gè)指令的 視頻編碼方式,一個(gè)指定的使用 libx264,一個(gè)使用h264, 懷疑是這里的不一致導(dǎo)致關(guān)鍵幀丟失

經(jīng)過試驗(yàn),發(fā)現(xiàn)猜測正確。

問題5的解決辦法:

將音畫合成和視頻截?cái)嗟囊纛l解碼方式統(tǒng)一為 libx264,就能保證截?cái)嗪笠曨l的關(guān)鍵幀不丟失:

1,音畫合成:
ffmpeg -loop 1 
-i mulan.jpg 
-i 2191.aac 
-r 1 
-c:v libx264 -x264-params keyint=1:scenecut=0 
-c:a aac 
-b:a 32k -pix_fmt yuvj420p  
-shortest 
liutao_test_2191_mulan_r1_key1.mp4
2,截?cái)啵?ffmpeg -i output1.mp4 
-ss 00:00:00 
-t 00:00:06.80 
-acodec aac 
-vcodec libx264 -x264-params keyint=1:scenecut=0 
-strict -2 output1_cut.mp4

3.3 最終的視頻處理命令

三個(gè)步驟:

  1. 音畫合成,圖片+音頻合成視頻
ffmpeg -loop 1 
-i mulan.jpg 
-i 2191.aac 
-r 1 
-c:v libx264 -x264-params keyint=1:scenecut=0 
-c:a aac 
-b:a 32k 
-pix_fmt yuvj420p  
-shortest liutao_test_2191_mulan_r1_key1.mp4

該指令人為設(shè)置合成幀率為1,降低處理耗時(shí)和生成文件大小,
人為設(shè)置關(guān)鍵幀間隔為每間隔1幀設(shè)置一個(gè),解決安卓RN播放無法拉動(dòng)進(jìn)度條的問題

  1. 對(duì)音畫合成后的視頻片段進(jìn)行截?cái)?/li>
ffmpeg 
-ss 00:00:00 
-t 00:00:20.096 
-accurate_seek 
-i liutao_test_pre_2191.mp4 
-acodec aac 
-vcodec libx264 -x264-params keyint=1:scenecut=0 
-strict -2 
liutao_test_final_2191.mp4

參考:我是CSDN博客鏈接
截?cái)嗍菫榱吮WC音軌長度和畫面軌道長度
盡量保持一致,杜絕拼接后的音畫不同步問題

  1. 視頻mp4拼接,不同的視頻片段拼接成一整段視頻
$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat 
-i mylist.txt 
-c copy output

參考來源:我是Stack Overflow鏈接
參考上面 Stack Overflow回答中”Jack Miller“ 的回答

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,762評(píng)論 0 3
  • 最近學(xué)習(xí)播放器的一些東西,所以接觸了ffmpeg,看源碼的過程中,就想了解一下ffplay是怎么處理音視頻同步的,...
    smm987閱讀 4,441評(píng)論 0 5
  • ### YUV顏色空間 視頻是由一幀一幀的數(shù)據(jù)連接而成,而一幀視頻數(shù)據(jù)其實(shí)就是一張圖片。 yuv是一種圖片儲(chǔ)存格式...
    天使君閱讀 3,394評(píng)論 0 4
  • 0 概述 FFmpeg是一套領(lǐng)先的音視頻多媒體處理開源框架,采用LGPL或GPL許可證。它提供了對(duì)音視頻的采集、編...
    但行耕者閱讀 6,916評(píng)論 0 19
  • 我近期的目標(biāo)是讓兒子快樂學(xué)習(xí)、提高的學(xué)習(xí)熱情和書寫的認(rèn)真,提升學(xué)習(xí)成績,各科成績達(dá)到95分,為小升初打下堅(jiān)實(shí)的基礎(chǔ)...
    歸韻閱讀 120評(píng)論 0 3