avfilter/vf_mpdecimate: Add option to keep the first N similar frames before dropping

This allows for decimating large similar portions of a video while preserving small ones.
This commit is contained in:
Thilo Borgmann 2023-05-08 14:37:26 +02:00
parent 1eed7f6562
commit 21a0b6bca8
3 changed files with 25 additions and 3 deletions

View File

@ -17656,6 +17656,13 @@ number of previous sequentially dropped frames.
Default value is 0.
@item keep
Set the maximum number of consecutive similar frames to ignore before to start dropping them.
If the value is 0, the frame is dropped disregarding the
number of previous sequentially similar frames.
Default value is 0.
@item hi
@item lo
@item frac

View File

@ -32,7 +32,7 @@
#include "version_major.h"
#define LIBAVFILTER_VERSION_MINOR 7
#define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_MICRO 102
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \

View File

@ -46,6 +46,9 @@ typedef struct DecimateContext {
int drop_count; ///< if positive: number of frames sequentially dropped
///< if negative: number of sequential frames which were not dropped
int max_keep_count; ///< number of similar frames to ignore before to start dropping them
int keep_count; ///< number of similar frames already ignored
int hsub, vsub; ///< chroma subsampling values
AVFrame *ref; ///< reference picture
av_pixelutils_sad_fn sad; ///< sum of absolute difference function
@ -57,6 +60,8 @@ typedef struct DecimateContext {
static const AVOption mpdecimate_options[] = {
{ "max", "set the maximum number of consecutive dropped frames (positive), or the minimum interval between dropped frames (negative)",
OFFSET(max_drop_count), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS },
{ "keep", "set the number of similar consecutive frames to be kept before starting to drop similar frames",
OFFSET(max_keep_count), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
{ "hi", "set high dropping threshold", OFFSET(hi), AV_OPT_TYPE_INT, {.i64=64*12}, INT_MIN, INT_MAX, FLAGS },
{ "lo", "set low dropping threshold", OFFSET(lo), AV_OPT_TYPE_INT, {.i64=64*5}, INT_MIN, INT_MAX, FLAGS },
{ "frac", "set fraction dropping threshold", OFFSET(frac), AV_OPT_TYPE_FLOAT, {.dbl=0.33}, 0, 1, FLAGS },
@ -112,6 +117,12 @@ static int decimate_frame(AVFilterContext *ctx,
DecimateContext *decimate = ctx->priv;
int plane;
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;
@ -196,20 +207,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) {
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
} else {
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 similiar frames to ignore before dropping
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\n",
"%s pts:%s pts_time:%s drop_count:%d keep_count:%d\n",
decimate->drop_count > 0 ? "drop" : "keep",
av_ts2str(cur->pts), av_ts2timestr(cur->pts, &inlink->time_base),
decimate->drop_count);
decimate->drop_count,
decimate->keep_count);
if (decimate->drop_count > 0)
av_frame_free(&cur);