PipedInputStream / PipedOutputStream、ImageIO 和 ffmpeg
PipedInputStream / PipedOutputStream, ImageIO and ffmpeg
我在 Scala 中有以下代码:
val pos = new PipedOutputStream()
val pis = new PipedInputStream(pos)
Future {
LOG.trace("Start rendering")
generateFrames(videoRenderParams.length) {
img ⇒ ImageIO.write(img, "PNG", pos)
}
pos.flush()
IOUtils.closeQuietly(pos)
LOG.trace("Finished rendering")
} onComplete {
case Success(_) ⇒
LOG.trace("Complete successfully")
case Failure(err) ⇒
LOG.error("Can't render stuff", err)
IOUtils.closeQuietly(pis)
IOUtils.closeQuietly(pos)
}
val prc = (ffmpegCli #< pis).!(logger)
Future 只是简单地将生成的图像一张一张写入OutputStream。现在 ffmpeg 进程从 stdin 读取输入图像并将它们转换为 MP4 文件。
效果很好,但出于某种原因,有时我会得到以下堆栈跟踪:
I/O error Pipe closed for process: <input stream>
java.io.IOException: Pipe closed
at java.io.PipedInputStream.checkStateForReceive(PipedInputStream.java:260)
at java.io.PipedInputStream.receive(PipedInputStream.java:226)
at java.io.PipedOutputStream.write(PipedOutputStream.java:149)
at scala.sys.process.BasicIO$.loop(BasicIO.scala:236)
at scala.sys.process.BasicIO$.transferFullyImpl(BasicIO.scala:242)
at scala.sys.process.BasicIO$.transferFully(BasicIO.scala:223)
at scala.sys.process.ProcessImpl$PipeThread.runloop(ProcessImpl.scala:159)
at scala.sys.process.ProcessImpl$PipeSource.run(ProcessImpl.scala:179)
同时我从另一个流中收到以下错误:
javax.imageio.IIOException: I/O error writing PNG file!
at com.sun.imageio.plugins.png.PNGImageWriter.write(PNGImageWriter.java:1168)
at javax.imageio.ImageWriter.write(ImageWriter.java:615)
at javax.imageio.ImageIO.doWrite(ImageIO.java:1612)
at javax.imageio.ImageIO.write(ImageIO.java:1578)
at
所以似乎流在两者之间的某个地方中断了,所以 ffmpeg 无法读取数据,并且 ImageIO 无法写入数据。
更有趣的是 - 该问题只能在某些 Linux 服务器(亚马逊)上重现。它在其他 Linux 盒子上完美运行。所以我想知道是否有人可以指出这个错误的可能原因。
到目前为止我尝试过的:
- 使用 Oracle JDK 8 和 OpenJDK
- 使用不同版本的 FFMPEG
目前没有任何效果。
这个问题既可以预见又很奇怪。因此,安排了十个并发 ffmpeg 进程来处理输入,输入是一组数百张 FullHD 图片。显然这需要大量的计算能力,因此内核随机关闭 ffmpeg 进程,导致 Java wrapper 同时报告损坏的输入和输出管道。
因此/var/log/messages包含许多如下日志:
Out of memory: Kill process 25778 (java) score 159 or sacrifice child
Killed process 25931 (ffmpeg) total-vm:2337040kB, anon-rss:966340kB, file-rss:104kB
减少并发数 ffmpeg 进程解决了这个问题。
我在 Scala 中有以下代码:
val pos = new PipedOutputStream()
val pis = new PipedInputStream(pos)
Future {
LOG.trace("Start rendering")
generateFrames(videoRenderParams.length) {
img ⇒ ImageIO.write(img, "PNG", pos)
}
pos.flush()
IOUtils.closeQuietly(pos)
LOG.trace("Finished rendering")
} onComplete {
case Success(_) ⇒
LOG.trace("Complete successfully")
case Failure(err) ⇒
LOG.error("Can't render stuff", err)
IOUtils.closeQuietly(pis)
IOUtils.closeQuietly(pos)
}
val prc = (ffmpegCli #< pis).!(logger)
Future 只是简单地将生成的图像一张一张写入OutputStream。现在 ffmpeg 进程从 stdin 读取输入图像并将它们转换为 MP4 文件。
效果很好,但出于某种原因,有时我会得到以下堆栈跟踪:
I/O error Pipe closed for process: <input stream>
java.io.IOException: Pipe closed
at java.io.PipedInputStream.checkStateForReceive(PipedInputStream.java:260)
at java.io.PipedInputStream.receive(PipedInputStream.java:226)
at java.io.PipedOutputStream.write(PipedOutputStream.java:149)
at scala.sys.process.BasicIO$.loop(BasicIO.scala:236)
at scala.sys.process.BasicIO$.transferFullyImpl(BasicIO.scala:242)
at scala.sys.process.BasicIO$.transferFully(BasicIO.scala:223)
at scala.sys.process.ProcessImpl$PipeThread.runloop(ProcessImpl.scala:159)
at scala.sys.process.ProcessImpl$PipeSource.run(ProcessImpl.scala:179)
同时我从另一个流中收到以下错误:
javax.imageio.IIOException: I/O error writing PNG file!
at com.sun.imageio.plugins.png.PNGImageWriter.write(PNGImageWriter.java:1168)
at javax.imageio.ImageWriter.write(ImageWriter.java:615)
at javax.imageio.ImageIO.doWrite(ImageIO.java:1612)
at javax.imageio.ImageIO.write(ImageIO.java:1578)
at
所以似乎流在两者之间的某个地方中断了,所以 ffmpeg 无法读取数据,并且 ImageIO 无法写入数据。
更有趣的是 - 该问题只能在某些 Linux 服务器(亚马逊)上重现。它在其他 Linux 盒子上完美运行。所以我想知道是否有人可以指出这个错误的可能原因。
到目前为止我尝试过的:
- 使用 Oracle JDK 8 和 OpenJDK
- 使用不同版本的 FFMPEG
目前没有任何效果。
这个问题既可以预见又很奇怪。因此,安排了十个并发 ffmpeg 进程来处理输入,输入是一组数百张 FullHD 图片。显然这需要大量的计算能力,因此内核随机关闭 ffmpeg 进程,导致 Java wrapper 同时报告损坏的输入和输出管道。
因此/var/log/messages包含许多如下日志:
Out of memory: Kill process 25778 (java) score 159 or sacrifice child
Killed process 25931 (ffmpeg) total-vm:2337040kB, anon-rss:966340kB, file-rss:104kB
减少并发数 ffmpeg 进程解决了这个问题。