繁体   English   中英

FFMPEG in Java问题

[英]FFMPEG in Java issue

我在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,知道发生了什么吗?

首先,用代码编写一个小的nitpick ...当您创建FileOutputStream您使用字符串而不是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();

如果以此方式启动,那么您当前的代码将能够完全读取两个输入流。 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(); 确保它成功完成。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM