Mam listę .ts
plików:
out1.ts ... out749.ts out8159.ts out8818.ts
Jak mogę uzyskać całkowity czas trwania (czas działania) wszystkich tych plików?
Mam listę .ts
plików:
out1.ts ... out749.ts out8159.ts out8818.ts
Jak mogę uzyskać całkowity czas trwania (czas działania) wszystkich tych plików?
Odpowiedzi:
Nie mam .ts
tutaj, ale to działa .mp4
. Użyj ffprobe
(część ffmpeg
), aby uzyskać czas w sekundach, np .:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
więc dla wszystkich .mp4
plików w bieżącym katalogu:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
następnie użyć paste
aby przekazać wyjście do bc
i uzyskać całkowity czas w sekundach:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
W przypadku .ts
plików możesz spróbować:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Innym narzędziem, które działa dla plików wideo, które tu mam, jest exiftool
np .:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Całkowita długość wszystkich .mp4
plików w bieżącym katalogu:
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
Możesz również przesłać dane wyjściowe do innego polecenia, aby przekonwertować sumę DD:HH:MM:SS
, zobacz odpowiedzi tutaj .
Lub użyj do tego exiftool
wewnętrznego ConvertDuration
(potrzebujesz jednak stosunkowo nowej wersji):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobe
wcześniej.
paste
i bc
! znacznie czystsze niż awk
powiedzmy.
bc
będzie to miało dowolną precyzję, jedną wadą jest to, że ...| paste -sd+ - | bc
albo osiągnie limit rozmiaru linii w niektórych bc
implementacjach (na przykład seq 429 | paste -sd+ - | bc
zawiedzie w OpenSolarisa bc
), albo może potencjalnie wykorzystać całą pamięć w innych.
avprobe
w repozytoriach Arch (prolly, ponieważ powoduje konflikt ffmpeg
), więc nie można wypróbować bankomatu, ale czy daje on czas trwania pliku, jeśli uruchomisz go w ten sposób: avprobe -show_format_entry duration myfile.mp4
lub avprobe -loglevel quiet -show_format_entry duration myfile.mp4
? Myślę, że jedno z tych poleceń powinno dać ci jeden wiersz wyniku z czasem trwania pliku. Nie jestem pewien.
Spowoduje to użycie ffmpeg
i wydrukowanie limitu czasu w całkowitych sekundach:
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
Wyjaśnienie:
for f in *.ts; do
iteruje każdy z plików, który kończy się na „.ts”
ffmpeg -i "$f" 2>&1
przekierowuje wyjście do stderr
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' '
izoluje czas
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
Konwertuje czas na sekundy
times+=("$_t")
dodaje sekundy do tablicy
echo "${times[@]}" | sed 's/ /+/g' | bc
rozwija każdy z argumentów i zastępuje spacje i potokuje je do bc
wspólnego kalkulatora linux
Usprawniając odpowiedź @ jmunsch i korzystając z odpowiedzi , paste
którą właśnie nauczyłem się z @ slm , możesz otrzymać coś takiego:
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
Podobnie jak jmunsch, używam ffmpeg
do drukowania czasu trwania, ignorując błąd dotyczący brakującego pliku wyjściowego i zamiast tego szukam w wierszu czasu trwania błędu. Inwokuję ffmpeg
ze wszystkimi aspektami ustawień narodowych wymuszonymi na standardowe ustawienia regionalne C, aby nie musiałem się martwić o zlokalizowane komunikaty wyjściowe.
Następnie używam singla awk
zamiast jego grep | grep | head | tr | awk
. To awk
wywołanie szuka wiersza zawierającego (miejmy nadzieję unikatowego) Duration:
. Używając dwukropka jako separatora, etykieta jest polem 1, godziny są polem 2, minutami zapisanymi 3 i polem sekund 4. Przecinek końcowy po sekundach nie przeszkadza mi awk
, ale jeśli ktoś ma problemy, on może zawierać tr -d ,
w potoku między ffmpeg
i awk
.
Teraz zaczyna się od SLM: Używam paste
zastąpić newlines z znaki plus, ale bez wpływu na nowej linii spływu (w przeciwieństwie do tr \\n +
miałem w poprzedniej wersji tej odpowiedzi). To daje sumę wyrażenia, którą można podać bc
.
Zainspirowana pomysłem SLM dotyczącym date
obsługi formatów podobnych do czasu, oto wersja, która używa go do formatowania wynikowych sekund jako dni, godzin, minut i sekund z częścią ułamkową:
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]*$//'
Część wewnątrz $(…)
jest dokładnie taka jak poprzednio. Używając tego @
znaku jako wskaźnika, używamy go jako liczby sekund od 1 stycznia 1970 roku. Powstała „data” jest formatowana jako dzień roku, godzina i nanosekundy. Od tego dnia roku odejmujemy jeden, ponieważ wprowadzanie wartości zero sekund prowadzi już do dnia 1 tego roku 1970. Nie sądzę, że istnieje sposób, aby liczenie dnia roku zaczynało się od zera.
Finał sed
pozbywa się dodatkowych zer końcowych. TZ
Ustawienie powinno nadzieją wymusić użycie UTC, tak że czas letni nie będzie kolidować z naprawdę dużych zbiorów wideo. Jeśli masz wideo dłuższe niż rok, to podejście nadal nie zadziała.
Nie znam .ts
rozszerzenia, ale zakładając, że jest to jakiś plik wideo, którego można użyć ffmpeg
do określenia czasu trwania pliku:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Następnie możemy podzielić ten wynik, wybierając tylko czas trwania.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Teraz potrzebujemy tylko sposobu na iterację naszych plików i zebranie tych wartości czasu trwania.
$ 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
UWAGA: Tutaj dla mojego przykładu po prostu skopiowałem mój przykładowy plik some.mp4
i nadałem mu nazwę 1.mp4
,2.mp4
i 3.mp4
.
Poniższy fragment zabierze czas trwania z góry i zamieni go na sekundy.
$ 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
To zajmuje nasze czasy trwania i umieszcza je w zmiennej, $dur
gdy przeglądamy pliki. date
Polecenia te są następnie wykorzystywane do obliczenia liczby sekund sinusoidalnych epoki owych (1970/01/01). Oto powyższe date
polecenie, dzięki czemu łatwiej zobaczyć:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
UWAGA: Używanie date
w ten sposób będzie działać tylko wtedy, gdy wszystkie twoje pliki mają czas trwania <24 godziny (tj. 86400 sekund). Jeśli potrzebujesz czegoś, co poradzi sobie z dłuższym czasem trwania, możesz użyć tego jako alternatywy:
sed 's/^/((/; s/:/)*60+/g' | bc
Przykład
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Następnie możemy pobrać dane wyjściowe z naszej for
pętli i uruchomić je w paste
poleceniu, które będzie zawierało +
znaki między każdą liczbą, w następujący sposób:
$ 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
Na koniec uruchamiamy to w kalkulatorze wiersza poleceń, bc
aby je podsumować:
$ 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
Łączny czas trwania wszystkich plików, w sekundach. W razie potrzeby można to oczywiście przekonwertować na inny format.
date
może się udusić, jeśli ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
zwróci coś podobnego 26:33:21.68
(to znaczy czas trwania ≥ 24 godziny / 86400 sekund)
paste
to moje ulubione polecenie 8-)
Wyjście z zaakceptowanej odpowiedzi i użycie klasycznego narzędzia do polerowania w systemie 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
Tj .: dodawanie, +
a p
następnie wpuszczanie tego do, dc
a otrzymasz swoją sumę.
$ 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'
Upewnij się, że masz zainstalowany MPlayer .
Cóż, te wszystkie rozwiązania wymagają trochę pracy, to co zrobiłem było bardzo proste, 1)
poszedł do żądanego folderu i kliknij prawym przyciskiem myszy -> otwórz za pomocą innej aplikacji
Następnie wybierz odtwarzacz multimedialny VLC,
oto przykład
Możesz zobaczyć tuż pod paskiem narzędzi, napisana jest lista odtwarzania [10:35:51] , więc folder zawiera 10 godzin 35 minut i 51 sekund czasu trwania wszystkich filmów