一次用ffmpeg实现图片+音频合成视频的开发

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一次用ffmpeg实现图片+音频合成视频的开发相关的知识,希望对你有一定的参考价值。

参考技术A 用户针对一个PPT的每一页图片,进行语音录制,输出多段音频文件,将用户每段音频和对应的PPT图片拼接起来,最后输出成一整段MP4视频,作为教学视频播放

针对需求,最开始提出了几个主要的方案

最终定了方案三,原因是该功能的受众是老年用户,手机性能可能很差,耗时的操作交给服务端来比较合适

查询了一下,对应图片+音频合成视频,这样的音画合成的操作,七牛并没有提供API~
所以只能服务端采用万能的多媒体处理工具:ffmpeg 了,整体方案如下

可以看到上述方案,有两个关键操作:

注意,七牛提供了视频mp4拼接的接口,但是经过实践,用ffmpeg进行本地视频mp4拼接没有任何问题,并且速度很快,所以这里所有操作都用 本地 ffmpeg 来进行

ffmpeg 不具体介绍,详情可自行google:

官网: https://ffmpeg.org/

参数详解: https://zhuanlan.zhihu.com/p/31674583

具体ffmpeg的命令执行操作,第一版的执行如下:

咨询了人森导师手哥,他给我介绍了一个工具:mediainfo,该工具可以查看视频详情,如音轨(Audio)和画面(Video)的时长,通过该工具可以看到通过第一版操作音画合成的视频,画面时长只有40ms,然而音轨时长却有7s,这里存在严重的不同步,因此在有些浏览器(safari)中并不能正常拖动进度条播放:

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

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

现象是明明是第一个PPT的录音,画面已经翻到PPT第二页了,录音还在播放第一页PPT尾段的录制语音

原因:通过 mediainfo 查看最后生成的 最终拼接视频,发现还是存在 Video_Duration和Audio_Duration 不一致的问题

应该是第一步音画合成的视频片段本身就有 Video_Duration和Audio_Duration 不完全一致,将他们拼接起来后,是音轨和画面轨道分别拼接,最后两条轴出现了不一致的问题。

因此,我们需要在第一步音画合成的时候做处理,让 Video_Duration和Audio_Duration 保持严格一致或尽量接近

在音画合成后,多一步操作,对合成的视频片段,进行人为剪裁~让视频的 Video_Duration和Audio_Duration 保持一致:

如此生成的视频 Video_Duration和Audio_Duration 不会有太大差距。

和安卓端同学沟通后,定位问题是视频缺少关键帧,需要为视频加入关键帧

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

在音画合成截断,就针对视频插入关键帧,关键命令:

上面的keyint=1表示每隔1帧插入设置一个关键帧

首先观察现象,发现 图片大小为 212k,音频 .aac 文件大小为 132k,生成的视频文件居然会是540k

怀疑是帧率问题,google了一下,ffmpeg指令如果不人为设定帧率,默认帧率为25,而我们音画合成的视频就是一张图片,并不需要太高的帧率,这个地方应该可以优化下

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

经过人为设置帧率为1,生成文件大小优化为356k

人为设置帧率为1的关键指令如下:

同时,写了个小脚本,做了下实验验证,人为设置帧率,也大大降低了处理速度:

从上面的实验看起来,针对1分钟的音频,人为设置帧率为2使得处理耗时降低了至少50%,生成文件大小降低了近60%

音画合成后的视频,是带有关键帧信息的,为何截断后又丢失了关键帧?

经过仔细对比,发现音画合成和截断的命令,有着细微差距

仔细观察上面两个命令,经过google,发现 【-c:a】和【-acodec】是一个意思,表示音频编码方式,【-c:v】和【-vcodec】是一个意思,表示视频编码方式

这里两个指令的 视频编码方式,一个指定的使用 libx264,一个使用h264, 怀疑是这里的不一致导致关键帧丢失

经过试验,发现猜测正确。

将音画合成和视频截断的音频解码方式统一为 libx264,就能保证截断后视频的关键帧不丢失:

三个步骤:

该指令人为设置合成帧率为1,降低处理耗时和生成文件大小,
人为设置关键帧间隔为每间隔1帧设置一个,解决安卓RN播放无法拉动进度条的问题

参考: 我是CSDN博客链接
截断是为了保证音轨长度和画面轨道长度
尽量保持一致,杜绝拼接后的音画不同步问题

以上是关于一次用ffmpeg实现图片+音频合成视频的开发的主要内容,如果未能解决你的问题,请参考以下文章

视频提取图片/图片合成视频ffmpeg(二十)

Python使用ffmpeg合成视频音频

第十章 视频播放器开发之音频播放

aforge.video.ffmpeg 支持音频吗

ffmpeg合并音频和视频

ffmpeg 视频抽取音频,视音频分离