Ich habe eine Liste von .ts
Dateien:
out1.ts ... out749.ts out8159.ts out8818.ts
Wie kann ich die Gesamtdauer (Laufzeit) all dieser Dateien ermitteln?
Ich habe eine Liste von .ts
Dateien:
out1.ts ... out749.ts out8159.ts out8818.ts
Wie kann ich die Gesamtdauer (Laufzeit) all dieser Dateien ermitteln?
Antworten:
Ich habe keine .ts
hier, aber das funktioniert für .mp4
. Verwenden Sie ffprobe
(Teil von ffmpeg
), um die Zeit in Sekunden abzurufen, z. B .:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
Also für alle .mp4
Dateien im aktuellen Verzeichnis:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
Verwenden Sie dann paste
, um die Ausgabe an zu übergeben bc
und die Gesamtzeit in Sekunden zu erhalten:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Also, für .ts
Dateien, die Sie versuchen könnten:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Ein anderes Tool, das für die Videodateien funktioniert, die ich hier habe, ist exiftool
zB:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Gesamtlänge für alle .mp4
Dateien im aktuellen Verzeichnis:
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
Sie können die Ausgabe auch an einen anderen Befehl weiterleiten, um die Summe in umzuwandeln. DD:HH:MM:SS
Die Antworten finden Sie hier .
Oder benutze exiftool
's intern ConvertDuration
dafür (du brauchst aber eine relativ aktuelle Version):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobe
.
paste
und bc
! viel sauberer als mit awk
sagen wir mal.
bc
dies eine willkürliche Genauigkeit bewirkt, besteht ein Nachteil darin, dass ...| paste -sd+ - | bc
in einigen bc
Implementierungen entweder die Zeilengrößenbeschränkung erreicht wird (z. B. seq 429 | paste -sd+ - | bc
bei OpenSolaris ein Fehler auftritt bc
) oder der gesamte Speicher in anderen Implementierungen belegt werden kann .
avprobe
in Arch Repos (hauptsächlich, weil es Konflikte gibt ffmpeg
). Kann ich es also nicht mit ATM versuchen, aber gibt es dir die Dauer der Datei, wenn du es so ausführst : avprobe -show_format_entry duration myfile.mp4
oder avprobe -loglevel quiet -show_format_entry duration myfile.mp4
? Ich denke, einer dieser Befehle sollte Ihnen eine einzige Ausgabezeile mit der Dauer der Datei geben. Bin mir aber nicht sicher.
Dies verwendet ffmpeg
und druckt das Zeitlimit in Sekunden:
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
Erläuterung:
for f in *.ts; do
iteriert jede der Dateien, die mit ".ts" enden
ffmpeg -i "$f" 2>&1
Leitet die Ausgabe auf stderr um
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' '
isoliert die Zeit
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
Wandelt die Zeit in Sekunden um
times+=("$_t")
Fügt die Sekunden zu einem Array hinzu
echo "${times[@]}" | sed 's/ /+/g' | bc
Erweitert jedes der Argumente und ersetzt die Leerzeichen und leitet sie an bc
einen gemeinsamen Linux-Rechner weiter
Streamlining @ jmunsch Antwort , und mit dem paste
ich gerade gelernt , von @ slm Antwort , könnte man mit etwas so enden:
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
Genau wie jmunsch drucke ich ffmpeg
die Dauer, ignoriere den Fehler wegen einer fehlenden Ausgabedatei und suche stattdessen in der Fehlerausgabe nach der Dauerzeile. Ich rufe ffmpeg
alle Aspekte des Gebietsschemas auf, die zum Standard-C-Gebietsschema gezwungen sind, damit ich mich nicht um lokalisierte Ausgabenachrichten kümmern muss.
Als nächstes benutze ich eine Single awk
anstelle seiner grep | grep | head | tr | awk
. Dieser awk
Aufruf sucht nach der (hoffentlich eindeutigen) Zeile, die enthält Duration:
. Mit Doppelpunkt als Trennzeichen ist diese Bezeichnung Feld 1, die Stunden sind Feld 2, die Minuten sind Feld 3 und das Sekundenfeld 4. Das nachgestellte Komma nach den Sekunden scheint mich nicht zu stören awk
, aber wenn jemand dort Probleme hat, hat er könnte ein tr -d ,
in der Pipeline zwischen ffmpeg
und enthalten awk
.
Nun kommt der Teil von slm: Ich paste
ersetze Zeilenumbrüche durch Pluszeichen, ohne jedoch den Zeilenumbruch zu beeinflussen (im Gegensatz zu dem, den tr \\n +
ich in einer früheren Version dieser Antwort hatte). Das gibt den Summenausdruck an, der gefüttert werden kann bc
.
Inspiriert von der Idee von slm, zeitähnliche date
Formate zu verarbeiten, ist hier eine Version, in der die resultierenden Sekunden als Tage, Stunden, Minuten und Sekunden mit Bruchteilen formatiert werden:
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]*$//'
Das Teil im Inneren $(…)
ist genau wie zuvor. @
Wir verwenden das Zeichen als Anhaltspunkt für die Anzahl der Sekunden seit dem 1. Januar 1970. Das resultierende „Datum“ wird als Tag des Jahres, Uhrzeit und Nanosekunden formatiert. Von diesem Tag des Jahres subtrahieren wir eins, da eine Eingabe von null Sekunden bereits zu Tag 1 des Jahres 1970 führt. Ich glaube, es gibt keine Möglichkeit, die Anzahl der Tage des Jahres bei null zu beginnen.
Das Finale sed
wird von zusätzlichen nachgestellten Nullen befreit. Die TZ
Einstellung sollte hoffentlich die Verwendung von UTC erzwingen, damit die Sommerzeit nicht bei sehr großen Videosammlungen stört . Wenn Sie Videos für mehr als ein Jahr haben, funktioniert dieser Ansatz jedoch immer noch nicht.
Ich kenne die .ts
Erweiterung nicht, gehe aber davon aus, dass es sich um eine Art Videodatei handelt, mit der Sie ffmpeg
die Dauer einer Datei wie folgt ermitteln können:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Wir können diese Ausgabe dann aufteilen und nur die Dauer auswählen.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Jetzt brauchen wir nur noch eine Möglichkeit, unsere Dateien zu durchlaufen und diese Dauerwerte zu erfassen.
$ 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
HINWEIS: Hier mein Beispiel habe ich einfach meine Beispieldatei kopiert some.mp4
und nannte sie 1.mp4
, 2.mp4
und 3.mp4
.
Das folgende Snippet nimmt die Dauer von oben und konvertiert sie in Sekunden.
$ 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
Dies nimmt unsere Zeit in Anspruch und fügt sie in eine Variable ein $dur
, während wir die Dateien durchlaufen. Der date
Befehl wird dann verwendet, um die Anzahl der Sekunden seit der Unix-Epoche (1. Januar 1970) zu berechnen. Hier ist der obige date
Befehl aufgeschlüsselt, damit er leichter zu sehen ist:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
HINWEIS: Mit date
auf diese Weise funktioniert nur, wenn alle Ihre Dateien haben eine Dauer , dass die <24 Stunden (dh 86.400 Sekunden). Wenn Sie etwas benötigen, das längere Zeiten bewältigen kann, können Sie dies als Alternative verwenden:
sed 's/^/((/; s/:/)*60+/g' | bc
Beispiel
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Wir können dann die Ausgabe unserer for
Schleife nehmen und sie in einen paste
Befehl ausführen, der +
Zeichen zwischen den einzelnen Zahlen enthält, wie folgt :
$ 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
Zuletzt führen wir dies in den Kommandozeilenrechner ein, bc
um sie zusammenzufassen:
$ 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
Dies ergibt die Gesamtdauer aller Dateien in Sekunden. Dies kann natürlich bei Bedarf in ein anderes Format konvertiert werden.
date
zu einer Erstickungsgefahr führen kann, wenn ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
etwas zurückgegeben wird 26:33:21.68
(
paste
ist mein Lieblingsbefehl 8-)
Gehen Sie von der akzeptierten Antwort aus und verwenden Sie das klassische UNIX-Umkehrpolierwerkzeug:
{ find . -maxdepth 2 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 \
-show_entries format=duration {} \; ; printf '+\n60\n*\np'; } | dc
783.493000
Dh: Appening +
und p
Rohrleitungen , die dann in dc
und Sie werden Ihre Summe erhalten.
$ 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'
Stellen Sie sicher, dass MPlayer installiert ist.
Nun, all diese Lösungen brauchen ein bisschen Arbeit. Was ich getan habe, war sehr einfach. 1)
Gehe in den gewünschten Ordner und klicke mit der rechten Maustaste -> mit anderer Anwendung öffnen
Dann wählen Sie VLC Media Player,
Hier ist ein Beispiel
Sie können direkt unter der Symbolleiste sehen, dass eine Wiedergabeliste [10:35:51] geschrieben ist, sodass der Ordner 10 Stunden 35 Minuten und 51 Sekunden Gesamtvideodauer enthält