Захват большого количества продукции от Apache Commons-Exec - PullRequest
5 голосов
/ 05 июня 2009

Я пишу видео приложение на Java, выполнив ffmpeg и записав его вывод в стандартный вывод. Я решил использовать Apache Commons-Exec вместо Java Runtime, потому что он кажется лучше. Тем не менее, мне трудно захватить весь вывод.

Я подумал, что использование каналов - это путь, потому что это стандартный способ межпроцессного взаимодействия. Однако мои настройки, использующие PipedInputStream и PipedOutputStream, неверны. Кажется, это работает, но только для первых 1042 байтов потока, что, как ни странно, равно значению PipedInputStream.PIPE_SIZE.

У меня нет любовной связи с использованием каналов, но я хочу избежать использования дискового ввода-вывода (если это возможно) из-за скорости и объема данных (видео размером 1 м 20 с разрешением 512x384 создает 690 M данных по каналам ).

Думаете о лучшем решении для обработки больших объемов данных, поступающих из канала? Мой код для моих двух классов ниже. (да, 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();
        }
    }
}

1 Ответ

4 голосов
/ 06 июня 2009

Проблема в методе выполнения класса YUV4MPEGPipeParser. Есть две последовательные петли. Второй цикл немедленно завершается, если в данный момент нет доступных данных в потоке (например, все входные данные до сих пор обрабатывались парсером, а ffmpeg или потоковый насос были недостаточно быстрыми, чтобы обслуживать для него новые данные -> available () == 0 -> цикл прерывается -> резьба насоса заканчивается).

Просто избавьтесь от этих двух циклов и спите и просто выполните простую блокировку read () вместо проверки, доступны ли какие-либо данные для обработки. Также, вероятно, нет необходимости в 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 ...
     }
 }
...