rendered paste bodyIndex: 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; };