Java问题中的FFMPEG

8vi*_*ius 0 java command-line ffmpeg process file-conversion

我在java Web服务中有以下代码:

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;
    }
Run Code Online (Sandbox Code Playgroud)

它曾经工作,现在它只是因为某些原因不会执行ffmpeg转换.我认为这是我的文件的问题但是从终端运行命令后没有抛出任何错误或任何事情,认为它可能是权限问题,但所有权限都已在我保存文件的文件夹中被授予.我注意到输入BufferedReader ins在运行进程后被设置为null,任何想法发生了什么?

Tho*_*mas 5

首先,使用你的代码进行一个小的挑剔...当你创建FileOutputStream它时,你使用字符串而不是a创建它File,当你已经创建了File之前,所以你也可以回收它而不是强制FileOutputStream实例化它File自己.

另一个小的挑剔事实是,当你写出音频文件时,你应该将它包含在一个try块中并关闭一个块中的输出流finally.如果允许您向项目添加新库,则可以使用具有方法的Guava,该方法Files.write(byte[],File)将为您处理所有脏资源管理.

我能看到的唯一看起来像是一个明确错误的事实是你忽略了ffmpeg的错误流.如果你阻止在ffmpeg的stdout上等待输入,那么它将无法工作.

处理此错误的最简单方法是使用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();
Run Code Online (Sandbox Code Playgroud)

如果以这种方式启动它,那么您当前的代码将能够完全读取两个输入流.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());
// ...
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,我会将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
    } 
}
Run Code Online (Sandbox Code Playgroud)

我创建该closeQuietly(Closeable)方法的原因是,如果您不以这种方式关闭它,则该方法可能会抛出异常close(),并且该异常将模糊最初抛出的异常.如果你把这些在一个工具类(虽然看你的代码,我认为,这是目前在被命名文件实用程序类),那么你就可以在你需要处理的文件输出到使用它们整个应用程序.

这将允许您将块重写为:

File file = new File(getUserFolderPath() + fileName + amr);
file.createNewFile()
write(Base64.decode(audio),file);
convertFile(fileName);
Run Code Online (Sandbox Code Playgroud)

我不知道你是否应该这样做,但是如果你想确定ffmpeg过程已经完成,那么你应该说ffmpeg.waitFor();确保它已经完成了.如果你这样做,那么你应该检查ffmpeg.exitValue();以确保它成功完成.

您可能想要做的另一件事是,一旦完成,将输出内容写入日志文件,以便记录发生的事情,以防万一发生.