This select filter should skip the first 5 frames:

$ ffmpeg -i input_file -vf select="gte(n\, 5)" ...

For timespan it's even easier. Here's how you skip the first 30 seconds:

$ ffmpeg -i input_file -ss 30 ...

To skip the first 30 seconds and keep the next 120 seconds of the original video, add -t:

$ ffmpeg -t input_file -ss 30 -t 120 ...
-ss  time_off        set the start time offset
-t   duration        record or transcode "duration" seconds of audio/video

Both -ss and -t take a time duration:

The following examples are all valid time duration:

55 55 seconds

12:03:45 12 hours, 03 minutes and 45 seconds

23.189 23.189 seconds

None of these methods will be perfectly accurate due to the very mechanics of how video compression works (P and B frames can not stand on their own). ffmpeg will try to adjust accordingly:

Note that in most formats it is not possible to seek exactly, so ffmpeg will seek to the closest seek point before position. When transcoding and -accurate_seek is enabled (the default), this extra segment between the seek point and position will be decoded and discarded. When doing stream copy or when -noaccurate_seek is used, it will be preserved.

Refer to the ffmpeg documentation for more.

Answer from evilSnobu on Stack Overflow
🌐
Shotstack
shotstack.io › home › learn › use ffmpeg to skip frames
Use FFmpeg to skip frames — Shotstack
February 19, 2025 - Learn how to skip frames in FFmpeg using -ss, select filter, and -skip_frame to reduce file size, speed up processing, and optimize workflows.
🌐
Reddit
reddit.com › r/ffmpeg › how to process every n-th frame of a video without reading the whole file?
r/ffmpeg on Reddit: How to process every N-th frame of a video without reading the whole file?
January 17, 2022 -

I am making a script that applies a filter to every N-th frame of the video to gather some metrics about the stream.

Now I am using the framestep filter to achieve this. But I noticed that it doesn't matter if I process every 10-th or 1000-th frames, ffmpeg reads to whole file anyway, and different framestep intervals don't really have an effect on the speed of the script. There is no significant performance difference between framestep 10 or 1000.

So I am looking for a way to speed this whole thing up. I would like to make ffmpeg to skip reading all frames from the input, and only read the necessary data from the source.

How is it possible the achieve that?

Top answer
1 of 2
19

To work accurately, first convert the video to RAW YUV bitstream (if it is not already) by:

ffmpeg -i input.mp4 -an -vcodec rawvideo -pix_fmt yuv420p rawbitstream.yuv

Next step: The select filter takes an expression, where n is the frame number.

ffmpeg -r 2 -s WxH -i rawbitstream.yuv -filter:v select="mod(n-1\,2)" \
-c:v rawvideo -r 1 -format rawvideo -pix_fmt yuv420p -an odd.yuv

ffmpeg -r 2 -s WxH -i rawbitstream.yuv -filter:v select="not(mod(n-1\,2))" \
-c:v rawvideo -r 1 -format rawvideo -pix_fmt yuv420p -an even.yuv

To have ffmpeg not duplicate frames, you have to force half of the framerate of your input - so you set "2" as the input and "1" to the output. Don't forget to replace the WxH with the actual dimensions of your clip because the raw bitstream doesn't have a header that carries this information.

Instead of the above, another possibility would be to add the setpts filter to set new timestamps for the output. But be careful since it drops frames not accurately. Here, 25 is the actual output frame rate you want:

ffmpeg -i input.mp4 -filter:v select="mod(n-1\,2)",setpts="N/(25*TB)" \
-c:v rawvideo -r 12.5 -format rawvideo -pix_fmt yuv420p -an odd.yuv

ffmpeg -i input.mp4 -filter:v select="not(mod(n-1\,2))",setpts="N/(25*TB)" \
-c:v rawvideo -r 12.5 -format rawvideo -pix_fmt yuv420p -an even.yuv

You can of course choose another pixel format (any of ffmpeg -pix_fmts). Make sure that when reading the file you know the pixel size and pixel format:

ffmpeg -f rawvideo -s:v 1280x720 -pix_fmt yuv420p input.yuv …
2 of 2
3

If your ffmpeg was built with the AviSynth flag, then I believe you can pass an .avs file.

You can check by running ffmpeg and looking for --enable-avisynth in the configuration data.

If it's there you can use it like so: ffmpeg -i blahEven.avs blahEven.yuv.

Where blahEven.avs is simply:

ffvideosource("blah.yuv").SelectEven()

For odd frames, use SelectOdd().

For more advanded usage, see the SelectEvery documentation.

🌐
GitHub
github.com › blakeblackshear › frigate › issues › 2360
[Support]: [Documentation error?]: Skipping output frames to improve performance does not work · Issue #2360 · blakeblackshear/frigate
December 1, 2021 - Describe the problem you are having I'm using a NVidia GPU for decoding and wanted to boost performance by skipping output frames as explained in the docs. Setting ffmpeg to skip frames in the output, using the fps filter as shown at the...
Author: blakeblackshear
🌐
Reddit
reddit.com › r/ffmpeg › cutting a video with no frame skip?
r/ffmpeg on Reddit: Cutting a video with no frame skip?
June 30, 2023 -

Hi all,
Long time lurker, first time poster.
I need some help from some ffmpeg legends on this problem im having.

So I am trying to split a video at a certain second value. The thing is, the split videos when put back together is frame skipping! Expected i guess, but just want to see if anyone here has a solution to this.
Cheers!!

Using ffmpeg within nodejs script.

execSync(`ffmpeg -y -i ${inputVideo} -t 2.001 -c:v copy -an -r 30 output1.mp4`, { stdio: 'inherit' });
    
execSync(`ffmpeg -y -i ${inputVideo} -ss 2.001 -t 1 -c:v copy -an -r 30 output2.mp4`, { stdio: 'inherit' });
   
execSync(`ffmpeg -y -i ${inputVideo} -ss 3.001 -t 1 -c:v copy -an -r 30 output3.mp4`, { stdio: 'inherit' });

Top answer
1 of 3
2
You can only cut videos losslessly (e.g. use -c:v copy) at key frames. If ffmpeg is given a non-key frame, it will pick the next key frame as the cut point. You can list the video frames with the following command; the time stamps you can losslessly cut at are those that end with I (key frames): ffprobe -select_streams v -show_frames -show_entries frame=pkt_pts_time,pict_type -of csv ${inputVideo} If you really want to cut at non-key frames, you need to encode into the output video, e.g. use something like -c:v libmp4 (and likely options to configure the encoding) instead of -c:v copy.
2 of 3
1
I got it somewhat working with the help of ChatGPT. This is for anyone in the future coming to this post. Asked ChatGPT, It mentioned it to do this execSync(`ffmpeg -y -i ${inputVideo} -t 2 -c:v libx264 -crf 23 -an -force_key_frames 0,1,2 -r 240 ${tempPath}cut1_${videoId}`, { stdio: 'inherit' }); execSync(`ffmpeg -y -i ${inputVideo} -ss 2 -t 1 -c:v libx264 -crf 23 -an -force_key_frames 0,1 -r 240 ${tempPath}cut2_${videoId}`, { stdio: 'inherit' }); execSync(`ffmpeg -y -i ${inputVideo} -ss 3 -t 1 -c:v libx264 -crf 23 -an -force_key_frames 0,1 -r 240 ${tempPath}cut3_${videoId}`, { stdio: 'inherit' }); From ChatGPT itself: If you're still experiencing choppiness or jumpiness even after using the -force_key_frames option, there are a few additional steps you can take to improve the smoothness of the video cuts: Re-encode the segments: Instead of using -c:v copy to copy the video codec directly, you can re-encode the segments using a video codec such as H.264. This ensures consistent encoding settings across all segments and can help improve compatibility and smoothness. Use the same frame rate for all segments: Ensure that all segments have the same frame rate by explicitly setting the frame rate for each segment using the -r option. This helps maintain consistency and avoid any potential frame rate mismatches.
Find elsewhere
🌐
GitHub
github.com › yihui › animation › issues › 74
saveVideo: ffmpeg drops frames (use -framerate on input) · Issue #74 · yihui/animation
January 5, 2016 - Using ffmpeg -framerate 30 -i Rplot%d.png -c:v libx264 -r 30 out.mp4 correctly makes a 30fps video with no dropped frames. For vlc, any combination where -framerate matches -r works fine (and minimizes final size), thus solving A above.
Author: yihui
🌐
Ericswpark
ericswpark.com › blog › 2022 › 2022-12-03-ffmpeg-cut-videos-to-the-exact-frame
Eric Park | ffmpeg: cut videos to the exact frame
December 3, 2022 - Well, it all comes down to keyframe ... to render. So if your supplied timecode does not start on a I-frame, ffmpeg skips over until it finds the first I-frame, then repeats that to the start of the video, like this...
🌐
FFmpeg
ffmpeg.org › pipermail › ffmpeg-user › 2011-August › 002127.html
[FFmpeg-user] Skip specific number of frames at start of mp4 file
Or is there a way on the command line? You can try with the select filter, for example to skip the first 10 frames: -vf select="gte(n\, 10)" -- ffmpeg-user random tip #20 VHOOK has been removed, check out libavfilter: http://wiki.multimedia.cx/index.php?title=Libavfilter
🌐
Medium
medium.com › @georgechmr › skipping-black-frame-when-generating-video-thumbnail-with-ffmpeg-9e26bf2f67e3
Skipping black frame when generating video thumbnail with FFmpeg | by George Chou | Medium
November 26, 2023 - Normally, we wouldn’t want to use the first frame of a video as the thumbnail as it might be a black screen or something insignificant. The filter in FFmpeg supports filtering black frames.
🌐
jdhao's digital space
jdhao.github.io › 2021 › 12 › 25 › ffmpeg-extract-key-frame-video
How to Extract Key Frames from A Video with FFmpeg · jdhao's digital space
January 25, 2022 - To extract I-frames, we can run the following command: ffmpeg -skip_frame nokey -i test.mp4 -vsync vfr -frame_pts true out-d.jpeg
Top answer
1 of 2
1

I ended up writing a python script to do this

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
'''
converts sequence of images to video
uses glob pattern and allows skipping images

---
uses sk-video
```> pip install sk-video```

backend uses ffmpeg or libav

TODO:
- add more input & output dict opts 

For full list of flags see
- https://ffmpeg.org/ffmpeg.html 
- https://trac.ffmpeg.org/wiki/Encode/H.264

Note: Not using opencv2.VideoWriter because it fails silently on Anaconda

'''
from __future__ import print_function
from __future__ import division

import argparse
import glob
import os
from imageio import imread
from skvideo.io import FFmpegWriter
from tqdm import tqdm
from pprint import pprint

parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input_folder', default='.', help='path to folder containing images')
parser.add_argument('-p', '--file_pattern', default='*.png', help='Unix filename pattern. For details see https://docs.python.org/2/library/fnmatch.html')
parser.add_argument('-o', '--output_path', default='output.mp4', help='path to output video file')
parser.add_argument('-n', '--every', default=10, type=int, help='include every nth image. i.e. every==1 uses every image. every==2 takes every other image ')
parser.add_argument('-m', '--max_count', default=None, type=int, help='if > 0, cap at this many frames')
parser.add_argument('-v', '--verbose', default=False, type=int, help='dump a lot of stuff to the console')

# ffmpeg args
parser.add_argument('-r', '--fps', default='30', type=str, help='frames per second')
parser.add_argument('-vcodec', default='libx264', type=str, help='output video codec')
parser.add_argument('-b', '--bitrate', default=None, type=str, help='bitrate')
parser.add_argument('-crf', default=None, type=str, help='Constant Rate Factor. The range of the CRF scale is 0–51, where 0 is lossless, 23 is the default, and 51 is worst quality possible. A lower value generally leads to higher quality, and a subjectively sane range is 17–28. Consider 17 or 18 to be visually lossless or nearly so; it should look the same or nearly the same as the input but it isnt technically lossless')
args = parser.parse_args()


#%% Get input file list
glob_path = os.path.join(os.path.expanduser(os.path.expandvars(args.input_folder)), args.file_pattern)

# read all files in folder matching pattern
print('Reading folder "{}"'.format(glob_path))
paths = sorted(glob.glob(glob_path))
args.stats = {'file_count_total' : len(paths) }
print(args.stats['file_count_total'], 'files found')

# skip 
if args.every > 1:
    paths = [x for i,x in enumerate(paths) if i % args.every == 0]
    args.stats['file_count_with_skip'] = len(paths)
    print(args.stats['file_count_with_skip'], 'files with skip')

# cap to max_count
if args.max_count:
    paths = paths[:args.max_count]
    args.stats['file_count_capped'] = len(paths)
    print(args.stats['file_count_capped'], 'files after cap')

#%% init video writer with parameters
inputdict = {}
outputdict = {}

if args.fps:
    inputdict['-r'] = args.fps
    outputdict['-r'] = args.fps           

if args.vcodec: outputdict['-vcodec'] = args.vcodec
if args.bitrate: outputdict['-b'] = args.bitrate
if args.crf: outputdict['-crf'] = args.crf

video_writer = FFmpegWriter(args.output_path, inputdict=inputdict, outputdict=outputdict)

#%%
print('Starting with args:')
pprint(vars(args))
for path in tqdm(paths):
    img = imread(path)
    if args.verbose: print('processing file', i, path)
    video_writer.writeFrame(img)

print('\n-')
print('Finished. Video saved at', args.output_path)

video_writer.close()
2 of 2
0

The easiest way to do this is to submit the list of filenames you want in your video using a file - combined with using awk or sed to select specific files.

So, let's create 101 frames each with recognisable content, i.e. their frame number:

#!/bin/bash
for f in {0..100}; do 
  printf -v out "%04d.png" $f
  magick -background red -pointsize 32 label:"$f" -gravity center -extent  100x100 $out
done

That creates 0000.png through 0100.png with 0078.png for example, looking like this:

Now we want to generate a file containing all the filenames, and massage it into a format accepted by ffmpeg:

ls ????.png | sed -e "s/^/file '/" -e "s/$/'/" > files.txt

The file files.txt looks like this:

file '0000.png'
file '0001.png'
file '0002.png'
file '0003.png'
file '0004.png'
...
...
file '0099.png'
file '0100.png'

And we can pass that to ffmpeg with:

ffmpeg -y -r 2 -f concat -i files.txt animated.gif


Now, if you want every 3rd record/frame from that file, use:

awk 'NR%3 == 0' files.txt > subset.txt

and pass the subset into ffmpeg:

ffmpeg -y -r 2 -f concat -i subset.txt animated.gif 

🌐
Narkive
libav-user.ffmpeg.narkive.com › BjaIN5Yi › hi-how-to-skip-frames
[libav-user] hi, how to skip frames?
at first, I'm synchronizing video to audio, judging the pts difference after a frame is shown, if the difference is larger than some kind of value, then start to set skip_frame, skip_idct, skip_loop_filter to AVDISCARD_NONREF, other values seems cause serious quality loss, and it seems not to be a very good idea.
🌐
GitHub
github.com › kkroening › ffmpeg-python › issues › 129
skip_frame · Issue #129 · kkroening/ffmpeg-python
September 23, 2018 - Is ffmpeg-python able to use this argument? I've been able to use .filter('select', 'eq(pict_type,I)') as a workaround for selecting key frames, but it's slower. If not, any hints on how to impleme...
Author: kkroening
Author: featherbear