【问题标题】:FFMPEG in Java issueJava中的FFMPEG问题
【发布时间】:2011-06-29 04:59:29
【问题描述】:

我在 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;
    }

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

【问题讨论】:

    标签: java command-line process ffmpeg file-conversion


    【解决方案1】:

    首先,对您的代码进行一个小小的挑剔...当您创建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(); 以确保它成功完成。

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

    【讨论】:

    • 谢谢,我现在在家,所以我明天必须测试这段代码。问题是您在上面看到的代码上周还在工作,今天当我进行另一项测试时,因为我做了一些更改(不在这部分代码中),它失败了,并且不会转换音频文件,以为是权限问题,但从终端执行命令有效。我会尽快回复你结果
    • 感谢它的工作:D 我将代码更改为新的,如果您有任何其他建议,我将不胜感激
    猜你喜欢
    • 2015-06-27
    • 2011-07-04
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 2018-01-15
    • 2011-09-19
    • 2018-06-21
    • 2012-01-06
    相关资源
    最近更新 更多