Java выполняет команды ffmpeg с (pipe) "... -f nut - | ffmpeg -i - ..." просто зависает - PullRequest
7 голосов
/ 13 марта 2019

Я не могу заставить это работать, потому что Java просто ждет ffmpeg. Но ffmpeg не дает ни ввода, ни потока ошибок. Он просто работает, но ничего не делает.

Вывод "System.out.println (" command: .. "вставки в bash просто работает нормально, как и ожидалось. Так что с синтаксисом ffmpeg все в порядке.

Вот код.

package mypackage;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.imageio.ImageIO;

/**
 *
 * @author test
 */
public class ffmpeg_hang {

        /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        String INPUT_FILE="/path/to/media";
        String FFMPEG_PATH="/path/to/ffmpegFolder/";

            for(int i=0;(i+4)<40;i+=4){                
            String[] ffmpeg_pipe = new String[]{
                FFMPEG_PATH + "ffmpeg_4.1.1",
                "-ss",(i+""),"-t", "4",             
                "-i", INPUT_FILE,                                        
                "-ac", "1", "-acodec", "pcm_s16le", "-ar", "16000", 
                "-f","nut","-","|",
                FFMPEG_PATH + "ffmpeg_4.1.1",
                "-i","-",
                "-lavfi", "showspectrumpic=s=128x75:legend=disabled:saturation=0:stop=8000",
                "-f","image2pipe","pipe:1"};

            System.out.println("command: "+String.join(" ", ffmpeg_pipe));

            Process p;
            //ffmpe wav->pipe->spectrogra->pipe->java
            p = Runtime.getRuntime().exec(ffmpeg_pipe);


            StringBuilder Boxbuffer = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            String line = "";

            while ((line = reader.readLine()) != null) {
                Boxbuffer.append(line);
            }


            System.out.println("ffmpeg errors->> "+Boxbuffer.toString());
            p.waitFor();


            BufferedImage image = ImageIO.read(p.getInputStream());
            //do stuff with image
            }

    }

}

Ответы [ 2 ]

5 голосов
/ 18 марта 2019

Канал не будет интерпретироваться при прямой передаче команды таким образом, это будет просто еще один аргумент для первого ffmpeg в начале вашей команды.Попробуйте использовать /bin/sh -c "command1 | command2" в качестве оболочки (при условии, что ОС не Windows ...).

Попробуйте добавить -nostdin к первой команде ffmpeg, чтобы избежать проблем number из с ffmpeg, пытающимся прочитать stdin, когда вы этого не ожидаете (очевидно, не во втором).

Попробуйте использовать String.format для создания сложных строк с переменными.

Попробуйте использовать ProcessBuilder для упрощения процесса создания.Здесь я перенаправляю ошибки, чтобы они попадали в ваш stderr java-процесса, чтобы вы могли читать stdout вашего дочернего процесса без использования потока. См. Альтернативы

Итак, вот предложение:

public static void main(String[] args) throws IOException, InterruptedException {
    String INPUT_FILE = "/path/to/media";
    String FFMPEG_PATH = "/path/to/ffmpegFolder";

    for (int i = 0; (i + 4) < 40; i += 4) {

        String command1 = String.format(
                "%s/ffmpeg_4.1.1 -nostdin -ss %d -t 4 -i '%s' -ac 1 -acodec pcm_s16le -ar 16000 -f nut -",
                FFMPEG_PATH, i, INPUT_FILE);

        String command2 = String.format(
                "%s/ffmpeg_4.1.1 -i - -lavfi showspectrumpic=s=128x75:legend=disabled:saturation=0:stop=8000",
                FFMPEG_PATH);

        Process process = new ProcessBuilder("sh", "-c", command1 + " | " + command2)
                .redirectError(ProcessBuilder.Redirect.INHERIT)
                .start();

        BufferedImage image = ImageIO.read(process.getInputStream());
        // ...
    }
}
1 голос
/ 17 марта 2019

Мне кажется, что вы блокируете закрываемый поток stderr. Если ffmpeg не закроет свой stderr до его выхода (и я бы не ожидал, что он это сделает), то ваша программа просто заблокируется.

Используйте java.lang.ProcessBuilder с pb.redirectErrorStream(true); вместо.

Также рекомендуется прочитать выходные данные процесса в потоке, отличном от того, который вызвал waitFor();, в противном случае вы рискуете зайти в тупик.

...