2013-09-25 19:35:33 +0000 2013-09-25 19:35:33 +0000
75
75

¿Cómo obtener la duración del vídeo en segundos?

¿Cómo puedo obtener la duración del vídeo en segundos?

Lo que he probado:

ffmpeg -i file.flv 2>&1 | grep "Duration"
  Duration: 00:39:43.08, start: 0.040000, bitrate: 386 kb/s

mediainfo file.flv | grep Duration
Duration : 39mn 43s

Esto qué se acerca, pero no es tan exacto, 2383 es 39.71 minutos

ffmpeg -i file.flv 2>&1 | grep "Duration"| cut -d ' ' -f 4 | sed s/,// | sed 's@\..*@@g' | awk '{ split($1, A, ":"); split(A[3], B, "."); print 3600*A[1] + 60*A[2] + B[1] }'
2383

Respuestas (9)

105
105
105
2015-07-26 22:07:37 +0000

Sólo hay que usar ffprobe directamente. No es necesario usar sed, grep, etc. Hay varias “duraciones” que puede adquirir (dependiendo de su entrada).

Formato (contenedor) de duración

$ ffprobe -v error -show_entries format=duration \
  -of default=noprint_wrappers=1:nokey=1 input.mp4

30.024000

Añadiendo la opción -sexagesimal utilizará el formato de unidad de tiempo HOURS:MM:SS.MICROSECONDS:

0:00:30.024000

Duración del flujo de vídeo

$ ffprobe -v error -select_streams v:0 -show_entries stream=duration \
  -of default=noprint_wrappers=1:nokey=1 input.mp4
30.000000

Los comandos anteriores son de FFmpeg Wiki: FFprobe Tips .

Con ffmpeg

Es posible que tenga que decodificar completamente la entrada si encuentra que el contenedor o la duración del flujo faltan o son inexactos (posiblemente debido a un archivo dañado o truncado).

$ ffmpeg -i input.mp4 -f null -
  …
  frame= 1587 fps=0.0 q=0.0 Lsize=N/A time=00:01:03.48 bitrate=N/A

En este ejemplo time=00:01:03.48 es la duración:

El tiempo que tarde dependerá, por supuesto, de la complejidad de la decodificación y de la duración de su entrada y de las capacidades de su ordenador.

35
35
35
2013-09-25 19:41:05 +0000

Para obtener los minutos, hay que dividir 2383 segundos entre 60.

39.7167

y luego multiplicar la parte fraccionaria .7167 por 60 para obtener los segundos restantes.

43.002

Entonces son 39 minutos, 43 segundos. Parece que la aplicación te da un valor exacto.

34
34
34
2013-09-25 21:10:07 +0000

Si tienes ffmpeg, también deberías tener ffprobe:

ffprobe -i input.file -show_format | grep duration
ffprobe -i input.file -show_format -v quiet | sed -n 's/duration=//p'

Esto también dará fracciones de segundos, si eso es un problema puedes procesar más allá con sed.

3
3
3
2018-05-05 08:00:38 +0000
mediainfo --Output='General;%Duration%' file.flv

Esto produce la duración en milisegundos como un único valor entero. No es necesario grep/cut/sed/…

3
3
3
2013-09-25 19:56:50 +0000

Solución con mplayer que da los segundos directamente:

mplayer -identify -frames 0 -vo null -nosound file.flv 2>&1 | awk -F= '/LENGTH/{print $2}'
3
3
3
2014-06-16 22:06:49 +0000

Para mi ffmpeg-0.6.5-1.el6.rf.x86_64, para obtener sólo el segundo, el formato del comando ffprobe es

ffprobe <file> -show_format 2>&1 | sed -n 's/duration=//p'
0
0
0
2019-08-30 19:39:55 +0000

Si sólo necesita consultar los metadatos:

ffprobe -hide_banner -v quiet -show_streams -print_format flat video.mp4

[…]

streams.stream.0.duration="5221.146009"

[…]

Entonces puede parsearlo:

while read -r; do
  if [["$REPLY" =~ ^streams\.stream\.([0-9])+\.duration=\"([^"]+)\"$ ]]; then
    echo -E Duration of stream "${BASH_REMATCH[1]}": "${BASH_REMATCH[2]}"
  fi
done < <(ffprobe -hide_banner -v quiet -show_streams -print_format flat video.mp4)

Pero si quiere obtener la duración efectiva del contenedor, necesita decodificarlo:

AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -c copy - 2>&1 | tail -n 2

Tardará algo de tiempo de CPU en decodificarlo, hasta:

[…]

frame=130527 fps=53271 q=-1.0 Lsize=N/A time=01:27:01.12 bitrate=N/A speed=2.13e+03x
video:152014kB audio:40790kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown

Entonces, puedes parsearlo:

if [["$(AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -c copy - 2>&1 | tail -n 2 | head -n 1)" =~ \ time=([0-9]+):([0-9]{2}):([0-9]{2})\.([0-9]+) ]]; then
  declare duration=0 us="${BASH_REMATCH[4]}" t
  for t in "${BASH_REMATCH[@]:1:3}"; do
    ((duration *= 60))
    ((duration += ${t#0} ))
  done
  while [${#us} -lt 6]; do us+=0; done
  ((us >= 500000)) && ((duration++))
  ((duration)) || ((duration++))
fi
echo -E Duration: "$duration"
0
0
0
2017-06-01 01:01:24 +0000

Me encontré con el problema de obtener algunos metadatos extraños e incorrectos de algunos archivos de vídeo con los que estaba trabajando y no pude tener éxito en la búsqueda de un patrón o cualquier tipo de manejo utilizando el código y herramientas como ffmpeg, mp4box, ffprobe, mediainfo, mplayer, para obtener la duración real del vídeo.

Identificar la duración real del vídeo era un requisito para un proyecto en el que estaba trabajando y la única forma que encontré para conseguirlo siempre bien fue recodificar el archivo de vídeo usando ffmpeg y forzando los archivos codificados para ignorar los metadatos del archivo original, como:

ffmpeg -i INPUT_FILENAME -acodec copy -vcodec copy -map_metadata -1 OUTPUT_FILENAME"

(Esto puede correr más rápido de lo que esperas. A mí me sorprendió que, para el tipo de contenido y en el entorno que estaba usando, el tiempo medio era de 2 segundos)

… y luego obtener la duración usando una herramienta a tu elección. Me gusta mediainfo, por cierto: - “mediainfo FILE –Inform="Video;%Duration%” te da la duración en milisegundos.

-6
-6
-6
2015-04-27 01:59:24 +0000

Si quieres una duración exacta, olvídate de FFmpeg. Sólo da una estimación basada en el tamaño de los archivos y la tasa de bits promedio. En algunos casos, he encontrado que la duración estimada es 2 veces menor.

En Linux, si el archivo se crea y se modifica sólo durante la grabación de vídeo, una solución alternativa sería utilizar la creación y la última modificación de tiempo para calcular la duración, como en:

stat -c "%X %Y" video.mpg | awk '{print $2 - $1}'