Question

Je suis en train d'écrire une application vidéo en Java en exécutant ffmpeg et en capturant sa sortie standard. J'ai décidé d'utiliser Apache Commons-Exec au lieu de Runtime de Java, car il semble mieux. Cependant, je suis un moment difficile de capturer toute la production.

Je pensais en utilisant des tuyaux serait la voie à suivre, car il est un moyen standard de communication inter-processus. Cependant, ma configuration à l'aide PipedInputStream et PipedOutputStream est erroné. Il semble fonctionner, mais seulement pour les premiers 1042 octets du flux, ce qui arrive curieusement à la valeur de PipedInputStream.PIPE_SIZE.

Je n'ai pas affaire d'amour avec l'aide de tuyaux, mais je veux éviter d'utiliser le disque d'E / S (si possible), en raison de la vitesse et le volume des données (20s 1m vidéo à 512x384 résolution produit 690M des données passepoilées).

Réflexions sur la meilleure solution pour gérer de grandes quantités de données provenant d'un tuyau? Mon code pour mes deux classes sont ci-dessous. (Oui, sleep est mauvais. À ce sujet? wait() et 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();
        }
    }
}
Était-ce utile?

La solution

Le problème est dans la méthode d'exécution de la classe YUV4MPEGPipeParser. Il y a deux boucles successives. La seconde boucle se termine immédiatement s'il n'y a pas de données actuellement disponibles sur le flux (par exemple, toutes les entrées jusqu'à présent a été traité par l'analyseur et ffmpeg ou une pompe à flux n'étaient pas assez vite pour servir de nouvelles données pour elle -> disponibles () == 0 -> boucle est terminée. -> fil de pompe se termine)

Il suffit de se débarrasser de ces deux boucles et le sommeil et juste effectuer simple lecture de blocage () au lieu de vérifier si des données sont disponibles pour le traitement. Il y a aussi sans doute pas besoin d'attendre () / notify () ou même dormir () parce que le code de l'analyseur est démarré sur un thread séparé.

Vous pouvez réécrire le code de la méthode run () comme ceci:

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 ...
     }
 }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top