当前位置: 首页 > 后端技术 > Java

使用ffmpeg拼接视频,踩坑记录

时间:2023-04-01 18:17:06 Java

最近在工作中遇到了一个ffmpeg的坑,记录在这里。在我们的工作中,有一个需要将分片存储的视频拼接成一个完整的视频,发现用ffmpeg拼接后的视频长度不对。比如用ffmpeg拼接4个半小时的mp4视频后,得到的视频长度远远超过2小时。看完之后发现在视频的连接点会有很长一段时间的卡顿,导致最终的视频很长。在ffmpeg官方文档Concatenatingmediafiles中,介绍了三种视频拼接方式,分别如下:1、对于相同编码的视频,可以将所有视频文件名列在一个文本文件中,格式如下:file'/path/to/file1.wav'file'/path/to/file2.wav'file'/path/to/file3.wav'然后使用命令ffmpeg-fconcat-safe0-imylist.txt-ccopyoutput.wav完成视频拼接,这种方式也是最快的拼接方式。大体原则是直接接视频的前几位,不涉及codec。整体执行时间主要是磁盘IO时间。我们实测了100个文件,拼接成一个5G长视频,只需要几十秒。时间。然而,这种拼接方法有其自身的局限性。首先,它只能拼接相同编码的视频,比如mp4。而且,这个方法也有bug。mp4视频文件拼接得到的视频长度不对,就是我开头提到的问题。由于这个错误,我们几乎改变了业务需求。不过这个bug是可以绕过的,就是先把所有的mp4文件都转成ts文件,然后再对ts文件进行拼接,ts视频的拼接就不会出现这个bug。mp4转ts文件的命令如下:ffmpeg-iinput.mp4-c:vcopyouput.ts因为mp4转ts的过程不涉及视频编解码,所以也很快,我们也绕过了它以这种方式出现错误,完成了整个要求。其实还有两种视频拼接方式,都不太适合我们,后面再说。2.使用concat协议ffmpeg-i"concat:input1.ts|input2.ts|input3.ts"-ccopyoutput.ts这个方法我们没有具体测试,好像不会涉及到codec,所以应该会很快,但是网上说执行这个命令的条件比较苛刻,不推荐使用。我们之所以没用,很简单,因为需要将数百个视频拼接在一起。此方法需要很长的命令行。3.使用Concat过滤器ffmpeg-iinput1.mp4-iinput2.webm-iinput3.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的使用还是比较复杂的。具体可以参考官方文档Concatenatingmediafiles。这种方式的优点是效果稳定,支持不同格式的视频,所以也是最推荐的视频拼接方式。但劣势也很明显。它需要涉及视频编解码器,因此会消耗大量性能。因为性能问题,我们也放弃了这个方案。说说我们测的数据吧。我们使用的是通用服务器,拼接一个60分钟的视频需要20-30分钟(视服务器配置而定)。看起来还可以,但是我们每天有几千小时的视频需要拼接,需要几十台机器。服务器只能满负荷24小时完成,成本对我们现在来说还是很高的。我们还委托别人尝试了使用GPU加速的拼接效果,确实快了很多,1分钟就能完成一个1小时的视频。综上所述,我们目前没有GPU资源,所以还是选择使用第一种视频拼接的方式。第一种方式最大的瓶颈只有网络IO(视频下载和上传),但是这种方案也限制了我们。对于视频拼接,其分辨率无法通过调整来达到减少存储的目的。从长远来看,我们必须考虑使用硬件加速来完成大视频量的处理。