Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch frame count with ffmpeg

Tags:

video

ffmpeg

People also ask

How do I set frame rate in ffmpeg?

How to change the frame rate. There are two ways to change the output frame rate: With the -r option used as an output option. With the ​fps filter.


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

  • FFprobe Documentation
  • FFmpeg Wiki: FFprobe Tips

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.

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 ' '

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.


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


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.


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


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.