]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_idet.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavfilter / vf_idet.c
index cd801b96bab0938127af8fab86abe2af1889b061..0441c78fd013e3efadc9478f3bff08baa661670b 100644 (file)
 #undef NDEBUG
 #include <assert.h>
 
+#define HIST_SIZE 4
+
+typedef enum {
+    TFF,
+    BFF,
+    PROGRSSIVE,
+    UNDETERMINED,
+} Type;
+
 typedef struct {
     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)
 {
@@ -70,13 +95,13 @@ static void filter(AVFilterContext *ctx)
     int y, i;
     int64_t alpha[2]={0};
     int64_t delta=0;
-    static int p=0, t=0, b=0, u=0;
+    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;
@@ -97,23 +122,50 @@ static void filter(AVFilterContext *ctx)
 #endif
 
     if      (alpha[0] / (float)alpha[1] > idet->interlace_threshold){
-        av_log(0, AV_LOG_INFO, "Interlaced, top field first\n");
-        t++;
+        type = TFF;
     }else if(alpha[1] / (float)alpha[0] > idet->interlace_threshold){
-        av_log(0, AV_LOG_INFO, "Interlaced, bottom field first\n");
-        b++;
+        type = BFF;
     }else if(alpha[1] / (float)delta    > idet->progressive_threshold){
-        av_log(0, AV_LOG_INFO, "Progressive\n");
-        p++;
+        type = PROGRSSIVE;
     }else{
-        av_log(0, AV_LOG_INFO, "Undetermined\n");
-        u++;
+        type = UNDETERMINED;
     }
-//     av_log(0,0, "t%d b%d p%d u%d\n", t,b,p,u);
-}
 
-static void return_frame(AVFilterContext *ctx)
-{
+    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      (idet->last_type == TFF){
+        idet->cur->video->top_field_first = 1;
+        idet->cur->video->interlaced = 1;
+    }else if(idet->last_type == BFF){
+        idet->cur->video->top_field_first = 0;
+        idet->cur->video->interlaced = 1;
+    }else if(idet->last_type == PROGRSSIVE){
+        idet->cur->video->interlaced = 0;
+    }
+
+    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)
@@ -191,6 +243,19 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     IDETContext *idet = ctx->priv;
 
+    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 );
     if (idet->next) avfilter_unref_buffer(idet->next);
@@ -229,7 +294,6 @@ static int query_formats(AVFilterContext *ctx)
 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;
 
@@ -238,6 +302,9 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 
     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;
@@ -255,16 +322,16 @@ AVFilter avfilter_vf_idet = {
     .query_formats = query_formats,
 
     .inputs    = (const AVFilterPad[]) {{ .name       = "default",
-                                    .type             = AVMEDIA_TYPE_VIDEO,
-                                    .start_frame      = start_frame,
-                                    .draw_slice       = null_draw_slice,
-                                    .end_frame        = end_frame,
-                                    .rej_perms        = AV_PERM_REUSE2, },
-                                  { .name = NULL}},
+                                          .type             = AVMEDIA_TYPE_VIDEO,
+                                          .start_frame      = start_frame,
+                                          .draw_slice       = null_draw_slice,
+                                          .end_frame        = end_frame,
+                                          .rej_perms        = AV_PERM_REUSE2, },
+                                        { .name = NULL}},
 
     .outputs   = (const AVFilterPad[]) {{ .name       = "default",
-                                    .type             = AVMEDIA_TYPE_VIDEO,
-                                    .poll_frame       = poll_frame,
-                                    .request_frame    = request_frame, },
-                                  { .name = NULL}},
+                                          .type             = AVMEDIA_TYPE_VIDEO,
+                                          .poll_frame       = poll_frame,
+                                          .request_frame    = request_frame, },
+                                        { .name = NULL}},
 };