All pastes #1027041 Raw Edit

Combing Detection

public diff v1 · immutable
#1027041 ·published 2008-05-23 12:56 UTC
rendered paste body
Index: test/test.c===================================================================--- test/test.c	(revision 1469)+++ test/test.c	(working copy)@@ -40,6 +40,8 @@ static char * denoise_opt           = 0; static int    detelecine            = 0; static char * detelecine_opt        = 0;+static int    decomb                = 0;+static char * decomb_opt            = 0; static int    grayscale   = 0; static int    vcodec      = HB_VCODEC_FFMPEG; static int    h264_13     = 0;@@ -819,6 +821,11 @@                 hb_filter_detelecine.settings = detelecine_opt;                 hb_list_add( job->filters, &hb_filter_detelecine );             }+            if( decomb )+            {+                hb_filter_decomb.settings = decomb_opt;+                hb_list_add( job->filters, &hb_filter_decomb );+            }             if( deinterlace )             {                 hb_filter_deinterlace.settings = deinterlace_opt;@@ -1474,6 +1481,8 @@      "          <weak/medium/strong>\n"      "    -9, --detelecine        Detelecine video with pullup filter\n"      "          <L:R:T:B:SB:MP>   (default 1:1:4:4:0:0)\n"+     "    -5, --decomb           Selectively deinterlaces when it detects combing\n"+     "          <M:EQ:DF:TR:EQ:DF:TR>     (default: 4:10:15:9:10:35:9)\n"     "    -g, --grayscale         Grayscale encoding\n"     "    -p, --pixelratio        Store pixel aspect ratio in video stream\n"     "    -P, --loosePixelratio   Store pixel aspect ratio with specified width\n"@@ -1612,6 +1621,7 @@             { "deblock",     optional_argument, NULL,    '7' },             { "denoise",     optional_argument, NULL,    '8' },             { "detelecine",  optional_argument, NULL,    '9' },+            { "decomb",      optional_argument, NULL,    '5' },                         { "grayscale",   no_argument,       NULL,    'g' },             { "pixelratio",  no_argument,       NULL,    'p' },             { "loosePixelratio", optional_argument,   NULL,    'P' },@@ -1641,7 +1651,7 @@         int c;  		c = getopt_long( argc, argv,-						 "hvuC:f:4i:Io:t:Lc:m::a:6:s:UFN:e:E:2dD:789gpOP::w:l:n:b:q:S:B:r:R:Qx:TY:X:VZ:z",+						 "hvuC:f:4i:Io:t:Lc:m::a:6:s:UFN:e:E:2dD:7895gpOP::w:l:n:b:q:S:B:r:R:Qx:TY:X:VZ:z",                          long_options, &option_index );         if( c < 0 )         {@@ -1874,6 +1884,13 @@                 }                 detelecine = 1;                 break;+            case '5':+                if( optarg != NULL )+                {+                    decomb_opt = strdup( optarg );+                }+                decomb = 1;+                break;             case 'g':                 grayscale = 1;                 break;Index: libhb/Jamfile===================================================================--- libhb/Jamfile	(revision 1469)+++ libhb/Jamfile	(working copy)@@ -11,7 +11,7 @@ demuxmpeg.c fifo.c render.c reader.c muxcommon.c muxmp4.c sync.c stream.c decsub.c deca52.c decdca.c encfaac.c declpcm.c encx264.c decavcodec.c encxvid.c muxavi.c enclame.c muxogm.c encvorbis.c dvd.c muxmkv.c deblock.c deinterlace.c -denoise.c detelecine.c lang.c enctheora.c ;+denoise.c detelecine.c decomb.c lang.c enctheora.c ;  Library libhb : $(LIBHB_SRC) ; Index: libhb/hb.c===================================================================--- libhb/hb.c	(revision 1469)+++ libhb/hb.c	(working copy)@@ -446,18 +446,25 @@  * @param color_diff  Sensitivity for detecting different colors  * @param threshold   Sensitivity for flagging planes as combed  */-int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold )+int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold ) {-    int j, k, n, off, block, cc_1, cc_2, cc[3], flag[3];+    int j, k, n, off, cc_1, cc_2, cc[3], flag[3], plane_color_equal, plane_color_diff;     uint16_t s1, s2, s3, s4;     cc_1 = 0; cc_2 = 0;      int offset = 0;+    +    if ( buf->flags & 16 )+    {+        /* Frame is progressive, be more discerning. */+        color_diff = prog_diff;+        color_equal = prog_equal;+        threshold = prog_threshold;+    } +    /* One pas for Y, one pass for Cb, one pass for Cr */         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@@ -466,9 +473,6 @@             offset = width * height;             width >>= 1;             height >>= 1;-            threshold >>= 1;-            color_equal >>= 1;-            color_diff >>= 1;         }         else if ( k == 2 )         {@@ -477,10 +481,7 @@             offset *= 5/4;         } -        /* Look at one horizontal line at a time */-        block = width;--        for( j = 0; j < block; ++j )+        for( j = 0; j < width; ++j )         {             off = 0; @@ -488,9 +489,9 @@             {                 /* 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 );+                s2 = ( ( buf->data + offset )[ off + j + width     ] & 0xff );+                s3 = ( ( buf->data + offset )[ off + j + 2 * width ] & 0xff );+                s4 = ( ( buf->data + offset )[ off + j + 3 * width ] & 0xff );                  /* Note if the 1st and 2nd lines are more different in                    color than the 1st and 3rd lines are similar in color.*/@@ -505,39 +506,38 @@                         ++cc_2;                  /* Now move down 2 horizontal lines before starting over.*/-                off += 2 * block;+                off += 2 * width;             }         }          // 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. */+        /*  The final cc score for a plane is the percentage of combed pixels it contains.+            Because sensitivity goes down to hundreths of a percent, multiply by 1000+            so it will be easy to compare against the threhold value which is an integer. */         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] > threshold )-        {-            flag[k] = 1;-        }     } ++    /* HandBrake is all yuv420, so weight the average percentage of all 3 planes accordingly.*/+    int average_cc = ( 2 * cc[0] + ( cc[1] / 2 ) + ( cc[2] / 2 ) ) / 3;+    +    /* Now see if that average percentage of combed pixels surpasses the threshold percentage given by the user.*/+    if( average_cc > threshold )+    { #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]);+            hb_log("Average %i combed (Threshold %i) %i/%i/%i | PTS: %lld (%fs) %s", average_cc, threshold, cc[0], cc[1], cc[2], buf->start, (float)buf->start / 90000, (buf->flags & 16) ? "Film" : "Video" ); #endif--    /* When more than one plane shows combing, tell the caller. */-    if (flag[0] || flag[1] || flag[2] )-    {         return 1;     } +#if 0+    hb_log("SKIPPED Average %i combed (Threshold %i) %i/%i/%i | PTS: %lld (%fs) %s", average_cc, threshold, cc[0], cc[1], cc[2], buf->start, (float)buf->start / 90000, (buf->flags & 16) ? "Film" : "Video" );+#endif++    /* Reaching this point means no combing detected. */     return 0; } - /**  * Calculates job width and height for anamorphic content,  *Index: libhb/Makefile===================================================================--- libhb/Makefile	(revision 1469)+++ libhb/Makefile	(working copy)@@ -25,7 +25,7 @@ 	   update.c demuxmpeg.c fifo.c render.c reader.c muxcommon.c stream.c \ 	   muxmp4.c sync.c decsub.c deca52.c decdca.c encfaac.c declpcm.c encx264.c \ 	   decavcodec.c encxvid.c muxmkv.c muxavi.c enclame.c muxogm.c encvorbis.c \-	   dvd.c  ipodutil.cpp deblock.c deinterlace.c denoise.c detelecine.c lang.c+	   dvd.c  ipodutil.cpp deblock.c deinterlace.c denoise.c detelecine.c decomb.c lang.c OTMP = $(SRCS:%.c=%.o)  OBJS = $(OTMP:%.cpp=%.o) Index: libhb/hb.h===================================================================--- libhb/hb.h	(revision 1469)+++ libhb/hb.h	(working copy)@@ -79,7 +79,7 @@ /* 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 );+int hb_detect_comb( hb_buffer_t * buf, int width, int height, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold );  void          hb_get_preview( hb_handle_t *, hb_title_t *, int,                               uint8_t * );Index: libhb/internal.h===================================================================--- libhb/internal.h	(revision 1469)+++ libhb/internal.h	(working copy)@@ -224,7 +224,8 @@     FILTER_DEINTERLACE = 1,     FILTER_DEBLOCK,     FILTER_DENOISE,-    FILTER_DETELECINE+    FILTER_DETELECINE,+    FILTER_DECOMB };  extern hb_work_object_t * hb_objects;Index: libhb/scan.c===================================================================--- libhb/scan.c	(revision 1469)+++ libhb/scan.c	(working copy)@@ -432,7 +432,7 @@         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 ) )+        if( hb_detect_comb( buf_raw, title->width, title->height, 10, 30, 9, 10, 30, 9 ) )         {             hb_log("Interlacing detected in preview frame %i", i);             interlaced_preview_count++;Index: libhb/decomb.c===================================================================--- libhb/decomb.c	(revision 0)+++ libhb/decomb.c	(revision 0)@@ -0,0 +1,800 @@+/* $Id: decomb.c,v 1.14 2008/04/25 5:00:00 jbrjake Exp $++   This file is part of the HandBrake source code.+   Homepage: <http://handbrake.fr/>.+   It may be used under the terms of the GNU General Public License. +   +   The yadif algorithm was created by Michael Niedermayer. */+#include "hb.h"+#include "ffmpeg/avcodec.h"+#include "mpeg2dec/mpeg2.h"++#define SUPPRESS_AV_LOG++#define MODE_DEFAULT     4+#define PARITY_DEFAULT   -1++#define MCDEINT_MODE_DEFAULT   -1+#define MCDEINT_QP_DEFAULT      1++#define ABS(a) ((a) > 0 ? (a) : (-(a)))+#define MIN3(a,b,c) MIN(MIN(a,b),c)+#define MAX3(a,b,c) MAX(MAX(a,b),c)++struct hb_filter_private_s+{+    int              pix_fmt;+    int              width[3];+    int              height[3];++    int              mode;+    int              parity;+    +    int              yadif_ready;++    int              mcdeint_mode;+    int              mcdeint_qp;++    int              mcdeint_outbuf_size;+    uint8_t        * mcdeint_outbuf;+    AVCodecContext * mcdeint_avctx_enc;+    AVFrame        * mcdeint_frame;+    AVFrame        * mcdeint_frame_dec;++    int              comb;+    int              color_equal;+    int              color_diff;+    int              threshold;+    int              prog_equal;+    int              prog_diff;+    int              prog_threshold;+    int              deinterlaced_frames;+    int              passed_frames;++    uint8_t        * ref[4][3];+    int              ref_stride[3];++    AVPicture        pic_in;+    AVPicture        pic_out;+    hb_buffer_t *    buf_out[2];+    hb_buffer_t *    buf_settings;+};++hb_filter_private_t * hb_decomb_init( int pix_fmt,+                                           int width,+                                           int height,+                                           char * settings );++int hb_decomb_work( hb_buffer_t * buf_in,+                         hb_buffer_t ** buf_out,+                         int pix_fmt,+                         int width,+                         int height,+                         hb_filter_private_t * pv );++void hb_decomb_close( hb_filter_private_t * pv );++hb_filter_object_t hb_filter_decomb =+{+    FILTER_DECOMB,+    "Decombs selectively with (ffmpeg or yadif/mcdeint or blending)",+    NULL,+    hb_decomb_init,+    hb_decomb_work,+    hb_decomb_close,+};++int cubic_interpolate( int y0, int y1, int y2, int y3 )+{+    /* From http://www.neuron2.net/library/cubicinterp.html */+    int result = ( y0 * -3 ) + ( y1 * 23 ) + ( y2 * 23 ) + ( y3 * -3 );+    result /= 40;+    +    if( result > 255 )+    {+        result = 255;+    }+    else if( result < 0 )+    {+        result = 0;+    }+    +    return result;+}++static void store_ref( const uint8_t ** pic,+                             hb_filter_private_t * pv )+{+    memcpy( pv->ref[3],+            pv->ref[0],+            sizeof(uint8_t *)*3 );++    memmove( pv->ref[0],+             pv->ref[1],+             sizeof(uint8_t *)*3*3 );++    int i;+    for( i = 0; i < 3; i++ )+    {+        const uint8_t * src = pic[i];+        uint8_t * ref = pv->ref[2][i];++        int w = pv->width[i];+        int h = pv->height[i];+        int ref_stride = pv->ref_stride[i];++        int y;+        for( y = 0; y < pv->height[i]; y++ )+        {+            memcpy(ref, src, w);+            src = (uint8_t*)src + w;+            ref = (uint8_t*)ref + ref_stride;+        }+    }+}++static void 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->ref[frm][i];+        int w = pv->width[i];+        int ref_stride = pv->ref_stride[i];+        +        int y;+        for( y = 0; y < pv->height[i]; y++ )+        {+            memcpy(dst, ref, w);+            dst += w;+            ref += ref_stride;+        }+    }+}++int blend_filter_pixel( int up2, int up1, int current, int down1, int down2 )+{+    /* Low-pass 5-tap filter */+    int result = 0;+    result += -up2;+    result += up1 * 2;+    result += current * 6;+    result += down1 *2;+    result += -down2;+    result /= 8;++    if( result > 255 )+    {+        result = 255;+    }+    if( result < 0 )+    {+        result = 0;+    }+    +    return result;+}++static void blend_filter_line( uint8_t *dst,+                               uint8_t *cur,+                               int plane,+                               int y,+                               hb_filter_private_t * pv )+{+    int w = pv->width[plane];+    int refs = pv->ref_stride[plane];+    int x;++    for( x = 0; x < w; x++)+    {+        +        dst[0] = blend_filter_pixel( cur[-2*refs], cur[-refs], cur[0], cur[+refs], cur[2*refs] );++        dst++;+        cur++;+    }+}++static void yadif_filter_line( uint8_t *dst,+                               uint8_t *prev,+                               uint8_t *cur,+                               uint8_t *next,+                               int plane,+                               int parity,+                               int y,+                               hb_filter_private_t * pv )+{+    uint8_t *prev2 = parity ? prev : cur ;+    uint8_t *next2 = parity ? cur  : next;++    int w = pv->width[plane];+    int refs = pv->ref_stride[plane];+    int x;+        +    for( x = 0; x < w; x++)+    {        ++#if 0+        if( !detect_combed_pixel(cur[0], cur[-refs], cur[+refs], cur[2*refs], prev[0], next[0] ) )+        {+            dst[0] = cur[0];+            goto end_of_yadif_filter_pixel;+        }+#endif+        +        /* Pixel above*/+        int c              = cur[-refs];+        /* Temporal average -- the current pixel location in the previous and next fields */+        int d              = (prev2[0] + next2[0])>>1;+        /* Pixel below */+        int e              = cur[+refs];+        +        /* How the current pixel changes from the field before to the field after */+        int temporal_diff0 = ABS(prev2[0] - next2[0]);+        /* The average of how much the pixels above and below change from the field before to now. */+        int temporal_diff1 = ( ABS(prev[-refs] - cur[-refs]) + ABS(prev[+refs] - cur[+refs]) ) >> 1;+        /* The average of how much the pixels above and below change from now to the next field. */+        int temporal_diff2 = ( ABS(next[-refs] - cur[-refs]) + ABS(next[+refs] - cur[+refs]) ) >> 1;+        /* For the actual difference, use the largest of the previous average diffs. */+        int diff           = MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2);+        +        /* SAD of how the pixel-1, the pixel, and the pixel+1 change from the line above to below. */ +        int spatial_score  = ABS(cur[-refs-1] - cur[+refs-1]) + ABS(cur[-refs]-cur[+refs]) ++                                     ABS(cur[-refs+1] - cur[+refs+1]) - 1;         +        int spatial_pred;+         +        /* Spatial pred is either a bilinear or cubic vertical interpolation. */+        if( pv->mode >= 4  )+        {+            spatial_pred = cubic_interpolate( cur[-3*refs], cur[-refs], cur[+refs], cur[3*refs] );+        }+        else+        {+            spatial_pred = (c+e)>>1;+        }++/* EDDI: Edge Directed Deinterlacing Interpolation+   Uses the Martinez-Lim Line Shift Parametric Modeling algorithm...I think.+   Checks 4 different slopes to see if there is more similarity along a diagonal+   than there was vertically. If a diagonal is more similar, then it indicates+   an edge, so interpolate along that instead of a vertical line, using either+   linear or cubic interpolation depending on mode. */+#define YADIF_CHECK(j)\+        {   int score = ABS(cur[-refs-1+j] - cur[+refs-1-j])\+                      + ABS(cur[-refs  +j] - cur[+refs  -j])\+                      + ABS(cur[-refs+1+j] - cur[+refs+1-j]);\+            if( score < spatial_score ){\+                spatial_score = score;\+                if( pv->mode >= 4)\+                {\+                    switch(j)\+                    {\+                        case -1:\+                            spatial_pred = cubic_interpolate(cur[-3 * refs - 3], cur[-refs -1], cur[+refs + 1], cur[3* refs + 3] );\+                        break;\+                        case -2:\+                            spatial_pred = cubic_interpolate( ( ( cur[-3*refs - 4] + cur[-refs - 4] ) / 2 ) , cur[-refs -2], cur[+refs + 2], ( ( cur[3*refs + 4] + cur[refs + 4] ) / 2 ) );\+                        break;\+                        case 1:\+                            spatial_pred = cubic_interpolate(cur[-3 * refs +3], cur[-refs +1], cur[+refs - 1], cur[3* refs -3] );\+                        break;\+                        case 2:\+                            spatial_pred = cubic_interpolate(( ( cur[-3*refs + 4] + cur[-refs + 4] ) / 2 ), cur[-refs +2], cur[+refs - 2], ( ( cur[3*refs - 4] + cur[refs - 4] ) / 2 ) );\+                        break;\+                    }\+                }\+                else\+                {\+                    spatial_pred = ( cur[-refs +j] + cur[+refs -j] ) >>1;\+                }\+                +                YADIF_CHECK(-1) YADIF_CHECK(-2) }} }}+                YADIF_CHECK( 1) YADIF_CHECK( 2) }} }}+                                +        /* Temporally adjust the spatial prediction by comparing against the+           alternate (associated) fields in the previous and next frames. */+        int b = (prev2[-2*refs] + next2[-2*refs])>>1;+        int f = (prev2[+2*refs] + next2[+2*refs])>>1;+        +        /* Find the median value */+        int max = MAX3(d-e, d-c, MIN(b-c, f-e));+        int min = MIN3(d-e, d-c, MAX(b-c, f-e));+        diff = MAX3( diff, min, -max );+        +        if( spatial_pred > d + diff )+        {+            spatial_pred = d + diff;+        }+        else if( spatial_pred < d - diff )+        {+            spatial_pred = d - diff;+        }+        +        dst[0] = spatial_pred;+                        +end_of_yadif_filter_pixel:+        dst++;+        cur++;+        prev++;+        next++;+        prev2++;+        next2++;+    }+}++static void yadif_filter( uint8_t ** dst,+                          int parity,+                          int tff,+                          hb_filter_private_t * pv )+{+    int i;+    for( i = 0; i < 3; i++ )+    {+        int w = pv->width[i];+        int h = pv->height[i];+        int ref_stride = pv->ref_stride[i];++        int y;+        for( y = 0; y < h; y++ )+        {+            if( pv->mode == 3)+            {+                uint8_t *prev = &pv->ref[0][i][y*ref_stride];+                uint8_t *cur  = &pv->ref[1][i][y*ref_stride];+                uint8_t *next = &pv->ref[2][i][y*ref_stride];+                uint8_t *dst2 = &dst[i][y*w];++                blend_filter_line( dst2, cur, i, y, pv );+            }+            else if( (y ^ parity) &  1 )+            {+                uint8_t *prev = &pv->ref[0][i][y*ref_stride];+                uint8_t *cur  = &pv->ref[1][i][y*ref_stride];+                uint8_t *next = &pv->ref[2][i][y*ref_stride];+                uint8_t *dst2 = &dst[i][y*w];++                yadif_filter_line( dst2, prev, cur, next, i, parity ^ tff, y, pv );+            }+            else+            {+                memcpy( &dst[i][y*w],+                        &pv->ref[1][i][y*ref_stride],+                        w * sizeof(uint8_t) );              +            }+        }+    }+}++static void mcdeint_filter( uint8_t ** dst,+                            uint8_t ** src,+                            int parity,+                            hb_filter_private_t * pv )+{+    int x, y, i;+    int out_size;++#ifdef SUPPRESS_AV_LOG+    /* TODO: temporarily change log level to suppress obnoxious debug output */+    int loglevel = av_log_get_level();+    av_log_set_level( AV_LOG_QUIET );+#endif++    for( i=0; i<3; i++ )+    {+        pv->mcdeint_frame->data[i] = src[i];+        pv->mcdeint_frame->linesize[i] = pv->width[i];+    }+    pv->mcdeint_avctx_enc->me_cmp     = FF_CMP_SAD;+    pv->mcdeint_avctx_enc->me_sub_cmp = FF_CMP_SAD;+    pv->mcdeint_frame->quality        = pv->mcdeint_qp * FF_QP2LAMBDA;++    out_size = avcodec_encode_video( pv->mcdeint_avctx_enc,+                                     pv->mcdeint_outbuf,+                                     pv->mcdeint_outbuf_size,+                                     pv->mcdeint_frame );++    pv->mcdeint_frame_dec = pv->mcdeint_avctx_enc->coded_frame;++    for( i = 0; i < 3; i++ )+    {+        int w    = pv->width[i];+        int h    = pv->height[i];+        int fils = pv->mcdeint_frame_dec->linesize[i];+        int srcs = pv->width[i];++        for( y = 0; y < h; y++ )+        {+            if( (y ^ parity) & 1 )+            {+                for( x = 0; x < w; x++ )+                {+                    if( (x-2)+(y-1)*w >= 0 && (x+2)+(y+1)*w < w*h )+                    {+                        uint8_t * filp =+                            &pv->mcdeint_frame_dec->data[i][x + y*fils];+                        uint8_t * srcp = &src[i][x + y*srcs];++                        int diff0 = filp[-fils] - srcp[-srcs];+                        int diff1 = filp[+fils] - srcp[+srcs];++                        int spatial_score =+                              ABS(srcp[-srcs-1] - srcp[+srcs-1])+                            + ABS(srcp[-srcs  ] - srcp[+srcs  ])+                            + ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;++                        int temp = filp[0];++#define MCDEINT_CHECK(j)\+                        {   int score = ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\+                                      + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\+                                      + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\+                            if( score < spatial_score ) {\+                                spatial_score = score;\+                                diff0 = filp[-fils+j] - srcp[-srcs+j];\+                                diff1 = filp[+fils-j] - srcp[+srcs-j];++                        MCDEINT_CHECK(-1) MCDEINT_CHECK(-2) }} }}+                        MCDEINT_CHECK( 1) MCDEINT_CHECK( 2) }} }}++                        if(diff0 + diff1 > 0)+                        {+                            temp -= (diff0 + diff1 -+                                     ABS( ABS(diff0) - ABS(diff1) ) / 2) / 2;+                        }+                        else+                        {+                            temp -= (diff0 + diff1 ++                                     ABS( ABS(diff0) - ABS(diff1) ) / 2) / 2;+                        }++                        filp[0] = dst[i][x + y*w] =+                            temp > 255U ? ~(temp>>31) : temp;+                    }+                    else+                    {+                        dst[i][x + y*w] =+                            pv->mcdeint_frame_dec->data[i][x + y*fils];+                    }+                }+            }+        }++        for( y = 0; y < h; y++ )+        {+            if( !((y ^ parity) & 1) )+            {+                for( x = 0; x < w; x++ )+                {+                    pv->mcdeint_frame_dec->data[i][x + y*fils] =+                        dst[i][x + y*w]= src[i][x + y*srcs];+                }+            }+        }+    }++#ifdef SUPPRESS_AV_LOG+    /* TODO: restore previous log level */+    av_log_set_level(loglevel);+#endif+}++hb_filter_private_t * hb_decomb_init( int pix_fmt,+                                           int width,+                                           int height,+                                           char * settings )+{+    if( pix_fmt != PIX_FMT_YUV420P )+    {+        return 0;+    }++    hb_filter_private_t * pv = calloc( 1, sizeof(struct hb_filter_private_s) );++    pv->pix_fmt = pix_fmt;++    pv->width[0]  = width;+    pv->height[0] = height;+    pv->width[1]  = pv->width[2]  = width >> 1;+    pv->height[1] = pv->height[2] = height >> 1;++    int buf_size = 3 * width * height / 2;+    pv->buf_out[0] = hb_buffer_init( buf_size );+    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->color_equal = 10;+    pv->color_diff = 15;+    pv->threshold = 9;+    pv->prog_equal = 10;+    pv->prog_diff = 35;+    pv->prog_threshold = 9;+    +    pv->yadif_ready    = 0;+    pv->mode     = MODE_DEFAULT;+    pv->parity   = PARITY_DEFAULT;++    pv->mcdeint_mode   = MCDEINT_MODE_DEFAULT;+    pv->mcdeint_qp     = MCDEINT_QP_DEFAULT;++    if( settings )+    {+        sscanf( settings, "%d:%d:%d:%d:%d:%d:%d",+                &pv->mode,+                &pv->color_equal,+                &pv->color_diff,+                &pv->threshold,+                &pv->prog_equal,+                &pv->prog_diff,+                &pv->prog_threshold );+    }+    +    if( pv->mode == 2 || pv->mode == 5 )+    {+        pv->mcdeint_mode = 0;+    }+    +    /* Allocate yadif specific buffers */+    if( pv->mode > 0 )+    {+        int i, j;+        for( i = 0; i < 3; i++ )+        {+            int is_chroma = !!i;+            int w = ((width   + 31) & (~31))>>is_chroma;+            int h = ((height+6+ 31) & (~31))>>is_chroma;++            pv->ref_stride[i] = w;++            for( j = 0; j < 3; j++ )+            {+                pv->ref[j][i] = malloc( w*h*sizeof(uint8_t) ) + 3*w;+            }+        }+    }++    /* Allocate mcdeint specific buffers */+    if( pv->mcdeint_mode >= 0 )+    {+        avcodec_init();+        avcodec_register_all();++        AVCodec * enc = avcodec_find_encoder( CODEC_ID_SNOW );++        int i;+        for (i = 0; i < 3; i++ )+        {+            AVCodecContext * avctx_enc;++            avctx_enc = pv->mcdeint_avctx_enc = avcodec_alloc_context();++            avctx_enc->width                    = width;+            avctx_enc->height                   = height;+            avctx_enc->time_base                = (AVRational){1,25};  // meaningless+            avctx_enc->gop_size                 = 300;+            avctx_enc->max_b_frames             = 0;+            avctx_enc->pix_fmt                  = PIX_FMT_YUV420P;+            avctx_enc->flags                    = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;+            avctx_enc->strict_std_compliance    = FF_COMPLIANCE_EXPERIMENTAL;+            avctx_enc->global_quality           = 1;+            avctx_enc->flags2                   = CODEC_FLAG2_MEMC_ONLY;+            avctx_enc->me_cmp                   = FF_CMP_SAD; //SSE;+            avctx_enc->me_sub_cmp               = FF_CMP_SAD; //SSE;+            avctx_enc->mb_cmp                   = FF_CMP_SSE;++            switch( pv->mcdeint_mode )+            {+                case 3:+                    avctx_enc->refs = 3;+                case 2:+                    avctx_enc->me_method = ME_UMH;+                case 1:+                    avctx_enc->flags |= CODEC_FLAG_4MV;+                    avctx_enc->dia_size =2;+                case 0:+                    avctx_enc->flags |= CODEC_FLAG_QPEL;+            }++            avcodec_open(avctx_enc, enc);+        }++        pv->mcdeint_frame       = avcodec_alloc_frame();+        pv->mcdeint_outbuf_size = width * height * 10;+        pv->mcdeint_outbuf      = malloc( pv->mcdeint_outbuf_size );+    }++    return pv;+}++void hb_decomb_close( hb_filter_private_t * pv )+{+    if( !pv )+    {+        return;+    }++    hb_log("decomb: deinterlaced %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] )+    {+        hb_buffer_close( &pv->buf_out[0] );+    }+    if( pv->buf_out[1] )+    {+        hb_buffer_close( &pv->buf_out[1] );+    }+    if (pv->buf_settings )+    {+        hb_buffer_close( &pv->buf_settings );+    }++    /* Cleanup yadif specific buffers */+    if( pv->mode > 0 )+    {+        int i;+        for( i = 0; i<3*3; i++ )+        {+            uint8_t **p = &pv->ref[i%3][i/3];+            if (*p)+            {+                free( *p - 3*pv->ref_stride[i/3] );+                *p = NULL;+            }+        }+    }++    /* Cleanup mcdeint specific buffers */+    if( pv->mcdeint_mode >= 0 )+    {+        if( pv->mcdeint_avctx_enc )+        {+            avcodec_close( pv->mcdeint_avctx_enc );+            av_freep( &pv->mcdeint_avctx_enc );+        }+        if( pv->mcdeint_outbuf )+        {+            free( pv->mcdeint_outbuf );+        }+    }++    free( pv );+}++int hb_decomb_work( hb_buffer_t * buf_in,+                         hb_buffer_t ** buf_out,+                         int pix_fmt,+                         int width,+                         int height,+                         hb_filter_private_t * pv )+{+    if( !pv ||+        pix_fmt != pv->pix_fmt ||+        width   != pv->width[0] ||+        height  != pv->height[0] )+    {+        return FILTER_FAILED;+    }++    avpicture_fill( &pv->pic_in, buf_in->data,+                    pix_fmt, width, height );++    /* Use libavcodec deinterlace if mode == 0 */+    if( pv->mode == 0 )+    {+        avpicture_fill( &pv->pic_out, pv->buf_out[0]->data,+                        pix_fmt, width, height );++        /* Check for combing on the input frame */+        int interlaced =  hb_detect_comb(buf_in, width, height, pv->color_equal, pv->color_diff, pv->threshold, pv->prog_equal, pv->prog_diff, pv->prog_threshold);+        +        if(interlaced)+        {+            avpicture_deinterlace( &pv->pic_out, &pv->pic_in,+                                   pix_fmt, width, height );++            pv->deinterlaced_frames++;+            //hb_log("Frame %i is combed (Progressive: %s )", pv->deinterlaced_frames + pv->passed_frames, (buf_in->flags & 16) ? "Y" : "N");+            +            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;+    }+    +    /* Determine if top-field first layout */+    int tff;+    if( pv->parity < 0 )+    {+        tff = !!(buf_in->flags & PIC_FLAG_TOP_FIELD_FIRST);+    }+    else+    {+        tff = (pv->parity & 1) ^ 1;+    }++    /* Store current frame in yadif cache */+    store_ref( (const uint8_t**)pv->pic_in.data, pv );++    /* Note down if the input frame is combed */+    pv->comb = (pv->comb << 1) | hb_detect_comb(buf_in, width, height, pv->color_equal, pv->color_diff, pv->threshold, pv->prog_equal, pv->prog_diff, pv->prog_threshold);++    /* If yadif is not ready, store another ref and return FILTER_DELAY */+    if( pv->yadif_ready == 0 )+    {+        store_ref( (const uint8_t**)pv->pic_in.data, pv );++        hb_buffer_copy_settings( pv->buf_settings, buf_in );++        /* don't let 'work_loop' send a chapter mark upstream */+        buf_in->new_chap  = 0;++        pv->yadif_ready = 1;++        return FILTER_DELAY;+    }++    /* yadif works one frame behind so if the previous frame+     * had combing, deinterlace it otherwise just output it. */+    if(  (pv->comb & 2 ) == 0 )+    {+        /* 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 );+        get_ref( (uint8_t**)pv->pic_out.data, pv, 1 );+        *buf_out = pv->buf_out[0];+    }+    else+    {+        /* Perform yadif filtering */+        +        pv->deinterlaced_frames++;+        int frame;+        for( frame = 0; frame <= ( ( pv->mode == 2 || pv->mode == 5 )? 1 : 0 ) ; 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 )+            {+                /* Perform mcdeint filtering */+                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)];+        }+    }++    /* Copy buffered settings to output buffer settings */+    hb_buffer_copy_settings( *buf_out, pv->buf_settings );++    /* Replace buffered settings with input buffer settings */+    hb_buffer_copy_settings( pv->buf_settings, buf_in );++    /* don't let 'work_loop' send a chapter mark upstream */+    buf_in->new_chap  = 0;++    return FILTER_OK;+}Index: libhb/common.h===================================================================--- libhb/common.h	(revision 1469)+++ libhb/common.h	(working copy)@@ -574,6 +574,7 @@ extern hb_filter_object_t hb_filter_deinterlace; extern hb_filter_object_t hb_filter_deblock; extern hb_filter_object_t hb_filter_denoise;+extern hb_filter_object_t hb_filter_decomb;  typedef void hb_error_handler_t( const char *errmsg ); Index: macosx/HandBrake.xcodeproj/project.pbxproj===================================================================--- macosx/HandBrake.xcodeproj/project.pbxproj	(revision 1469)+++ macosx/HandBrake.xcodeproj/project.pbxproj	(working copy)@@ -89,6 +89,8 @@ 		593034EC0BBA39A100172349 /* ChapterTitles.m in Sources */ = {isa = PBXBuildFile; fileRef = 593034EA0BBA39A100172349 /* ChapterTitles.m */; }; 		59CBD2370BBB44DA004A3BE3 /* parsecsv.c in Sources */ = {isa = PBXBuildFile; fileRef = 59CBD2360BBB44DA004A3BE3 /* parsecsv.c */; }; 		59CBD2650BBB4D1B004A3BE3 /* ChapterTitles.m in Sources */ = {isa = PBXBuildFile; fileRef = 593034EA0BBA39A100172349 /* ChapterTitles.m */; };+		7497010F0DC281BB009200D8 /* decomb.c in Sources */ = {isa = PBXBuildFile; fileRef = 7497010E0DC281BB009200D8 /* decomb.c */; };+		749701100DC281BB009200D8 /* decomb.c in Sources */ = {isa = PBXBuildFile; fileRef = 7497010E0DC281BB009200D8 /* decomb.c */; }; 		A22C85EC0D05D35000C10E36 /* HBPresets.h in Headers */ = {isa = PBXBuildFile; fileRef = A22C85EA0D05D35000C10E36 /* HBPresets.h */; }; 		A22C85ED0D05D35100C10E36 /* HBPresets.m in Sources */ = {isa = PBXBuildFile; fileRef = A22C85EB0D05D35000C10E36 /* HBPresets.m */; }; 		A25289E60D87A27D00461D5B /* enctheora.c in Sources */ = {isa = PBXBuildFile; fileRef = A25289E50D87A27D00461D5B /* enctheora.c */; };@@ -257,6 +259,7 @@ 		593034E90BBA39A100172349 /* ChapterTitles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChapterTitles.h; sourceTree = "<group>"; }; 		593034EA0BBA39A100172349 /* ChapterTitles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChapterTitles.m; sourceTree = "<group>"; }; 		59CBD2360BBB44DA004A3BE3 /* parsecsv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parsecsv.c; path = ../test/parsecsv.c; sourceTree = SOURCE_ROOT; };+		7497010E0DC281BB009200D8 /* decomb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = decomb.c; path = ../libhb/decomb.c; sourceTree = SOURCE_ROOT; }; 		A22C85EA0D05D35000C10E36 /* HBPresets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPresets.h; sourceTree = "<group>"; }; 		A22C85EB0D05D35000C10E36 /* HBPresets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPresets.m; sourceTree = "<group>"; }; 		A25289E50D87A27D00461D5B /* enctheora.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = enctheora.c; path = ../libhb/enctheora.c; sourceTree = SOURCE_ROOT; };@@ -434,6 +437,7 @@ 			isa = PBXGroup; 			children = ( 				A25289E50D87A27D00461D5B /* enctheora.c */,+				7497010E0DC281BB009200D8 /* decomb.c */, 				B48359A70C82960500E04440 /* lang.c */, 				EAA526920C3B25D200944FF2 /* stream.c */, 				0DFA5C7E0B8DD3B60020BC09 /* declpcm.c */,@@ -785,6 +789,7 @@ 				FC8519550C59A02C0073812C /* deinterlace.c in Sources */, 				FC8519560C59A02C0073812C /* deblock.c in Sources */, 				FC8519570C59A02C0073812C /* detelecine.c in Sources */,+				749701100DC281BB009200D8 /* decomb.c in Sources */, 			); 			runOnlyForDeploymentPostprocessing = 0; 		};@@ -830,6 +835,7 @@ 				FC8519530C59A02C0073812C /* detelecine.c in Sources */, 				B48359A80C82960500E04440 /* lang.c in Sources */, 				A25289E60D87A27D00461D5B /* enctheora.c in Sources */,+				7497010F0DC281BB009200D8 /* decomb.c in Sources */, 			); 			runOnlyForDeploymentPostprocessing = 0; 		};