У меня есть список .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+ - | bc
OpenSolaris произойдет сбой 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 секундную продолжительность всего видео.