一、需求
用戶針對一個PPT的每一頁圖片,進行語音錄制黄虱,輸出多段音頻文件,將用戶每段音頻和對應(yīng)的PPT圖片拼接起來下梢,最后輸出成一整段MP4視頻,作為教學(xué)視頻播放
二塞蹭、方案選擇
針對需求孽江,最開始提出了幾個主要的方案
方案 | 優(yōu)點 | 缺點 |
---|---|---|
方案一:直播推流錄制 | 使用現(xiàn)成直播方案,上手成本小 | 業(yè)務(wù)邏輯要和直播業(yè)務(wù)切割隔離番电,重新弄一套岗屏,不合適,而且感覺殺雞用牛刀 |
方案二:客戶端處理圖片漱办、音頻合成这刷,視頻拼接等多媒體操作 | 1、后端業(yè)務(wù)簡單; 2娩井、大多數(shù)視頻處理類APP都是如此,方案成熟 |
1咐刨、前端要新嵌入七牛多媒體處理SDK昙衅,對包穩(wěn)定性有影響 2、APP處理視頻而涉,可能比較耗費手機性能,如果APP受眾用戶是中老年用戶联予,可能手機性能扛不住 |
方案三:服務(wù)端統(tǒng)一處理圖片啼县、音頻合成沸久,視頻拼接等多媒體操作 | 1卷胯、客戶端無需再嵌入SDK 2诵竭、對用戶手機性能的要求降到最低 |
服務(wù)端交互邏輯變復(fù)雜卵慰,并且要處理耗時的多媒體合成任務(wù) |
最終定了方案三,原因是該功能的受眾是老年用戶鲤嫡,手機性能可能很差暖眼,耗時的操作交給服務(wù)端來比較合適
三、方案執(zhí)行
3.1 初版方案
查詢了一下栋豫,對應(yīng)圖片+音頻合成視頻,這樣的音畫合成的操作嫩絮,七牛并沒有提供API~
所以只能服務(wù)端采用萬能的多媒體處理工具:ffmpeg 了摔踱,整體方案如下
可以看到上述方案蛹批,有兩個關(guān)鍵操作:
關(guān)鍵操作 | 描述 | 如何觸發(fā) |
---|---|---|
音畫合成 | 圖片+音頻合成視頻 | 客戶端接口觸發(fā),用戶每錄一段語音猪勇,則服務(wù)端立馬調(diào)異步任務(wù)進行音畫合成 |
視頻mp4拼接 | 不同的視頻片段拼接成一整段視頻 | 客戶端接口觸發(fā)泣刹,用戶點擊預(yù)覽或提交審核寡键,服務(wù)端檢查所有語音片段是否音畫合成完畢西轩,條件符合則進行視頻mp4拼接 |
注意马僻,七牛提供了視頻mp4拼接的接口韭邓,但是經(jīng)過實踐诗力,用ffmpeg進行本地視頻mp4拼接沒有任何問題袜茧,并且速度很快俺夕,所以這里所有操作都用 本地 ffmpeg 來進行
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ǎo)師手哥悦陋,他給我介紹了一個工具:mediainfo,該工具可以查看視頻詳情筑辨,如音軌(Audio)和畫面(Video)的時長俺驶,通過該工具可以看到通過第一版操作音畫合成的視頻,畫面時長只有40ms棍辕,然而音軌時長卻有7s暮现,這里存在嚴(yán)重的不同步还绘,因此在有些瀏覽器(safari)中并不能正常拖動進度條播放:
問題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:將不同的音畫合成后的視頻片段拼接起來后生成的 最終課程錄制視頻栖袋,會有音畫不同步的問題
現(xiàn)象是明明是第一個PPT的錄音拍顷,畫面已經(jīng)翻到PPT第二頁了,錄音還在播放第一頁PPT尾段的錄制語音
原因:通過 mediainfo 查看最后生成的 最終拼接視頻塘幅,發(fā)現(xiàn)還是存在 Video_Duration和Audio_Duration 不一致的問題
應(yīng)該是第一步音畫合成的視頻片段本身就有 Video_Duration和Audio_Duration 不完全一致昔案,將他們拼接起來后,是音軌和畫面軌道分別拼接电媳,最后兩條軸出現(xiàn)了不一致的問題爱沟。
因此,我們需要在第一步音畫合成的時候做處理匆背,讓 Video_Duration和Audio_Duration 保持嚴(yán)格一致或盡量接近
問題2的解決辦法
在音畫合成后呼伸,多一步操作,對合成的視頻片段钝尸,進行人為剪裁~讓視頻的 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 不會有太大差距括享。
問題3:安卓端的播放器,播放合成的課程視頻珍促,依然無法拖動視頻的進度條
和安卓端同學(xué)溝通后铃辖,定位問題是視頻缺少關(guān)鍵幀,需要為視頻加入關(guān)鍵幀
問題3的解決辦法
參考:https://codeday.me/bug/20180927/259812.html
在音畫合成截斷猪叙,就針對視頻插入關(guān)鍵幀娇斩,關(guān)鍵命令:
ffmpeg -x264-params keyint=1:scenecut=0
上面的keyint=1表示每隔1幀插入設(shè)置一個關(guān)鍵幀
問題4:音畫合成的速度特別慢,音畫合成生成的文件也特別的大
首先觀察現(xiàn)象穴翩,發(fā)現(xiàn) 圖片大小為 212k犬第,音頻 .aac 文件大小為 132k,生成的視頻文件居然會是540k
懷疑是幀率問題芒帕,google了一下歉嗓,ffmpeg指令如果不人為設(shè)定幀率,默認(rèn)幀率為25背蟆,而我們音畫合成的視頻就是一張圖片鉴分,并不需要太高的幀率,這個地方應(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è)置幀率伦糯,也大大降低了處理速度:
實驗:對比使用 -r 2 設(shè)置幀率(fps) 來對靜態(tài)圖的mp4處理速度和大小進行優(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
)
生成文件大小的對比
[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
從上面的實驗看起來,針對1分鐘的音頻,人為設(shè)置幀率為2使得處理耗時降低了至少50%舔株,生成文件大小降低了近60%
問題5:音畫合成后的視頻莺琳,截斷后又丟失了關(guān)鍵幀
音畫合成后的視頻,是帶有關(guān)鍵幀信息的载慈,為何截斷后又丟失了關(guān)鍵幀惭等?
經(jīng)過仔細(xì)對比,發(fā)現(xiàn)音畫合成和截斷的命令办铡,有著細(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辞做,截斷:
ffmpeg -i output1.mp4
-ss 00:00:00
-t 00:00:06.80
-acodec aac
-vcodec h264
-strict -2 output1_cut.mp4
仔細(xì)觀察上面兩個命令,經(jīng)過google寡具,發(fā)現(xiàn) 【-c:a】和【-acodec】是一個意思秤茅,表示音頻編碼方式,【-c:v】和【-vcodec】是一個意思童叠,表示視頻編碼方式
這里兩個指令的 視頻編碼方式框喳,一個指定的使用 libx264,一個使用h264, 懷疑是這里的不一致導(dǎo)致關(guān)鍵幀丟失
經(jīng)過試驗厦坛,發(fā)現(xiàn)猜測正確五垮。
問題5的解決辦法:
將音畫合成和視頻截斷的音頻解碼方式統(tǒng)一為 libx264,就能保證截斷后視頻的關(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,截斷:
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 最終的視頻處理命令
三個步驟:
- 音畫合成杜秸,圖片+音頻合成視頻
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è)置關(guān)鍵幀間隔為每間隔1幀設(shè)置一個,解決安卓RN播放無法拉動進度條的問題
- 對音畫合成后的視頻片段進行截斷
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博客鏈接
截斷是為了保證音軌長度和畫面軌道長度
盡量保持一致撬碟,杜絕拼接后的音畫不同步問題
- 視頻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“ 的回答