给透明背景的视频自动叠加一张背景图片
我测试发现的本需求的最小依赖:
<!-- Optional GPL builds with (almost) everything enabled --> <dependency> <groupId>org.bytedeco</groupId> <artifactId>ffmpeg-platform-gpl</artifactId> <version>5.0-1.5.7</version> </dependency>
核心代码:
String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class); String tempFilePath = newVideoName; ProcessBuilder pb = new ProcessBuilder(ffmpeg, "-y", "-i", BACKGROUND_PNG, "-c:v", "libvpx-vp9", "-i", aliVideoUrl, "-filter_complex", "[0][1]overlay=0:0[video2];[video2]select=between(n\\,1\\,54000)", "-b:v", "2m", "-r", "30", "-c:v", "libx264", "-pix_fmt", "yuv420p", "-profile:v", "high", "-preset:v", "veryslow", "-tune", "film", "-level", "4.2", tempFilePath); pb.inheritIO().start().waitFor(); File tempFile = new File(tempFilePath);
服务器内存不足导致合成视频实际失败,许多的合成文件只有48B,但是没有与之相关的错误日志。
每个服务器节点原来只有2G内存,扩容后解决。
这只是一种推测。现象是我会有多个Java线程,每个线程都来调用ffmpeg命令。合成的视频有概率缺失后面一段,并可以在日志中观察到io error, read error。源视频越大,Java线程数越多,出现这种情况的概率越大。当我把Java程序改为单线程,就没有这种问题了。但当我尝试用iostat命令去服务器节点观察IO状态时,并没有观察到所谓IO负载大的证据。2
只发生在我本地Mac,在服务器没有出现过。我找了很久原因,最后发现是我的Mac跑了一段时间后自动休眠了。。不过也记录下很多人都遇到过的这个坑吧:
大意是:当Runtime对象调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立三个管道连接:标准输入,标准输出和标准错误流。假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,而Java的waitfor()是阻塞等待子进程完成的。所以会最终造成阻塞在waitfor()这里。解决的主要思路是Java要及时消费这个缓冲区的io流,或者直接不让ffmpeg输出日志。一些参考:
使用Procees+Runtime操作ffmpeg时,执行比较大的文件操作会卡死,但cmd打开ffmpeg能正常执行
Java process.waitFor() 卡死问题里提到了,也可以直接给ffmpeg命令加上-loglevel quiet
参数来不让输出日志。