Подтвердить что ты не робот

Как получить реальную, фактическую продолжительность файла MP3 (VBR или CBR) на стороне сервера

Я использовал для вычисления продолжительности файлов MP3 файлов на стороне сервера, используя ffmpeg, который, казалось, работал нормально. Сегодня я обнаружил, что некоторые вычисления были неправильными. Почему-то, по какой-то причине, ffmpeg будет просчитывать продолжительность и, кажется, происходит только с файлами с переменной скоростью передачи в битрейтах.

При локальном тестировании я заметил, что ffmpeg напечатал две дополнительные строки зеленым цветом.

Используемая команда:

ffmpeg -i song_9747c077aef8.mp3

ffmpeg говорит:

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

После приятного теплого сеанса google я обнаружил некоторые сообщения об этом, но решение не найдено.

Затем я попытался увеличить максимальную продолжительность:

ffmpeg -analyzeduration 999999999 -i song_9747c077aef8.mp3

После этого ffmpeg вернул только вторую строку:

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

Но в любом случае рассчитанная продолжительность была просто неправильной. Сравнивая его с VLC, я заметил, что продолжительность правильная.

После нескольких исследований я наткнулся на mp3info - который я установил и использовал.

mp3info -p "%S" song_9747c077aef8.mp3

mp3info затем вернула длительность CORRECT, но только как целое число, которое я не могу использовать, поскольку мне нужно более точное число здесь. Причина этого была объяснена в комментарии ниже, пользователем blahdiblah - mp3info просто вытаскивает ID3-информацию из файла и фактически не выполняет никаких вычислений.

Я также попытался использовать mplayer для извлечения продолжительности, но так же, как ffmpeg, mplayer возвращает неправильное значение.

4b9b3361

Ответ 1

Наконец-то я нашел правильное решение этой проблемы с помощью sox, которое возвращает правильную информацию.

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

Длина (в секундах): 219.062857

Ответ 2

Вы можете полностью декодировать файл, чтобы получить фактическую продолжительность:

ffmpeg -i input.mp3 -f null -

Вторая в последней строке вывода консоли будет выглядеть примерно так:

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

Где time - фактическая продолжительность. В этом примере весь процесс занял около 0,5 секунды.

Ответ 3

Расширение решения от LordNeckbeard. Чтобы получить только статистику, вы можете добавить флаги -v тихий -stats

ffmpeg -v quiet -stats -i input.mp3 -f null - 

Ответ 4

Проще использовать ffmpeg для копирования файла из файла с ошибочной продолжительностью в его тег ID3. Это заставляет его писать правильную информацию.

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

Поскольку он использует копирование, он занимает часть времени, которое занимает оригинальная кодировка. Это едва заметно в песне, но вы действительно оцените ее с 7-часовой аудиокнигой. После перекодирования тег ID3" Duration" теперь содержит правильную информацию.

Ответ 5

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
if [[ "$(AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -c copy - 2>&1 | tail -n 2 | head -n 1)" =~ \ 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"