質問

私は実行してJavaでビデオアプリケーションを書いています ffmpeg 出力を標準出力にキャプチャします。 Javaの代わりにApache Commons-Execを使用することにしました Runtime, 、それはより良いように見えるからです。しかし、私はすべての出力をキャプチャするのに苦労しています。

パイプの使用は、プロセス間通信の標準的な方法であるため、行く方法だと思いました。ただし、使用したセットアップ PipedInputStreamPipedOutputStream 間違っている。それは機能しているようですが、ストリームの最初の1042バイトの場合にのみ、不思議なことに、 PipedInputStream.PIPE_SIZE.

私はパイプを使用することに恋をしていませんが、データの速度と量のためにディスクI/O(可能であれば)の使用を避けたいです(512x384の1m 20秒のビデオは690を生成しますM パイプデータの)。

パイプから来る大量のデータを処理するための最良のソリューションについての考え?私の2つのクラスの私のコードは以下にあります。 (はい、 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クラスの実行方法です。 2つの連続したループがあります。ストリームに現在使用可能なデータがない場合、2番目のループはすぐに終了します(例えば、これまでのすべての入力はパーサーによって処理され、FFMPEGまたはストリームポンプは、新しいデータを提供するのに十分な速度ではありませんでした - >利用可能()== 0 - >ループが終了します - >ポンプスレッド仕上げ)。

これら2つのループを取り除いてスリープし、処理にデータが利用可能かどうかを確認する代わりに、単純なブロッキング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 ...
     }
 }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top