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

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

问题描述

我正在通过执行 ffmpeg 并将其输出捕获到标准输出来用 Java 编写视频应用程序.我决定使用 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.

我认为使用管道会是一种方法,因为它是进程间通信的标准方式.但是,我使用 PipedInputStreamPipedOutputStream 的设置是错误的.它似乎有效,但仅适用于流的前 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 视频产生 690M).

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

关于处理来自管道的大量数据的最佳解决方案的想法?我的两个类的代码如下.(是的,sleep 很糟糕.对此有何想法?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

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

只需摆脱这两个循环和睡眠,只需执行一个简单的阻塞 read() 而不是检查是否有任何数据可用于处理.也可能不需要 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天全站免登陆