Ho un elenco di .ts
file:
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 .ts
file:
out1.ts ... out749.ts out8159.ts out8818.ts
Come posso ottenere la durata totale (tempo di esecuzione) di tutti questi file?
Risposte:
Non ho .ts
qui 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 .mp4
file 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 paste
per passare l'output a bc
e 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 .ts
file 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 .mp4
file 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 exiftool
l'interno ConvertDuration
per quello (hai bisogno di una versione relativamente recente):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobe
prima.
paste
e bc
! molto più pulito che con awk
diciamo.
bc
farà una precisione arbitraria, uno svantaggio è che ...| paste -sd+ - | bc
raggiungerà il limite della dimensione della linea in alcune bc
implementazioni (per esempio seq 429 | paste -sd+ - | bc
fallisce con OpenSolaris bc
) o avrà il potenziale di esaurire tutta la memoria in altre.
avprobe
nei 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.mp4
oppure 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 ffmpeg
e 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' | bc
espande ciascuno degli argomenti e sostituisce gli spazi e lo convoglia a bc
un comune calcolatore linux
Ottimizzando la risposta di @ jmunsch e usando la risposta che paste
ho 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 ffmpeg
per 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 awk
posto del suo grep | grep | head | tr | awk
. Quell'invocazione awk
cerca 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 ffmpeg
eawk
.
Ora arriva la parte da slm: sto usando paste
per 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 date
per 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 sed
si sbarazza degli zeri finali in più. Si TZ
spera 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' .ts
estensione, ma supponendo che siano un tipo di file video che puoi usare ffmpeg
per 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.mp4
e la chiamò 1.mp4
, 2.mp4
e 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 date
comando viene quindi utilizzato per calcolare il numero di secondi sin dall'epoca Unix (1970/01/01). Ecco il date
comando sopra suddiviso, quindi è più facile da vedere:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
NOTA: l' utilizzo date
in 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 for
loop ed eseguirlo in un paste
comando 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, bc
per 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.
date
potrebbe 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 p
poi convogliandolo dc
e 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