捕获Apache Commons-Exec的大量输出

我正在用Java编写video应用程序,执行ffmpeg并将其输出捕获到标准输出。 我决定使用Apache Commons-Exec而不是Java的Runtime ,因为它似乎更好。 但是,我很难捕获所有输出。

我认为使用管道是可行的方法,因为它是进程间通信的标准方式。 但是,我使用PipedInputStreamPipedOutputStream设置是错误的。 它似乎工作,但仅适用于流的前1042个字节,奇怪的是它恰好是PipedInputStream.PIPE_SIZE的值。

我对使用管道并不感兴趣,但我想避免使用磁盘I / O(如果可能的话),因为数据的速度和数量(分辨率为512×384的1m 20svideo产生690M的管道数据)。

关于处理来自管道的大量数据的最佳解决方案的想法? 我的两个课程的代码如下。 (是的, sleep很糟糕。想一想吗? wait()notifyAll() ?)

WriteFrames.java

 public class WriteFrames { public static void main(String[] args) { String commandName = "ffmpeg"; CommandLine commandLine = new CommandLine(commandName); File filename = new File(args[0]); String[] options = new String[] { "-i", filename.getAbsolutePath(), "-an", "-f", "yuv4mpegpipe", "-"}; for (String s : options) { commandLine.addArgument(s); } PipedOutputStream output = new PipedOutputStream(); PumpStreamHandler streamHandler = new PumpStreamHandler(output, System.err); DefaultExecutor executor = new DefaultExecutor(); try { DataInputStream is = new DataInputStream(new PipedInputStream(output)); YUV4MPEGPipeParser p = new YUV4MPEGPipeParser(is); p.start(); executor.setStreamHandler(streamHandler); executor.execute(commandLine); } catch (IOException e) { e.printStackTrace(); } } } 

YUV4MPEGPipeParser.java

 public class YUV4MPEGPipeParser extends Thread { private InputStream is; int width, height; public YUV4MPEGPipeParser(InputStream is) { this.is = is; } public void run() { try { while (is.available() == 0) { Thread.sleep(100); } while (is.available() != 0) { // do stuff.... like write out YUV frames } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } 

问题出在YUV4MPEGPipeParser类的run方法中。 有两个连续的循环。 如果流上当前没有可用的数据,则第二个循环立即终止(例如,到目前为止所有输入都由解析器处理,并且ffmpeg或流泵的速度不足以为其提供一些新数据 – > available()== 0 – >循环终止 – >泵螺纹完成)。

只需摆脱这两个循环并hibernate,只需执行简单的阻塞读取(),而不是检查是否有任何数据可供处理。 也许不需要wait()/ notify()甚至sleep(),因为解析器代码是在一个单独的线程上启动的。

您可以像这样重写run()方法的代码:

 public class YUV4MPEGPipeParser extends Thread { ... // optimal size of buffer for reading from pipe stream :-) private static final int BUFSIZE = PipedInputStream.PIPE_SIZE; public void run() { try { byte buffer[] = new byte[BUFSIZE]; int len = 0; while ((len = is.read(buffer, 0, BUFSIZE) != -1) { // we have valid data available // in first 'len' bytes of 'buffer' array. // do stuff.... like write out YUV frames } } catch ... } }