Tengo una lista de .ts
archivos:
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 .ts
archivos:
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 .ts
aquí 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 .mp4
archivos 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 paste
para pasar la salida a bc
y 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 .ts
archivos 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 .mp4
archivos 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 exiftool
el interno ConvertDuration
para eso (aunque necesita una versión relativamente reciente):
exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)
}' ./*.mp4| tail -n1
0:09:15
ffprobe
antes.
paste
y bc
! mucho más limpio que con awk
digamos.
bc
hará una precisión arbitraria, un inconveniente es que ...| paste -sd+ - | bc
alcanzará el límite de tamaño de línea en algunas bc
implementaciones (por ejemplo, seq 429 | paste -sd+ - | bc
falla con OpenSolaris bc
) o tendrá el potencial de usar toda la memoria en otras.
avprobe
en 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.mp4
o 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 ffmpeg
e 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' | bc
expande cada uno de los argumentos y reemplaza los espacios y los canaliza a bc
una 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 ffmpeg
para 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 awk
lugar del suyo grep | grep | head | tr | awk
. Esa awk
invocació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 ffmpeg
y awk
.
Ahora viene la parte de slm: estoy usando paste
para 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 date
para 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 sed
elimina los ceros finales adicionales. Con TZ
suerte, 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 .ts
extensión, pero suponiendo que sean algún tipo de archivo de video que pueda usar ffmpeg
para 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.mp4
y la llamó 1.mp4
, 2.mp4
y 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 date
comando se usa para calcular el número de segundos sinusoidal de la época de Unix (01/01/1970). Aquí está el date
comando 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 date
de 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 for
bucle y ejecutarlo en un paste
comando 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, bc
para 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.
date
podrí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)
paste
es 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 p
luego canalizando eso dc
y 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