How does ffprobe determine duration?
Asked Answered
S

2

16

I'm using ffprobe to analyze media files stored on a remote server. This seems to work well, but for some files the duration is missing or incorrect (usually longer than it should be). Other times it returns this information accurately, and it doesn't seem to be related to the media type (codec, etc.).

Here's an example of a command that works:

ffprobe -v quiet -print_format json -show_streams -show_format http://host.com/file.aiff

{
"streams": [
    {
        "index": 0,
        "codec_name": "pcm_s16be",
        "codec_long_name": "PCM signed 16-bit big-endian",
        "codec_type": "audio",
        "codec_time_base": "1/44100",
        "codec_tag_string": "[0][0][0][0]",
        "codec_tag": "0x0000",
        "sample_fmt": "s16",
        "sample_rate": "44100",
        "channels": 2,
        "bits_per_sample": 16,
        "r_frame_rate": "0/0",
        "avg_frame_rate": "0/0",
        "time_base": "1/44100",
        "start_pts": 0,
        "start_time": "0.000000",
        "duration_ts": 8494248,
        "duration": "192.613333",
        "bit_rate": "1411200",
        "nb_frames": "8494248",
        "disposition": {
            "default": 0,
            "dub": 0,
            "original": 0,
            "comment": 0,
            "lyrics": 0,
            "karaoke": 0,
            "forced": 0,
            "hearing_impaired": 0,
            "visual_impaired": 0,
            "clean_effects": 0,
            "attached_pic": 0
        }
    }
],
"format": {
    "filename": "http://host.com/file.aiff",
    "nb_streams": 1,
    "nb_programs": 0,
    "format_name": "aiff",
    "format_long_name": "Audio IFF",
    "start_time": "0.000000",
    "duration": "192.613333",
    "probe_score": 100
}
}

Here's an example of one that doesn't:

ffprobe -v quiet -print_format json -show_streams -show_format "http://host.com/file.wav"

Which generates this result:

{
"streams": [
    {
        "index": 0,
        "codec_name": "pcm_s16le",
        "codec_long_name": "PCM signed 16-bit little-endian",
        "codec_type": "audio",
        "codec_time_base": "1/44100",
        "codec_tag_string": "[1][0][0][0]",
        "codec_tag": "0x0001",
        "sample_fmt": "s16",
        "sample_rate": "44100",
        "channels": 2,
        "bits_per_sample": 16,
        "r_frame_rate": "0/0",
        "avg_frame_rate": "0/0",
        "time_base": "1/44100",
        "bit_rate": "1411200",
        "disposition": {
            "default": 0,
            "dub": 0,
            "original": 0,
            "comment": 0,
            "lyrics": 0,
            "karaoke": 0,
            "forced": 0,
            "hearing_impaired": 0,
            "visual_impaired": 0,
            "clean_effects": 0,
            "attached_pic": 0
        }
    }
],
"format": {
    "filename": "http://host.com/file.wav",
    "nb_streams": 1,
    "nb_programs": 0,
    "format_name": "wav",
    "format_long_name": "WAV / WAVE (Waveform Audio)",
    "bit_rate": "1411200",
    "probe_score": 99
}
}

These two examples are different formats, but I've seen it work and not work when the format is the same, I just don't have an example handy.

What I'd like to know is if there is something I can change about the parameters I'm using with ffprobe to allow the duration to be determined consistently and accurate, or any information I can find as to how ffprobe works so I figure out how I might change the input files, etc. so they work correctly.

Alternatively, if there is a different tool that works more reliably (it would need to be an open-source Linux tool) any suggestions or recommendations are welcome.

Slaveholder answered 1/6, 2015 at 20:14 Comment(6)
The most accurate way would probably be to fully decode the file then look at the console output: ffmpeg -i input -f null -. Unfortunately this can take some time depending on your input.Arteriotomy
I thought FFmpeg used the container to calculate duration (basically by trusting whatever metadata was in the container...)?Excuse
@LordNeckbeard ffmpeg does provide an accurate duration after the transcoding process is complete, but for my application I can't afford to store the result before I begin returning it to the client (or alternatively, the time to run the transcoding operation twice).Slaveholder
@Excuse I suspected this but it would be interesting to confirm it; do you know of a source for this information?Slaveholder
I ran into a similar problem while trying to get the duration of mp3s with ffprobe. In windows 7 there are three sample mp3s, 1st and 2nd work well with ffprobe, but for the 3rd (Sleep Away.mp3 from Bob Acri) ffprobe shows me a duration of 150 seconds, but it is actual 200 seconds long (Windows explorer shows the correct duration) BUT ffmpeg also shows wrong result ('ffprobe.exe -v quiet -print_format json -show_streams -show_format "C:\Users\Public\Music\Sample Music\Sleep Away.mp3"' vs 'ffmpeg.exe -i "C:\Users\Public\Music\Sample Music\Sleep Away.mp3"') - both is wrong :/Liebknecht
FWIW I gave up on this and decided to parse the file headers myself. So far I'm able to identify WAVE/RIFF files accurately (even the ones that tripped-up ffprobe). I'll be working on other formats as well, but WAVE was most important for my application.Slaveholder
D
7

One simple solution is to use -show_packets option

ffprobe -i input.mp4 -show_packets > a.txt

Now open a.txt and go to the last packet and see dts_time value that would be the accurate duration of file. If dts_time is not defined check for the pts_time value.

Deadman answered 26/10, 2015 at 13:7 Comment(0)
D
5

Metadata may not be correct. The most correct way is decoding the whole file:

$ ffmpeg -i input.webm -f null -
...
frame=206723 fps=1390 q=-0.0 Lsize=N/A time=00:57:28.87 bitrate=N/A speed=23.2x

Source: https://trac.ffmpeg.org/wiki/FFprobeTips#Getdurationbydecoding

During answered 10/1, 2019 at 15:25 Comment(1)
$ ffmpeg -i input.webm -f null - 2>&1 | grep timeAcre

© 2022 - 2024 — McMap. All rights reserved.