From 557e0bd0824130e82068cf76735caf958e5956b4 Mon Sep 17 00:00:00 2001 From: jbrjake Date: Sun, 12 Jul 2009 17:04:50 +0000 Subject: [PATCH] - Introduces a new mode structure for decomb, to make more flexible combinations of options possible, as well as a debug mode that overlays the combing mask on the output. A full explanation of the new modes can be found at the top of libhb/decomb.c. The new default parameter string is: 7:2:6:9:80:16:16:10:20:20:4:2:50:24:1 - Cleans up some compiler warnings for decomb. - Partially fixes mcdeint in decomb. I would not suggest using it yet, but it's getting piped the right data, it no longer outstrides its memory, and lavc finally fixed their Snow bug that broke iterative ME). Seems to work well on fully interlaced material, with the spatial metric (2nd paramter) set to -1. Output with hybrid material and when actually decombing is...poor, but these are, hopefully, surmountable problems. - Lays some groundwork for bobbing. git-svn-id: svn://localhost/HandBrake/trunk@2685 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/decomb.c | 479 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 382 insertions(+), 97 deletions(-) diff --git a/libhb/decomb.c b/libhb/decomb.c index bcf215f1..fc5e863b 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -9,6 +9,59 @@ http://web.missouri.edu/~kes25c/ */ +/***** +Parameters: + Mode : Spatial metric : Motion thresh : Spatial thresh : Block thresh : + Block width : Block height + +Appended for EEDI2: + Magnitude thresh : Variance thresh : Laplacian thresh : Dilation thresh : + Erosion thresh : Noise thresh : Max search distance : Post-processing + +Defaults: + 7:2:6:9:80:16:16:10:20:20:4:2:50:24:1 +*****/ + +#define MODE_YADIF 1 // Use yadif +#define MODE_BLEND 2 // Use blending interpolation +#define MODE_CUBIC 4 // Use cubic interpolation +#define MODE_EEDI2 8 // Use EEDI2 interpolation +#define MODE_MCDEINT 16 // Post-process with mcdeint +#define MODE_MASK 32 // Output combing masks instead of pictures + +/***** +These modes can be layered. For example, Yadif (1) + EEDI2 (8) = 9, +which will feed EEDI2 interpolations to yadif. + +** Working combos: + 1: Just yadif + 2: Just blend + 3: Switch between yadif and blend + 4: Just cubic interpolate + 5: Cubic->yadif + 6: Switch between cubic and blend + 7: Switch between cubic->yadif and blend + 8: Just EEDI2 interpolate + 9: EEDI2->yadif +10: Switch between EEDI2 and blend +11: Switch between EEDI2->yadif and blend +17: Yadif->mcdeint +18: Blend->mcdeint +19: Switch between blending and yadif -> mcdeint +20: Cubic->mdeint +21: Cubic->yadif->mcdeint +22: Cubic or blend -> mcdeint +23: Cubic->yadif or blend -> mcdeint +24: EEDI2->mcdeint +25: EEDI2->yadif->mcdeint +...okay I'm getting bored now listing all these different modes +32: Passes through the combing mask for every combed frame (white for combed pixels, otherwise black) +33+: Overlay the combing mask for every combed frame on top of the filtered output (white for combed pixels) + +12-15: EEDI2 will override cubic interpolation +16: DOES NOT WORK BY ITSELF-- mcdeint needs to be fed by another deinterlacer +*****/ + #include "hb.h" #include "hbffmpeg.h" #include "mpeg2dec/mpeg2.h" @@ -16,7 +69,6 @@ #define SUPPRESS_AV_LOG -#define MODE_DEFAULT 1 #define PARITY_DEFAULT -1 #define MCDEINT_MODE_DEFAULT -1 @@ -112,8 +164,8 @@ struct hb_filter_private_s AVFrame * mcdeint_frame; AVFrame * mcdeint_frame_dec; - int yadif_deinterlaced_frames; - int blend_deinterlaced_frames; + int deinterlaced_frames; + int blended_frames; int unfiltered_frames; uint8_t * ref[4][3]; @@ -150,7 +202,8 @@ struct hb_filter_private_s hb_lock_t ** eedi2_begin_lock; // Thread has work hb_lock_t ** eedi2_complete_lock; // Thread has completed work eedi2_arguments_t *eedi2_arguments; // Arguments to thread for work - + +// int alternator; // for bobbing parity when framedoubling }; hb_filter_private_t * hb_decomb_init( int pix_fmt, @@ -177,7 +230,7 @@ hb_filter_object_t hb_filter_decomb = hb_decomb_close, }; -int cubic_interpolate( int y0, int y1, int y2, int y3 ) +int cubic_interpolate_pixel( 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 ); @@ -195,6 +248,111 @@ int cubic_interpolate( int y0, int y1, int y2, int y3 ) return result; } +static void cubic_interpolate_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++) + { + int a, b, c, d; + a = b = c = d = 0; + + if( y >= 3 ) + { + /* Normal top*/ + a = cur[-3*refs]; + b = cur[-refs]; + } + else if( y == 2 || y == 1 ) + { + /* There's only one sample above this pixel, use it twice. */ + a = cur[-refs]; + b = cur[-refs]; + } + else if( y == 0 ) + { + /* No samples above, triple up on the one below. */ + a = cur[+refs]; + b = cur[+refs]; + } + + if( y <= ( pv->height[plane] - 4 ) ) + { + /* Normal bottom*/ + c = cur[+refs]; + d = cur[3*refs]; + } + else if( y == ( pv->height[plane] - 3 ) || y == ( pv->height[plane] - 2 ) ) + { + /* There's only one sample below, use it twice. */ + c = cur[+refs]; + d = cur[+refs]; + } + else if( y == pv->height[plane] - 1) + { + /* No samples below, triple up on the one above. */ + c = cur[-refs]; + d = cur[-refs]; + } + + dst[0] = cubic_interpolate_pixel( a, b, c, d ); + + dst++; + cur++; + } +} + +void apply_mask_line( uint8_t * srcp, + uint8_t * mskp, + int width ) +{ + int x; + + for( x = 0; x < width; x++ ) + { + if( mskp[x] == 255 ) + { + srcp[x] = 255; + } + } +} + +void apply_mask( hb_filter_private_t * pv ) +{ + int plane, height; + + for( plane = 0; plane < 3; plane++ ) + { + uint8_t * srcp = ( pv->mode & MODE_MCDEINT ) ? pv->pic_in.data[plane] : pv->pic_out.data[plane]; + uint8_t * mskp = pv->mask[plane]; + + for( height = 0; height < pv->height[plane]; height++ ) + { + if( pv->mode == MODE_MASK && plane == 0 ) + { + memcpy( srcp, mskp, pv->width[plane] ); + } + else if( pv->mode == MODE_MASK ) + { + memset( srcp, 128, pv->width[plane] ); + } + else if( plane == 0 ) + { + apply_mask_line( srcp, mskp, pv->width[plane] ); + } + + srcp += pv->pic_out.linesize[plane]; + mskp += pv->ref_stride[plane]; + } + } +} + static void store_ref( const uint8_t ** pic, hb_filter_private_t * pv ) { @@ -217,7 +375,7 @@ static void store_ref( const uint8_t ** pic, int ref_stride = pv->ref_stride[i]; int y; - for( y = 0; y < pv->height[i]; y++ ) + for( y = 0; y < h; y++ ) { memcpy(ref, src, w); src = (uint8_t*)src + w; @@ -226,6 +384,8 @@ static void store_ref( const uint8_t ** pic, } } +/* This function may be useful in the future, if we want to output + a reference to an AVPicture, since they have different strides. static void get_ref( uint8_t ** pic, hb_filter_private_t * pv, int frm ) { int i; @@ -245,6 +405,7 @@ static void get_ref( uint8_t ** pic, hb_filter_private_t * pv, int frm ) } } } +*/ int blend_filter_pixel( int up2, int up1, int current, int down1, int down2 ) { @@ -380,7 +541,7 @@ int check_combing_mask( hb_filter_private_t * pv ) if( block_score >= ( threshold / 2 ) ) { #if 0 - hb_log("decomb: frame %i | score %i | type %s", pv->yadif_deinterlaced_frames + pv->blend_deinterlaced_frames + pv->unfiltered_frames + 1, block_score, pv->buf_settings->flags & 16 ? "Film" : "Video"); + hb_log("decomb: frame %i | score %i | type %s", pv->deinterlaced_frames + pv->blended_frames + pv->unfiltered_frames + 1, block_score, pv->buf_settings->flags & 16 ? "Film" : "Video"); #endif if ( block_score <= threshold && !( pv->buf_settings->flags & 16) ) { @@ -417,7 +578,7 @@ int check_combing_mask( hb_filter_private_t * pv ) } } -int detect_combed_segment( hb_filter_private_t * pv, int segment_start, int segment_stop ) +void detect_combed_segment( hb_filter_private_t * pv, int segment_start, int segment_stop ) { /* A mish-mash of various comb detection tricks picked up from neuron2's Decomb plugin for @@ -513,7 +674,7 @@ int detect_combed_segment( hb_filter_private_t * pv, int segment_start, int segm motion = 1; } - if( motion || ( pv->yadif_deinterlaced_frames==0 && pv->blend_deinterlaced_frames==0 && pv->unfiltered_frames==0) ) + if( motion || ( pv->deinterlaced_frames==0 && pv->blended_frames==0 && pv->unfiltered_frames==0) ) { /* That means it's time for the spatial check. We've got several options here. */ @@ -781,9 +942,7 @@ void decomb_filter_thread( void *thread_args_v ) for( plane = 0; plane < 1; plane++) { - int w = pv->width[plane]; int h = pv->height[plane]; - int ref_stride = pv->ref_stride[plane]; segment_start = ( h / pv->cpu_count ) * segment; if( segment == pv->cpu_count - 1 ) { @@ -855,7 +1014,7 @@ static void yadif_filter_line( uint8_t *dst, int w = pv->width[plane]; int refs = pv->ref_stride[plane]; int x; - int eedi2_mode = (pv->mode == 5); + int eedi2_mode = ( pv->mode & MODE_EEDI2 ); /* We can replace spatial_pred with this interpolation*/ uint8_t * eedi2_guess = &pv->eedi_full[DST2PF][plane][y*refs]; @@ -863,9 +1022,9 @@ static void yadif_filter_line( uint8_t *dst, /* Decomb's cubic interpolation can only function when there are three samples above and below, so regress to yadif's traditional two-tap interpolation when filtering at the top and bottom edges. */ - int edge = 0; + int vertical_edge = 0; if( ( y < 3 ) || ( y > ( pv->height[plane] - 4 ) ) ) - edge = 1; + vertical_edge = 1; for( x = 0; x < w; x++) { @@ -900,9 +1059,9 @@ static void yadif_filter_line( uint8_t *dst, ABS(cur[-refs+1] - cur[+refs+1]) - 1; /* Spatial pred is either a bilinear or cubic vertical interpolation. */ - if( pv->mode > 0 && !edge) + if( ( pv->mode & MODE_CUBIC ) && !vertical_edge) { - spatial_pred = cubic_interpolate( cur[-3*refs], cur[-refs], cur[+refs], cur[3*refs] ); + spatial_pred = cubic_interpolate_pixel( cur[-3*refs], cur[-refs], cur[+refs], cur[3*refs] ); } else { @@ -920,21 +1079,21 @@ static void yadif_filter_line( uint8_t *dst, + ABS(cur[-refs+1+j] - cur[+refs+1-j]);\ if( score < spatial_score ){\ spatial_score = score;\ - if( pv->mode > 0 && !edge )\ + if( ( pv->mode & MODE_CUBIC ) && !vertical_edge )\ {\ switch(j)\ {\ case -1:\ - spatial_pred = cubic_interpolate(cur[-3 * refs - 3], cur[-refs -1], cur[+refs + 1], cur[3* refs + 3] );\ + spatial_pred = cubic_interpolate_pixel(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 ) );\ + spatial_pred = cubic_interpolate_pixel( ( ( 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] );\ + spatial_pred = cubic_interpolate_pixel(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 ) );\ + spatial_pred = cubic_interpolate_pixel(( ( cur[-3*refs + 4] + cur[-refs + 4] ) / 2 ), cur[-refs +2], cur[+refs - 2], ( ( cur[3*refs - 4] + cur[refs - 4] ) / 2 ) );\ break;\ }\ }\ @@ -943,8 +1102,22 @@ static void yadif_filter_line( uint8_t *dst, spatial_pred = ( cur[-refs +j] + cur[+refs -j] ) >>1;\ }\ - YADIF_CHECK(-1) YADIF_CHECK(-2) }} }} - YADIF_CHECK( 1) YADIF_CHECK( 2) }} }} + if( x >= 2 && x <= w - 3 ) + { + YADIF_CHECK(-1) + if( x >= 3 && x <= w - 4 ) + { + YADIF_CHECK(-2) }} }} + } + } + if( x >= 2 && x <= w - 3 ) + { + YADIF_CHECK(1) + if( x >= 3 && x <= w - 4 ) + { + YADIF_CHECK(2) }} }} + } + } } /* Temporally adjust the spatial prediction by @@ -1051,17 +1224,26 @@ void yadif_decomb_filter_thread( void *thread_args_v ) for( y = segment_start; y < segment_stop; y++ ) { - if( ( pv->mode == 4 && is_combed ) || is_combed == 2 ) + if( is_combed == 2 ) { /* This line gets blend filtered, not yadif filtered. */ - uint8_t *prev = &pv->ref[0][plane][y*ref_stride]; uint8_t *cur = &pv->ref[1][plane][y*ref_stride]; - uint8_t *next = &pv->ref[2][plane][y*ref_stride]; uint8_t *dst2 = &dst[plane][y*w]; + /* These will be useful if we ever do temporal blending. */ + // uint8_t *prev = &pv->ref[0][plane][y*ref_stride]; + // uint8_t *next = &pv->ref[2][plane][y*ref_stride]; blend_filter_line( dst2, cur, plane, y, pv ); } - else if( ( ( y ^ parity ) & 1 ) && ( is_combed == 1 ) ) + else if( pv->mode == MODE_CUBIC && is_combed && ( ( y ^ parity ) & 1 ) ) + { + /* Just apply vertical cubic interpolation */ + uint8_t *cur = &pv->ref[1][plane][y*ref_stride]; + uint8_t *dst2 = &dst[plane][y*w]; + + cubic_interpolate_line( dst2, cur, plane, y, pv ); + } + else if( pv->mode & MODE_YADIF && ( ( y ^ parity ) & 1 ) && ( is_combed == 1 ) ) { /* This line gets yadif filtered. It is the bottom field when TFF and vice-versa. It's the field that gets @@ -1136,23 +1318,53 @@ static void yadif_filter( uint8_t ** dst, int tff, hb_filter_private_t * pv ) { - /* If we're running comb detection, do it now, otherwise blend if mode 4 and interpolate if not. */ - int is_combed = pv->spatial_metric >= 0 ? comb_segmenter( pv ) : pv->mode == 4 ? 2 : 1; - + /* If we're running comb detection, do it now, otherwise default to true. */ + int is_combed = pv->spatial_metric >= 0 ? comb_segmenter( pv ) : 1; + + /* The comb detector suggests three different values: + 0: Don't comb this frame. + 1: Deinterlace this frame. + 2: Blend this frame. + Since that might conflict with the filter's mode, + it may be necesary to adjust this value. */ + if( is_combed == 1 && (pv->mode == MODE_BLEND) ) + { + /* All combed frames are getting blended */ + is_combed = 2; + } + else if( is_combed == 2 && !( pv->mode & MODE_BLEND ) ) + { + /* Blending is disabled, so force interpolation of these frames. */ + is_combed = 1; + } + if( is_combed == 1 && + ( pv->mode & MODE_BLEND ) && + !( pv->mode & ( MODE_YADIF | MODE_EEDI2 | MODE_CUBIC ) ) ) + { + /* Deinterlacers are disabled, blending isn't, so blend these frames. */ + is_combed = 2; + } + else if( is_combed && + !( pv->mode & ( MODE_BLEND | MODE_YADIF | MODE_EEDI2 | MODE_CUBIC | MODE_MASK ) ) ) + { + /* No deinterlacer or mask chosen, pass the frame through. */ + is_combed = 0; + } + if( is_combed == 1 ) { - pv->yadif_deinterlaced_frames++; + pv->deinterlaced_frames++; } else if( is_combed == 2 ) { - pv->blend_deinterlaced_frames++; + pv->blended_frames++; } else { pv->unfiltered_frames++; } - if( is_combed == 1 && pv->mode == 5 ) + if( is_combed == 1 && ( pv->mode & MODE_EEDI2 ) ) { /* Generate an EEDI2 interpolation */ eedi2_planer( pv ); @@ -1160,47 +1372,75 @@ static void yadif_filter( uint8_t ** dst, if( is_combed ) { - int segment; + if( ( pv->mode & MODE_EEDI2 ) && !( pv->mode & MODE_YADIF ) && is_combed == 1 ) + { + // Just pass through the EEDI2 interpolation + int i; + for( i = 0; i < 3; i++ ) + { + uint8_t * ref = pv->eedi_full[DST2PF][i]; + uint8_t * dest = dst[i]; + + int w = pv->width[i]; + int ref_stride = pv->ref_stride[i]; + + int y; + for( y = 0; y < pv->height[i]; y++ ) + { + memcpy(dest, ref, w); + dest += w; + ref += ref_stride; + } + } + } + else + { + int segment; + + for( segment = 0; segment < pv->cpu_count; segment++ ) + { + /* + * Setup the work for this plane. + */ + pv->yadif_arguments[segment].parity = parity; + pv->yadif_arguments[segment].tff = tff; + pv->yadif_arguments[segment].dst = dst; + pv->yadif_arguments[segment].is_combed = is_combed; + + /* + * Let the thread for this plane know that we've setup work + * for it by releasing the begin lock (ensuring that the + * complete lock is already locked so that we block when + * we try to lock it again below). + */ + hb_lock( pv->yadif_complete_lock[segment] ); + hb_unlock( pv->yadif_begin_lock[segment] ); + } - for( segment = 0; segment < pv->cpu_count; segment++ ) - { /* - * Setup the work for this plane. + * Wait until all three threads have completed by trying to get + * the complete lock that we locked earlier for each thread, which + * will block until that thread has completed the work on that + * plane. */ - pv->yadif_arguments[segment].parity = parity; - pv->yadif_arguments[segment].tff = tff; - pv->yadif_arguments[segment].dst = dst; - pv->yadif_arguments[segment].is_combed = is_combed; + for( segment = 0; segment < pv->cpu_count; segment++ ) + { + hb_lock( pv->yadif_complete_lock[segment] ); + hb_unlock( pv->yadif_complete_lock[segment] ); + } /* - * Let the thread for this plane know that we've setup work - * for it by releasing the begin lock (ensuring that the - * complete lock is already locked so that we block when - * we try to lock it again below). + * Entire frame is now deinterlaced. */ - hb_lock( pv->yadif_complete_lock[segment] ); - hb_unlock( pv->yadif_begin_lock[segment] ); - } - - /* - * Wait until all three threads have completed by trying to get - * the complete lock that we locked earlier for each thread, which - * will block until that thread has completed the work on that - * plane. - */ - for( segment = 0; segment < pv->cpu_count; segment++ ) - { - hb_lock( pv->yadif_complete_lock[segment] ); - hb_unlock( pv->yadif_complete_lock[segment] ); } - - /* - * Entire frame is now deinterlaced. - */ } else { /* Just passing through... */ + + /* For mcdeint's benefit... */ + pv->yadif_arguments[0].is_combed = is_combed; // 0 + int i; for( i = 0; i < 3; i++ ) { @@ -1219,6 +1459,12 @@ static void yadif_filter( uint8_t ** dst, } } } + + if( pv->mode & MODE_MASK && pv->spatial_metric >= 0 ) + { + if( pv->mode == MODE_MASK || is_combed ) + apply_mask( pv ); + } } static void mcdeint_filter( uint8_t ** dst, @@ -1264,7 +1510,7 @@ static void mcdeint_filter( uint8_t ** dst, { for( x = 0; x < w; x++ ) { - if( (x-2)+(y-1)*w >= 0 && (x+2)+(y+1)*w < w*h ) + if( (x-1)+(y-1)*w >= 0 && (x+1)+(y+1)*w < w*h ) { uint8_t * filp = &pv->mcdeint_frame_dec->data[i][x + y*fils]; @@ -1272,11 +1518,12 @@ static void mcdeint_filter( uint8_t ** dst, 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 spatial_score; + + 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]; @@ -1289,8 +1536,22 @@ static void mcdeint_filter( uint8_t ** dst, 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( x >= 2 && x <= w - 3 ) + { + MCDEINT_CHECK(-1) + if( x >= 3 && x <= w - 4 ) + { + MCDEINT_CHECK(-2) }} }} + } + } + if( x >= 2 && x <= w - 3 ) + { + MCDEINT_CHECK(1) + if( x >= 3 && x <= w - 4 ) + { + MCDEINT_CHECK(2) }} }} + } + } if(diff0 + diff1 > 0) { @@ -1313,11 +1574,7 @@ static void mcdeint_filter( uint8_t ** dst, } } } - } - - for( y = 0; y < h; y++ ) - { - if( !((y ^ parity) & 1) ) + else { for( x = 0; x < w; x++ ) { @@ -1357,13 +1614,13 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, pv->buf_out[1] = hb_video_buffer_init( width, height ); pv->buf_settings = hb_buffer_init( 0 ); - pv->yadif_deinterlaced_frames = 0; - pv->blend_deinterlaced_frames = 0; + pv->deinterlaced_frames = 0; + pv->blended_frames = 0; pv->unfiltered_frames = 0; pv->yadif_ready = 0; - pv->mode = MODE_DEFAULT; + pv->mode = MODE_YADIF | MODE_BLEND | MODE_CUBIC; pv->spatial_metric = 2; pv->motion_threshold = 6; pv->spatial_threshold = 9; @@ -1408,9 +1665,9 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, pv->cpu_count = hb_get_cpu_count(); - if( pv->mode == 2 || pv->mode == 3 ) + if( pv->mode & MODE_MCDEINT ) { - pv->mcdeint_mode = 0; + pv->mcdeint_mode = 2; } /* Allocate yadif specific buffers */ @@ -1425,7 +1682,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, for( j = 0; j < 3; j++ ) { - pv->ref[j][i] = malloc( w*h*sizeof(uint8_t) ) + 3*w; + pv->ref[j][i] = calloc( 1, w*h*sizeof(uint8_t) ) + 3*w; } } @@ -1439,7 +1696,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, pv->mask[i] = calloc( 1, w*h*sizeof(uint8_t) ) + 3*w; } - if( pv->mode == 5 ) + if( pv->mode & MODE_EEDI2 ) { /* Allocate half-height eedi2 buffers */ height = pv->height[0] / 2; @@ -1451,7 +1708,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, for( j = 0; j < 4; j++ ) { - pv->eedi_half[j][i] = malloc( w*h*sizeof(uint8_t) ) + 3*w; + pv->eedi_half[j][i] = calloc( 1, w*h*sizeof(uint8_t) ) + 3*w; } } @@ -1465,7 +1722,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, for( j = 0; j < 5; j++ ) { - pv->eedi_full[j][i] = malloc( w*h*sizeof(uint8_t) ) + 3*w; + pv->eedi_full[j][i] = calloc( 1, w*h*sizeof(uint8_t) ) + 3*w; } } } @@ -1553,7 +1810,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, } } - if( pv->mode == 5 ) + if( pv->mode & MODE_EEDI2 ) { /* * Create eedi2 threads and locks. @@ -1615,9 +1872,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, { avcodec_init(); avcodec_register_all(); - AVCodec * enc = avcodec_find_encoder( CODEC_ID_SNOW ); - int i; for (i = 0; i < 3; i++ ) { @@ -1644,7 +1899,7 @@ hb_filter_private_t * hb_decomb_init( int pix_fmt, case 3: avctx_enc->refs = 3; case 2: - avctx_enc->me_method = ME_UMH; + avctx_enc->me_method = ME_ITER; case 1: avctx_enc->flags |= CODEC_FLAG_4MV; avctx_enc->dia_size =2; @@ -1670,7 +1925,7 @@ void hb_decomb_close( hb_filter_private_t * pv ) return; } - hb_log("decomb: %s deinterlaced %i | blend deinterlaced %i | unfiltered %i | total %i", pv->mode == 5 ? "yadif+eedi2" : "yadif", pv->yadif_deinterlaced_frames, pv->blend_deinterlaced_frames, pv->unfiltered_frames, pv->yadif_deinterlaced_frames + pv->blend_deinterlaced_frames + pv->unfiltered_frames); + hb_log("decomb: deinterlaced %i | blended %i | unfiltered %i | total %i", pv->deinterlaced_frames, pv->blended_frames, pv->unfiltered_frames, pv->deinterlaced_frames + pv->blended_frames + pv->unfiltered_frames); /* Cleanup frame buffers */ if( pv->buf_out[0] ) @@ -1709,7 +1964,7 @@ void hb_decomb_close( hb_filter_private_t * pv ) } } - if( pv->mode == 5 ) + if( pv->mode & MODE_EEDI2 ) { /* Cleanup eedi-half buffers */ int j; @@ -1741,7 +1996,7 @@ void hb_decomb_close( hb_filter_private_t * pv ) } } - if( pv->post_processing > 1 && pv->mode == 5 ) + if( pv->post_processing > 1 && ( pv->mode & MODE_EEDI2 ) ) { if (pv->cx2) eedi2_aligned_free(pv->cx2); if (pv->cy2) eedi2_aligned_free(pv->cy2); @@ -1791,7 +2046,7 @@ void hb_decomb_close( hb_filter_private_t * pv ) free( pv->decomb_complete_lock ); free( pv->decomb_arguments ); - if( pv->mode == 5 ) + if( pv->mode & MODE_EEDI2 ) { for( i = 0; i < 3; i++) { @@ -1863,8 +2118,6 @@ int hb_decomb_work( const hb_buffer_t * cbuf_in, tff = (pv->parity & 1) ^ 1; } - pv->tff = tff; - /* Store current frame in yadif cache */ store_ref( (const uint8_t**)pv->pic_in.data, pv ); @@ -1885,16 +2138,48 @@ int hb_decomb_work( const hb_buffer_t * cbuf_in, /* Perform yadif filtering */ int frame; - for( frame = 0; frame <= ( ( pv->mode == 2 || pv->mode == 3 )? 1 : 0 ) ; frame++ ) + for( frame = 0; frame <= ( ( pv->mode & MODE_MCDEINT ) ? 1 : 0 ) ; frame++ ) +// This would be what to use for bobbing: for( frame = 0; frame <= 0 ; frame++ ) { + +#if 0 + /* Perhaps skip the second run if the frame is uncombed? */ + if( frame && !pv->yadif_arguments[0].is_combed ) + { + break; + } +#endif int parity = frame ^ tff ^ 1; +// This will be for bobbing +#if 0 + if( pv->alternator ) + { + parity = !parity; + pv->alternator = 0; + } + else + { + pv->alternator = 1; + } +#endif + pv->tff = !parity; + avpicture_fill( &pv->pic_out, pv->buf_out[!(frame^1)]->data, pix_fmt, width, height ); + /* XXX + Should check here and only bother filtering field 2 when + field 1 was detected as combed. + And when it's not, it's a progressive frame, + so mcdeint should be skipped... + */ yadif_filter( pv->pic_out.data, parity, tff, pv ); - if( pv->mcdeint_mode >= 0 ) + /* Commented out code in the line below would skip mcdeint + on uncombed frames. Possibly a bad idea, since mcdeint + maintains the same snow context for the entire video... */ + if( pv->mcdeint_mode >= 0 /* && pv->yadif_arguments[0].is_combed */) { /* Perform mcdeint filtering */ avpicture_fill( &pv->pic_in, pv->buf_out[(frame^1)]->data, -- 2.11.0