#undef NDEBUG
#include <assert.h>
+#define HIST_SIZE 4
+
typedef enum {
TFF,
BFF,
float interlace_threshold;
float progressive_threshold;
-
+ Type last_type;
Type prestat[4];
+ Type poststat[4];
+
+ uint8_t history[HIST_SIZE];
AVFilterBufferRef *cur;
AVFilterBufferRef *next;
AVFilterBufferRef *prev;
AVFilterBufferRef *out;
- int (*filter_line)(uint8_t *prev, uint8_t *cur, uint8_t *next, int w);
+ int (*filter_line)(const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w);
const AVPixFmtDescriptor *csp;
} IDETContext;
+static const char *type2str(Type type)
+{
+ switch(type) {
+ case TFF : return "Top Field First ";
+ case BFF : return "Bottom Field First";
+ case PROGRSSIVE : return "Progressive ";
+ case UNDETERMINED: return "Undetermined ";
+ }
+ return NULL;
+}
static int filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w)
{
int y, i;
int64_t alpha[2]={0};
int64_t delta=0;
- Type type;
+ Type type, best_type;
+ int match = 0;
for (i = 0; i < idet->csp->nb_components; i++) {
int w = idet->cur->video->w;
int h = idet->cur->video->h;
int refs = idet->cur->linesize[i];
- int df = (idet->csp->comp[i].depth_minus1 + 8) / 8;
if (i && i<3) {
w >>= idet->csp->log2_chroma_w;
type = UNDETERMINED;
}
- idet->prestat[type] ++;
+ memmove(idet->history+1, idet->history, HIST_SIZE-1);
+ idet->history[0] = type;
+ best_type = UNDETERMINED;
+ for(i=0; i<HIST_SIZE; i++){
+ if(idet->history[i] != UNDETERMINED){
+ if(best_type == UNDETERMINED)
+ best_type = idet->history[i];
+
+ if(idet->history[i] == best_type) {
+ match++;
+ }else{
+ match=0;
+ break;
+ }
+ }
+ }
+ if(idet->last_type == UNDETERMINED){
+ if(match ) idet->last_type = best_type;
+ }else{
+ if(match>2) idet->last_type = best_type;
+ }
- if (type == TFF){
- av_log(ctx, AV_LOG_INFO, "Interlaced, top field first\n");
+ if (idet->last_type == TFF){
idet->cur->video->top_field_first = 1;
idet->cur->video->interlaced = 1;
- }else if(type == BFF){
- av_log(ctx, AV_LOG_INFO, "Interlaced, bottom field first\n");
+ }else if(idet->last_type == BFF){
idet->cur->video->top_field_first = 0;
idet->cur->video->interlaced = 1;
- }else if(type == PROGRSSIVE){
- av_log(ctx, AV_LOG_INFO, "Progressive\n");
+ }else if(idet->last_type == PROGRSSIVE){
idet->cur->video->interlaced = 0;
- }else{
- av_log(ctx, AV_LOG_INFO, "Undetermined\n");
- idet->cur->video->interlaced = idet->prev->video->interlaced;
- idet->cur->video->top_field_first = idet->prev->video->top_field_first;
}
+
+ idet->prestat [ type] ++;
+ idet->poststat[idet->last_type] ++;
+ av_log(ctx, AV_LOG_DEBUG, "Single frame:%s, Multi frame:%s\n", type2str(type), type2str(idet->last_type));
}
static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
{
IDETContext *idet = ctx->priv;
- av_log(ctx, AV_LOG_INFO, "TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
+ av_log(ctx, AV_LOG_INFO, "Single frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
idet->prestat[TFF],
idet->prestat[BFF],
idet->prestat[PROGRSSIVE],
idet->prestat[UNDETERMINED]
);
+ av_log(ctx, AV_LOG_INFO, "Multi frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
+ idet->poststat[TFF],
+ idet->poststat[BFF],
+ idet->poststat[PROGRSSIVE],
+ idet->poststat[UNDETERMINED]
+ );
if (idet->prev) avfilter_unref_buffer(idet->prev);
if (idet->cur ) avfilter_unref_buffer(idet->cur );
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
{
IDETContext *idet = ctx->priv;
- int cpu_flags = av_get_cpu_flags();
idet->csp = NULL;
if (args) sscanf(args, "%f:%f", &idet->interlace_threshold, &idet->progressive_threshold);
+ idet->last_type = UNDETERMINED;
+ memset(idet->history, UNDETERMINED, HIST_SIZE);
+
idet->filter_line = filter_line_c;
return 0;