183

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.

Stu Thompson
  • 38,370
  • 19
  • 110
  • 156
Hansl
  • 1,831
  • 2
  • 12
  • 3

17 Answers17

283

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 for nb_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.
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
llogan
  • 121,796
  • 28
  • 232
  • 243
  • 7
    Or, 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` – juanitogan Jan 27 '17 at 01:01
  • This outputs the answer twice for me (i.e. 2600 \n 2600). Any particular reason that would be happening? – jbodily Jan 10 '18 at 00:04
  • @jbodily My example or juanitogan's? I can't duplicate it using either. Not much to work with here. – llogan Jan 10 '18 at 01:31
  • 1
    +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. – Ray Mar 06 '18 at 14:52
  • 1
    Note that the first option, query the container, actually processes the file due to count_frames. See @juanitogan's comment. – aggieNick02 Jul 26 '18 at 21:12
  • *This is a slow method. Because the whole file must be decoded* --> you're using `-c copy`, so no decoding. – Gyan Jul 27 '18 at 05:00
  • *-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). – Gyan Jul 27 '18 at 05:06
34

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 ' '
Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
ataraxic
  • 2,157
  • 2
  • 17
  • 10
15

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.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Stu Thompson
  • 38,370
  • 19
  • 110
  • 156
  • 1
    Excuse 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? – Omar Ali Aug 26 '10 at 21:33
  • 3
    @Omar, As a .NET dev, what I do is I create a `TimeSpan` from it, then use `currentDurationTimeSpan.Ticks / (totalDurationTimeSpan.Ticks / 100)`. The TimeSpan also provides a powerful Parse function, [check it out](http://msdn.microsoft.com/en-us/library/se73z7b9.aspx) – Shimmy Weitzhandler Sep 11 '11 at 07:29
  • excellent solution, my time is in hh:mm:ss:ms so I suppose that in these 3 years FFMPEG improved the output time format. – ElektroStudios Nov 20 '13 at 08:39
  • 1
    Note 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. – llogan Feb 06 '15 at 23:37
  • 3
    As a note, this doesn't work for variable framerate videos (obviously). – Timothy Zorn Mar 05 '17 at 00:32
  • I'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? – David Graham Jan 26 '18 at 17:23
14

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).

Timothy Zorn
  • 3,022
  • 2
  • 20
  • 18
12

You can use ffprobe to get frame number with the following commands

  1. 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

David Zwicker
  • 23,581
  • 6
  • 62
  • 77
Hadi Rasekh
  • 2,622
  • 2
  • 20
  • 28
10

Not all formats store their frame count or total duration - and even if they do, the file might be incomplete - so ffmpeg doesn't detect either of them accurately by default.

Instead, try seeking to the end of the file and read the time, then count the current time while you go.

Alternatively, you can try AVFormatContext->nb_index_entries or the detected duration, which should work on fine at least undamaged AVI/MOV, or the library FFMS2, which is probably too slow to bother with for a progress bar.

alex strange
  • 1,249
  • 9
  • 9
9

Try something like:

ffmpeg -i "path to file" -f null /dev/null

It writes the frame number to stderr, so you can retrieve the last frame from this.

Stu Thompson
  • 38,370
  • 19
  • 110
  • 156
a1kmm
  • 1,354
  • 7
  • 13
5

try this:

ffmpeg -i "path to file" -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '
Stu Thompson
  • 38,370
  • 19
  • 110
  • 156
Julien
  • 51
  • 1
  • 1
4

Sorry for the necro answer, but maybe will need this (as I didn't found a solution for recent ffmpeg releases.

With ffmpeg 3.3.4 I found one can find with the following:

ffprobe -i video.mp4 -show_streams -hide_banner | grep "nb_frames"

At the end it will output frame count. It worked for me on videos with audio. It gives twice a "nb_frames" line, though, but the first line was the actual frame count on the videos I tested.

acidrums4
  • 217
  • 3
  • 12
  • Thanks @acidrums4. Verified this method works with the latest version from github I built today. – Paul J Mar 14 '18 at 07:44
  • Worked 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. – jgraup Mar 14 '21 at 22:23
  • Thanks, this works. If there is audio stream and video stream, then two numbers are displayed, one for audio and one for video – Jacko May 26 '23 at 18:25
3

The only accurate I've been able to do this is the following:

ffprobe -i my_video.mp4 -show_frames 2>&1|grep -c '^\[FRAME'

To make sure this works with video:

ffprobe -i my_video.mp4 -show_frames 2>&1 | grep -c media_type=video
llogan
  • 121,796
  • 28
  • 232
  • 243
Lloyd Moore
  • 3,117
  • 1
  • 32
  • 32
  • I 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` – Gobe Feb 05 '15 at 20:07
2

to build on stu's answer. here's how i found the frame rate for a video from my mobile phone. i ran the following command for a while. i let the frame count get up to about ~ 10,000 before i got impatient and hit ^C:

$ ffmpeg -i 2013-07-07\ 12.00.59.mp4 -f null /dev/null 2>&1
...
Press [q] to stop, [?] for help
[null @ 0x7fcc80836000] Encoder did not produce proper pts, making some up.
frame= 7989 fps= 92 q=0.0 Lsize=N/A time=00:04:26.30 bitrate=N/A dup=10 drop=0    
video:749kB audio:49828kB subtitle:0 global headers:0kB muxing overhead -100.000042%
Received signal 2: terminating.
$

then, i grabbed two pieces of information from that line which starts with "frame=", the frame count, 7989, and the time, 00:04:26.30. You first need to convert the time into seconds and then divide the number of frames by seconds to get "frames per second". "frames per second" is your frame rate.

$ bc -l
0*60*60 + 4*60 + 26.3
266.3

7989/(4*60+26.3)
30.00000000000000000000
$

the framerate for my video is 30 fps.

margaret
  • 190
  • 1
  • 6
1
Cmd ->

ffprobe.exe -v error -select_streams v:0 -show_entries stream=r_frame_rate,duration -of default=nw=1 "d:\movies\The.Matrix.1999.1080p.BrRip.x264.YIFY.dut.mp4"

Result ->

r_frame_rate=24000/1001
duration=8177.794625

Calculation ->

Frames=24000/1001*8177.794625=196071

Proof -> 

ffmpeg -i "d:\movies\The.Matrix.1999.1080p.BrRip.x264.YIFY.dut.mp4" -f null /dev/null
ffmpeg version N-92938-g0aaaca25e0-ffmpeg-windows-pacman Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 8.2.0 (GCC)
  configuration: --pkg-config=pkg-config --pkg-config-flags=--static --extra-version=ffmpeg-windows-pacman --enable-version3 --disable-debug --disable-w32threads --arch=x86_64 --target-os=mingw32 --cross-prefix=/opt/sandbox/cross_compilers/mingw-w64-x86_64/bin/x86_64-w64-mingw32- --enable-libcaca --enable-gray --enable-libtesseract --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libbs2b --enable-libflite --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libzimg --enable-libzvbi --enable-libmysofa --enable-libaom --enable-libopenjpeg --enable-libopenh264 --enable-liblensfun --enable-nvenc --enable-nvdec --extra-libs=-lm --extra-libs=-lpthread --extra-cflags=-DLIBTWOLAME_STATIC --extra-cflags=-DMODPLUG_STATIC --extra-cflags=-DCACA_STATIC --enable-amf --enable-libmfx --enable-gpl --enable-avisynth --enable-frei0r --enable-filter=frei0r --enable-librubberband --enable-libvidstab --enable-libx264 --enable-libx265 --enable-libxvid --enable-libxavs --enable-avresample --extra-cflags='-march=core2' --extra-cflags=-O2 --enable-static --disable-shared --prefix=/opt/sandbox/cross_compilers/mingw-w64-x86_64/x86_64-w64-mingw32 --enable-nonfree --enable-decklink --enable-libfdk-aac
  libavutil      56. 25.100 / 56. 25.100
  libavcodec     58. 43.100 / 58. 43.100
  libavformat    58. 25.100 / 58. 25.100
  libavdevice    58.  6.101 / 58.  6.101
  libavfilter     7. 47.100 /  7. 47.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  4.100 /  5.  4.100
  libswresample   3.  4.100 /  3.  4.100
  libpostproc    55.  4.100 / 55.  4.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'd:\movies\The.Matrix.1999.1080p.BrRip.x264.YIFY.dut.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.25.100
  Duration: 02:16:17.91, start: 0.000000, bitrate: 2497 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x800 [SAR 1:1 DAR 12:5], 2397 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 93 kb/s (default)
    Metadata:
      handler_name    : GPAC ISO Audio Handler
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))
  Stream #0:1 -> #0:1 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, null, to '/dev/null':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.25.100
    Stream #0:0(und): Video: wrapped_avframe, yuv420p, 1920x800 [SAR 1:1 DAR 12:5], q=2-31, 200 kb/s, 23.98 fps, 23.98 tbn, 23.98 tbc (default)
    Metadata:
      handler_name    : VideoHandler
      encoder         : Lavc58.43.100 wrapped_avframe
    Stream #0:1(und): Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s (default)
    Metadata:
      handler_name    : GPAC ISO Audio Handler
      encoder         : Lavc58.43.100 pcm_s16le
frame=196071 fps=331 q=-0.0 Lsize=N/A time=02:16:17.90 bitrate=N/A speed=13.8x
video:102631kB audio:1408772kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
  • Framerate 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). –  May 12 '19 at 09:59
1

I use the php_ffmpeg then I can get all the times and all the frames of an movie . As belows

$input_file='/home/strone/workspace/play/CI/abc.rmvb';
$ffmpegObj = new ffmpeg_movie($input_file);
echo $ffmpegObj->getDuration();
    echo $ffmpegObj->getFrameCount();

And then the detail is on the page.

http://ffmpeg-php.sourceforge.net/doc/api/ffmpeg_movie.php

xingyue
  • 122
  • 1
  • 9
0

linux

ffmpeg -i "/home/iorigins/Завантаження/123.mov" -f null /dev/null

ruby

result = `ffmpeg -i #{path} -f null - 2>&1`
r = result.match("frame=([0-9]+)")
p r[1]
Yaroslav Malyk
  • 409
  • 5
  • 15
0

The problem with ffprobe and ffmpeg info is that the actual length in frames differs by some number.

This script tries to extract the last frames. The frame number that succeeds works inside blender, too. Frames beyond that number cannot be extracted in blender, neither.

#!/usr/bin/env bash
# find the number of frames in a movie clip
FMAYBE=$(ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 $1)
let FMAYBE=$FMAYBE+1
FEMPTY="-"
while [ -n "$FEMPTY" ] ; do
  let FMAYBE=$FMAYBE-1
  echo "Trying $FMAYBE"
  FEMPTY=$(ffmpeg -i $1 -vf select="between(n\,$FMAYBE\,$FMAYBE)" -vsync 0 /tmp/fmaybe%d.png 2>&1 | grep 'empty')
done
echo "Succeeds: $FMAYBE"
Roland Puntaier
  • 3,250
  • 30
  • 35
0

Get duration in seconds and multiply by frame rate. (This method is fast)

Get duration:

ffprobe -i input.mkv -show_entries format=duration -v quiet -of csv="p=0"

Get frame rate:

ffprobe -v 0 -of csv="p=0" -select_streams V:0 -show_entries stream=r_frame_rate input.mkv

If the answer has a fractional part then just truncate it.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Timmy Jun 03 '22 at 13:37
0

To count frames in ffmpeg you need to get the fps and duration of the file in seconds fps*duration=number of frames to get the duration and fps you can use ffprobe

CodeCalf
  • 49
  • 3