如何 read/write ProcessBuilder 流并最终在 ffmpeg 中创建输出文件

How to read/write streams of ProcessBuilder and finally create a output file in ffmpeg

我正在尝试使用带有 java.ProcessBuilder 的 ffmpeg 对视频进行转码。我阅读了与此相关的其他主题,但它并没有真正解决我的问题。

我认为在进程 p=pb.start() 之前一切顺利。我知道我必须读取一些 ProcessBuilder 流并将其转换为 byte[] 并将其写入文件。我认为 ffmpeg 会为我做所有这些,因为我正在传递 "inputFile" 和 OutputFile 路径。无论如何,我 post 我到这里为止所拥有的。我该如何修复此代码,以便在结果后看到完全转码的视频文件?

目前所有代码执行无误,输出文件已创建,但其大小为 0KB。我是 运行 来自 windows 服务器的 Java (.jar) 程序中的代码。

这是程序的一个片段

try {

    File encodingFile = new File("c:\ffmpeg\bin\output.mp4");
    File errorFile = new File("c:\ffmpeg\bin\error.txt");
    errorFile.createNewFile();
    encodingFile.createNewFile();

    ProcessBuilder pb = new ProcessBuilder("c:\ffmpeg\bin\ffmpeg.exe", "-i", "c:\ffmpeg\bin\input.mp4", "-y", "-s", "360" + "480" + "-1", "-vcodec", "libx264", "c:\ffmpeg\bin\output.mp4"); //or other command....
    pb.redirectErrorStream(true);
    pb.redirectError(errorFile);
    //pb.redirectOutput(encodingFile);

    Process p=pb.start();
    byte[] videoIn;
    File file = new File("c:\ffmpeg\bin\input.mp4");
    videoIn = new byte[(int)file.length()];

    FileInputStream fileInputStream = new FileInputStream(file);
    fileInputStream.read(videoIn);
           */
    gui.textArea1.append("\n+++++++Finished while converting!++++++++\n");

}catch(IOException ex){
    gui.textArea1.append("\nIOException converting: "+ex.getMessage());
}finally{
    try{
        if(is!=null){
            is.close();
        }
        if(fos!=null){
            fos.close();
        }
    }catch(IOException ioe){
        gui.textArea1.append("\nClosing streams while converting:"+ioe.getMessage());
    }
}
gui.textArea1.append("converting finished!");  

你的问题在这里:

pb.redirectErrorStream(true);
pb.redirectError(errorFile);
//pb.redirectOutput(encodingFile);

你在这里做的是将stderr重定向到stdout;并且都被重定向到 errorFile.

而您的 encodingFile 是刚刚创建的:

encodingFile.createNewFile();

甚至不能保证成功。

修复:

final Path videoIn = Paths.get("c:\ffmpeg\bin\input.mp4");
final Path encodingFile = Paths.get("c:\ffmpeg\bin\output.mp4");
final Path errorFile = Paths.get("c:\ffmpeg\bin\error.txt");

int retCode;

try {
    Files.deleteIfExists(encodingFile);
    Files.deleteIfExists(errorFile);

    final ProcessBuilder pb 
        = new ProcessBuilder("c:\ffmpeg\bin\ffmpeg.exe",
            "-i", videoIn.toString(),
            "-y", 
            "-s", "360x480", // stripped the extraneous "-1"
            "-vcodec", "libx264",                    
            "c:\ffmpeg\bin\output.mp4"
    ); //or other command....

    pb.redirectError(errorFile.toFile());
    pb.redirectOutput(encodingFile.toFile());

    final Process p = pb.start();

    // CHECK FOR THIS!
    retcode = p.waitFor();

    // Reproduced here; not sure this is anything useful,
    // since the old code, just like this one, just reads the contents
    // from the video file to be converted... Huh?
    final byte[] videoIn = Files.readAllBytes(videoIn);
} catch (IOException e) {
    // deal with e here
}

原代码注意事项:

  • 为什么要阅读原始视频文件的内容?这没有意义;
  • 您没有检查 .createNewFile() 的 return 值;它可能会失败;这里我使用 java.nio.file,这将在错误时抛出异常;
  • 您没有检查进程的 return 代码;这里它在一个 retCode 变量中,你必须在之后检查它。有关可能的错误代码,请参阅 ffmpeg 手册页。