29

I used to calculate the duration of MP3 files server-side using ffmpeg - which seemed to work fine. Today i discovered that some of the calculations were wrong. Somehow, for some reason, ffmpeg will miscalculate the duration and it seems to happen with variable bit rate mp3 files only.

When testing this locally, i noticed that ffmpeg printed two extra lines in green.

Command used:

ffmpeg -i song_9747c077aef8.mp3

ffmpeg says:

[mp3 @ 0x102052600] max_analyze_duration 5000000 reached at 5015510
[mp3 @ 0x102052600] Estimating duration from bitrate, this may be inaccurate

After a nice, warm google session, i discovered some posts on this, but no solution was found.

I then tried to increase the maximum duration:

ffmpeg -analyzeduration 999999999 -i song_9747c077aef8.mp3

After this, ffmpeg returned only the second line:

[mp3 @ 0x102052600] Estimating duration from bitrate, this may be inaccurate

But in either case, the calculated duration was just plain wrong. Comparing it to VLC i noticed that there the duration is correct.

After more research i stumbled over mp3info - which i installed and used.

mp3info -p "%S" song_9747c077aef8.mp3

mp3info then returned the CORRECT duration, but only as an integer, which i cannot use as i need a more accurate number here. The reason for this was explained in a comment below, by user blahdiblah - mp3info is simply pulling ID3 info from the file and not actually performing any calculations.

I also tried using mplayer to retrieve the duration, but just as ffmpeg, mplayer is returning the wrong value.

SquareCat
  • 5,699
  • 9
  • 41
  • 75
  • Thank You, but i cannot assume proper duration information in the MP3s headers / ID3 tags, even if i wanted to. I have to calculate it to get a 100% accurate result. – SquareCat May 03 '12 at 19:07
  • Ahh, then I think you would have to go through the mp3, and find every frame, then compute a duration from that. – 1321941 May 03 '12 at 19:09
  • Thank You for your input, but the reason i am looking for a prepared solution is because this is exactly what i don't want to (have to) do. – SquareCat May 03 '12 at 19:11
  • mp3info isn't what you're looking for, it just pulls information from the ID3 tags and MP3 headers. – blahdiblah May 03 '12 at 19:12
  • Ah, that's good to know. Thanks for the input, so i will dump mp3info altogether. – SquareCat May 03 '12 at 19:13
  • Can you provide one of the files that ffmpeg gets the duration wrong for so that we can test possible solutions? – blahdiblah May 03 '12 at 19:13
  • I wish i could, but i can't. I am not allowed to. I could try to get similar results with re-encoding files to VBR but that would take quite some time. – SquareCat May 03 '12 at 19:15
  • Can you duplicate the issue with recent ffmpeg from Git? No need to install: just get the [FFmpeg source](http://ffmpeg.org/download.html) via git, use a plain `./configure`, run `make`, and then run the resulting binary. – llogan May 03 '12 at 23:55
  • Does it have to be Git? I just messaged the server admin to update ffmpeg to the latest version and will see what happens then.. – SquareCat May 04 '12 at 14:02
  • FFmpeg development is very active. Duplicating the issue with recent Git would eliminate the possibility that the issue has already been fixed. Again, you don't have to replace your current ffmpeg, but just test ffmpeg from Git. – llogan May 04 '12 at 17:51
  • After further testing with the latest release of ffmpeg, the issue is still there. Wrong durations are calculated for a variety of MP3s. Does anyone have some more suggestions on this? – SquareCat May 06 '12 at 20:34
  • The "Estimating" message may be spurious - http://patches.libav.org/patch/36540/ fixed the message in Mar 2013. Do you still get this message with latest ffmpeg? Anyway, doesn't help you if the durations are wrong. – Beni Cherniavsky-Paskin Oct 22 '13 at 23:43

7 Answers7

24

I finally found a proper solution to this problem using sox - which returns the correct information.

sox file.mp3 -n stat
Samples read:          19321344
Length (seconds):    219.062857
Scaled by:         2147483647.0
Maximum amplitude:     1.000000
Minimum amplitude:    -1.000000
Midline amplitude:    -0.000000
Mean    norm:          0.141787
Mean    amplitude:     0.000060
RMS     amplitude:     0.191376
Maximum delta:         0.947598
Minimum delta:         0.000000
Mean    delta:         0.086211
RMS     delta:         0.115971
Rough   frequency:         4253
Volume adjustment:        1.000

Length (seconds): 219.062857

SquareCat
  • 5,699
  • 9
  • 41
  • 75
  • If you need faster solution (it seems that sox will read all samples from the file) check out the solution using NAudio - mono works on linux without problem it should be doable... – Daniel Mošmondor Nov 13 '12 at 09:55
  • 5
    It outputs `sox FAIL formats: no handler for file extension mp3` by default. How should I install it? – shukshin.ivan Oct 26 '16 at 19:53
  • 2
    @shukshin.ivan: You need to install either `libsox-fmt-mp3` or `libsox-fmt-all` in case you need support for other formats as well. – SDwarfs Sep 18 '20 at 04:17
20

You can decode the file completely to get the actual duration:

ffmpeg -i input.mp3 -f null -

The second to the last line of the console output will show something like:

size=N/A time=00:03:49.12 bitrate=N/A

Where time is the actual duration. In this example the whole process took about 0.5 seconds.

llogan
  • 121,796
  • 28
  • 232
  • 243
8

Extending solution from llogan (LordNeckbeard). To get only stats you can add flags -v quiet -stats

ffmpeg -v quiet -stats -i input.mp3 -f null - 
Mitja Gomboc
  • 663
  • 12
  • 17
  • Are you able to convert this to seconds? – John Pollard May 18 '21 at 19:00
  • It's not entirely clear whether the asker wants to have a correct time value, or just to not have this (relatively innocuous, in at least some cases) message displayed. This is a useful answer for the latter case; thanks! – lindes Apr 12 '22 at 20:32
8

Simpler is to use ffmpeg to copy the file from the one with the faulty duration in its ID3 tag. This causes it to write the correct information.

ffmpeg -i "audio.mp3" -acodec copy "audio_fixed.mp3"

Because it uses copy it takes a fraction of the time the original encoding takes. This is hardly noticeable with a song, but you really appreciate it with a 7 hour audiobook. After re-encoding, the ID3 "Duration" tag now has the correct information.

miriam
  • 407
  • 5
  • 4
  • I could not figure out why my audiobook kept "compiling" but using only the first few minutes of each chapter. This was the solution. THANK YOU. – Pierce May 11 '21 at 22:29
5

ffmpeg will print all file information if no other arguments are provided.

Use grep or awk to only return the "Duration":

ffmpeg -i file.mp3 2>&1 | grep Duration

ffmpeg -i file.mp3 2>&1 | awk '/Duration/ { print substr($2,0,length($2)-1) }'

JSON C11
  • 11,272
  • 7
  • 78
  • 65
  • 2
    The ffmpeg output is not meant to be machine parsed. [Use ffprobe instead](https://stackoverflow.com/a/22243834/1109017). An exception is if you want to [use ffmpeg to fully decode the file to get the duration](https://stackoverflow.com/a/33115316/1109017), but your example does not do that. – llogan Dec 09 '19 at 23:04
1
AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i audio.mp3 -f null -vn -c:a copy - 2>&1 | tail -n 2
declare out="$(AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -vn -c:a copy - 2>&1 | tail -n 2 | head -n 1)"
if [[ "$out" =~ \ time=([0-9]+):([0-9]{2}):([0-9]{2})\.([0-9]+) ]]; then
  declare duration=0 us="${BASH_REMATCH[4]}" t
  for t in "${BASH_REMATCH[@]:1:3}"; do
    ((duration *= 60))
    ((duration += ${t#0} ))
  done
  while [ ${#us} -lt 6 ]; do us+=0; done
  ((us >= 500000)) && ((duration++))
  ((duration)) || ((duration++))
fi
echo -E Duration: "$duration"
Luchostein
  • 2,314
  • 20
  • 24
0
sudo apt install sox 
sudo apt-get install libsox-fmt-mp3

and then:

sox yourfile.mp3 -n stat
kassbohm
  • 31
  • 3
  • Have a look at the second comment of the top voted answer. I could not make a comment on that comment, so just did what I did... – kassbohm Mar 25 '20 at 19:09