Ruft die Gesamtdauer der Videodateien in einem Verzeichnis ab


30

Ich habe eine Liste von .tsDateien:

out1.ts ... out749.ts   out8159.ts  out8818.ts

Wie kann ich die Gesamtdauer (Laufzeit) all dieser Dateien ermitteln?


Wie erhält man die Dauer einer einzelnen Datei?
Hauke ​​Laging

Das weiß ich auch nicht
k961

@Hauke ​​Laging Ich fand dieses Programm "mediainfo"
k961

Dies sind Mediendateien, wahrscheinlich Videos.
slm

1
Alle Mediendateien (z. B. MP4, ASF & .264 ...) haben vordefinierte Standard-Header-Informationen. Wir können die Informationen aus dieser Datei abrufen, z Medien ...
Kantam Nagesh

Antworten:


55

Ich habe keine .tshier, 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 .mp4Dateien 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 bcund 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 .tsDateien, 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 exiftoolzB:

exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69

Gesamtlänge für alle .mp4Dateien 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:SSDie Antworten finden Sie hier .

Oder benutze exiftool's intern ConvertDurationdafür (du brauchst aber eine relativ aktuelle Version):

exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
                    }' ./*.mp4| tail -n1
0:09:15

Sehr schön, hatte diesen Trick noch nie gesehen ffprobe.
slm

1
Schöner Trick mit pasteund bc! viel sauberer als mit awksagen wir mal.
Fduff

@fduff. Während bcdies eine willkürliche Genauigkeit bewirkt, besteht ein Nachteil darin, dass ...| paste -sd+ - | bcin einigen bcImplementierungen entweder die Zeilengrößenbeschränkung erreicht wird (z. B. seq 429 | paste -sd+ - | bcbei OpenSolaris ein Fehler auftritt bc) oder der gesamte Speicher in anderen Implementierungen belegt werden kann .
Stéphane Chazelas

Kannst du das (ffprobe Methode) mit so etwas wie avconv machen? Ich kann ffmpeg in meinen Repos für Kubuntu 14.04 nicht finden - habe ich also auch keine ffprobe? Ich habe avprobe, aber es mag diese Argumente nicht.
Joe

@ Joe - Nein avprobein 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.mp4oder 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.
don_crissti

6

Dies verwendet ffmpegund 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' | bcErweitert jedes der Argumente und ersetzt die Leerzeichen und leitet sie an bceinen gemeinsamen Linux-Rechner weiter


1
Nett! Sehen Sie sich auch meine Version an, die stark auf Ihren Ideen basiert.
MvG

Kurze und elegante Lösung
Neo

4

Streamlining @ jmunsch Antwort , und mit dem pasteich 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 ffmpegdie Dauer, ignoriere den Fehler wegen einer fehlenden Ausgabedatei und suche stattdessen in der Fehlerausgabe nach der Dauerzeile. Ich rufe ffmpegalle 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 awkanstelle seiner grep | grep | head | tr | awk. Dieser awkAufruf 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 ffmpegund enthalten awk.

Nun kommt der Teil von slm: Ich pasteersetze 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 dateFormate 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 sedwird von zusätzlichen nachgestellten Nullen befreit. Die TZEinstellung 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.


3

Ich kenne die .tsErweiterung nicht, gehe aber davon aus, dass es sich um eine Art Videodatei handelt, mit der Sie ffmpegdie 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.mp4und nannte sie 1.mp4, 2.mp4und 3.mp4.

Umrechnung von Zeiten in Sekunden

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 dateBefehl wird dann verwendet, um die Anzahl der Sekunden seit der Unix-Epoche (1. Januar 1970) zu berechnen. Hier ist der obige dateBefehl aufgeschlüsselt, damit er leichter zu sehen ist:

$ date -ud "1970/01/01 00:23:17.01" +%s
1397

HINWEIS: Mit dateauf 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

Die Zeiten aufsummieren

Wir können dann die Ausgabe unserer forSchleife nehmen und sie in einen pasteBefehl 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, bcum 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.


@DamenSalvatore - kein Problem, hoffentlich zeigt es Ihnen, wie Sie die Aufgabe in verschiedene Schritte aufteilen können, damit Sie sie nach Bedarf anpassen können.
slm

@slm - Ich würde eine andere Methode verwenden, um die Videodauer in Sekunden umzuwandeln, da dies datezu einer Erstickungsgefahr führen kann, wenn ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"etwas zurückgegeben wird 26:33:21.68(
dh eine

@don_crissti - danke, ich habe es nicht länger als 20 Stunden ausprobiert, als ich es ausprobiert habe. Ich werde eine Notiz hinzufügen, die eine alternative Methode zeigt.
slm

Danke für deine Antwort! Nicht nur , dass es inspiriert Mine , aber es bringt auch pastemeine Aufmerksamkeit. Ich denke java -classpath $(find -name \*.jar | paste -sd:), es wird sehr nützlich für mich sein, wenn man bedenkt, welche Hacks ich in der Vergangenheit verwendet hatte.
MvG

@ MVG - pasteist mein Lieblingsbefehl 8-)
slm

1

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 pRohrleitungen , die dann in dcund Sie werden Ihre Summe erhalten.


2
bcbekommt viel zu viel Liebe. Sie alle setzen +Zeichen zwischen den Zeilen (Beitritt auf +), während mit Reverse-Politur können Sie nur Futter +am Ende und prucken es aus;)
AT

0
$ 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.


Es gibt mir keine Ausgabe
k961

hast du mplayer und perl installiert?
Ryanmjacobs

Ja, ich habe mplayer installiert und Perl war bereits installiert
k961

1
Entschuldigung, ich weiß nicht, warum es nicht funktioniert. aber du hast sowieso schon genug anständige antworten. :)
Ryanmjacobs

0

Als Ubuntu Schiff libav anstelle von ffmpeg:

#!/bin/sh
for f in *.mp4; do
    avprobe -v quiet -show_format_entry duration "$f"
done | paste -sd+ | bc

Stark basierend auf MvG- Ideen


0

Nun, all diese Lösungen brauchen ein bisschen Arbeit. Was ich getan habe, war sehr einfach. 1)

  1. Gehe in den gewünschten Ordner und klicke mit der rechten Maustaste -> mit anderer Anwendung öffnen

  2. Dann wählen Sie VLC Media Player,

  3. Dann wird eines der Videos abgespielt
  4. drücke Strg + L und du siehst die Wiedergabeliste der Videos und oben links die Gesamtdauer

Hier ist ein Beispiel

1. Listenpunkt

2.Bildbeschreibung hier eingeben

3.Bildbeschreibung hier eingeben

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


0

Ich hatte Unterverzeichnisse im aktuellen Ordner, also musste ich die Dauer rekursiv berechnen:

find . -iname '*.mp4' -print0 | xargs --null exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)}' | tail -n1

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.