Ho un elenco di .tsfile:
out1.ts ... out749.ts out8159.ts out8818.ts
Come posso ottenere la durata totale (tempo di esecuzione) di tutti questi file?
Ho un elenco di .tsfile:
out1.ts ... out749.ts out8159.ts out8818.ts
Come posso ottenere la durata totale (tempo di esecuzione) di tutti questi file?
Risposte:
Non ho .tsqui ma questo funziona per .mp4. Utilizzare ffprobe(parte di ffmpeg) per ottenere il tempo in secondi, ad esempio:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
quindi per tutti i .mp4file nella directory corrente:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
quindi utilizzare pasteper passare l'output a bce ottenere il tempo totale in secondi:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Quindi, per i .tsfile potresti provare:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Un altro strumento che funziona per i file video che ho qui è exiftool, ad esempio:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Lunghezza totale per tutti i .mp4file nella directory corrente:
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
È inoltre possibile reindirizzare l'output a un altro comando per convertire il totale in DD:HH:MM:SS, vedere le risposte qui .
O usa exiftooll'interno ConvertDurationper quello (hai bisogno di una versione relativamente recente):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobeprima.
pastee bc! molto più pulito che con awkdiciamo.
bcfarà una precisione arbitraria, uno svantaggio è che ...| paste -sd+ - | bcraggiungerà il limite della dimensione della linea in alcune bcimplementazioni (per esempio seq 429 | paste -sd+ - | bcfallisce con OpenSolaris bc) o avrà il potenziale di esaurire tutta la memoria in altre.
avprobenei repository Arch (principalmente perché è in conflitto con ffmpeg), quindi non puoi provarlo ATM ma ti dà la durata del file se lo esegui in questo modo: avprobe -show_format_entry duration myfile.mp4oppure avprobe -loglevel quiet -show_format_entry duration myfile.mp4? Penso che uno di questi comandi dovrebbe darti una sola riga di output con la durata del file. Non sono sicuro però.
Questo utilizza ffmpege stampa il timeout in secondi totali:
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
Spiegazione:
for f in *.ts; do scorre ogni file che termina con ".ts"
ffmpeg -i "$f" 2>&1 reindirizza l'output su stderr
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' isola il tempo
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' Converte il tempo in secondi
times+=("$_t") aggiunge i secondi a un array
echo "${times[@]}" | sed 's/ /+/g' | bcespande ciascuno degli argomenti e sostituisce gli spazi e lo convoglia a bcun comune calcolatore linux
Ottimizzando la risposta di @ jmunsch e usando la risposta che pasteho appena appreso da @ slm , potresti finire con qualcosa del genere:
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
Proprio come ha fatto jmunsch, sto usando ffmpegper stampare la durata, ignorando l'errore su un file di output mancante e invece cercando l'output dell'errore per la linea di durata. Invocoffmpeg con tutti gli aspetti della locale forzati alla locale C standard, in modo da non dovermi preoccupare dei messaggi di output localizzati.
Quindi sto usando un singolo al awkposto del suo grep | grep | head | tr | awk. Quell'invocazione awkcerca la riga (si spera unica) contenente Duration:. Usando i due punti come separatore, quell'etichetta è il campo 1, le ore sono il campo 2, i minuti archiviati 3 e il campo dei secondi 4. La virgola finale dopo i secondi non sembra disturbare il mio awk, ma se qualcuno ha problemi lì, lui potrebbe includere a tr -d ,nella pipeline tra ffmpegeawk .
Ora arriva la parte da slm: sto usando pasteper sostituire le nuove righe con segni più, ma senza influenzare la nuova riga finale (contrariamente a quanto tr \\n +avevo in una versione precedente di questa risposta). Ciò fornisce l'espressione somma a cui può essere fornita bc.
Ispirato dall'idea di slm di utilizzare dateper gestire i formati simili al tempo, ecco una versione che lo utilizza per formattare i secondi risultanti come giorni, ore, minuti e secondi con parte frazionaria:
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]*$//'
La parte interna $(…)è esattamente come prima. Usando il @carattere come indicazione, usiamo questo come numero di secondi dal 1 ° gennaio 1970. La "data" risultante viene formattata come giorno dell'anno, ora e nanosecondi. Da quel giorno dell'anno ne sottraggiamo uno, poiché un input di zero secondi porta già al primo giorno di quell'anno 1970. Non credo che ci sia un modo per ottenere i conteggi del giorno dell'anno a partire da zero.
Il finale sedsi sbarazza degli zeri finali in più. Si TZspera che l'impostazione forzare l'uso di UTC, in modo che l'ora legale non interferisca con raccolte video molto grandi. Se hai più di un anno di video, questo approccio non funzionerà comunque.
Non ho familiarità con l' .tsestensione, ma supponendo che siano un tipo di file video che puoi usare ffmpegper identificare la durata di un file in questo modo:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Possiamo quindi suddividere questo output, selezionando solo il tempo di durata.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Quindi ora abbiamo solo bisogno di un modo per scorrere i nostri file e raccogliere questi valori di durata.
$ 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
NOTA: qui per il mio esempio ho semplicemente copiato il mio file di esempio some.mp4e la chiamò 1.mp4, 2.mp4e 3.mp4.
Il frammento seguente prenderà le durate dall'alto e le convertirà in secondi.
$ 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
Questo richiede le nostre durate e le inserisce in una variabile $dur, mentre eseguiamo il ciclo tra i file. Il datecomando viene quindi utilizzato per calcolare il numero di secondi sin dall'epoca Unix (1970/01/01). Ecco il datecomando sopra suddiviso, quindi è più facile da vedere:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
NOTA: l' utilizzo datein questo modo funziona solo se tutti i file hanno una durata inferiore a 24 ore (ovvero 86400 secondi). Se hai bisogno di qualcosa in grado di gestire durate più grandi, puoi usarlo come alternativa:
sed 's/^/((/; s/:/)*60+/g' | bc
Esempio
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Possiamo quindi prendere l'output del nostro forloop ed eseguirlo in un pastecomando che incorporerà i +segni tra ogni numero, in questo modo:
$ 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
Alla fine lo eseguiamo nel calcolatore della riga di comando, bcper riassumere:
$ 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
Con conseguente durata totale di tutti i file, in secondi. Questo può ovviamente essere convertito in qualche altro formato, se necessario.
datepotrebbe soffocare se ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"restituisce qualcosa del tipo 26:33:21.68(ovvero durata ≥ 24 ore / 86400 secondi)
pasteè un ordine preferito 8-)
Disattivazione della risposta accettata e utilizzo del classico strumento di lucidatura inversa 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
Vale a dire: aprendo +e ppoi convogliandolo dce otterrai la tua somma.
$ 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'
Assicurati di aver installato MPlayer .
Bene, tutte queste soluzioni richiedono un po 'di lavoro, quello che ho fatto è stato molto semplice, 1)
è andato alla cartella desiderata e fare clic con il tasto destro -> apri con un'altra applicazione
Quindi seleziona VLC media player,
ecco un esempio
Puoi vedere proprio sotto la barra degli strumenti, c'è una playlist [10:35:51] scritta, quindi la cartella contiene 10 ore e 35 minuti e 51 secondi di durata dei video totali