PR #22261 opened by dana-feng URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22261 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22261.patch
Fix the following issues with the keep option: - Add similarity check during keep period. Previously, the code returned early during the keep period without checking if the frame is actually similar to the reference. - Reset keep_count on different frames. Previously, the counter could accumulate across non-consecutive similar frames, causing frames to be dropped earlier than expected. - Keep the same frame reference if appropriate. Previously, the code made similar frames the new reference, causing reference drift and gradual scene changes. Signed-off-by: Dana Feng <[email protected]> >From dbe69d8ed9b5e4027b6789de3cc7ea3902f5ef13 Mon Sep 17 00:00:00 2001 From: Dana Feng <[email protected]> Date: Sun, 22 Feb 2026 21:33:55 -0500 Subject: [PATCH] vf_mpdecimate: Fix keep option logic for keep > 0 Fix the following issues with the keep option: - Add similarity check during keep period. Previously, the code returned early during the keep period without checking if the frame is actually similar to the reference. - Reset keep_count on different frames. Previously, the counter could accumulate across non-consecutive similar frames, causing frames to be dropped earlier than expected. - Keep the same frame reference if appropriate. Previously, the code made similar frames the new reference, causing reference drift and gradual scene changes. Signed-off-by: Dana Feng <[email protected]> --- libavfilter/vf_mpdecimate.c | 50 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/libavfilter/vf_mpdecimate.c b/libavfilter/vf_mpdecimate.c index 0fc95556b7..f91bd6cd29 100644 --- a/libavfilter/vf_mpdecimate.c +++ b/libavfilter/vf_mpdecimate.c @@ -109,19 +109,18 @@ static int diff_planes(AVFilterContext *ctx, /** * Tell if the frame should be decimated, for example if it is no much * different with respect to the reference frame ref. + + @return 1 if frame should be dropped (similar), + 0 if frame should be kept (different), + -1 if frame should be kept (similar, under keep_count). */ static int decimate_frame(AVFilterContext *ctx, AVFrame *cur, AVFrame *ref) { DecimateContext *decimate = ctx->priv; int plane; + int is_similar; - if (decimate->max_keep_count > 0 && - decimate->keep_count > -1 && - decimate->keep_count < decimate->max_keep_count) { - decimate->keep_count++; - return 0; - } if (decimate->max_drop_count > 0 && decimate->drop_count >= decimate->max_drop_count) return 0; @@ -129,6 +128,8 @@ static int decimate_frame(AVFilterContext *ctx, (decimate->drop_count-1) > decimate->max_drop_count) return 0; + is_similar = 1; + for (plane = 0; ref->data[plane] && ref->linesize[plane]; plane++) { /* use 8x8 SAD even on subsampled planes. The blocks won't match up with * luma blocks, but hopefully nobody is depending on this to catch @@ -141,10 +142,21 @@ static int decimate_frame(AVFilterContext *ctx, cur->data[plane], cur->linesize[plane], ref->data[plane], ref->linesize[plane], AV_CEIL_RSHIFT(ref->width, hsub), - AV_CEIL_RSHIFT(ref->height, vsub))) - return 0; + AV_CEIL_RSHIFT(ref->height, vsub))) { + is_similar = 0; + break; + } + } + if (!is_similar) { + return 0; + } + /* Frame is similar - apply keep_count logic */ + if (decimate->max_keep_count > 0 && + decimate->keep_count > -1 && + decimate->keep_count < decimate->max_keep_count) { + decimate->keep_count++; + return -1; /* Similar but under keep threshold - keep without updating ref*/ } - return 1; } @@ -200,29 +212,35 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *cur) DecimateContext *decimate = inlink->dst->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; int ret; + int result = decimate->ref ? decimate_frame(inlink->dst, cur, decimate->ref) : 0; - if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) { + if (result == 1){ + /* Drop: similar frame, over keep threshold */ decimate->drop_count = FFMAX(1, decimate->drop_count+1); - decimate->keep_count = -1; // do not keep any more frames until non-similar frames are detected + decimate->keep_count = -1; + } else if (result == -1) { + /* Keep: similar frame, under keep threshold - don't update ref */ + decimate->drop_count = FFMIN(-1, decimate->drop_count-1); + if ((ret = ff_filter_frame(outlink, cur)) < 0) + return ret; } else { + /* Keep: different frame - update ref and reset keep_count */ av_frame_free(&decimate->ref); decimate->ref = cur; decimate->drop_count = FFMIN(-1, decimate->drop_count-1); - if (decimate->keep_count < 0) // re-enable counting similar frames to ignore before dropping - decimate->keep_count = 0; - + decimate->keep_count = 0; if ((ret = ff_filter_frame(outlink, av_frame_clone(cur))) < 0) return ret; } av_log(inlink->dst, AV_LOG_DEBUG, "%s pts:%s pts_time:%s drop_count:%d keep_count:%d\n", - decimate->drop_count > 0 ? "drop" : "keep", + result > 0 ? "drop" : "keep", av_ts2str(cur->pts), av_ts2timestr(cur->pts, &inlink->time_base), decimate->drop_count, decimate->keep_count); - if (decimate->drop_count > 0) + if (result > 0) av_frame_free(&cur); return 0; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
