Fetch frame count with ffmpeg
Solution 1
ffprobe
ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4
This actually counts packets instead of frames but it is much faster. Result should be the same. If you want to verify by counting frames change -count_packets
to -count_frames
and nb_read_packets
to nb_read_frames
.
What the ffprobe options mean
-
-v error
This hides "info" output (version info, etc) which makes parsing easier (but makes it harder if you ask for help since it hides important info). -
-count_frames
Count the number of packets per stream and report it in the corresponding stream section. -
-select_streams v:0
Select only the first video stream. -
-show_entries stream=nb_read_packets
Show only the entry fornb_read_frames
. -
-of csv=p=0
sets the output formatting. In this case it hides the descriptions and only shows the value. See FFprobe Writers for info on other formats including JSON.
Only counting keyframes
See Checking keyframe interval?
MP4 Edit List
The presence of an edit list in MP4/M4V/M4A/MOV can affect your frame count.
Also see
mediainfo
The well known mediainfo
tool can output the number of frames:
mediainfo --Output="Video;%FrameCount%" input.avi
MP4Box
For MP4/M4V/M4A files.
MP4Box
from gpac can show the number of frames:
MP4Box -info input.mp4
Refer to the Media Info
line in the output for the video stream in question:
Media Info: Language "Undetermined (und)" - Type "vide:avc1" - 2525 samples
In this example the video stream has 2525 frames.
boxdumper
For MP4/M4V/M4A/MOV files.
boxdumper
is a simple tool from l-smash. It will output a large amount of information. Under the stsz
sample size box section refer to sample_count
for the number of frames. In this example the input has 1900 video frames:
boxdumper input.mp4
...
[stsz: Sample Size Box]
position = 342641
size = 7620
version = 0
flags = 0x000000
sample_size = 0 (variable)
sample_count = 1900
- Be aware that a file may have more than one
stsz
atom.
Solution 2
In Unix, this works like a charm:
ffmpeg -i 00000.avi -vcodec copy -acodec copy -f null /dev/null 2>&1 \
| grep 'frame=' | cut -f 2 -d ' '
Solution 3
Calculate it based on time, instead.
That's what I do and it works great for me, and many others. First, find the length of the video in the below snippet:
Seems stream 0 codec frame rate differs from container frame rate: 5994.00
(5994/1) -> 29.97 (30000/1001)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/stu/Movies/District9.mov':
Duration: 00:02:32.20, start: 0.000000, bitrate: 9808 kb/s
Stream #0.0(eng): Video: h264, yuv420p, 1920x1056, 29.97tbr, 2997tbn, 5994tbc
Stream #0.1(eng): Audio: aac, 44100 Hz, 2 channels, s16
Stream #0.2(eng): Data: tmcd / 0x64636D74
You'll should be able to consistently and safely find Duration: hh:mm:ss.nn
to determine the source video clip size. Then, for each update line (CR, no LF) you can parse the text for the current time mark it is at:
frame= 84 fps= 18 q=10.0 size= 5kB time=1.68 bitrate= 26.1kbits/s
frame= 90 fps= 17 q=10.0 size= 6kB time=1.92 bitrate= 23.8kbits/s
frame= 94 fps= 16 q=10.0 size= 232kB time=2.08 bitrate= 913.0kbits/s
Just be careful to not always expect perfect output from these status lines. They can include error messages like here:
frame= 24 fps= 24 q=-1.0 size= 0kB time=1.42 bitrate= 0.3kbits/s
frame= 41 fps= 26 q=-1.0 size= 0kB time=2.41 bitrate= 0.2kbits/s
[h264 @ 0x1013000]Cannot parallelize deblocking type 1, decoding such frames in
sequential order
frame= 49 fps= 24 q=26.0 size= 4kB time=0.28 bitrate= 118.1kbits/s
frame= 56 fps= 22 q=23.0 size= 4kB time=0.56 bitrate= 62.9kbits/s
Once you have the time, it is simple math: time / duration * 100 = % done
.
Solution 4
You can use ffprobe
to get frame number with the following commands
- first method
ffprobe.exe -i video_name -print_format json -loglevel fatal -show_streams -count_frames -select_streams v
which tell to print data in json
format
select_streams v
will tell ffprobe
to just give us video
stream data and if you remove it, it will give you audio
information as well
and the output will be like
{
"streams": [
{
"index": 0,
"codec_name": "mpeg4",
"codec_long_name": "MPEG-4 part 2",
"profile": "Simple Profile",
"codec_type": "video",
"codec_time_base": "1/25",
"codec_tag_string": "mp4v",
"codec_tag": "0x7634706d",
"width": 640,
"height": 480,
"coded_width": 640,
"coded_height": 480,
"has_b_frames": 1,
"sample_aspect_ratio": "1:1",
"display_aspect_ratio": "4:3",
"pix_fmt": "yuv420p",
"level": 1,
"chroma_location": "left",
"refs": 1,
"quarter_sample": "0",
"divx_packed": "0",
"r_frame_rate": "10/1",
"avg_frame_rate": "10/1",
"time_base": "1/3000",
"start_pts": 0,
"start_time": "0:00:00.000000",
"duration_ts": 256500,
"duration": "0:01:25.500000",
"bit_rate": "261.816000 Kbit/s",
"nb_frames": "855",
"nb_read_frames": "855",
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0
},
"tags": {
"creation_time": "2005-10-17 22:54:33",
"language": "eng",
"handler_name": "Apple Video Media Handler",
"encoder": "3ivx D4 4.5.1"
}
}
]
}
2. you can use
ffprobe -v error -show_format -show_streams video_name
which will give you stream data, if you want selected information like frame rate, use the following command
ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of default=noprint_wrappers=1:nokey=1 video_name
which give a number base on your video information, the problem is when you use this method, its possible you get a N/A
as output.
for more information check this page FFProbe Tips
Solution 5
Since my comment got a few upvotes, I figured I'd leave it as an answer:
ffmpeg -i 00000.avi -map 0:v:0 -c copy -f null -y /dev/null 2>&1 | grep -Eo 'frame= *[0-9]+ *' | grep -Eo '[0-9]+' | tail -1
This should be fast, since no encoding is being performed. ffmpeg
will just demux the file and read (decode) the first video stream as quickly as possible. The first grep
command will grab the text that shows the frame. The second grep
command will grab just the number from that. The tail
command will just show the final line (final frame count).
Related videos on Youtube
Hansl
Updated on May 06, 2021Comments
-
Hansl about 3 years
Does anyone know how to fetch the number of total frames from a video file using ffmpeg? The render output of ffmpeg shows the current frame and I need the frame count to calculate the progress in percent.
-
Ciro Santilli OurBigBook.com about 8 years
-
-
Omar Ali almost 14 yearsExcuse me for being stupid but how can I do time / duration when duration is in hh:mm:ss.nn format and time is always xx.yy format?
-
Shimmy Weitzhandler almost 13 years@Omar, As a .NET dev, what I do is I create a
TimeSpan
from it, then usecurrentDurationTimeSpan.Ticks / (totalDurationTimeSpan.Ticks / 100)
. The TimeSpan also provides a powerful Parse function, check it out -
rekire almost 12 yearsReally a nice one. Just you don't need to copy the audio stream. You can use -an instat.
-
ElektroStudios over 10 yearsexcellent solution, my time is in hh:mm:ss:ms so I suppose that in these 3 years FFMPEG improved the output time format.
-
Lloyd Moore almost 10 yearsAllowing for a space after 'frame=' seems to at least improve constistency.
-
Gobe over 9 yearsI upvoted your answer, but that will only work if the video doesn't contain audio. If it does contain, this one will work:
ffprobe -i my_video.mp4 -show_frames 2>&1 | grep -c media_type=video
-
llogan over 9 yearsNote that the console output may say 29.97, but that is short for 30000/1001. Same for 23.98 which is 24000/1001 and 59.94 is 60000/1001.
-
Antonio about 9 years@PrakharMohanSrivastava Check this answer
-
juanitogan over 7 yearsOr, if you want more speed and if nb_frames is reliable enough, simplify as:
ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 input.mkv
-
Timothy Zorn over 7 yearsAs a note, this doesn't work for variable framerate videos (obviously).
-
Timothy Zorn over 7 yearsActualy, this seems fast and reliable:
ffmpeg -i 00000.avi -map 0:v:0 -c copy -f null -y /dev/null 2>&1 | grep -Eo 'frame= *[0-9]+ *' | grep -Eo '[0-9]+' | tail -1
-
jbodily over 6 yearsThis outputs the answer twice for me (i.e. 2600 \n 2600). Any particular reason that would be happening?
-
llogan over 6 years@jbodily My example or juanitogan's? I can't duplicate it using either. Not much to work with here.
-
Michael over 6 years@LloydMoore That's because charms don't work. (Sorry, that expression drives me nuts)
-
Lloyd Moore over 6 years@Michael thanks for the smile with my morning coffee :-)
-
horseman1210 over 6 yearsI'm trying to match a frame count from VirtualDub of 178253. 23.976fps 02:03:54.71 duration. I can get close but never exact! 178254.7852147852 is the closest I can make it. Anyone know how to get that frame count?
-
Ray over 6 years+1, not least because, unlike too many other answers about any command line tool, this one actually explains all the command line options. Thank you.
-
Paul J over 6 yearsThanks @acidrums4. Verified this method works with the latest version from github I built today.
-
aggieNick02 almost 6 yearsNote that the first option, query the container, actually processes the file due to count_frames. See @juanitogan's comment.
-
Gyan almost 6 yearsThis is a slow method. Because the whole file must be decoded --> you're using
-c copy
, so no decoding. -
Gyan almost 6 years-skip_frame nokey --> decoder option, so not used when copying..
-discard nokey
is demuxer-level so decoding not needed but works only for formats with KF index in header (like MP4s). -
Admin about 5 yearsFramerate is normally calculated out of two parameters. r_frame_rate=24000/1001 (=23,97602397602397...) Rounded by ffmpeg to: 23.98 Duration = hours*3600+minutes*60+seconds.remainder = 8177,91 While duration parameter = 8177.794625 But Frames=24000/1001*8177.794625=196071 gives exact number of frames. (No kidding).
-
Mladen Danic over 4 years@TimothyZorn You made my day!
-
Victor Polevoy over 4 yearsDoesn't work with the
*.ts
. The output is an empty line. -
user1767754 about 4 yearsWhat about on mac, for me I'm just getting blank, no output
-
Sollace almost 4 years+1 for redirecting stderr to stdout for grep. Would have saved me a lot of time googling if I'd just read a little farther down.
-
jgraup over 3 yearsWorked for me using
ffprobe -i video.mp4 -show_streams -hide_banner | grep "nb_frames" | head -n1 | cut -d"=" -f2
which reduces the output to just the number.