Fetch frame count with ffmpeg

2019-01-08 08:09发布

问题:

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.

回答1:

Note: The presence of an edit list in MP4/M4V/M4A/MOV can affect your frame number. See Edit lists below.


ffprobe: Query the container

ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=nokey=1:noprint_wrappers=1 input.mp4
  • This is a fast method.
  • Not all formats (such as Matroska) will report the number of frames resulting in the output of N/A. See the other methods listed below.

ffprobe: Count the number of frames

ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 input.mkv
  • This is a slow method.
  • Add the -skip_frame nokey option to only count key frames.

ffmpeg: Count the number of frames

If you do not have ffprobe you can use ffmpeg instead:

ffmpeg -i input.mkv -map 0:v:0 -c copy -f null -
  • This is a somewhat fast method.
  • Refer to frame= near the end of the console output.
  • Add the -discard nokey input option (before -i) to only count key frames.

Edit lists

Ignore the MP4/M4V/M4A/MOV edit list with the -ignore_editlist 1 input option. Default is to not ignore the edit list.

What the ffprobe options mean

  • -v error This hides "info" output (version info, etc) which makes parsing easier.

  • -count_frames Count the number of frames per stream and report it in the corresponding stream section.

  • -select_streams v:0 Select only the video stream.

  • -show_entries stream=nb_frames or -show_entries stream=nb_read_frames Show only the entry for nb_frames or nb_read_frames.

  • -of default=nokey=1:noprint_wrappers=1 Set output format (aka the "writer") to default, do not print the key of each field (nokey=1), and do not print the section header and footer (noprint_wrappers=1). There are shorter alternatives such as -of csv=p=0.

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.


回答2:

In Unix, this works like charm:

ffmpeg -i 00000.avi -vcodec copy -acodec copy -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '


回答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 becareful 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 / durration * 100 = % done.



回答4:

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.



回答5:

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.



回答6:

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



回答7:

try this:

ffmpeg -i "path to file" -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '


回答8:

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.



回答9:

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


回答10:

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



回答11:

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.



回答12:

In one of answers mentioned how to count the number of frames with 'mediainfo':

mediainfo --Output="Video;%FrameCount%" input.avi

If the input file is h264 elementary stream 'mediainfo' does not report number of frames. Only if the input file is a container (mp4,ts or avi) the number of frames is counted and reported.



回答13:

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]


标签: video ffmpeg