Tengo una lista de .tsarchivos:
out1.ts ... out749.ts out8159.ts out8818.ts
¿Cómo puedo obtener la duración total (tiempo de ejecución) de todos estos archivos?
Tengo una lista de .tsarchivos:
out1.ts ... out749.ts out8159.ts out8818.ts
¿Cómo puedo obtener la duración total (tiempo de ejecución) de todos estos archivos?
Respuestas:
No tengo .tsaquí pero esto funciona .mp4. Use ffprobe(parte de ffmpeg) para obtener el tiempo en segundos, por ejemplo:
ffprobe -v quiet -of csv=p=0 -show_entries format=duration Inception.mp4
275.690000
así que para todos los .mp4archivos en el directorio actual:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \;
149.233333
130.146667
275.690000
a continuación, utilizar pastepara pasar la salida a bcy obtener el tiempo total en segundos:
find . -maxdepth 1 -iname '*.mp4' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
555.070000
Entonces, para los .tsarchivos que podrías probar:
find . -maxdepth 1 -iname '*.ts' -exec ffprobe -v quiet -of csv=p=0 -show_entries format=duration {} \; | paste -sd+ -| bc
Otra herramienta que funciona para los archivos de video que tengo aquí es exiftool, por ejemplo:
exiftool -S -n Inception.mp4 | grep ^Duration
Duration: 275.69
exiftool -q -p '$Duration#' Inception.mp4
275.69
Longitud total de todos los .mp4archivos en el directorio actual:
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
También puede canalizar la salida a otro comando para convertir el total DD:HH:MM:SS, consulte las respuestas aquí .
O use exiftoolel interno ConvertDurationpara eso (aunque necesita una versión relativamente reciente):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobeantes.
pastey bc! mucho más limpio que con awkdigamos.
bchará una precisión arbitraria, un inconveniente es que ...| paste -sd+ - | bcalcanzará el límite de tamaño de línea en algunas bcimplementaciones (por ejemplo, seq 429 | paste -sd+ - | bcfalla con OpenSolaris bc) o tendrá el potencial de usar toda la memoria en otras.
avprobeen los repositorios de Arch (prolly porque entra en conflicto con ffmpeg), así que no puedo probarlo en ATM, pero ¿te da la duración del archivo si lo ejecutas así: avprobe -show_format_entry duration myfile.mp4o avprobe -loglevel quiet -show_format_entry duration myfile.mp4? Creo que uno de estos comandos debería darle una sola línea de salida con la duración del archivo. Aunque no estoy seguro.
Esto usa ffmpege imprime el tiempo de espera en segundos 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
Explicación:
for f in *.ts; do itera cada uno de los archivos que termina en ".ts"
ffmpeg -i "$f" 2>&1 redirige la salida a stderr
grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' aísla el tiempo
awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' Convierte el tiempo en segundos.
times+=("$_t") agrega los segundos a una matriz
echo "${times[@]}" | sed 's/ /+/g' | bcexpande cada uno de los argumentos y reemplaza los espacios y los canaliza a bcuna calculadora Linux común
Simplificando la respuesta de @ jmunsch , y usando la respuestapaste que acabo de aprender de @ slm , podría terminar con algo como esto:
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
Al igual que jmunsch, estoy usando ffmpegpara imprimir la duración, ignorando el error sobre un archivo de salida faltante y en su lugar buscando la salida de error para la línea de duración. Yo invocoffmpeg con todos los aspectos de la configuración regional forzados a la configuración regional C estándar, para que no tenga que preocuparme por los mensajes de salida localizados.
Luego estoy usando un single en awklugar del suyo grep | grep | head | tr | awk. Esa awkinvocación busca la línea (con suerte única) que contiene Duration:. Usando dos puntos como separador, esa etiqueta es el campo 1, las horas son el campo 2, los minutos archivados 3 y los segundos campo 4. La coma final después de los segundos no parece molestarme awk, pero si alguien tiene problemas allí, él podría incluir un tr -d ,en la tubería entre ffmpegy awk.
Ahora viene la parte de slm: estoy usando pastepara reemplazar las nuevas líneas con signos más, pero sin afectar la nueva línea final (al contrario de lo tr \\n +que tenía en una versión anterior de esta respuesta). Eso da la expresión de suma que se puede alimentar bc.
Inspirado por la idea de slm de usar datepara manejar formatos similares al tiempo, aquí hay una versión que lo usa para formatear los segundos resultantes como días, horas, minutos y segundos con parte fraccional:
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 interior $(…)es exactamente como antes. Utilizando la@ carácter como una indicación, usamos esto como el número de segundos desde el 1 de enero de 1970. La "fecha" resultante se formatea como día del año, hora y nanosegundos. A partir de ese día del año, restamos uno, ya que una entrada de cero segundos ya conduce al día 1 de ese año 1970. No creo que haya una manera de obtener los recuentos del día del año comenzando en cero.
La final sedelimina los ceros finales adicionales. Con TZsuerte, la configuración debería forzar el uso de UTC, para que el horario de verano no interfiera con colecciones de videos realmente grandes. Sin embargo, si tiene más de un año de video, este enfoque aún no funcionará.
No estoy familiarizado con la .tsextensión, pero suponiendo que sean algún tipo de archivo de video que pueda usar ffmpegpara identificar la duración de un archivo de esta manera:
$ ffmpeg -i some.mp4 2>&1 | grep Dura
Duration: 00:23:17.01, start: 0.000000, bitrate: 504 kb/s
Luego podemos dividir esta salida, seleccionando solo el tiempo de duración.
$ ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"
00:23:17.01
Así que ahora solo necesitamos una forma de recorrer nuestros archivos y recopilar estos valores de duración.
$ 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: Aquí para mi ejemplo simplemente copiar mi archivo de muestra some.mp4y la llamó 1.mp4, 2.mp4y 3.mp4.
El siguiente fragmento tomará las duraciones de arriba y las convertirá a segundos.
$ 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
Esto toma nuestras duraciones y las pone en una variable $dur, a medida que recorremos los archivos. El datecomando se usa para calcular el número de segundos sinusoidal de la época de Unix (01/01/1970). Aquí está el datecomando anterior desglosado para que sea más fácil de ver:
$ date -ud "1970/01/01 00:23:17.01" +%s
1397
NOTA: El uso datede esta manera solo funcionará si todos sus archivos tienen una duración <24 horas (es decir, 86400 segundos). Si necesita algo que pueda manejar duraciones más largas, puede usar esto como una alternativa:
sed 's/^/((/; s/:/)*60+/g' | bc
Ejemplo
$ echo 44:29:36.01 | sed 's/^/((/; s/:/)*60+/g' | bc
160176.01
Luego podemos tomar la salida de nuestro forbucle y ejecutarlo en un pastecomando que incorporará +signos entre cada número, así:
$ 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
Finalmente ejecutamos esto en la calculadora de línea de comando, bcpara resumirlos:
$ 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
Resultando en la duración total de todos los archivos, en segundos. Por supuesto, esto se puede convertir a otro formato si es necesario.
datepodría ahogarse si ffmpeg -i some.mp4 2>&1 | grep -oP "(?<=Duration: ).*(?=, start.*)"devuelve algo como 26:33:21.68(es decir, duración ≥ 24 horas / 86400 segundos)
pastees mi comando favorito 8-)
Saliendo de la respuesta aceptada y utilizando la herramienta clásica de pulido inverso 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
Es decir: apelando +y pluego canalizando eso dcy obtendrás tu suma.
$ 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'
Asegúrese de tener instalado MPlayer .
Bueno, todas estas soluciones necesitan un poco de trabajo, lo que hice fue muy simple, 1)
fue a la carpeta deseada y haga clic derecho -> abrir con otra aplicación
Luego seleccione el reproductor multimedia VLC,
aquí hay un ejemplo
Puede ver justo debajo de la barra de herramientas, hay una lista de reproducción [10:35:51] escrita, por lo que la carpeta contiene 10 horas 35 minutos y 51 segundos de duración del total de videos