rendered paste bodyIndex: test/test.c===================================================================--- test/test.c (revision 1452)+++ 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;@@ -826,7 +828,12 @@ hb_filter_denoise.settings = denoise_opt; hb_list_add( job->filters, &hb_filter_denoise ); }-+ if( decomb )+ {+ hb_filter_decomb.settings = decomb_opt;+ hb_list_add( job->filters, &hb_filter_decomb );+ }+ if( width && height ) { job->width = width;@@ -1455,6 +1462,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> (default: 1:10:30: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"@@ -1592,6 +1601,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' },@@ -1621,7 +1631,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 ) {@@ -1854,6 +1864,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 1452)+++ 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 1452)+++ libhb/hb.c (working copy)@@ -448,7 +448,7 @@ */ 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];+ int j, k, n, off, block, cc_1, cc_2, cc[3], flag[3], plane_threshold, plane_width, plane_height, plane_color_equal, plane_color_diff; uint16_t s1, s2, s3, s4; cc_1 = 0; cc_2 = 0; @@ -456,6 +456,15 @@ for( k = 0; k < 3; k++ ) {+ if( k == 0 )+ {+ plane_width = width;+ plane_height = height;+ plane_color_equal = color_equal;+ plane_color_diff = color_diff;+ plane_threshold = threshold;+ + } /* One pas for Y, one pass for Cb, one pass for Cr */ if( k == 1 )@@ -463,12 +472,12 @@ /* 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;- threshold >>= 1;- color_equal >>= 1;- color_diff >>= 1;+ offset = plane_width * plane_height;+ plane_width >>= 1;+ plane_height >>= 1;+ plane_threshold >>= 1;+ plane_color_equal >>= 1;+ plane_color_diff >>= 1; } else if ( k == 2 ) {@@ -478,13 +487,13 @@ } /* Look at one horizontal line at a time */- block = width;+ block = plane_width; for( j = 0; j < block; ++j ) { off = 0; - for( n = 0; n < ( height - 4 ); n = n + 2 )+ for( n = 0; n < ( plane_height - 4 ); n = n + 2 ) { /* Look at groups of 4 sequential horizontal lines */ s1 = ( ( buf->data + offset )[ off + j ] & 0xff );@@ -494,14 +503,14 @@ /* 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 ) < color_equal ) &&- ( abs( s1 - s2 ) > color_diff ) )+ if ( ( abs( s1 - s3 ) < plane_color_equal ) &&+ ( abs( s1 - s2 ) > plane_color_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 ) < color_equal ) &&- ( abs( s2 - s3 ) > color_diff) )+ if ( ( abs( s2 - s4 ) < plane_color_equal ) &&+ ( abs( s2 - s3 ) > plane_color_diff) ) ++cc_2; /* Now move down 2 horizontal lines before starting over.*/@@ -510,30 +519,48 @@ } // 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 ) );+ /* 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 / ( plane_width * plane_height ) ); - /* If the plane's cc score meets the threshold, flag it as combed. */+ /* If the plane's cc score surpasses the threshold (by default 0.09%), flag it as combed.+ That means, with default settings, a frame is flagged if 1% or more of it is combed. */ flag[k] = 0;- if ( cc[k] > threshold )+ if ( cc[k] > plane_threshold ) {+ //hb_log("Threhold %i: %i/%i | PTS: %lld (%fs)", k, cc[k], plane_threshold, buf->start, (float)buf->start / 90000 ); flag[k] = 1; } } #if 0 /* Debugging info */-// if(flag)+ if(flag[0] || flag[1] || flag[2]) 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] )+ if( buf->flags & 16 ) {- return 1;+ /* It's a progressive frame.*/+ if( flag[0] && ( flag[1] || flag[2] ) )+ {+ /* So only mark as combed if luma and one chroma show combing. */+ return 1;+ } }-+ else+ {+ /* It's not a progressive frame */+ if( flag[0] || flag[1] || flag[2] )+ {+ /* So mark as framed if any plane shows combing. */+ return 1;+ + }+ }+ + /* Reaching this point means no combing detected. */ return 0; } Index: libhb/Makefile===================================================================--- libhb/Makefile (revision 1452)+++ 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/internal.h===================================================================--- libhb/internal.h (revision 1452)+++ 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/decomb.c===================================================================--- libhb/decomb.c (revision 0)+++ libhb/decomb.c (revision 0)@@ -0,0 +1,791 @@+/* $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 0+#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 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)",+ NULL,+ hb_decomb_init,+ hb_decomb_work,+ hb_decomb_close,+};++int EfficientCubicInterpolate( int y0, int y1, int y2, int y3 )+{+ 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;+}++int detect_combed_pixel( int current, int above, int below1, int below2, int before, int after )+{+ if ( ABS( current - ( ( above + below1 ) / 2 ) ) > ABS( current - ( ( before + after ) / 2 ) ) ) + {+ return 1;+ }+ if( ABS( current - below1 ) > ABS( current - below2 ) )+ {+ return 1;+ }+ return 0;+}+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;+ }+ }+}++static void blend_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++)+ {++ int result = 0;+ result += -cur[-2*refs];+ result += cur[-refs] * 2;+ result += cur[0] * 6;+ result += cur[+refs] * 2;+ result += -cur[2*refs];+ result /= 8;+ + if( result > 255 )+ {+ result = 255;+ }+ if( result < 0 )+ {+ result = 0;+ }+ + dst[0] = result;++ dst++;+ cur++;+ prev++;+ next++;+ prev2++;+ next2++;+ }+}++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+ + int c = cur[-refs];+ int d = (prev2[0] + next2[0])>>1;+ int e = cur[+refs];+ int temporal_diff0 = ABS(prev2[0] - next2[0]);+ int temporal_diff1 = ( ABS(prev[-refs] - cur[-refs]) + ABS(prev[+refs] - cur[+refs]) ) >> 1;+ int temporal_diff2 = ( ABS(next[-refs] - cur[-refs]) + ABS(next[+refs] - cur[+refs]) ) >> 1;+ int diff = MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2);+ + 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;+ + if( pv->mode >= 4 )+ {+ spatial_pred = EfficientCubicInterpolate( cur[-3*refs], cur[-refs], cur[+refs], cur[3*refs] );+ }+ else+ {+ spatial_pred = (c+e)>>1;+ }++#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 = EfficientCubicInterpolate(cur[-3 * refs - 3], cur[-refs -1], cur[+refs + 1], cur[3* refs + 3] );\+ break;\+ case -2:\+ spatial_pred = EfficientCubicInterpolate(cur[-3 * refs -5], cur[-refs -2], cur[+refs + 2], cur[3* refs + 5] );\+ break;\+ case 1:\+ spatial_pred = EfficientCubicInterpolate(cur[-3 * refs +3], cur[-refs +1], cur[+refs - 1], cur[3* refs -3] );\+ break;\+ case 2:\+ spatial_pred = EfficientCubicInterpolate(cur[-3 * refs +5], cur[-refs +2], cur[+refs - 2], cur[3*refs - 5] );\+ 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;+ + 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, prev, cur, next, i, parity ^ tff, 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 = 30;+ pv->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",+ &pv->mode,+ &pv->color_equal,+ &pv->color_diff,+ &pv->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("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] )+ {+ 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);+ + 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);++ /* 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 1452)+++ 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 1452)+++ macosx/HandBrake.xcodeproj/project.pbxproj (working copy)@@ -90,6 +90,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 */; };@@ -258,6 +260,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; };@@ -435,6 +438,7 @@ isa = PBXGroup; children = ( A25289E50D87A27D00461D5B /* enctheora.c */,+ 7497010E0DC281BB009200D8 /* decomb.c */, B48359A70C82960500E04440 /* lang.c */, EAA526920C3B25D200944FF2 /* stream.c */, 0DFA5C7E0B8DD3B60020BC09 /* declpcm.c */,@@ -787,6 +791,7 @@ FC8519550C59A02C0073812C /* deinterlace.c in Sources */, FC8519560C59A02C0073812C /* deblock.c in Sources */, FC8519570C59A02C0073812C /* detelecine.c in Sources */,+ 749701100DC281BB009200D8 /* decomb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };@@ -832,6 +837,7 @@ FC8519530C59A02C0073812C /* detelecine.c in Sources */, B48359A80C82960500E04440 /* lang.c in Sources */, A25289E60D87A27D00461D5B /* enctheora.c in Sources */,+ 7497010F0DC281BB009200D8 /* decomb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };