У меня есть список .tsфайлов:
out1.ts ... out749.ts out8159.ts out8818.ts
Как я могу получить общую продолжительность (время выполнения) всех этих файлов?
У меня есть список .tsфайлов:
out1.ts ... out749.ts out8159.ts out8818.ts
Как я могу получить общую продолжительность (время выполнения) всех этих файлов?
Ответы:
У меня нет .tsздесь, но это работает для .mp4. Используйте ffprobe(часть ffmpeg), чтобы получить время в секундах, например:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
поэтому для всех .mp4файлов в текущем каталоге:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
затем использовать pasteдля передачи выходных данных, чтобы bcи получить общее время в секундах:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Итак, для .tsфайлов вы можете попробовать:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Еще один инструмент, который работает с видеофайлами, которые у меня здесь есть exiftool, например:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Общая длина всех .mp4файлов в текущем каталоге:
exiftool -S -n ./*.mp4 | awk '/^Duration/ {print $2}' | paste -sd+ -| bc
555.070000000000
exiftool -q -p '$Duration#' ./*.mp4 | awk '{sum += $0}; END{print sum}'
555.070000000000
Вы также можете перенаправить вывод в другую команду, чтобы преобразовать итог DD:HH:MM:SS, см. Ответы здесь .
Или используйте для этого exiftoolвнутреннюю ConvertDuration(вам нужна относительно недавняя версия):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobeдо.
pasteи bc! намного чище, чем awkскажем.
bcэтом ...| paste -sd+ - | bcдостигается произвольная точность, один недостаток заключается в том, что в некоторых bcреализациях либо будет достигнут предел размера строки (например, в seq 429 | paste -sd+ - | bcOpenSolaris произойдет сбой bc), либо будет возможно использование всей памяти в других.
avprobeв репозиториях Arch (возможно, потому что он конфликтует с ffmpeg), поэтому не может попробовать его в ATM, но даст ли он вам продолжительность файла, если вы запустите его следующим образом: avprobe -show_format_entry duration myfile.mp4или avprobe -loglevel quiet -show_format_entry duration myfile.mp4? Я думаю, что одна из этих команд должна дать вам одну строку вывода с продолжительностью файла. Не уверен, хотя.
Это использует ffmpegи печатает время ожидания в полных секундах:
times=()
for f in *.ts; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
done
echo "${times[@]}" | sed 's/ /+/g' | bc
Объяснение:
for f in *.ts; do повторяет каждый из файлов, заканчивающийся на ".ts"
ffmpeg -i "$f" 2>&1 перенаправляет вывод в stderr
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' изолирует время
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' Преобразует время в секунды
times+=("$_t") добавляет секунды в массив
echo "${times[@]}" | sed 's/ /+/g' | bcрасширяет каждый из аргументов и заменяет пробелы и передает его в bcобщий калькулятор linux
Оптимизация ответа @ jmunsch и использование pasteтолько что полученного из ответа @ slm ответа на вопрос , вы можете получить что-то вроде этого:
for i in *.ts; do LC_ALL=C ffmpeg -i "$i" 2>&1 | \
awk -F: '/Duration:/{print $2*3600+$3*60+$4}'; done | paste -sd+ | bc
Как и в случае с jmunsch, я использую ffmpegдля печати длительность, игнорируя ошибку об отсутствующем выходном файле и вместо этого ищу в выводе ошибки строку продолжительности. Я обращаюсь ffmpegко всем аспектам локали, вынужденным использовать стандартную локаль C, чтобы мне не пришлось беспокоиться о локализованных выходных сообщениях.
Далее я использую сингл awkвместо его grep | grep | head | tr | awk. Этот awkвызов ищет (надеюсь уникальную) строку, содержащую Duration:. Используя двоеточие в качестве разделителя, эта метка представляет собой поле 1, часы - это поле 2, минуты, поданные 3, и поле секунд 4. Задняя запятая после секунд, кажется, не беспокоит меня awk, но если у кого-то есть проблемы, он может включать tr -d ,в конвейер между ffmpegи awk.
Теперь приходит часть из слх: Я использую pasteзаменить новую строку с плюсами, но не затрагивая символ новой строки ( в отличие от tr \\n +меня был в предыдущей версии этого ответа). Это дает выражение суммы, которое можно подавать bc.
Вдохновленная идеей использования slm dateдля обработки временных форматов, вот версия, которая использует ее для форматирования результирующих секунд как дней, часов, минут и секунд с дробной частью:
TZ=UTC+0 date +'%j %T.%N' --date=@$(for i in *.ts; do LC_ALL=C \
ffmpeg -i "$i" 2>&1 | awk -F: '/Duration:/{print $2*3600+$3*60+$4}'; done \
| paste -sd+ | bc) | awk '{print $1-1 "d",$2}' | sed 's/[.0]*$//'
Часть внутри $(…)точно так же, как и раньше. Используя @символ в качестве указания, мы используем это как количество секунд с 1 января 1970 года. Результирующая «дата» форматируется как день года, время и наносекунды. С того дня года мы вычитаем один, так как ввод нулевых секунд уже приводит к 1-му дню 1970-го года. Я не думаю, что есть способ получить подсчет числа дней в году, начинающийся с нуля.
Финал sedизбавляется от лишних конечных нулей. Надеемся, что TZнастройка должна принудительно использовать UTC, чтобы переход на летнее время не мешал работе действительно больших коллекций видео. Если у вас есть видео на срок более одного года, этот подход все равно не сработает.
Я не знаком с .tsрасширением, но предположим, что это какой-то тип видеофайла, который вы можете использовать ffmpegдля определения продолжительности файла, например так:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Затем мы можем разделить этот вывод, выбрав только продолжительность.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Так что теперь нам просто нужен способ перебирать наши файлы и собирать эти значения продолжительности.
$ for i in *.mp4; do
ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"; done
00:23:17.01
00:23:17.01
00:23:17.01
Примечание: Здесь для моего примера я просто скопировал мой образец файл some.mp4и назвал его 1.mp4, 2.mp4и 3.mp4.
Следующий фрагмент возьмет длительности сверху и преобразует их в секунды.
$ for i in *.mp4; do
dur=$(ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)");
date -ud "1970/01/01 $dur" +%s; done
1397
1397
1397
Это берет наши длительности и помещает их в переменную $dur, когда мы перебираем файлы. Затем эта dateкоманда используется для расчета количества секунд в эпоху Unix (1970/01/01). Вот вышеприведенная dateкоманда, поэтому ее легче увидеть:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
ПРИМЕЧАНИЕ. Использование dateтаким способом будет работать только в том случае, если продолжительность всех ваших файлов <24 часа (т.е. 86400 секунд). Если вам нужно что-то, что может обрабатывать большие промежутки времени, вы можете использовать это как альтернативу:
sed 's/^/((/; s/:/)*60+/g' | bc
пример
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Затем мы можем взять вывод нашего forцикла и запустить его в pasteкоманду, которая будет включать +знаки между каждым числом, например, так:
$ for i in *.mp4; do
dur=$(ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)");
date -ud "1970/01/01 $dur" +%s; done | paste -s -d+
1397+1397+1397
Наконец, мы запускаем это в калькуляторе командной строки, bcчтобы суммировать их:
$ for i in *.mp4; do
dur=$(ffmpeg -i "$i" 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)");
date -ud "1970/01/01 $dur" +%s; done | paste -s -d+ | bc
4191
В результате общая продолжительность всех файлов, в секундах. Это, конечно, может быть преобразовано в другой формат, если это необходимо.
dateможет подавиться, если ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"возвращает что-то вроде 26:33:21.68(то есть, длительность ≥ 24 часа / 86400 секунд)
pasteмоя любимая команда 8-)
Отказ от принятого ответа и использование классического инструмента обратной полировки UNIX:
{ find . -maxdepth 2 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 \
-show_entries format=duration {} \; ; printf '+\n60\n*\np'; } | dc
783.493000
То есть: добавляя, +а pзатем обматывая это, dcвы получите свою сумму.
$ find -iname '*.ts' -print0 |\
xargs -0 mplayer -vo dummy -ao dummy -identify 2>/dev/null |\
perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t += $1) && printf "%02d:%02d:%02d:%02d\n",$t/86400,$t/3600%24,$t/60%60,$t%60'
Убедитесь, что у вас установлен MPlayer .
Ну, все эти решения требуют немного работы, то, что я сделал, было очень просто, 1)
Перейдите в нужную папку и щелкните правой кнопкой мыши -> открыть с другим приложением
Затем выберите медиаплеер VLC,
вот пример
Вы можете видеть прямо под панелью инструментов, там написан плейлист [10:35:51] , поэтому папка содержит 10 часов 35 минут и 51 секундную продолжительность всего видео.