J'ai une liste de .ts
fichiers:
out1.ts ... out749.ts out8159.ts out8818.ts
Comment puis-je obtenir la durée totale (durée d'exécution) de tous ces fichiers?
J'ai une liste de .ts
fichiers:
out1.ts ... out749.ts out8159.ts out8818.ts
Comment puis-je obtenir la durée totale (durée d'exécution) de tous ces fichiers?
Réponses:
Je n'ai pas .ts
ici mais cela fonctionne pour .mp4
. Utilisez ffprobe
(une partie de ffmpeg
) pour obtenir le temps en secondes, par exemple:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
donc pour tous les .mp4
fichiers du répertoire courant:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
puis utilisez paste
pour passer la sortie à bc
et obtenir le temps total en secondes:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Donc, pour les .ts
fichiers, vous pouvez essayer:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Un autre outil qui fonctionne pour les fichiers vidéo que j'ai ici est exiftool
, par exemple:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Longueur totale de tous les .mp4
fichiers du répertoire courant:
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
Vous pouvez également diriger la sortie vers une autre commande pour convertir le total en DD:HH:MM:SS
, voir les réponses ici .
Ou utilisez exiftool
interne ConvertDuration
pour cela (vous avez cependant besoin d'une version relativement récente):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobe
avant.
paste
et bc
! beaucoup plus propre qu'avec awk
disons.
bc
que la précision soit arbitraire, un inconvénient est que ...| paste -sd+ - | bc
cela atteindra la limite de taille de ligne dans certaines bc
implémentations (par exemple, seq 429 | paste -sd+ - | bc
échoue avec OpenSolaris bc
) ou a le potentiel d'utiliser toute la mémoire dans d'autres.
avprobe
dans Arch repos (prolly car il entre en conflit avec ffmpeg
) donc ne peut pas l'essayer ATM mais cela vous donne-t-il la durée du fichier si vous l'exécutez comme ceci: avprobe -show_format_entry duration myfile.mp4
ou avprobe -loglevel quiet -show_format_entry duration myfile.mp4
? Je pense que l'une de ces commandes devrait vous donner une seule ligne de sortie avec la durée du fichier. Pas sûr cependant.
Cela utilise ffmpeg
et imprime le délai d'expiration en secondes totales:
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
Explication:
for f in *.ts; do
itère chacun des fichiers se terminant par ".ts"
ffmpeg -i "$f" 2>&1
redirige la sortie vers stderr
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' '
isole le temps
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
Convertit le temps en secondes
times+=("$_t")
ajoute les secondes à un tableau
echo "${times[@]}" | sed 's/ /+/g' | bc
développe chacun des arguments et remplace les espaces et les redirige vers bc
une calculatrice linux commune
En rationalisant la réponse de @ jmunsch et en utilisant la réponse quepaste
je viens d'apprendre de @ slm , vous pourriez vous retrouver avec quelque chose comme ceci:
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
Tout comme jmunsch l'a fait, j'utilise ffmpeg
pour imprimer la durée, en ignorant l'erreur sur un fichier de sortie manquant et en cherchant plutôt la sortie d'erreur pour la ligne de durée. J'invoque ffmpeg
avec tous les aspects des paramètres régionaux forcés vers les paramètres régionaux C standard, de sorte que je n'ai pas à me soucier des messages de sortie localisés.
Ensuite, j'utilise un single awk
au lieu du sien grep | grep | head | tr | awk
. Cette awk
invocation recherche la ligne (si tout va bien unique) contenant Duration:
. En utilisant deux points comme séparateur, cette étiquette est le champ 1, les heures sont le champ 2, les minutes déposées 3 et le champ des secondes 4. La virgule de fin après les secondes ne semble pas déranger awk
, mais si quelqu'un a des problèmes là-bas, il pourrait inclure un tr -d ,
dans le pipeline entre ffmpeg
et awk
.
Vient maintenant la partie de slm: j'utilise paste
pour remplacer les retours à la ligne par des signes plus, mais sans affecter le retour à la ligne (contrairement à ce tr \\n +
que j'avais dans une version précédente de cette réponse). Cela donne l'expression somme qui peut être alimentée bc
.
Inspiré par l'idée de slm d'utiliser date
pour gérer des formats de type temps, voici une version qui l'utilise pour formater les secondes résultantes en jours, heures, minutes et secondes avec partie fractionnaire:
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 partie à l'intérieur $(…)
est exactement comme avant. En utilisant le @
caractère comme indication, nous utilisons ceci comme le nombre de secondes depuis le 1er janvier 1970. La «date» résultante est formatée en jour de l'année, heure et nanosecondes. À partir de ce jour de l'année, nous soustrayons un, car une entrée de zéro seconde mène déjà au jour 1 de cette année 1970. Je ne pense pas qu'il existe un moyen d'obtenir des comptes de jours de l'année commençant à zéro.
La finale sed
se débarrasse des zéros de fin supplémentaires. Nous TZ
espérons que le paramètre forcera l'utilisation de l'UTC, afin que l'heure d'été n'interfère pas avec les très grandes collections de vidéos. Si vous avez plus d'un an de vidéo, cette approche ne fonctionnera toujours pas.
Je ne connais pas l' .ts
extension, mais en supposant qu'il s'agit d'un type de fichier vidéo que vous pouvez utiliser ffmpeg
pour identifier la durée d'un fichier comme ceci:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Nous pouvons ensuite diviser cette sortie en sélectionnant uniquement la durée.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Alors maintenant, nous avons juste besoin d'un moyen d'itérer dans nos fichiers et de collecter ces valeurs de durée.
$ 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
REMARQUE: pour mon exemple , je simplement copié mon exemple de fichier some.mp4
et l'a nommé 1.mp4
, 2.mp4
et 3.mp4
.
L'extrait suivant prendra les durées ci-dessus et les convertira en secondes.
$ 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
Cela prend nos durées et les place dans une variable $dur
, pendant que nous parcourons les fichiers. La date
commande est ensuite utilisée pour calculer le nombre de secondes sinus de l'époque Unix (1970/01/01). Voici la date
commande ci-dessus décomposée afin qu'elle soit plus facile à voir:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
REMARQUE: L' utilisation date
de cette manière ne fonctionnera que si tous vos fichiers ont une durée <24 heures (soit 86400 secondes). Si vous avez besoin de quelque chose qui peut gérer de plus longues durées, vous pouvez l'utiliser comme alternative:
sed 's/^/((/; s/:/)*60+/g' | bc
Exemple
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Nous pouvons ensuite prendre la sortie de notre for
boucle et l'exécuter dans une paste
commande qui incorporera des +
signes entre chaque nombre, comme ceci:
$ 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
Enfin, nous l'exécutons dans la calculatrice de ligne de commande, bc
pour les résumer:
$ 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
Résultat: la durée totale de tous les fichiers, en secondes. Cela peut bien sûr être converti en un autre format si nécessaire.
date
pourrait s'étouffer si elle ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
renvoie quelque chose comme 26:33:21.68
(c'est-à-dire une durée ≥ 24 heures / 86400 secondes)
paste
est ma commande préférée 8-)
En quittant la réponse acceptée et en utilisant l'outil classique de polissage inversé 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
À savoir: Appening +
et p
puis tuyauterie dans dc
et vous aurez votre somme.
$ 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'
Assurez-vous que MPlayer est installé.
Eh bien, toutes ces solutions nécessitent un peu de travail, ce que j'ai fait était très simple, 1)
est allé dans le dossier souhaité et faites un clic droit -> ouvrir avec une autre application
Sélectionnez ensuite VLC media player,
voici un exemple
Vous pouvez voir juste sous la barre d'outils, il y a une liste de lecture [10:35:51] écrite, donc le dossier contient 10 heures 35 minutes et 51 secondes de durée totale des vidéos