Is there any way to detect duplicate frames within the video using ffmpeg
.
I tried -vf
flag with select=gt(scene\,0.xxx)
for scene change. But, it did not work for my case.
Is there any way to detect duplicate frames within the video using ffmpeg
.
I tried -vf
flag with select=gt(scene\,0.xxx)
for scene change. But, it did not work for my case.
I also had this problem and Gyan's excellent answer above got me started but the result of it was desynchronized audio so I had to explore more options:
mpdecimate vs decimate filters
mpdecimate
is the standard recommendation I found all over SO and the internet, but I don't think it should be the first pickfrac
parameter, but that's extra work you may want to avoid if you canmp4
container (source), but I was usingmkv
so this limitation didn't apply on my case, but good to be aware of itdecimate
removes frames precisely, but it is useful only for periodically occurring duplicatesdetected vs actual frame rate
ffprobe in.mkv
will output the detected FPS; it may look like thisStream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
the actual frame rate can be found out if you open the media
in.mkv
in a media player that lets you step one frame at the time; then count the steps needed to advance the playback time for 1 second, in my case it was 30 fpswhat is
N/FRAME_RATE/TB
except the use of
FRAME_RATE
variable theN/FRAME_RATE/TB
is equal to the example below from ffmpeg documentation (source)the math behind it perfectly explained in What is video timescale, timebase, or timestamp in ffmpeg?
TB
to enhance precisionFRAME_RATE
variable vs literal FPS value (e.g. 25)FRAME_RATE
variable inN/FRAME_RATE/TB
FRAME_RATE
on your ownN/25/TB
FRAME_RATE
(and I actually tried that) it would take the wrong detected fps of 25 frames i.e.FRAME_RATE=25
, run it throughmpdecimate
filter which would remove every 6th frame and it would update toFRAME_RATE=20.833
soN/FRAME_RATE/TB
would actually beN/20.833/TB
which is completely wrongto use or not to use setpts
here is what I used with good results
ffmpeg -i in.mkv -vf mpdecimate out.mkv
ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv
but the following gave me desynchronized audio
ffmpeg -i in.mkv -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mkv
ffmpeg -i in.mkv -vf mpdecimate,setpts=N/25/TB out.mkv
ffmpeg -i in.mkv -vf decimate=cycle=6 out.mkv
as you see
FRAME_RATE
variable and useN/25/TB
instead because the actual FPS was not detected properlynote on asetpts
-af asetpts=N/SAMPLE_RATE/TB
SAMPLE_RATE
according to the ratio of duplicate frames removed, but it seems to me like extra unnecessary work especially when my video had the audio in sync at the beginning, so it is better to use commands that will keep it that way instead of fixing it latertl;dr
If the usually recommended command
ffmpeg -i in.mkv -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mkv
does not work for you try this:ffmpeg -i in.mkv -vf mpdecimate out.mkv
or
ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv
(
cycle=6
because every 6th frame is duplicate andN/25/TB
because after removing the duplicates the video will have 25 fps (avoid theFRAME_RATE
variable); adjust for your use case)Use the mpdecimate filter, whose purpose is to "Drop frames that do not differ greatly from the previous frame in order to reduce frame rate."
This will generate a console readout showing which frames the filter thinks are duplicates.
ffmpeg -i input.mp4 -vf mpdecimate -loglevel debug -f null -
To generate a video with the duplicates removed
ffmpeg -i input.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mp4
Th setpts filter expression generates smooth timestamps for a video at FRAME_RATE fps. See an explanation for timestamps at What is video timescale, timebase, or timestamp in ffmpeg?