From d8141813d2987a2f7f06f738062301254ecb4c28 Mon Sep 17 00:00:00 2001 From: Kevin Mitchell <kevmi...@gmail.com> Date: Sat, 1 Nov 2014 03:12:48 -0700 Subject: [PATCH 3/3] avfilter/vf_idet: add repeated field detection
This is useful for detecting telecine --- doc/filters.texi | 25 +++++++++++++++++++++---- libavfilter/version.h | 2 +- libavfilter/vf_idet.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- libavfilter/vf_idet.h | 12 +++++++++++- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 2896978..5128a02 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -5574,11 +5574,13 @@ value. Detect video interlacing type. -This filter tries to detect if the input is interlaced or progressive, -top or bottom field first. +This filter tries to detect if the input frames as interlaced, progressive, +top or bottom field first. It will also try and detect fields that are +repeated between adjacent frames (a sign of telecine). -Single frame detection considers only immediately adjacent frames when classifying each frame. -Multiple frame detection incorporates the classification history of previous frames. +There are two detection modes. Single frame detection considers only +immediately adjacent frames when classifying each frame. Multiple frame +detection incorporates the classification history of previous frames. The filter will log these metadata values: @@ -5619,6 +5621,19 @@ Cumulative number of frames that could not be classified using single-frame dete @item multiple.undetermined Cumulative number of frames that could not be classified using multiple-frame detection. + +@item repeated.current_frame +Which field in the current frame is repeated from the last. One of ``neither'', ``top'', or ``bottom''. + +@item repeated.neither +Cumulative number of frames with no repeated field. + +@item repeated.top +Cumulative number of frames with the top field repeated from the previous frame's top field. + +@item repeated.bottom +Cumulative number of frames with the bottom field repeated from the previous frame's bottom field. + @end table The filter accepts the following options: @@ -5628,6 +5643,8 @@ The filter accepts the following options: Set interlacing threshold. @item prog_thres Set progressive threshold. +@item repeat_thres +Threshold for repeat detection. @item reset_count Number of frames after which idet will reset all previously collected statistics. The current statistics are logged before being diff --git a/libavfilter/version.h b/libavfilter/version.h index dab9b45..6f61aee 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #define LIBAVFILTER_VERSION_MAJOR 5 #define LIBAVFILTER_VERSION_MINOR 2 -#define LIBAVFILTER_VERSION_MICRO 102 +#define LIBAVFILTER_VERSION_MICRO 103 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c index 79dc9be..74cdb44 100644 --- a/libavfilter/vf_idet.c +++ b/libavfilter/vf_idet.c @@ -32,6 +32,7 @@ static const AVOption idet_options[] = { { "intl_thres", "set interlacing threshold", OFFSET(interlace_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 1.04}, -1, FLT_MAX, FLAGS }, { "prog_thres", "set progressive threshold", OFFSET(progressive_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 1.5}, -1, FLT_MAX, FLAGS }, + { "rep_thres", "set repeat threshold", OFFSET(repeat_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 3.0}, -1, FLT_MAX, FLAGS }, { "reset_count", "drop statistics after this many frames", OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { NULL } }; @@ -49,6 +50,16 @@ static const char *type2str(Type type) return NULL; } +static const char *rep2str(RepeatedField repeated_field) +{ + switch(repeated_field) { + case REPEAT_NONE : return "neither"; + case REPEAT_TOP : return "top"; + case REPEAT_BOTTOM : return "bottom"; + } + return NULL; +} + int ff_idet_filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w) { int x; @@ -78,6 +89,12 @@ int ff_idet_filter_line_c_16bit(const uint16_t *a, const uint16_t *b, const uint static void log_cumulative_stats(AVFilterContext *ctx) { IDETContext *idet = ctx->priv; + av_log(ctx, AV_LOG_INFO, "Repeated Fields: Neither:%d Top:%d Bottom:%d Total: %d\n", + idet->repeats[REPEAT_NONE], + idet->repeats[REPEAT_TOP], + idet->repeats[REPEAT_BOTTOM], + idet->frames_total + ); av_log(ctx, AV_LOG_INFO, "Single frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d Total: %d\n", idet->prestat[TFF], idet->prestat[BFF], @@ -100,7 +117,9 @@ static void filter(AVFilterContext *ctx) int y, i; int64_t alpha[2]={0}; int64_t delta=0; + int64_t gamma[2]={0}; Type type, best_type; + RepeatedField repeat; int match = 0; AVDictionary **metadata = avpriv_frame_get_metadatap(idet->cur); @@ -109,10 +128,12 @@ static void filter(AVFilterContext *ctx) log_cumulative_stats(ctx); memset(idet->prestat, 0 , 4*sizeof(int)); memset(idet->poststat, 0 , 4*sizeof(int)); + memset(idet->repeats, 0 , 3*sizeof(int)); memset(idet->history, UNDETERMINED, HIST_SIZE); idet->frames_total=0; } + for (i = 0; i < idet->csp->nb_components; i++) { int w = idet->cur->width; int h = idet->cur->height; @@ -127,9 +148,10 @@ static void filter(AVFilterContext *ctx) uint8_t *prev = &idet->prev->data[i][y*refs]; uint8_t *cur = &idet->cur ->data[i][y*refs]; uint8_t *next = &idet->next->data[i][y*refs]; - alpha[ y &1] += idet->filter_line(cur-refs, prev, cur+refs, w); - alpha[(y^1)&1] += idet->filter_line(cur-refs, next, cur+refs, w); - delta += idet->filter_line(cur-refs, cur, cur+refs, w); + alpha[ y &1] += idet->filter_line(cur-refs , prev, cur+refs , w); + alpha[(y^1)&1] += idet->filter_line(cur-refs , next, cur+refs , w); + delta += idet->filter_line(cur-refs , cur, cur+refs , w); + gamma[(y^1)&1] += idet->filter_line(cur , prev, cur , w); } } @@ -143,6 +165,14 @@ static void filter(AVFilterContext *ctx) type = UNDETERMINED; } + if ( gamma[0] > idet->repeat_threshold * gamma[1] ){ + repeat = REPEAT_TOP; + } else if ( gamma[1] > idet->repeat_threshold * gamma[0] ){ + repeat = REPEAT_BOTTOM; + } else { + repeat = REPEAT_NONE; + } + memmove(idet->history+1, idet->history, HIST_SIZE-1); idet->history[0] = type; best_type = UNDETERMINED; @@ -179,10 +209,15 @@ static void filter(AVFilterContext *ctx) idet->prestat [ type] ++; idet->poststat[idet->last_type] ++; - av_log(ctx, AV_LOG_DEBUG, "Single frame:%12s, Multi frame:%12s\n", type2str(type), type2str(idet->last_type)); + av_log(ctx, AV_LOG_DEBUG, "Repeated Field:%12s, Single frame:%12s, Multi frame:%12s\n", rep2str(repeat), type2str(type), type2str(idet->last_type)); av_dict_set_int(metadata, "lavfi.idet.frames_total", idet->frames_total, 0); + av_dict_set (metadata, "lavfi.idet.repeated.current_frame", rep2str(repeat), 0); + av_dict_set_int(metadata, "lavfi.idet.repeated.neither", idet->repeats[REPEAT_NONE], 0); + av_dict_set_int(metadata, "lavfi.idet.repeated.top", idet->repeats[REPEAT_TOP], 0); + av_dict_set_int(metadata, "lavfi.idet.repeated.bottom", idet->repeats[REPEAT_BOTTOM], 0); + av_dict_set (metadata, "lavfi.idet.single.current_frame", type2str(type), 0); av_dict_set_int(metadata, "lavfi.idet.single.tff", idet->prestat[TFF], 0); av_dict_set_int(metadata, "lavfi.idet.single.bff", idet->prestat[BFF], 0); @@ -195,6 +230,9 @@ static void filter(AVFilterContext *ctx) av_dict_set_int(metadata, "lavfi.idet.multiple.progressive", idet->poststat[PROGRESSIVE], 0); av_dict_set_int(metadata, "lavfi.idet.multiple.undetermined", idet->poststat[UNDETERMINED], 0); + idet->repeats [ repeat] ++; + idet->prestat [ type] ++; + idet->poststat[idet->last_type] ++; } static int filter_frame(AVFilterLink *link, AVFrame *picref) diff --git a/libavfilter/vf_idet.h b/libavfilter/vf_idet.h index 97a7e3f..476422f 100644 --- a/libavfilter/vf_idet.h +++ b/libavfilter/vf_idet.h @@ -33,14 +33,23 @@ typedef enum { UNDETERMINED, } Type; +typedef enum { + REPEAT_NONE, + REPEAT_TOP, + REPEAT_BOTTOM, +} RepeatedField; + typedef struct { const AVClass *class; float interlace_threshold; float progressive_threshold; int reset_count; + float repeat_threshold; + - Type last_type; int frames_total; + Type last_type; + int repeats[3]; int prestat[4]; int poststat[4]; @@ -49,6 +58,7 @@ typedef struct { AVFrame *cur; AVFrame *next; AVFrame *prev; + ff_idet_filter_func filter_line; const AVPixFmtDescriptor *csp; -- 2.1.1
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel