乐趣区

关于java:使用ffmpeg拼接视频踩坑记录

最近在工作中遇到一个 ffmpeg 的坑,特此记录下。咱们在工作中,有个需要是将分段存储的视频拼接成一个残缺的视频,发现应用 ffmpeg 拼接后视频时长不对。举个列子,我用 ffmpeg 将 4 个半小时的 mp4 视频拼接后,失去的视频长度远超过 2 小时,观看后发现在视频的连接点,会呈现长时间的卡顿,导致最终视频工夫超长。

在 ffmpeg 官网文档 Concatenating media files 中,介绍了三种视频拼接的形式,别离如下:

1. 针对同种编码的视频

能够将所有视频文件名列到一个文本文件中,格局如下:

file '/path/to/file1.wav'
file '/path/to/file2.wav'
file '/path/to/file3.wav'

而后应用命令 ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.wav 实现对视频的拼接,这种形式也是拼接最快的形式。大抵原理是间接将视频首位相接,不会波及到编解码,整体执行的工夫次要是磁盘 IO 的工夫,咱们实测 100 个文件,拼接成一个 5g 大的长视频,也只须要几十秒的工夫。
然而,这种拼接形式有本人的局限,首先它只能拼接雷同编码的视频,比方都是 mp4。而且,这种形式也有 bug,拼接 mp4 视频文件得进去的视频时长不对,就是我结尾所说的问题,因为这个 bug 咱们差点改业务需要。不过这个 bug 能够绕过去,就是将所有 mp4 文件先转成 ts 文件,而后对 ts 文件拼接,拼接 ts 视频不会呈现这个 bug。

mp4 转 ts 文件的命令如下:

ffmpeg -i input.mp4 -c:v copy ouput.ts

因为 mp4 转 ts 的过程也不波及到视频编解码,所以也很快,咱们也是用这种形式绕开了 bug,实现了整个需要。其实视频拼接还有两种形式,对咱们都不太适合,后续会说到。

2. 应用 concat 协定

ffmpeg -i "concat:input1.ts|input2.ts|input3.ts" -c copy output.ts

这个形式咱们没有具体测试,貌似不会波及到编解码,所以应该也挺快的,但网上说这个命令执行的条件也比拟刻薄,也不举荐应用。咱们没有用的起因单纯是因为须要拼接上百个视频,这种形式须要拼一个十分长的命令行。

3. 应用 Concat filter

ffmpeg -i input1.mp4 -i input2.webm -i input3.mov -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mkv

这种应用形式还是偏简单,具体能够参考下官网文档 Concatenating media files。该办法的长处就是成果稳固、且反对不同格局的视频,所以也是最举荐的视频拼接形式。但毛病也很显著,须要波及到视频的编解码,所以会十分耗性能,就是因为性能问题,咱们也摈弃这种计划了。

说下咱们实测的数据,咱们用通用服务器,拼接 60 分钟的视频须要 20-30 分钟(和服务器配置无关),看着还行,但咱们每天有数千小时的视频须要拼接,须要几十台服务器 24 小时满负荷工作能力实现,对于咱们当下来说老本还是偏高。咱们也委托他人试了应用 GPU 减速的拼接成果,的确快了很多,1 小时视频 1 分钟内就能够实现。

总结

咱们以后没有 GPU 资源,所以当下还是抉择了应用第一种视频拼接形式,第一种形式目前最大的瓶颈只在于网络 IO(视频下载上传)上,但这种计划也限度了咱们只能实现对视频的拼接,无奈调整其分辨率以达到升高存储的目标。长期来看咱们必定得思考应用硬件加速的形式实现超大视频量的解决。

退出移动版