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?


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

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


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.


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.


@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.


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é.


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


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


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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.