bramp / ffmpeg-cli-wrapper

Java wrapper around the FFmpeg command line tool
BSD 2-Clause "Simplified" License
1.67k stars 412 forks source link

Extract actual duration from a file/link #237

Open anz000 opened 2 years ago

anz000 commented 2 years ago

I used to use ff-probe to gather the duration of a media file. However, I've noticed that some reported durations are incorrect. I've read that having a variable bit-rate might be one of the issues.

Anywho, I was using

FFprobe ffprobe = new FFprobe(props.getProperty(FFPROBE_BIN_KEY));
return ffprobe.probe(link);

Running a similar command on the terminal ffprobe -i Audio.file returns a similar output. I can see that there is disclaimer in the output [mp3 @ 0x559ca5e87320] Estimating duration from bitrate, this may be inaccurate.

As I was looking around, I did find a terminal-based solution that can correctly find the duration of the audio file. ffmpeg -i -v quiet -stats Audio.mpga -f null -

The input may be a remote link. From a few tests I ran, it may take up to 30 seconds for a 1-hr media to render the correct duration. The output will be like:

$ ffmpeg -v quiet -stats -i Audio632246514690744417.tmp -f null -
size=N/A time=01:02:46.09 bitrate=N/A speed=1.24e+04x 

I need to then extract the time component from the output.

I was having a difficult trying to convert that command like ffmpeg -i -v quiet -stats Audio.link -f null - to a compatible code and parse the duration. So far, I have got the code to work (turned on the log level to see the command issued and hit-and-trial my way around to get it to work). But still have no idea about how to parse once it is done.

FFmpegBuilder builder = new FFmpegBuilder()
                .addExtraArgs("-stats")
                .addInput(link)
                .addStdoutOutput()
                .addExtraArgs("-f", "null")
                .done();

So, this code works. The input is a remote audio file. The console output is:

2021-09-15 13:23:55.138  INFO 5859 --- [tp1559154670-33] n.b.f.RunProcessFunction                 : /usr/bin/ffmpeg -version
2021-09-15 13:23:55.255  INFO 5859 --- [tp1559154670-33] n.b.f.RunProcessFunction                 : /usr/bin/ffmpeg -y -v error -stats -i https://some-audio-file.mpga -f null -
size=N/A time=01:02:46.09 bitrate=N/A speed=42.1x 

I need to extract the time from the output. How can I get this?

anz000 commented 2 years ago

I did find one way to do it. I wonder if there are more elegant way to do it.

I ended up building a custom ProgressListener that returns the duration.

public class CustomtProgressListener implements ProgressListener {

    private double duration;

    @Override
    public void progress(Progress progress) {
        if (progress.status.equals(Progress.Status.END)) {
            duration = (double) progress.out_time_ns / 1000000000;
        }
    }

    public double getDuration() {
        return duration;
    }
}

Then, use it as :

FFmpegBuilder builder = new FFmpegBuilder()
                .addExtraArgs("-stats")
                .addInput(link)
                .addStdoutOutput()
                .addExtraArgs("-f", "null")
                .done();

FFmpegExecutor executor = new FFmpegExecutor(ffmpeg);

ProgressListener progressListener = new CustomProgressListener();

FFmpegJob job = executor.createJob(builder, progressListener);
job.run();

System.out.println("Duration :: " + ((CustomProgressListener) progressListener).getDuration());