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:
5555 seconds
12:03:4512 hours, 03 minutes and 45 seconds
23.18923.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_seekis enabled (the default), this extra segment between the seek point and position will be decoded and discarded. When doing stream copy or when-noaccurate_seekis used, it will be preserved.
Refer to the ffmpeg documentation for more.
Answer from evilSnobu on Stack OverflowThis 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:
5555 seconds
12:03:4512 hours, 03 minutes and 45 seconds
23.18923.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_seekis enabled (the default), this extra segment between the seek point and position will be decoded and discarded. When doing stream copy or when-noaccurate_seekis used, it will be preserved.
Refer to the ffmpeg documentation for more.
ffmpeg -i {videofile} -vf select=gte(n\,{skip}) -c:v libx264 -c:a aac {outfile}
Where {skip} = number of frames to skip at atart.
Unlike previous solution, there's no loss in quality here.
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?
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 …
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.
When I convert png images to avi video ffmpeg is dropping frames. At the end I have over 130 dropped frames and with the 24fps video that's 5 second difference at the end. How can I prevent ffmpeg from dropping frames I tried every -vsync option and -frame_drop_threshold 0 but nothing worked. I run
ffmpeg -i ./pictures/asp_%04d.png -vsync 0/1/2/drop -r 24 video.avi ffmpeg -i ./pictures/asp_%04d.png -frame_drop_threshold 0 -r 24 video.avi
but neither worked, for -vsync 0/drop I got errors
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' });
I realize this is an old question, but in case someone else (like me) stumbles upon it, the answer is that the time code skips you see are not an error, but work as intended.
Since you have specified 29.97 fps drop frame (by using a semicolon in the timecode) the two-frame skip is according to the specification (read more here: https://en.wikipedia.org/wiki/SMPTE_timecode#Drop_frame_timecode).
In short: Since 29.97 is a fractional speed, and a video file cannot contain fractional frames, frames have to be dropped to maintain a correlation between the time code and wall clock time. Note that no actual video frames are dropped, only time codes are skipped. The specification says that on the first second of every minute, the first two frames (zero and one) are skipped, except for when the minute value is divisible by ten.
So seeing the time code go from 00:00:59:29 to 00:01:00:02 is expected behaviour. In order not to get this you have to switch to another frame rate, and write the time code using only colons: 00:00:00:00.
I found a StackOverflow post on the same topic; I think that solution is a little more elegant, so check this out.
What method are you using to examine the video? Have you confirmed somehow that it is the video itself at fault, as opposed to the video decoder skipping the frames?
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()
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
