Domanda

Sto scrivendo un'applicazione video in Java eseguendo ffmpeg e catturare il suo output sullo standard output. Ho deciso di usare Apache Commons-Exec invece di Runtime di Java, perché sembra meglio. Tuttavia, io sono un momento difficile catturare tutto l'output.

Ho pensato che utilizzando tubi sarebbe la strada da percorrere, perché è un modo standard di comunicazione tra processi. Tuttavia, la mia messa a punto utilizzando PipedInputStream e PipedOutputStream è sbagliato. Sembra funzionare, ma solo per i primi 1042 byte del flusso, che risulta stranamente essere il valore di PipedInputStream.PIPE_SIZE.

Non ho storia d'amore con l'utilizzo di tubi, ma voglio evitare l'utilizzo del disco I / O (se possibile), a causa della velocità e volume di dati (un video 20s 1m a 512x384 risoluzione produce 690M dei dati pipe).

Pensieri sulla soluzione migliore per gestire grandi quantità di dati provenienti da un tubo? Il mio codice per i miei due classi sono al di sotto. (Sì, sleep è male. Pensieri su questo? wait() e 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();
        }
    }
}
È stato utile?

Soluzione

Il problema è nel metodo run di classe YUV4MPEGPipeParser. Ci sono due cicli successivi. Il secondo ciclo termina immediatamente se ci sono dati attualmente disponibili sul flusso (ad esempio tutti gli input finora è stato elaborato dal parser e ffmpeg o pompa flusso non fosse abbastanza veloce per servire alcuni nuovi dati per esso -> disponibile () == 0 -> ciclo viene terminato -.> Rivestimenti filo pompa)

Proprio sbarazzarsi di questi due loop e il sonno e solo eseguire una semplice lettura di blocco () invece di controllare se tutti i dati sono disponibili per l'elaborazione. V'è anche probabilmente bisogno di wait () / notify () o anche dormire () perché il codice parser viene avviato in un thread separato.

Metodo

È possibile riscrivere il codice di run () in questo modo:

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 ...
     }
 }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top