从命令行调用ffmpeg不会等到文件完全写入硬盘之后 [英] Calling ffmpeg from command line does not wait until file was fully written do hard drive

查看:47
本文介绍了从命令行调用ffmpeg不会等到文件完全写入硬盘之后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在从事一项允许音频文件转换的服务.我在引擎盖下使用 ffmpeg 并使用 Runtime 进行呼叫.

I am currently working on a service to allower conversion of audio files. I am using ffmpeg under the hood and use the Runtime in order to make the call.

通话后,我读取了转换后的文件并将其上传到云存储中.

After the call I read the converted file and upload it to a cloud storage.

问题:

问题是,从驱动器读回文件仅给我几个字节.经过调查,它实际上在驱动器上有5 MB的空间,但是 readFileToByArray()只能读取几个kb.我认为这是因为文件在我想读回该文件时并未完全保留.

The problem is, that reading the file back from the drive gives me only a few bytes. After investigating, it actually has like 5 MB on the drive but readFileToByArray() reads only a few kb. I assume this is because the file was not completely persisted at the point where I want to read it back.

有什么方法可以确保将 ffmpeg 写入硬盘吗?看来 ffmpeg 所运行的主要进程在负责编写的并行进程之前完成了.也许吗?

Is there any way I can make sure that ffmpeg is done writing to the hard drive? It seems that the main process that ffmpeg was running in finishes before a parallel process that is responsible for writing. Maybe?

以下是将任意文件转换为AAC格式的相关代码:

Below is the relevant code that converts an arbitrary file to AAC-format:

File tempFile = File.createTempFile("input-", ".tmp", new File("/tmp"));
OutputStream outStream = new FileOutputStream(tempFile);
outStream.write(bytes);

String convertedFilePath = String.format("/tmp/output-%s.aac", UUID.randomUUID().toString());

String command = String.format(
        "ffmpeg -i %s -c:a aac -b:a 256k %s",
        tempFile.getAbsolutePath(),
        convertedFilePath
);

LOGGER.debug(String.format("Converting file to AAC; Running %s", command));

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(command);
try {
    process.waitFor(200, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
    throw new RuntimeException("Time out");
}

File convertedFile = new File(convertedFilePath);
byte[] result = FileUtils.readFileToByteArray(convertedFile);

// Upload "result" to cloud storage ..

推荐答案

我认为这里的问题是,您没有等到 ffmpeg 进程完成,而仅需200毫秒之后尝试在不检查 ffmpeg 进程是否正确退出的情况下读取转换后的文件.

I think the problem here is that you don't wait enough for ffmpeg process to finish and after only 200 milliseconds you go on trying to read the converted file without checking whether ffmpeg process exited correctly.

来自

from waitFor​(long timeout, TimeUnit unit) docs (emphasis mine):

在必要时使当前线程等待,直到此Process对象表示的进程终止或或经过指定的等待时间.

...

返回:

如果进程已退出,则为true;如果如果进程已退出,则等待时间为.

true if the process has exited and false if the waiting time elapsed before the process has exited.

这里是利用 waitFor()返回值来决定是否需要保持等待状态的代码的重写:

here a rewrite of your code that takes advantage of waitFor() return value to decide if it needs to keep waiting or not:

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.Runtime;
import java.lang.RuntimeException;
import java.nio.file.Files;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class FFmpeg
{
        public static void main(String[] args) throws Exception
        {
                /* just for testing purpose */
                File fooFile = new File("foo.mp3");
                byte[] bytes = Files.readAllBytes(fooFile.toPath());

                File tempFile = File.createTempFile("input-", ".tmp", new File("/tmp"));
                OutputStream outStream = new FileOutputStream(tempFile);
                outStream.write(bytes);
                outStream.close();

                String convertedFilePath = String.format("output-%s.aac", UUID.randomUUID().toString());
                String command = String.format(
                        "ffmpeg -nostdin -i %s -c:a aac -b:a 256k %s",
                        tempFile.getAbsolutePath(),
                        convertedFilePath
                );

                Runtime runtime = Runtime.getRuntime();
                Process process = runtime.exec(command);

                System.out.print("converting");
                while ( ! process.waitFor(500, TimeUnit.MILLISECONDS)) {
                        /* here you have the opportunity to kill the process if
                         * it is taking too long, print something etc.. */
                        System.out.print(".");
                }
                System.out.print("\n");

                if (process.exitValue() != 0) {
                        System.err.printf("ffmpeg failed with value %d\n", process.exitValue());
                        return;
                }

                File convertedFile = new File(convertedFilePath);
                byte[] result = Files.readAllBytes(convertedFile.toPath());
                System.out.println(result.length);
        }
}

和一些演示:

$ ls -l
total 5368
-rw-r--r-- 1 marco marco    1557 Oct 10 17:46 FFmpeg.java
-rw-r--r-- 1 marco marco 5486341 Oct 10 17:09 foo.mp3
$ javac FFmpeg.java
$ java FFmpeg
converting.........
7329962
$ ls -l
total 12528
-rw-r--r-- 1 marco marco    1793 Oct 10 17:49 FFmpeg.class
-rw-r--r-- 1 marco marco    1557 Oct 10 17:46 FFmpeg.java
-rw-r--r-- 1 marco marco 5486341 Oct 10 17:09 foo.mp3
-rw-r--r-- 1 marco marco 7329962 Oct 10 17:50 output-176a2e73-82d6-483b-8a40-aec0819c749f.aac
$

(转换后的文件的长度显示在末尾,请注意它与 ls 输出中的文件匹配).

(length of converted file is printed at the end, notice how it matches the one in ls output).

我添加的另一个重要内容是 ffmpeg 命令的 -nostdin 标志. ffmpeg 通常作为交互式程序运行,从 stdin 中获取用户输入,例如当询问您是否要覆盖目标文件时.当然,在这里我们没有机会回答是".或否"和 -nostdin 将使该过程失败并在需要用户交互时退出.如果没有该标志,它将无限期地等待用户输入(您可能也对 -y -n 标志感兴趣).

another important thing I added is the -nostdin flag to ffmpeg command. ffmpeg is often run as an interactive program taking user input from stdin e.g. when it asks if you want to overwrite target file. here of course we don't have the chance to answer "yes" or "no" and -nostdin will make the process to fail and exit when a user interaction is required. without that flag, it will wait for user input indefinitely (you maybe interested in -y and -n flags also).

这篇关于从命令行调用ffmpeg不会等到文件完全写入硬盘之后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆