目录
- 需求
- 基于JavaCV跨平台执行ffmpeg命令[^1]
- 坑一 内存不足
- 坑二 多个ffmpeg进程并行导致IO负载大,进而导致io error?
- 坑三 使用Java操作ffmpeg时,有时会卡死
- 坑四 Process的waitFor死锁问题及解决办法
需求
给透明背景的视频自动叠加一张背景图片
基于JavaCV跨平台执行ffmpeg命令1
我测试发现的本需求的最小依赖:
<!-- 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内存,扩容后解决。
坑二 多个ffmpeg进程并行导致IO负载大,进而导致io error?
这只是一种推测。现象是我会有多个Java线程,每个线程都来调用ffmpeg命令。合成的视频有概率缺失后面一段,并可以在日志中观察到io error, read error。源视频越大,Java线程数越多,出现这种情况的概率越大。当我把Java程序改为单线程,就没有这种问题了。但当我尝试用iostat命令去服务器节点观察IO状态时,并没有观察到所谓IO负载大的证据。2
坑三 使用Java操作ffmpeg时,有时会卡死
只发生在我本地Mac,在服务器没有出现过。我找了很久原因,最后发现是我的Mac跑了一段时间后自动休眠了。。不过也记录下很多人都遇到过的这个坑吧:
坑四 Process的waitFor死锁问题及解决办法
大意是:当Runtime对象调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立三个管道连接:标准输入,标准输出和标准错误流。假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取的话,当缓冲区满之后将无法继续写入数据,而Java的waitfor()是阻塞等待子进程完成的。所以会最终造成阻塞在waitfor()这里。解决的主要思路是Java要及时消费这个缓冲区的io流,或者直接不让ffmpeg输出日志。