How do I reliably find the frame count of a video in less than a few seconds?

Viewed 1088

I need a fast and reliable way to get the total frame count of a video.

Here are the following methods that I have tried and their flaws:

  1. ffprobe (fast way)

    ffprobe -select_streams v:0 -show_entries stream=nb_frames -of default=noprint_wrappers=1 input.mp4

Problem: Often returns N/A, not reliable.

  1. ffprobe (slow way)

    ffprobe -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 input.mp4

Problem: Pretty slow, can take a minute for longer videos.

  1. ffmpeg (fast way)

    ffmpeg -i input.mp4 -map 0:v:0 -c copy -f null -

Problem: Needs to fully decode video once, which is rather slow

I know that what I'm looking for is possible because certain software (like Topaz Video Enhance) can do it. But I don't know how I can achieve this in my C# project or ffmpeg.

2 Answers

The command

ffmpeg -i input.mp4 -map 0:v:0 -c copy -f null -

does not decode frames and so is the fastest universal way.

For MP4/MOV family of files, there is another way which may be faster.

ffmpeg -i in.mp4 -v trace 2>&1 -hide_banner | grep -A 10 codec_type=0 | grep -oP "(?<=sample_count=)\d+"

FFmpeg parses the metadata when fed an input. The demuxers usually post some messages to the log with some of the key parameters read from the header. The MOV/MP4 demuxer does this at trace loglevel and it includes the 'sample count' for all tracks. The above command extracts it for the video track.

Mediainfo seems to be pretty fast.

This command will return the frame count:

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

From what I tested, mediainfo returns frame count faster than ffmpeg or ffprobe.

These related question may also help:
Fetch frame count with ffmpeg - stackoverflow
How do I get the number of frames in a video on the linux command line? - superuser

Here is a C# method that returns the video frame count of a video file using mediainfo:

private static int GetVideoFrameCount(string videoFileName)
{
    Process proc = new Process();
    proc.StartInfo.FileName = "mediainfo";
    proc.StartInfo.Arguments = $"--Output=\"Video;%FrameCount%\" \"{videoFileName}\"";
    proc.StartInfo.CreateNoWindow = true;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.RedirectStandardError = true;

    proc.Start();
    proc.WaitForExit();

    string output = proc.StandardOutput.ReadLine();
    return int.TryParse(output, out int frameCount) ? frameCount : -1;
}
Related