If you only need to query metadata:
ffprobe -hide_banner -v quiet -show_streams -print_format flat video.mp4
[...]
streams.stream.0.duration="5221.146009"
[...]
So you can parse it:
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)
But if you want to get the effective container's duration, you need to decode it:
AV_LOG_FORCE_NOCOLOR=y ffmpeg -nostdin -hide_banner -nostats -loglevel info -i video.mp4 -f null -c copy - 2>&1 | tail -n 2
It will take some CPU time to decode it, until:
[...]
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
Then, you can parse it:
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"
These do not work for .m2v files do you have a solution for them aswell – utdev – 2017-01-05T09:47:50.647
@utdev See the "With
ffmpeg
" section. – llogan – 2017-01-05T18:39:36.427Your third solution gives me a wrong time, my video has a length of 01:19:00 but the command returns me time=01:09:15.32, do you have a guess why this is happening – utdev – 2017-02-15T10:59:05.033
Very useful the media stream duration. Thank you. – We are Borg – 2018-04-20T09:40:33.733
For anyone using avprobe, the parameters are slightly different: avprobe -v error -show_format_entry duration .\Sample.mp4 – Brad – 2019-06-18T22:25:34.290