Obtenez la durée totale des fichiers vidéo dans un répertoire

30

J'ai une liste de .tsfichiers:

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?

k961
la source
Comment obtenez-vous la durée d'un seul fichier?
Hauke ​​Laging
je ne sais pas trop
k961
@Hauke ​​Laging j'ai trouvé ce programme "mediainfo"
k961
Ce sont des fichiers multimédias, probablement des vidéos.
slm
1
Tous les fichiers multimédias (par exemple: MP4, ASF et .264 ...) auront des informations d'en-tête standard prédéfinies, nous pouvons obtenir les informations de ce fichier comme la résolution, la fréquence d'images, le nombre d'images (GOP) et la longueur et la durée du fichier médias ...
Kantam Nagesh

Réponses:

55

Je n'ai pas .tsici 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 .mp4fichiers 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 pastepour passer la sortie à bcet 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 .tsfichiers, 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 .mp4fichiers 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 exiftoolinterne ConvertDurationpour 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
don_crissti
la source
Très bien, je n'avais jamais vu cette astuce ffprobeavant.
slm
1
Belle astuce avec pasteet bc! beaucoup plus propre qu'avec awkdisons.
fduff
@fduff. Bien bcque la précision soit arbitraire, un inconvénient est que ...| paste -sd+ - | bccela atteindra la limite de taille de ligne dans certaines bcimplé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.
Stéphane Chazelas
Pouvez-vous faire cela (méthode ffprobe) avec quelque chose comme avconv? Je ne trouve pas ffmpeg dans mes dépôts pour Kubuntu 14.04 - donc je n'ai pas non plus ffprobe? J'ai avprobe, mais il n'aime pas ces arguments.
Joe
@Joe - Non avprobedans 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.mp4ou 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.
don_crissti
6

Cela utilise ffmpeget 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' | bcdéveloppe chacun des arguments et remplace les espaces et les redirige vers bcune calculatrice linux commune

jmunsch
la source
1
Agréable! Voir aussi ma version qui est fortement basée sur vos idées.
MvG
Solution courte et élégante
Neo
4

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 ffmpegpour 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 ffmpegavec 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 awkau lieu du sien grep | grep | head | tr | awk. Cette awkinvocation 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 ffmpeget awk.

Vient maintenant la partie de slm: j'utilise pastepour 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 datepour 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 sedse débarrasse des zéros de fin supplémentaires. Nous TZespé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.

MvG
la source
3

Je ne connais pas l' .tsextension, mais en supposant qu'il s'agit d'un type de fichier vidéo que vous pouvez utiliser ffmpegpour 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.mp4et l'a nommé 1.mp4, 2.mp4et 3.mp4.

Conversion des temps en secondes

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 datecommande est ensuite utilisée pour calculer le nombre de secondes sinus de l'époque Unix (1970/01/01). Voici la datecommande 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 datede 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

Totalisation des temps

Nous pouvons ensuite prendre la sortie de notre forboucle et l'exécuter dans une pastecommande 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, bcpour 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.

slm
la source
@DamenSalvatore - pas de problème, j'espère que cela vous montre comment vous pouvez diviser la tâche en différentes étapes, afin que vous puissiez la personnaliser selon vos besoins.
slm
@slm - J'utiliserais une autre façon de convertir la durée de la vidéo en secondes, ce qui datepourrait 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)
don_crissti
@don_crissti - merci, je ne l'avais pas essayé au-delà de 20 heures lors du test. J'ajouterai une note montrant une méthode alternative.
slm
Merci pour votre réponse! Non seulement il a inspiré le mien , mais il a également attiré pastemon attention. Je suppose que ça java -classpath $(find -name \*.jar | paste -sd:)va être très utile pour moi, compte tenu des hacks que j'avais utilisés pour cela dans le passé.
MvG
@MvG - pasteest ma commande préférée 8-)
slm
1

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 ppuis tuyauterie dans dcet vous aurez votre somme.

À
la source
2
bcobtient beaucoup trop d'amour. Vous mettez tous des +signes entre chaque ligne (se rejoignant +), alors qu'avec le polissage inversé, vous pouvez simplement jeter un a +sur la fin et l' pimprimer;)
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'

Assurez-vous que MPlayer est installé.

ryanmjacobs
la source
il ne me donne aucune sortie
k961
avez-vous installé mplayer et perl?
ryanmjacobs
oui j'ai installé mplayer et perl était déjà installé
k961
1
Désolé, je ne sais pas pourquoi cela ne fonctionne pas; mais, de toute façon, vous avez déjà suffisamment de réponses décentes. :)
ryanmjacobs
0

Comme Ubuntu expédie libav au lieu de ffmpeg:

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

Fortement basé sur les idées MvG

Ahed Eid
la source
0

Eh bien, toutes ces solutions nécessitent un peu de travail, ce que j'ai fait était très simple, 1)

  1. est allé dans le dossier souhaité et faites un clic droit -> ouvrir avec une autre application

  2. Sélectionnez ensuite VLC media player,

  3. cela commencera à jouer une des vidéos, mais
  4. appuyez sur ctrl + L , et vous verrez la liste de lecture des vidéos et quelque part dans le coin supérieur gauche, vous verrez la durée totale

voici un exemple

1. Élément de liste

2.entrez la description de l'image ici

3.entrez la description de l'image ici

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

Patel Ujjval Rajeshbhai
la source
0

J'avais des sous-répertoires sur le dossier actuel, j'ai donc dû calculer de manière récursive la durée:

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

iMitwe
la source