捕获Apache Commons-Exec的大量输出 [英] Capturing large amounts of output from Apache Commons-Exec

查看:162
本文介绍了捕获Apache Commons-Exec的大量输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a video application in Java by executing ffmpeg and capturing its output to standard output. I decided to use Apache Commons-Exec instead of Java's Runtime, because it seems better. However, I am have a difficult time capturing all of the output.

我认为使用管道将是要走的路,因为它是一种标准的进程间方式通讯。但是,使用 PipedInputStream PipedOutputStream 的设置是错误的。它似乎工作,但仅适用于流的前1042个字节,奇怪的是恰好是 PipedInputStream.PIPE_SIZE 的值。

I thought using pipes would be the way to go, because it is a standard way of inter-process communication. However, my setup using PipedInputStream and PipedOutputStream is wrong. It seems to work, but only for the first 1042 bytes of the stream, which curiously happens to be the value of PipedInputStream.PIPE_SIZE.

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

I have no love affair with using pipes, but I want to avoid use disk I/O (if possible), because of speed and volume of data (a 1m 20s video at 512x384 resolution produces 690M of piped data).

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

Thoughts on the best solution to handle large amounts of data coming from a pipe? My code for my two classes are below. (yes, sleep is bad. Thoughts on that? wait() and notifyAll() ?)

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



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 - >循环终止 - >泵线程完成)。

The problem is in the run method of YUV4MPEGPipeParser class. There are two successive loops. The second loop terminates immediately if there are no data currently available on the stream (e.g. all input so far was processed by parser, and ffmpeg or stream pump were not fast enough to serve some new data for it -> available() == 0 -> loop is terminated -> pump thread finishes).

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

Just get rid of these two loops and sleep and just perform a simple blocking read() instead of checking if any data are available for processing. There is also probably no need for wait()/notify() or even sleep() because the parser code is started on a separate thread.

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

You can rewrite the code of run() method like this:

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 ...
     }
 }

这篇关于捕获Apache Commons-Exec的大量输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆