FFmpeg get duration of video file without meta data
Solution 1
For a raw bitstream, ffprobe can be used.
ffprobe -show_entries stream=r_frame_rate,nb_read_frames -select_streams v -count_frames -of compact=p=0:nk=1 -v 0 in.m2v
This produces
30/1|120
where first entry is the frame rate as a rational number, and second is the number of frames counted. Duration is 120 / (30/1) = 4.00s
Solution 2
If you don't have metadata, then you need to build those metadata by reading and parsing the whole file (this is what ffprobe
does), and get a correct answer based on the file's actual content.
There is no more accurate answer. There is, however, a faster answer. As noticed, "if you open such videos in VLC, it shows you the duration of the video immediately". In several places, VLC (and other tools too) appear to make an estimate, instead of reading in and parsing the whole file (which you might be unable or unwilling to do):
/* try to calculate movie time */
if( p_sys->p_fp->i_data_packets_count > 0 )
{
uint64_t i_count;
uint64_t i_size = stream_Size( p_demux->s );
if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end )
{
i_size = p_sys->i_data_end;
}
/* real number of packets */
i_count = ( i_size - p_sys->i_data_begin ) /
p_sys->p_fp->i_min_data_packet_size;
/* calculate the time duration in micro-s */
p_sys->i_length = VLC_TICK_FROM_MSFTIME(p_sys->p_fp->i_play_duration) *
(vlc_tick_t)i_count /
(vlc_tick_t)p_sys->p_fp->i_data_packets_count;
if( p_sys->i_length <= p_sys->p_fp->i_preroll )
p_sys->i_length = 0;
else
{
p_sys->i_length -= p_sys->p_fp->i_preroll;
p_sys->i_bitrate = 8 * i_size * CLOCK_FREQ / p_sys->i_length;
}
}
In this case,
Stream #0:0: Video: mpeg2video (Main), yuv420p(tv), 720x576 [SAR 64:45 DAR 16:9], max. 7000 kb/s, 25 fps, 25 tbr, 1200k tbn, 50 tbc
knowing that the stream speed is 7000 kb/s and the file size, dividing the file size by 7000 kbit and multiplying by 8 immediately gives the likely duration in seconds.
For example with a file I have here (actual file duration 02:32:19, file size 733,802,496)
Stream #0:0: Video: ... 562 kb/s, 25 fps ...
Stream #0:1: Audio: ... 54 kb/s
562+54 is 616 kbits, which is 77 kbytes. 733,802,496 divided by (77*1024) is 9306, and 9306 seconds are 2 hours, 35 minutes, 6 seconds, which is not exactly correct, but pretty close.
Depending on the actual codec used, the audio/video interleaving method, any padding for the same, and whether it's CBR or VBR, the actual accuracy might vary.
Lacking reliable metadata, if you value speed over accuracy, then I fear that estimate is the way to go.
In some scenarios you might be able to do both (provide an immediate estimate based on file header and size, then start reading whenever the UI/program has nothing better to do and refine the answer. You might then even save the newly calculated metadata somewhere, to retrieve them if needed later on - in a database, a thumbnail file, an alternate data stream, or even offer to update/"repair" the video file if feasible).
Command-line
From the command line, using ffmpeg:
#!/bin/bash
if [ ! -r "$1" ]; then
echo "File '$1' not found"
exit 1
fi
FILESIZE=$( stat -c "%s" "$1" )
STREAMS=$(
ffmpeg -i "$1" 2>&1 \
| grep 'Stream #' \
| tr "," "\n" \
| grep "kb/s" \
| tr " " "\n" \
| grep "^[1-9][0-9]*$" )
RATE=0
for r in $STREAMS; do
RATE=$[ $RATE + $r ]
done
# I don't think that bash has decimal support, so we use bc
SECONDS=$( echo "$FILESIZE / $RATE" | bc )
# To get seconds in HH:MM:SS format we use 'date'
DURATION=$( TZ=UTC date +"%H:%M:%S" -d @$SECONDS )
This should be accurate even if you have multiple audio streams in a video file. I am not sure what happens if there is some data stream such as subtitles. The size of such a stream shouldn't be much, so it shouldn't interfere, but then again, it might.
Related videos on Youtube
Comments
-
utdev over 1 year
I got a video file which has no meta data.
If I do this for example:
ffmpeg -i test.m2v
I get these values:
Duration: N/A, bitrate: N/A
Is there still a way to get the duration of the video / .m2v file ?
Edit:
The full console output:
ffmpeg version 2.8.4 Copyright (c) 2000-2015 the FFmpeg developers built with gcc 5.2.0 (GCC) configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libdcadec --enable-libfr eetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enab le-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-lzma --enable-decklink --enable-zlib libavutil 54. 31.100 / 54. 31.100 libavcodec 56. 60.100 / 56. 60.100 libavformat 56. 40.101 / 56. 40.101 libavdevice 56. 4.100 / 56. 4.100 libavfilter 5. 40.101 / 5. 40.101 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 2.101 / 1. 2.101 libpostproc 53. 3.100 / 53. 3.100 Input #0, mpegvideo, from '.\Test.m2v': Duration: N/A, bitrate: N/A Stream #0:0: Video: mpeg2video (Main), yuv420p(tv), 720x576 [SAR 64:45 DAR 16:9], max. 7000 kb/s, 25 fps, 25 tbr, 1200k tbn, 50 tbc
-
Admin over 7 yearsCan you show the entire console output, please?
-
Admin over 7 years@slhck ok I put the whole console output in the question edit
-
Admin over 7 yearsThat one does have the duration. But, in general, if it's a raw bitstream, ffprobe with count_frames will work.
-
Admin over 7 yearsWhops I posted a wrong output, I tested it with another file and that worked, I'll post the output from the original file. Thus how would the command look with ffprobe?
-
-
utdev about 7 yearsdoes the "in" belongs to the command or is that just a random filename`?
-
utdev about 7 yearsOk I tried this on a 25sec video and I got 27,48 after the calculation. It is not accurate, is it really accurate if you use it?
-
Gyan about 7 yearsWorks here .Can you upload the errant file?
-
utdev about 7 yearswhere do you want me to upload it?
-
Gyan about 7 yearsdatafilehost, dropbox. drive...
-
utdev about 7 years
-
Gyan about 7 yearsIs accurate. There are 687 frames, all of which I extracted as a image sequence. That's 27.48s. Why do you think it's exactly 25 seconds?
-
Gyan about 7 yearsUse
ffmpeg -i in.m2v -vsync 0 img-%d.png
to check -
utdev about 7 yearsDid you also try this with a length of ~10minutes, there is a higher gap when I tried it with a video which has a length of ~10 minutes.
-
Gyan about 7 yearsNo. But there's no gap, as duration is accurate in terms of # of frames stored and fps. How did you get
25s
as duration of your clip? -
utdev about 7 yearsif I put the video in a video player, in my case power dvd it shows 25s
-
Gyan about 7 yearsTry another player, or time it with an app/stopwatch..etc
-
utdev about 7 yearsThe time of the player is correct, any other idea
-
shivams almost 3 yearsThis is brilliant. Can you post some commands to do this? Does VLC have some CLI commands for this?
-
LSerni almost 3 yearsYes, no problem. But give me some hours :-) . I can do that for Linux shell, I'm not so very proficient with Windows PowerShell