FFMPEG в выпуске Java - PullRequest
       46

FFMPEG в выпуске Java

0 голосов
/ 17 февраля 2011

У меня есть следующий код в веб-службе Java:

public boolean makeFile(String fileName, String audio)
    {
        if (makeUserFolder())
        {
            File file = new File(getUserFolderPath() + fileName + amr);
            FileOutputStream fileOutputStream = null;
            try
            {

                file.createNewFile();
                fileOutputStream = new FileOutputStream(file);
                fileOutputStream.write(Base64.decode(audio));

                return true;

            }
            catch(FileNotFoundException ex)
            {
                return false;
            }
            catch(IOException ex)
            {
                return false;
            }
            finally{
                try {
                    fileOutputStream.close();
                    convertFile(fileName);
                } catch (IOException ex) {
                    Logger.getLogger(FileUtils.class.getName()).log(Level.SEVERE, null, ex);
            }
}

        }
        else
            return false;

    }

    public boolean convertFile(String fileName)
    {
        Process ffmpeg;
        String filePath = this.userFolderPath + fileName;
        try {
            ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",filePath + amr,filePath + mp3);
            pb.redirectErrorStream();
            ffmpeg = pb.start();
        } catch (IOException ex) {
            return false;
        }
        return true;
    }

Раньше он работал, и теперь по какой-то причине просто не будет выполнять преобразование ffmpeg. Я думал, что это проблема с моим файлом, но после запуска команды из терминала не выдается никаких ошибок или чего-то еще, подумал, что это может быть проблема с разрешениями, но все разрешения были предоставлены в папке, в которой я сохраняю файлы. Я заметил, что входные BufferedReader ins устанавливаются в нуль после запуска процесса, есть идеи, что происходит?

1 Ответ

5 голосов
/ 18 февраля 2011

Прежде всего, небольшая мелочь с вашим кодом ... когда вы создаете FileOutputStream, вы создаете его, используя строку, а не File, когда вы уже создали File ранее, так что вы можете а также переработайте это вместо того, чтобы заставлять FileOutputStream создавать экземпляр самого File.

Другим небольшим придиркой является тот факт, что при записи аудиофайла вы должны заключить его в блок try и закрыть выходной поток в блок finally. Если вам разрешено добавлять новую библиотеку в ваш проект, вы можете использовать Guava , у которого есть метод Files.write(byte[],File), который позаботится обо всем грязном управлении ресурсами для вас.

Единственное, что я вижу, что похоже на определенную ошибку - это то, что вы игнорируете поток ошибок ffmpeg. Если вы блокируете ожидание ввода на стандартный вывод ffmpeg, то он не будет работать.

Самый простой способ устранить эту ошибку - использовать ProcessBuilder вместо Runtime.

ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",filePath+amr,filePath+mp3);
pb.redirectErrorStream(); // This will make both stdout and stderr be redirected to process.getInputStream();
ffmpeg = pb.start();

Если вы запустите его таким образом, ваш текущий код сможет полностью прочитать оба входных потока. Возможно, что stderr скрывал какую-то ошибку, которую вы не смогли увидеть из-за того, что не читали ее.

Если бы это не было вашей проблемой, я бы рекомендовал использовать абсолютные пути с ffmpeg ... другими словами:

String lastdot = file.getName().lastIndexOf('.');
File mp3file = new File(file.getParentFile(),file.getName().substring(0,lastdot)+".mp3");
ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",file.getAbsolutePath(),mp3file.getAbsolutePath());
// ...

Если это не сработает, я бы также изменил ffmpeg на абсолютный путь (чтобы исключить проблемы с путями).

Редактировать: Дополнительные предложения.

Я бы лично реорганизовал написание кода в его собственный метод, чтобы вы могли использовать его где угодно. Другими словами:

public static boolean write(byte[] content, File to) {
    FileOutputStream fos = new FileOutputStream(to);
    try {
        fos.write(content);
    } catch (IOException io) {
        // logging code here
        return false;
    } finally {
        closeQuietly(fos);
    }
    return true;
}
public static void closeQuietly(Closeable toClose) {
    if ( toClose == null ) { return; }
    try {
        toClose.close();
    } catch (IOException e) {
        // logging code here
    } 
}

Причина, по которой я применил метод closeQuietly(Closeable), заключается в том, что если вы не закроете его таким образом, есть вероятность, что исключение будет вызвано методом close(), и это исключение будет скрыть исключение, которое было брошено изначально. Если вы поместите их в служебный класс (хотя, глядя на ваш код, я предполагаю, что класс, в котором он находится в настоящее время, называется FileUtils), то вы сможете использовать их в своем приложении всякий раз, когда вам нужно иметь дело с выводом файла.

Это позволит вам переписать блок как:

File file = new File(getUserFolderPath() + fileName + amr);
file.createNewFile()
write(Base64.decode(audio),file);
convertFile(fileName);

Я не знаю, следует ли вам это делать, однако, если вы хотите быть уверены, что процесс ffmpeg завершен, вам следует сказать ffmpeg.waitFor();, чтобы убедиться, что он завершен. Если вы это сделаете, то вам нужно проверить ffmpeg.exitValue();, чтобы убедиться, что оно успешно завершено.

Еще одна вещь, которую вы, возможно, захотите сделать, когда она будет завершена, запишите, что она выводит в файл журнала, чтобы у вас была запись о том, что произошло, на случай, если что-то случится.

...