Pregunta

Estoy escribiendo una aplicación de vídeo en Java mediante la ejecución de ffmpeg y la captura de su salida a la salida estándar. Decidí usar Apache Commons-Exec en lugar de Runtime de Java, porque parece mejor. Sin embargo, yo soy un momento difícil capturar toda la producción.

pensé utilizando tubos sería el camino a seguir, ya que es una forma estándar de comunicación entre procesos. Sin embargo, mi configuración utilizando PipedInputStream y PipedOutputStream está mal. Parece que funciona, pero sólo para los primeros 1042 bytes de la corriente, que curiosamente pasa a ser el valor de PipedInputStream.PIPE_SIZE.

No tengo ninguna historia de amor con el uso de tuberías, pero quiero evitar el uso como disco de E / S (si es posible), debido a la velocidad y el volumen de datos (un video 20s 1m en 512x384 resolución produce 690M de los datos por tubería).

Reflexiones sobre la mejor solución para manejar grandes cantidades de datos procedentes de una tubería? Mi código para mis dos clases están por debajo. (Sí, sleep es malo. Reflexiones sobre eso? wait() y 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();
        }
    }
}
¿Fue útil?

Solución

El problema está en el método run de la clase YUV4MPEGPipeParser. Hay dos bucles sucesivos. El segundo bucle termina inmediatamente si no hay datos disponibles en la actualidad en la corriente (por ejemplo, toda la entrada hasta el momento se procesó mediante analizador, y ffmpeg o bomba de corriente no fuera lo suficientemente rápido para servir algunos datos nuevos para ella -> disponible () == 0 -> bucle se termina -.> acaba hilo bomba)

Sólo deshacerse de estos dos bucles y sueño y simplemente realizar una lectura simple de bloqueo () en lugar de comprobar si están disponibles para el procesamiento de los datos. También es probable que no hay necesidad de esperar () / notify () o incluso dormir () debido a que el código de programa de análisis se inicia en un hilo separado.

Método

Puede volver a escribir el código de run () de esta manera:

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 ...
     }
 }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top