将FileInputStream和FileOutputStream传递给ffmpeg进行转码(使用JAVE-Java音频视频编码)

Jag*_*n S 6 java linux windows transcode ffmpeg

我试图使用调用ffmpeg的JAVE将*.mov文件转码为*.mp4文件.输入文件和输出文件都是InputStream和OutputStream形式.这意味着我需要将InputStream和OutputStream作为-f和-y parematers传递给ffmpeg.我怎么做 ?

    //Read a movfile.mov converted into a FileInputStream  
    InputStream fileInputStream = getFileInputStream();  
    OutputStream fileOutputStream = new FileOutputStrea(outputMP4File) //Output        
    Process p = Runtime.exec("ffmpeg -i - -y -");  
    InputStream pInStrm = p.getInputStream();  
    OutputStream pOutStrm = p.getOutputStream();  
    int vin = 0, vout = 0;   

    Thread read = new Thread() {  
         byte[] buff = new byte[4096];  
          void run() {   
            while ((vin=fileInputStream.read(buf))!=-1) {   
                 pOutStrm.write(buf, 0, vin);   
            }   
         }   
      }; read.start();

    Thread write = new Thread() {  
        byte[] buff = new byte[4096];  
        void run() {  
             while ((vout=pInStrm.read(buf))!=-1) {  
                 fileOutputStream.write(buf, 0, vout);  
            }  
         }  
      }; write.start();  
Run Code Online (Sandbox Code Playgroud)

但我一直收到"IOException:管道已关闭"错误.有人可以帮帮我吗?或者,如果有任何JAVA API可以执行此转码(在Windows和RedHat Linux上),那将非常有帮助

谢谢

fab*_*ian 4

那是行不通的。

请记住,JAVE 仅充当 ffmpeg 可执行文件的包装器,即您提供参数,例如目标编码、响度等,然后基本上告诉 JAVE 调用 fmpeg 并传递设置,您使用 Java 方法作为参数输入到 ffmpeg可执行的。

此步骤要求您指定的设置为 1. 可序列化 2. ffmpeg 可执行文件已知

现在你可能会说至少有一些InputStreams,比如FileInputStream是可以序列化的,因为有一个低级文件描述符对应于这个InputStream,但是考虑一个ByteArrayInputStream - 我不知道Java是如何在每个平台上实现的,但我以某种方式怀疑,有一个相应的文件描述符。

然而关键的一点是,ffmpeg 可执行文件不知道也不应该知道 InputStream 类型的 Java 对象是什么。它能做的最好的事情(至少在 posix 系统上)是获取一个整数(文件描述符 E)并尝试从中读取数据。然而,使用文件描述符时,很多事情都可能出错。例如,如果它是一个文件,它可能是可查找的,例如,如果它实际上表示从套接字读取的数据,则它可能是可查找的。

令人高兴的是,在 Posix 系统上,每个进程至少有 3 个文件描述符,即 STDIN、STDOUT 和 STDERR。这对应于一个概念,您可以通过管道将输入/输出从一个进程传输到另一个进程。我不知道这是否或如何在 Windows 上工作,但在 OSX 或 Linux 上,您可以将数据通过管道传输到 ffmpeg 可执行文件中。这实际上意味着,您指示 ffmpeg 从 STDIN 文件描述符中读取。

遗憾的是,JAVE 没有实现 ffmpeg 的这一特定功能,即没有方法将数据通过管道传输到 ffmpegs STDIN。

FWIW。您可以编写一些本机 (c/c++) 代码并使用同时保存输入流和输出流的JNI ( http://en.wikipedia.org/wiki/Java_Native_Interface )传递 Java 对象“DecodeFeed”

您必须编写的本机代码可以包含 ffmpeg 源,并使用它们来解码/转码从 DecodeFeed.in 读取的输入,然后写回到 DecodeFeed.out。

我正在Android项目中这样做,你可能想看看以供参考。 https://github.com/fscz/FFmpeg-Android

或者,您可以分叉 JAVE 并自己实现此功能。您可能知道 Java 提供了一种通过调用 Runtime.exec 来运行可执行文件的方法。此调用将返回提供 Process.getOutputStream 的 Process 类的实例。如果写入此输出流,实际上是写入刚刚创建的进程的 STDIN。

有关如何生成和写入进程的文档,请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html 。

有关 ffmpeg 的可用命令行选项(包括从 STDIN 读取),请参阅http://ffmpeg.org/ffmpeg.html 。