- Вопрос или проблема
- Формат (контейнер) продолжительности
- Длительность видеопотока
- С помощью ffmpeg
- Python
- Специальный случай Webm
- Ответ или решение
- 1. Использование FFprobe
- Получение продолжительности формата (контейнера):
- Получение продолжительности видео потока:
- 2. Использование FFmpeg
- 3. Использование Mediainfo
- 4. Использование MPlayer
- 5. Подход с использованием Python
- 6. Выполнение на Windows с помощью PowerShell
- Заключение
Вопрос или проблема
Как я могу получить продолжительность видео в секундах?
Что я пробовал:
ffmpeg -i file.flv 2>&1 | grep "Duration"
Продолжительность: 00:39:43.08, начало: 0.040000, битрейт: 386 кбит/с
mediainfo file.flv | grep Duration
Продолжительность: 39 мин 43 сек
Это близко, но не совсем точно, 2383 это 39.71 минуты
ffmpeg -i file.flv 2>&1 | grep "Duration"| cut -d ' ' -f 4 | sed s/,// | sed 's@\..*@@g' | awk '{ split($1, A, ":"); split(A[3], B, "."); print 3600*A[1] + 60*A[2] + B[1] }'
2383
Чтобы получить минуты, нужно разделить 2383 секунды на 60.
39.7167
А затем умножить дробную часть .7167 на 60, чтобы получить оставшиеся секунды.
43.002
Итак, это 39 минут, 43 секунды. Приложение, похоже, дает вам точное значение.
Просто используйте ffprobe
напрямую. Нет необходимости в sed
, grep
и т. д. Существует несколько “продолжительностей”, которые можно получить (в зависимости от вашего ввода).
Формат (контейнер) продолжительности
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
Результат:
30.024000
Добавление параметра -sexagesimal
будет использовать формат временной единицы ЧЧ:ММ:СС.МИКРОСЕКУНДЫ:
0:00:30.024000
Длительность видеопотока
Если вы хотите узнать продолжительность конкретного видеопотока или аудиопотока:
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
Результат:
30.000000
Вышеупомянутые команды взяты из FFmpeg Wiki: Советы по FFprobe.
С помощью ffmpeg
Вы можете использовать ffmpeg
для получения продолжительности, декодируя входной файл:
ffmpeg -i input.mp4 -f null -
…
frame= 1587 fps=0.0 q=0.0 Lsize=N/A time=00:01:03.48 bitrate=N/A
В этом примере time=00:01:03.48
— это продолжительность.
Это может занять много времени в зависимости от вашего входного файла.
Если у вас есть ffmpeg
, у вас также должен быть ffprobe
:
ffprobe -i input.file -show_format | grep duration
ffprobe -i input.file -show_format -v quiet | sed -n 's/duration=//p'
Это также даст доли секунды. Если это проблема, вы можете дополнительно обработать это с помощью sed.
mediainfo --Output="General;%Duration%" file.flv
Это выводит продолжительность в миллисекундах как одно целое число. Нет необходимости в grep/cut/sed/…
Решение с mplayer, которое дает секунды напрямую:
mplayer -identify -frames 0 -vo null -nosound file.flv 2>&1 | awk -F= '/LENGTH/{print $2}'
Для моего ffmpeg-0.6.5-1.el6.rf.x86_64, чтобы получить только секунды, формат команды ffprobe:
ffprobe <file> -show_format 2>&1 | sed -n 's/duration=//p'
Информация о продолжительности может появляться в нескольких местах, например, mp4
файлы могут иметь duration
под секциями stream
, но mkv
файлы могут не иметь. Поэтому цель — распечатать информацию о продолжительности из как можно большего количества мест:
ffprobe.exe -show_entries format=duration:stream_tags=duration:stream=duration -v quiet -print_format json input_file.mp4
-show_entries
— это флаг с очень странным синтаксисом, смысл вышеописанного в том, чтобы распечатать:
duration
под секциейformat
duration
подtags
под секциямиstream
duration
под секциямиstream
.
-print_format json
является необязательным. JSON более читабелен, чем формат по умолчанию.
Также вы можете использовать -sections
, чтобы увидеть, какие секции есть в файле, и добавить больше вышеуказанного, чтобы сделать его более полным.
Я столкнулся с проблемой получения странных и неправильных метаданных из некоторых виде файлов, с которыми работал, и не смог найти шаблон или любой тип обработки с помощью кода и инструментов вроде ffmpeg, mp4box, ffprobe, mediainfo, mplayer, чтобы получить реальную продолжительность видео.
Идентификация реальной продолжительности видео была требованиями для проекта, над которым я работал, и единственный способ, который я нашел, чтобы всегда получить ее правильно, заключался в повторном кодировании видеофайла с использованием ffmpeg и принуждении закодированных файлов игнорировать метаданные оригинального файла, такие как:
ffmpeg -i INPUT_FILENAME -acodec copy -vcodec copy -map_metadata -1 OUTPUT_FILENAME
(Это может выполняться быстрее, чем вы ожидаете. Я был удивлён: для типа контента и в среде, которую я использовал, среднее время составило 2 секунды)
… а затем получите продолжительность с помощью инструмента на ваш выбор. Кстати, мне нравится mediainfo:
– “mediainfo FILE –Inform=”Video;%Duration%” дает вам продолжительность в миллисекундах.
Python
Вы можете извлекать потоки, используя следующий код
import json
infile = "<путь к вашему файлу>"
command = "ffprobe -v quiet -print_format json -show_format -show_streams {}".format(infile)
res = json.loads(subprocess.check_output(command, shell=True))
streams = res.get('streams')
Каждый поток будет иметь поле duration
.
Специальный случай Webm
Если ваш входной файл — webm, ваш метод извлечения длительности потока будет отличаться, поскольку стандарт хранит его в другом месте.
В каждом потоке вы увидите поле ‘tags’
"tags": {
"language": "eng",
"HANDLER_NAME": "ISO Media file produced by Google Inc. Created on: 12/09/2019.",
"VENDOR_ID": "[0][0][0][0]",
"ENCODER": "Lavc59.4.101 libvorbis",
"DURATION": "00:03:14.703000000"
}
Вам нужно будет преобразовать этот человеко-читаемый формат времени в секунды. Что вы можете легко сделать с помощью следующей вспомогательной функции.
def convert_secs(text):
if isinstance(text, float):
num = str(text)
nums = num.split('.')
else:
nums = text.split(':')
if len(nums) == 2:
st_sn = int(nums[0]) * 60 + float(nums[1])
return st_sn
elif len(nums) == 3:
st_sn = int(nums[0]) * 3600 + int(nums[1]) * 60 + float(nums[2])
return st_sn
else:
raise ValueError("Некорректное время")
# Возвращает продолжительность (в секундах) видео $1 (использует ffmpeg).
get_video_duration() {
OUTPUT=$(ffmpeg -i "$1" -vframes 1 -f rawvideo -y /dev/null 2>&1) ||
{ debug -e "get_video_duration: ошибка при запуске ffmpeg:\n$OUTPUT"; return 1; }
DURATION=$(echo "$OUTPUT" | grep -m1 "^[[:space:]]*Duration:" |
cut -d":" -f2- | cut -d"," -f1 | sed "s/[:\.]/ /g") ||
{ debug -e "get_video_duration: ошибка при разборе продолжительности:\n$OUTPUT"; return 1; }
read HOURS MINUTES SECONDS DECISECONDS <<< "$DURATION"
echo $((10#$HOURS * 3600 + 10#$MINUTES * 60 + 10#$SECONDS))
}
Использование:DURATION=$(get_video_duration "$VIDEO")
Если вам нужно только запросить метаданные:
ffprobe -hide_banner -v quiet -show_streams -print_format flat video.mp4
[…]
streams.stream.0.duration="5221.146009"
[…]
Таким образом, вы можете разобрать это:
while read -r; do
if [[ "$REPLY" =~ ^streams\.stream\.([0-9])+\.duration=\"([^"]+)\"$ ]]; then
echo -E Длительность потока "${BASH_REMATCH[1]}": "${BASH_REMATCH[2]}"
fi
done < <(ffprobe -hide_banner -v quiet -show_streams -print_format flat video.mp4)
Но если вы хотите получить эффективную длительность контейнера, вам нужно его декодировать:
AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -c copy - 2>&1 | tail -n 2
Это займет некоторое время ЦП для декодирования, пока:
[…]
frame=130527 fps=53271 q=-1.0 Lsize=N/A time=01:27:01.12 bitrate=N/A speed=2.13e+03x
video:152014kB audio:40790kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Тогда можно разобрать это:
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"
Меня немного удивило, что самый простой способ сделать это не упомянут здесь, и что ближайшее решение не дает целых чисел, а добавляет неправильные десятичные знаки, которые нужно округлить.
Это довольно просто: просто используйте оператор остатка в вашем языке.
В php:
$vidLength = 2383; //секунды
$secondsPerMinute = 60;
$seconds = $vidLength % $secondsPerMinute;
//$seconds = 43
$minutes = ($vidLength - $seconds) / $secondsPerMinute;
//$minutes = 39
Нет ошибок округления или странных дробных частей. Просто простая, элементарная математика с использованием одного из 6 основных арифметических операторов, как + или -, которые можно найти в любом языке программирования.
Также фактическая воспринимаемая ошибка в том, что вы сделали целые минуты, а затем разделили секунды на 60. 43/60 = 0,7167, эффективно превращая это из фактических секунд в сотые доли минуты.
В Windows метаданные файлов можно получить напрямую с помощью Shell COM объекта‘s Folder.GetDetailsOf() метод
без установки каких-либо инструментов. Вот как Проведите Windows Explorer показывает детали файла, как вы всегда видели
Это означает, что вы можете использовать любые языки, которые поддерживают COM-объекты, такие как PowerShell, VBS, Jscript… для получения продолжительности видео. Вот пример на PowerShell:
Вы можете использовать следующий скрипт PowerShell
$path = $Args[0]
$columnNumber = 27 # Магическое число, может быть другим, см. ниже
$shell = New-Object -COMObject Shell.Application
$folder = Split-Path $path
$file = Split-Path $path -Leaf
$shellfolder = $shell.Namespace($folder)
$shellfile = $shellfolder.ParseName($file)
$duration = $shellfolder.GetDetailsOf($shellfile, 27) # Длительность в формате ЧЧ:ММ:СС
[timespan]::Parse($duration).TotalSeconds
Сохраните это как файл *.ps1, например, duration.ps1
, затем вызовите его следующим образом
duration.ps1 путь\к\видео\файлу
Это работает для любых типов, у которых есть длительность, которую Windows может прочитать. Вы можете найти больше деталей в
- Получить метаданные файла MP3/MP4
- Используйте PowerShell, чтобы найти метаданные из фотографических файлов
Конечно, поскольку он использует Shell.Application
, вы можете использовать любые языки WScript для достижения той же цели. Например, вот гибридная версия batch/Jscript, просто сохраните это как обычный *.bat файл и передайте путь к видеофайлу:
@if (@CodeSection == @Batch) @then
@echo off
cscript //e:jscript //nologo "%~f0" %1
exit /b
@end
// JScript Section
var filepath = WScript.Arguments.Item(0);
var slash = filepath.lastIndexOf('\\');
var folder = filepath.substring(0, slash);
var file = filepath.substring(slash + 1);
var shell = new ActiveXObject("Shell.Application");
var shellFolder = shell.NameSpace(folder);
shellfile = shellFolder.ParseName(file);
var duration = shellFolder.GetDetailsOf(shellfile, 27);
WScript.Echo(duration);
Вам также нужно будет разобрать время, как я использовал [timespan]
выше, потому что вывод в формате ЧЧ:ММ:СС
, а не только в секундах, но это тривиально.
Обратите внимание, что номер столбца 27 выше может быть изменен в будущих версиях Windows. Если он изменится, вы можете найти новое магическое число, выполнив это в PowerShell:
$objFolder = (New-Object -ComObject Shell.Application).Namespace('c:\')
$(for ($columnNumber = 0; $columnNumber -lt 500; ++$columnNumber)
{
$columnName = $objFolder.GetDetailsOf($objFolder.Items, $columnNumber)
if ($columnName)
{
[PsCustomObject]@{
MagicNum = ([string]$columnNumber).PadLeft(3);
ColumnName = $columnName
}
}
}) | where { $_.ColumnName -like "*duration*" -or $_.ColumnName -like "*len*" }
Пример вывода на моем ПК:
MagicNum ColumnName
-------- ----------
27 Длительность
43 Длительность
165 Имя файла
262 Фокусное расстояние
263 Фокусное расстояние 35 мм
265 Производитель объектива
266 Модель объектива
Ответ или решение
Чтобы получить продолжительность видео в секундах, существует несколько методов и инструментов, которые позволяют эффективно извлекать эту информацию. В зависимости от ваших предпочтений и доступных инструментов, вы можете выбрать наиболее подходящий для вас вариант.
1. Использование FFprobe
FFprobe – это мощный инструмент, входящий в состав FFmpeg, который позволяет извлекать метаданные медиафайлов, включая их продолжительность. Вот как вы можете использовать его:
Получение продолжительности формата (контейнера):
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
Этот метод выведет продолжительность в секундах, например, 30.024000
.
Получение продолжительности видео потока:
Если вам нужно получить продолжительность определенного видеопотока, выполните следующую команду:
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
2. Использование FFmpeg
Вы также можете использовать FFmpeg для извлечения информации о продолжительности, хотя это может занять больше времени, так как требует декодирования:
ffmpeg -i input.mp4 -f null -
После выполнения этой команды в выводе вы найдете строку, содержащую time=
, которая будет указывать на продолжительность видео.
3. Использование Mediainfo
Mediainfo – это еще один удобный инструмент для получения метаданных видеофайлов, включая продолжительность. Вы можете использовать следующую команду для получения продолжительности в миллисекундах:
mediainfo --Output="General;%Duration%" file.flv
4. Использование MPlayer
MPlayer также может быть использован для получения продолжительности видео файла. Вот как это сделать:
mplayer -identify -frames 0 -vo null -nosound file.flv 2>&1 | awk -F= '/LENGTH/{print $2}'
5. Подход с использованием Python
Если вы предпочитаете программно извлекать продолжительность, вы можете использовать Python вместе с библиотекой subprocess
и FFprobe:
import subprocess
import json
def get_video_duration(infile):
command = f"ffprobe -v quiet -print_format json -show_format -show_streams {infile}"
res = json.loads(subprocess.check_output(command, shell=True))
return res['format']['duration']
duration = get_video_duration("input.mp4")
print(duration) # Продолжительность в секундах
6. Выполнение на Windows с помощью PowerShell
Если вы используете Windows и хотите извлечь продолжительность видео, вы можете использовать PowerShell:
$path = $Args[0]
$shell = New-Object -COMObject Shell.Application
$folder = Split-Path $path
$file = Split-Path $path -Leaf
$shellfolder = $shell.Namespace($folder)
$shellfile = $shellfolder.ParseName($file)
$duration = $shellfolder.GetDetailsOf($shellfile, 27)
[timespan]::Parse($duration).TotalSeconds
Заключение
Часто выбор метода зависит от вашего окружения и требований к точности. Например, FFprobe и Mediainfo обеспечивают высокую точность и надежность для извлечения метаданных, тогда как скрипты на Python и PowerShell могут быть мощными инструментами для автоматизации таких задач.
Используйте предложенные методы для получения продолжительности видео в секундах, выбирая тот, который наиболее соответствует вашим потребностям.