All pastes #942949 Raw Edit

Combing Detection

public diff v1 · immutable
·published 2008-03-14 21:12 UTC
rendered paste body
Index: test/test.c===================================================================--- test/test.c	(revision 1336)+++ test/test.c	(working copy)@@ -300,6 +300,13 @@         fprintf( stderr, "    + %d, %s (iso639-2: %s)\n", i + 1, subtitle->lang,             subtitle->iso639_2);     }+    +    if(title->detected_interlacing)+    {+        /* Interlacing was found in 6 or more preview frames */+        fprintf( stderr, "  + interlacing artifacts detected\n");+    }+     }  static int HandleEvents( hb_handle_t * h )@@ -725,6 +732,13 @@             {                 job->pixel_ratio = pixelratio;             }+            +            if (vfr)+            {+                detelecine = 1;+                job->vfr = 1;+            }+                         /* Add selected filters */             job->filters = hb_list_init();             if( detelecine )@@ -926,9 +940,6 @@             if (maxHeight)                 job->maxHeight = maxHeight; -            if (vfr)-                job->vfr = 1;-             if( subtitle_force )             {                 job->subtitle_force = subtitle_force;@@ -1626,6 +1637,7 @@             {                 int    i;                 char * tmp = optarg;+//                fprintf(stderr, "cropping string is: %s", tmp);                 for( i = 0; i < 4; i++ )                 {                     if( !*tmp )@@ -1634,7 +1646,14 @@                     tmp++;                 }                 break;-            }+                +/*                sscanf( optarg, "%d:%d:%d:%d",+                        &crop[0],+                        &crop[1],+                        &crop[2],+                        &crop[3]);+                break;+*/            }             case 'r':             {                 int i;Index: libhb/detelecine.c===================================================================--- libhb/detelecine.c	(revision 1336)+++ libhb/detelecine.c	(working copy)@@ -1027,7 +1027,9 @@             pv->width[1] * pv->height[1] * sizeof(uint8_t) );     memcpy( pv->pic_out.data[2], frame->buffer->planes[2],             pv->width[2] * pv->height[2] * sizeof(uint8_t) );-+    +    pv->buf_out->length = frame->length;+             pullup_release_frame( frame );  output_frame:Index: libhb/hb.c===================================================================--- libhb/hb.c	(revision 1336)+++ libhb/hb.c	(working copy)@@ -426,6 +426,115 @@     avpicture_free( &pic_in ); } + /**+ * Analyzes a frame to detect interlacing artifacts+ * and returns true if interlacing (combing) is found.+ *+ * Code taken from Thomas Oestreich's 32detect filter+ * in the Transcode project, with minor formatting changes.+ *+ * @param buf An hb_buffer structure holding valid frame data.+ * @param width The frame's width in pixels.+ * @param height The frame's height in pixels.+ */+int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold)+{+    int j, k, n, off, block, cc_1, cc_2, cc[3], flag[3];+    uint16_t s1, s2, s3, s4;+    cc_1 = 0; cc_2 = 0;+    +    /* These values are defined in hb.h */+    int thres = threshold;+    int eq = color_equal;+    int diff = color_diff;+    +    int offset = 0;+    if( buf->telecined )+    {+        return 0;+    }+    +    for(k=0; k < 3; k++)+    {+        /* One pas for Y, one pass for Cb, one pass for Cr */+        if( k == 1 )+        {+            /* Y has already been checked, now offset by Y's dimensions+               and divide all the other values by 2, since Cr and Cb+               are half-size compared to Y.                               */+            offset = width * height;+            width >>= 1;+            height >>= 1;+            thres >>= 1;+            eq >>= 1;+            diff >>= 1;+        }+        else if (k == 2 )+        {+            /* Y and Cb are done, so the offset needs to be bumped+               so it's width*height + (width / 2) * (height / 2)  */+            offset *= 5/4;+        }+        +        /* Look at one horizontal line at a time */+        block = width;+        +        for(j=0; j<block; ++j)+        {+            off=0;+            +            for(n=0; n<(height-4); n=n+2)+            {+                /* Look at groups of 4 sequential horizontal lines */+                s1 = ((buf->data+offset)[off+j        ] & 0xff);+                s2 = ((buf->data+offset)[off+j+  block] & 0xff);+                s3 = ((buf->data+offset)[off+j+2*block] & 0xff);+                s4 = ((buf->data+offset)[off+j+3*block] & 0xff);+                +                /* Note if the 1st and 2nd lines are more different in+                   color than the 1st and 3rd lines are similar in color.*/+                if((abs(s1 - s3) < eq) &&+                    (abs(s1 - s2) > diff)) ++cc_1;+    +                /* Note if the 2nd and 3rd lines are more different in+                   color than the 2nd and 4th lines are similar in color.*/+                if((abs(s2 - s4) < eq) &&+                    (abs(s2 - s3) > diff)) ++cc_2;+                +                /* Now move down 2 horizontal lines before starting over.*/+                off +=2*block;+            }+        }+        +        // compare results+        /* The final metric seems to be doing some kind of bits per pixel style calculation+           to decide whether or not enough lines showed alternating colors for the frame size. */+        cc[k] = (int)((cc_1 + cc_2)*1000.0/(width*height));+        +        /* If the plane's cc score meets the threshold, flag it as combed. */+        flag[k] = 0;+        if(cc[k] > thres)+        {+            flag[k] = 1;+        }+    }+    +#if 0+/* Debugging info */+//    if(flag)+        hb_log("flags: %i/%i/%i | cc0: %i | cc1: %i | cc2: %i", flag[0], flag[1], flag[2], cc[0], cc[1], cc[2]);+#endif+    +    /* When more than one plane shows combing, tell the caller. */+    if (flag[0] || flag[1] || flag[2] )+    {+        return 1;+    }++    return 0;+}++ /**  * Calculates job width and height for anamorphic content,  *Index: libhb/hb.h===================================================================--- libhb/hb.h	(revision 1336)+++ libhb/hb.h	(working copy)@@ -75,6 +75,14 @@    Returns the list of valid titles detected by the latest scan. */ hb_list_t   * hb_get_titles( hb_handle_t * ); +/* hb_detect_comb()+   Analyze a frame for interlacing artifacts, returns true if they're found.+   Taken from Thomas Oestreich's 32detect filter in the Transcode project.  */+int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold);+#define COLOR_EQUAL  10 // Sensitivity for detecting similar colors.+#define COLOR_DIFF   30 // Sensitivity for detecting different colors+#define THRESHOLD     9 // Sensitivity for flagging planes as combed+ void          hb_get_preview( hb_handle_t *, hb_title_t *, int,                               uint8_t * ); void          hb_set_size( hb_job_t *, int ratio, int pixels );Index: libhb/render.c===================================================================--- libhb/render.c	(revision 1336)+++ libhb/render.c	(working copy)@@ -29,6 +29,7 @@     uint64_t             total_gained_time;     int64_t              chapter_time;     int                  chapter_val;+    int                  last_frame_length; };  int  renderInit( hb_work_object_t *, hb_job_t * );@@ -282,6 +283,14 @@             if( result == FILTER_OK )             {                 buf_tmp_in = buf_tmp_out;+                if (buf_tmp_in->length == 3 || pv->last_frame_length == 3)+                {+                    buf_tmp_in->telecined = 1;+                }+                else+                {+                    buf_tmp_in->telecined = 0;+                }             }             else if( result == FILTER_DELAY )             {@@ -420,7 +429,10 @@         /* The current frame exists. That means it hasn't been dropped by a filter.            Make it accessible as ivtc_buffer so we can edit its duration if needed. */         ivtc_buffer = *buf_out;+        +        pv->last_frame_length = ivtc_buffer->length; +        //hb_log("frame length: %i", ivtc_buffer->length);         if( pv->lost_time[3] > 0 )         {             /*@@ -562,6 +574,8 @@     pv->lost_time[0] = 0; pv->lost_time[1] = 0; pv->lost_time[2] = 0; pv->lost_time[3] = 0;     pv->chapter_time = 0;     pv->chapter_val  = 0;+    +    pv->last_frame_length = 0;      /* Setup filters */     /* TODO: Move to work.c? */Index: libhb/deinterlace.c===================================================================--- libhb/deinterlace.c	(revision 1336)+++ libhb/deinterlace.c	(working copy)@@ -42,6 +42,14 @@     int              yadif_parity;     int              yadif_ready; +    int              comb;+    int              comb_detect;+    int              color_equal;+    int              color_diff;+    int              threshold;+    int              deinterlaced_frames;+    int              passed_frames;+     uint8_t        * yadif_ref[4][3];     int              yadif_ref_stride[3]; @@ -115,6 +123,26 @@     } } +static void yadif_get_ref( uint8_t ** pic, hb_filter_private_t * pv, int frm )+{+    int i;+    for( i = 0; i < 3; i++ )+    {+        uint8_t * dst = pic[i];+        const uint8_t * ref = pv->yadif_ref[frm][i];+        int w = pv->width[i];+        int ref_stride = pv->yadif_ref_stride[i];+        +        int y;+        for( y = 0; y < pv->height[i]; y++ )+        {+            memcpy(dst, ref, w);+            dst += w;+            ref += ref_stride;+        }+    }+}+ static void yadif_filter_line( uint8_t *dst,                                uint8_t *prev,                                uint8_t *cur,@@ -356,6 +384,13 @@     pv->buf_out[1] = hb_buffer_init( buf_size );     pv->buf_settings = hb_buffer_init( 0 ); +    pv->deinterlaced_frames = 0;+    pv->passed_frames = 0;+    pv->comb_detect = 0;+    pv->color_equal = 10;+    pv->color_diff = 30;+    pv->threshold = 9;+     pv->yadif_ready    = 0;     pv->yadif_mode     = YADIF_MODE_DEFAULT;     pv->yadif_parity   = YADIF_PARITY_DEFAULT;@@ -365,11 +400,15 @@      if( settings )     {-        sscanf( settings, "%d:%d:%d:%d",+        sscanf( settings, "%d:%d:%d:%d:%d:%d:%d:%d",                 &pv->yadif_mode,                 &pv->yadif_parity,                 &pv->mcdeint_mode,-                &pv->mcdeint_qp );+                &pv->mcdeint_qp,+                &pv->comb_detect,+                &pv->color_equal,+                &pv->color_diff,+                &pv->threshold );     }      /* Allocate yadif specific buffers */@@ -451,6 +490,8 @@         return;     } +    hb_log("deinterlacer: filtered %i | unfiltered %i | total %i", pv->deinterlaced_frames, pv->passed_frames, pv->deinterlaced_frames + pv->passed_frames);+     /* Cleanup frame buffers */     if( pv->buf_out[0] )     {@@ -521,12 +562,29 @@         avpicture_fill( &pv->pic_out, pv->buf_out[0]->data,                         pix_fmt, width, height ); -        avpicture_deinterlace( &pv->pic_out, &pv->pic_in,-                               pix_fmt, width, height );+        /* Check for combing on the input frame */+        int interlaced = pv->comb_detect ? ( hb_detect_comb(buf_in, width, height, pv->color_equal, pv->color_diff, pv->threshold)) : 1;+        +        if(interlaced)+        {+            avpicture_deinterlace( &pv->pic_out, &pv->pic_in,+                                   pix_fmt, width, height ); -        hb_buffer_copy_settings( pv->buf_out[0], buf_in );+            pv->deinterlaced_frames++; -        *buf_out = pv->buf_out[0];+            hb_buffer_copy_settings( pv->buf_out[0], buf_in );+            *buf_out = pv->buf_out[0];            +        }+        else+        {+            /* No combing detected, pass input frame through unmolested.*/+            +            pv->passed_frames++;+            +            hb_buffer_copy_settings( pv->buf_out[0], buf_in );+            *buf_out = buf_in;+            +        }          return FILTER_OK;     }@@ -545,6 +603,9 @@     /* Store current frame in yadif cache */     yadif_store_ref( (const uint8_t**)pv->pic_in.data, pv ); +    /* Note down if the input frame is combed */+    pv->comb = (pv->comb << 1) | ( pv->comb_detect? hb_detect_comb(buf_in, width, height, pv->color_equal, pv->color_diff, pv->threshold) : 1);+     /* If yadif is not ready, store another ref and return FILTER_DELAY */     if( pv->yadif_ready == 0 )     {@@ -560,30 +621,48 @@         return FILTER_DELAY;     } -    /* Perform yadif and mcdeint filtering */-    int frame;-    for( frame = 0; frame <= (pv->yadif_mode & 1); frame++ )+    /* yadif & mcdeint work one frame behind so if the previous frame+     * had combing, deinterlace it otherwise just output it. */+    if(  (pv->comb & 2 ) == 0 )     {-        int parity = frame ^ tff ^ 1;+        /* previous frame not interlaced - copy cached input frame to buf_out */+        +        pv->passed_frames++;+        +        avpicture_fill( &pv->pic_out,  pv->buf_out[0]->data, pix_fmt, width, height );+        yadif_get_ref( (uint8_t**)pv->pic_out.data, pv, 1 );+        *buf_out = pv->buf_out[0];+    }+    else+    {+        /* Perform yadif and mcdeint filtering */+        +        pv->deinterlaced_frames++;+        +        int frame;+        for( frame = 0; frame <= (pv->yadif_mode & 1); frame++ )+        {+            int parity = frame ^ tff ^ 1; -        avpicture_fill( &pv->pic_out, pv->buf_out[!(frame^1)]->data,-                        pix_fmt, width, height );--        yadif_filter( pv->pic_out.data, parity, tff, pv );--        if( pv->mcdeint_mode >= 0 )-        {-            avpicture_fill( &pv->pic_in,  pv->buf_out[(frame^1)]->data,+            avpicture_fill( &pv->pic_out, pv->buf_out[!(frame^1)]->data,                             pix_fmt, width, height ); -            mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv );+            yadif_filter( pv->pic_out.data, parity, tff, pv ); -            *buf_out = pv->buf_out[ (frame^1)];+            if( pv->mcdeint_mode >= 0 )+            {+                avpicture_fill( &pv->pic_in,  pv->buf_out[(frame^1)]->data,+                                pix_fmt, width, height );+    +                mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv );+    +                *buf_out = pv->buf_out[ (frame^1)];+            }+            else+            {+                *buf_out = pv->buf_out[!(frame^1)];+            }         }-        else-        {-            *buf_out = pv->buf_out[!(frame^1)];-        }     }      /* Copy buffered settings to output buffer settings */Index: libhb/internal.h===================================================================--- libhb/internal.h	(revision 1336)+++ libhb/internal.h	(working copy)@@ -54,7 +54,9 @@ #define HB_FRAME_REF    0xF0     uint8_t       frametype;     uint16_t       flags;-+    int           length;+    int           telecined;+         /* Holds the output PTS from x264, for use by b-frame offsets in muxmp4.c */     int64_t     renderOffset; Index: libhb/fifo.c===================================================================--- libhb/fifo.c	(revision 1336)+++ libhb/fifo.c	(working copy)@@ -321,6 +321,8 @@     dst->new_chap  = src->new_chap;     dst->frametype = src->frametype;     dst->flags     = src->flags;+    dst->length    = src->length;+    dst->telecined = src->telecined; }  hb_fifo_t * hb_fifo_init( int capacity )Index: libhb/scan.c===================================================================--- libhb/scan.c	(revision 1336)+++ libhb/scan.c	(working copy)@@ -286,6 +286,8 @@     hb_list_t     * list_es, * list_raw;     hb_libmpeg2_t * mpeg2;     int progressive_count = 0;+    int interlacing[10];+     int ar16_count = 0, ar4_count = 0;      buf_ps   = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE );@@ -419,7 +421,7 @@                 */                 if( progressive_count == 6 )                 {-                    hb_log("Title's mostly progressive NTSC, setting fps to 23.976");+                    hb_log("Title's mostly NTSC Film, setting fps to 23.976");                 }                 title->rate_base = 1126125;             }@@ -449,7 +451,19 @@         }          buf_raw = hb_list_item( list_raw, 0 );-+        +        /* Check preview for interlacing artifacts */+        if( hb_detect_comb(buf_raw, title->width, title->height, 10, 30, 9) )+        {+            hb_log("Interlacing detected in preview frame %i", i);+            interlacing[i] = 1;+        }+        else+        {+            interlacing[i] = 0;+        }+        +                 hb_get_tempory_filename( data->h, filename, "%x%d",                                  (intptr_t)title, i ); @@ -522,7 +536,28 @@             (float) title->rate_base, title->crop[0], title->crop[1],             title->crop[2], title->crop[3],             title->aspect == HB_ASPECT_BASE * 16 / 9 ? "16:9" :-                title->aspect == HB_ASPECT_BASE * 4 / 3 ? "4:3" : "none" );+            title->aspect == HB_ASPECT_BASE * 4 / 3 ? "4:3" : "none" );++    /* Add up how many previews were interlaced.*/+    int interlacing_sum, t;+    for(t = 0; t < 10; t++ )+    {+        if( interlacing[t] == 1 )+        {+            interlacing_sum++;+        }+    }++    if( interlacing_sum >= 6)+    {+        hb_log("Title is mostly interlaced or telecined (%i out of 10 previews). You should do something about that.", interlacing_sum);+        title->detected_interlacing = 1;+    }+    else+    {+        title->detected_interlacing = 0;+    }+     goto cleanup;  error:Index: libhb/common.h===================================================================--- libhb/common.h	(revision 1336)+++ libhb/common.h	(working copy)@@ -426,6 +426,7 @@     int         rate;     int         rate_base;     int         crop[4];+    int         detected_interlacing;      uint32_t    palette[16];