У мене є список .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 repos (prolly тому, що це суперечить ffmpeg
), тому не можна спробувати його в банкоматі, але він дає вам тривалість файлу, якщо ви запускаєте його так: 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
.
Тепер йде частина від slm: я використовую 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 року. Отримана "дата" формується як день року, час та наносекунд. З цього дня року ми віднімаємо одне, оскільки введення нульових секунд вже призводить до першого дня 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 сек.