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 …
Answer from slhck on Stack Exchange
🌐
Shotstack
shotstack.io › home › learn › use ffmpeg to skip frames
Use FFmpeg to skip frames — Shotstack
February 19, 2025 - Using select is powerful for advanced scenarios where you want precise control over which frames get dropped based on frame index, time, or other conditions. FFmpeg’s -skip_frame parameter allows you to skip certain frame types (e.g., B-frames).
🌐
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?

Discussions

FFMPEG: how to extract every 2-nd I-frame from a video file - Stack Overflow
Finally I decided to cheat and ... and skip 8, 24, 40 etc. I compared files source/result files in Avidemux and made sure that the result is correct. Of course, this is not universal solution and it will not work with different video files 2022-11-30T07:41:51.603Z+00:00 ... Save this answer. ... Show activity on this post. Tell the decoder to only emit keyframes and then select every other frame. ffmpeg -skip_frame ... More on stackoverflow.com
🌐 stackoverflow.com
ffmpeg - How to re-encode leaving only every Nth frame in? - Video Production Stack Exchange
I have several hours of CCTV footage that I'd like to reasonably quickly skim. If there was a way to take every say 60th frame from it and put together a video from those frames that would be perfe... More on video.stackexchange.com
🌐 video.stackexchange.com
January 10, 2023
php - How to skip start frames with ffmpeg - Stack Overflow
This select filter should skip the first 5 frames: Copy$ ffmpeg -i input_file -vf select="gte(n\, 5)" ... More on stackoverflow.com
🌐 stackoverflow.com
editing - How would I remove a specific pattern (say, every n-n+59th frame) of frames from a lengthy video file? - Video Production Stack Exchange
I have large video files of screen recordings which I created with Camtasia Recorder. The content I am recording only updates once per minute (1/60 fps), however Camtasia appears to require at leas... More on video.stackexchange.com
🌐 video.stackexchange.com
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.

🌐
YouTube
youtube.com › a forum
using ffmpeg to drop every other frame, which can stop flickering - YouTube
Step 1:ffmpeg -i input.MOV -an -vcodec rawvideo -pix_fmt yuv420p rawbitstream.yuvStep 2:ffmpeg -r 2 -s WxH -i rawbitstream.yuv -filter:v select="mod(n-1\,2)"
Published: October 8, 2020
Views: 753
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 

Find elsewhere
Top answer
1 of 1
2

FFmpeg has a framestep filter to take every nth frame.

There's also mpdecimate, which outputs a frame whenever the input frame is different enough from the previous frame. (so if exactly every 60th frame isn't perfect, you could use mpdecimate instead to detect the changes, and make a potentially VFR video.)

I didn't test this command; post a comment if I screwed it up:

ffmpeg -i in.camrec -vf framestep=60 -r 1/60 -codec copy -map 0 -c:v libx264 -preset medium -crf 16 -movflags +faststart -vsync 2 out.mp4

Or use out.mkv if you like matroska better than the mp4 container.

copy (stream copy) won't work while dropping frames, I think even for an intra-only codec. So your output has to be encoded to some codec. My example uses lossy h.264, but with the quality cranked so high it should be transparent. You could use lossless h.264 (-preset ultrafast -qp 0), -c:v utvideo, or whatever else you like.

-vsync 2 turns on VFR output mode, which for some reason isn't the default in mp4. (but it is in mkv). You'll want that if you use mpdecimate, but you won't need it for framestep.

A quick google didn't tell me if camrec is already lossy or not. If it's lossy, then there's no way to get a file as small but with the same quality as just keeping every 60th CamRec frame without decoding them. (assuming there's an intra-only frame at the point you want one, if the format has any non-intra frames.)

With mjpeg, you can turn a video into a directory of images without decoding, and select whichever ones you want, and mux them up again. Since camrec frames probably aren't a stand-alone image format, it's unlikely there's something similar, so you just have to use video tools. Like I said, don't think ffmpeg can do clever things like frame dropping without decompressing, even for intra-only codecs. Other tools might exist that can do that, for some codecs.

If it's lossless, then it just takes more CPU time to decode / re-encode to a new lossless format.

edit: more about mpdecimate: As noted in the comments, I added some stats logging to mpdecimate.
git pull https://github.com/pcordes/FFmpeg.git mpdecimate
and then build ffmpeg as usual.

Then run ffmpeg -v debug ....
Or ffplav -v debug -vf mpdecimate input.avi

Testing mpdecimate threshold settings with ffplay is a lot faster than making an encode.

🌐
Reddit
reddit.com › r/ffmpeg › how do i remove every xth frame from a video?
r/ffmpeg on Reddit: How do I remove every xth frame from a video?
December 4, 2021 -

Let's say I have a 50,325 frame video and I want to remove every xth frame. How would I write this? I want the end result to be a shorter video(since the frames are removed). I've only seen answers online for odd frames. Some of the answers don't shorten the video length. One issue is that the frames might not be divisible by the 'xth frame' and thus i'm not sure what to do in that case.

🌐
FFmpeg
ffmpeg-user.ffmpeg.narkive.com › byF4dqJ0 › how-to-drop-every-nth-frame
[FFmpeg-user] How to drop every Nth frame?
So mod(n, 100) returns positive for any value of n except for multiples of 100, so Boolean negation of that will return false for everything except multiples of 100, thereby selecting one frame per hundred. So to select 23 frames per 24, do: select='mod(n,24)' ... Permalink I am sorry but it doesn't cut any frames at all. ffmpeg -y -i original-5614-frames.avi -filter:v "select='mod(n,24)'" out.avi The original video is 5614 frames and the output video is 5614 ones.
🌐
Reddit
reddit.com › r/ffmpeg › processing every nth frame
r/ffmpeg on Reddit: Processing every Nth frame
September 5, 2021 -

I have a short bit of code I want to optimize for %%f in ("*.mkv") do ( ffmpeg -v error -i "%%f" -f null - 2>error.log

It basically goes through the video and spits out any error messages to the "error.log" file. I use it as a basic file health check. However, this takes forever on longer / higher resolution videos. (My storage medium is not the bottleneck, tested on an NVME ssd and ram disks)

I'd like to process every 2 or 3 frames since 1~2 corrupted frames won't make the video unplayable. I can't figure out the best way to go about this. Any tips are welcome thanks in advance!

Top answer
1 of 1
5

One-by-one solution

You can use ffmpeg's select filter, which allows you to evaluate an expression using the sequential frame number, and decide whether or not to skip it (and which output to send it to if it isn't skipped).

To generate, for example, the second video where you are splitting into four each time, you would do the following:

ffmpeg -i input_video -vf select='not(mod(n-1\,4)), setpts=0.25*PTS' -an output_video

Change the 4 if you are splitting into a different number, and the 1 if you want a different selection (so for four you would run it four times, starting without subtracting anything, and ending with subtracting three.

The -vf ... -an segment is to get the video to play back at the right speed, and have the right length (which requires removing any audio tracks).

All-at-once solution

The select filter can also split the file and save each output separately. Here is a command that will split the file into k outputs, (change .mp4 if you want a different extension).

k=4;ffmpeg -i INPUT_FILE -an -filter_complex "setpts=`bc -l <<< 1/$k`*PTS[m];[m]select=n=$k:e=mod(n\,$k)+1`for ((i=1; i<=$k; i++)); do echo -n "[a$i]"; done`" `for ((i=1; i<=$k; i++)); do echo -n "-map [a$i] out$i.mp4 "; done`

The loops within the command are just to write out [a1][a2]... and -map [a1] out1.mp4.... Other than that the modification is to use filter_complex, which is required when dealing with multiple outputs, and changing the filter to direct each frame to its own output mod k.

🌐
FFmpeg
ffmpeg.org › pipermail › ffmpeg-user › 2013-September › 017558.html
[FFmpeg-user] How to drop every Nth frame?
April 16, 2014 - So to select 23 frames per 24, do: > > select='mod(n,24)' > _______________________________________________ > ffmpeg-user mailing list > ffmpeg-user at ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-user > Previous message: [FFmpeg-user] How to drop every Nth frame?
🌐
Reddit
reddit.com › r/ffmpeg › how to skip frames, after scene change is detected ?
r/ffmpeg on Reddit: How to skip frames, after scene change is detected ?
August 11, 2023 - For instance , I have a video, I want to start at 10 seconds , and ends 30 seconds before the end of the file , I want to output a screenshot of the first and last frame in that interval , then I would also like to select scene change "select='gt(scene,0.1)'" , then skip the next 5 seconds , and try again to find the next scene after that point. ... ffmpeg -i "video_path" -map 0:v:0 -filter_complex "select='gt(scene,0.1)'" -vsync vfr -pix_fmt gray -s 128x128 -frame_pts 1 -y "output_file"
🌐
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.