Передача FileInputStream и FileOutputStream в ffmpeg для перекодирования (с использованием JAVE-Java Audio Video Encoding) - PullRequest
6 голосов
/ 19 февраля 2012

Я пытаюсь перекодировать файл * .mov в файл * .mp4, используя JAVE, который вызывает ffmpeg.И входной файл, и выходной файл находятся в формах InputStream и OutputStream.Это означает, что мне нужно передать InputStream и OutputStream как -i и -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();  

Но я получаю ошибку «IOException: труба закрыта».Может ли кто-нибудь помочь мне?В качестве альтернативы, если есть какой-либо JAVA API, который мог бы выполнять это транскодирование (в Windows и RedHat Linux), это было бы очень полезно

Спасибо

1 Ответ

3 голосов
/ 17 февраля 2014

Это не сработает таким образом.

Помните, что JAVE просто действует как оболочка для исполняемого файла ffmpeg, то есть вы предоставляете параметры, такие как целевое кодирование, громкость и т. Д., А затем в основном говорите JAVEчтобы вызвать fmpeg и передать настройки, вы ввели с помощью методов Java в качестве параметров исполняемый файл ffmpeg.

Для этого шага необходимо указать следующие параметры: 1. Сериализуемый 2. Известен исполняемому файлу ffmpeg

Теперь можно утверждать, что, по крайней мере, некоторые InputStreams, такие как FileInputStream, могут быть каким-то образом сериализуемыми, поскольку существует дескриптор файла низкого уровня, соответствующий этому InputStream, но рассмотрим ByteArrayInputStream - я не знаю, как Java реализуется на каждой платформе, но япочему-то сомневаюсь, что существует соответствующий дескриптор файла.

Однако критический момент заключается в том, что исполняемый файл ffmpeg не знает и не должен знать, что такое Java-объект типа InputStream.Лучшее, что он может сделать (по крайней мере, в системах posix), это взять целое число (File DescriptorE) и попытаться прочитать данные из него.Однако при работе с дескриптором файла многое может пойти не так.Например, он может быть доступен для поиска, если это, например, файл или нет, если он действительно представляет данные, считываемые из сокета.

Радостно, в системах Posix, для каждого процесса есть как минимум 3 дескриптора файлаэто STDIN, STDOUT и STDERR.Это соответствует концепции, в которой вы можете направлять ввод / вывод от одного процесса к другому.Я не знаю, работает ли это в Windows или как это работает, но в OSX или Linux вы можете передавать данные в исполняемый файл ffmpeg.На самом деле это означает, что вы указываете ffmpeg читать из файлового дескриптора STDIN.

К сожалению, JAVE не реализует эту особую функцию ffmpeg, то есть нет метода, который передает данные в ffmpegs STDIN.

FWIW.Вы можете написать некоторый нативный (c / c ++) код и передать Java-объект DecodeFeed, используя JNI (http://en.wikipedia.org/wiki/Java_Native_Interface), который содержит и Inputstream, и OutputStream

Нативный код, который у вас естьзапись может включать источники ffmpeg и использовать их для декодирования / транскодирования ввода, который читается из DecodeFeed.in и затем записывается обратно в DecodeFeed.out.

Я делаю это в проекте Android, вы можете захотетьпосмотрите для справки. https://github.com/fscz/FFmpeg-Android

В качестве альтернативы, вы можете разветвить 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 для доступных опций командной строки (включая чтение из STDIN) для ffmpeg.

...