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

6

我正在尝试使用JAVE调用ffmpeg将*.mov文件转换为*.mp4文件。 输入文件和输出文件都以InputStream和OutputStream的形式存在。 这意味着我需要将InputStream和OutputStream作为-i和-y参数传递给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();  

但我一直收到“IOException:管道已关闭”错误。有人能帮助我吗?如果有任何可以在Windows和RedHat Linux上执行此转码的JAVA API,那将非常有帮助。谢谢。
1个回答

4

这样做行不通。

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

此步骤要求您指定的设置是:

  1. 可序列化的
  2. 已知于ffmpeg可执行文件

现在您可能会争辩说,至少某些InputStream(如FileInputStream)在某种程度上是可序列化的,因为与此InputStream相对应的有一个底层文件描述符,但请考虑ByteArrayInputStream - 我不知道Java在每个平台上如何实现,但我有点怀疑是否存在相应的文件描述符。

然而,关键点在于,ffmpeg可执行文件不知道也不应该知道InputStream类型的Java对象。它能做到的最好的事情(至少在posix系统上)是获取一个整数(文件描述符)并尝试从中读取数据。但是,在使用文件描述符时可能会出现许多问题。例如,如果它是文件,则可以进行寻址,例如,如果它实际上代表从套接字读取的数据,则不能进行寻址。

很高兴,在Posix系统上,每个进程至少有三个文件描述符,即STDIN、STDOUT和STDERR。这对应于一个概念,您可以将一个进程的输入/输出管道传递给另一个进程。我不知道在Windows上是否以及如何工作,但在OSX或Linux上,您可以将数据传送到ffmpeg可执行文件中。这实际上意味着,您指示ffmpeg从STDIN文件描述符中读取。
遗憾的是,JAVE没有实现ffmpeg的这个特定功能,也就是说,没有方法将数据传输到ffmpegs STDIN中。
顺便说一下,您可以编写一些本地(c/c++)代码,并使用JNI(http://en.wikipedia.org/wiki/Java_Native_Interface)传递一个名为'DecodeFeed'的Java对象,其中包含Inputstream和OutputStream。
您必须编写本地代码,其中包括ffmpeg源代码,并使用它们来解码/转码从DecodeFeed.in读取的输入,然后将其写回DecodeFeed.out。

我正在进行一个Android项目,你可能想要参考一下。 https://github.com/fscz/FFmpeg-Android

或者,你可以fork JAVE并自己实现这个功能。正如你所知,Java提供了一种通过调用Runtime.exec来运行可执行文件的方法。这个调用将返回一个Process类的实例,它提供了Process.getOutputStream。如果你向这个Outputstream写入数据,你实际上是在写入刚刚创建的进程的STDIN。

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接