Se você precisar apenas consultar metadados:
ffprobe -hide_banner -v quiet -show_streams -print_format flat video.mp4
[...]
streams.stream.0.duration="5221.146009"
[...]
Então você pode analisá-lo:
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)
Mas se você deseja obter a duração efetiva do contêiner, é necessário decodificá-lo:
AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -c copy - 2>&1 | tail -n 2
Levará algum tempo de CPU para decodificá-lo, até:
[...]
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
Em seguida, você pode analisá-lo:
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"