diff options
author | jstebbins <[email protected]> | 2012-05-01 17:17:55 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2012-05-01 17:17:55 +0000 |
commit | 3c2c830d58e7777d19b793fc7a6e08a921f0d12b (patch) | |
tree | d0db9229bd6d8c63a823aaafd366761022701b7a | |
parent | 31f5717ce0ab0e792342f193f5485bfe29790ffd (diff) |
libhb: bob deinterlacing
This is jbrjake's patch for bob deinterlacing applied to decomb and deinterlace
filters. Thanks to yeasah's for refinements and testing of this patch.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@4625 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | gtk/src/hb-backend.c | 12 | ||||
-rw-r--r-- | libhb/decomb.c | 187 | ||||
-rw-r--r-- | libhb/deinterlace.c | 190 | ||||
-rw-r--r-- | macosx/Controller.m | 12 | ||||
-rw-r--r-- | test/test.c | 23 |
5 files changed, 261 insertions, 163 deletions
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index af1b890e5..b3ca4afa7 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -202,6 +202,7 @@ static options_map_t d_decomb_opts[] = {"Custom", "custom", 1, ""}, {"Default","default",2, NULL}, {"Fast", "fast", 3, "7:2:6:9:1:80"}, + {"Bob", "bob", 4, "455"}, }; combo_opts_t decomb_opts = { @@ -211,11 +212,12 @@ combo_opts_t decomb_opts = static options_map_t d_deint_opts[] = { - {"Off", "off", 0, ""}, - {"Custom", "custom", 1, ""}, - {"Fast", "fast", 2, "-1:-1:-1:0:1"}, - {"Slow", "slow", 3, "2:-1:-1:0:1"}, - {"Slower", "slower", 4, "0:-1:-1:0:1"}, + {"Off", "off", 0, ""}, + {"Custom", "custom", 1, ""}, + {"Fast", "fast", 2, "0:-1:-1:0:1"}, + {"Slow", "slow", 3, "1:-1:-1:0:1"}, + {"Slower", "slower", 4, "3:-1:-1:0:1"}, + {"Bob", "bob", 5, "15:-1:-1:0:1"}, }; combo_opts_t deint_opts = { diff --git a/libhb/decomb.c b/libhb/decomb.c index fae95caea..74f0a7b35 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -27,13 +27,14 @@ Defaults: Original "Faster" settings: 7:2:6:9:1:80:16:16:10:20:20:4:2:50:24:1:-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 +#define MODE_BOB 64 // Deinterlace each field to a separate frame + #define MODE_GAMMA 128 // Scale gamma when decombing #define MODE_FILTER 256 // Filter combing mask #define MODE_COMPOSITE 512 // Overlay combing mask onto picture @@ -216,8 +217,6 @@ 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 }; static int hb_decomb_init( hb_filter_object_t * filter, @@ -328,7 +327,6 @@ void draw_mask_box( hb_filter_private_t * pv ) int stride = pv->ref_stride[0]; uint8_t * mskp = ( pv->mode & MODE_FILTER ) ? pv->mask_filtered[0] : pv->mask[0]; - int block_x, block_y; for( block_x = 0; block_x < box_width; block_x++) { @@ -364,7 +362,6 @@ void apply_mask_line( uint8_t * srcp, void apply_mask( hb_filter_private_t * pv ) { - /* draw_boxes */ draw_mask_box( pv ); @@ -681,7 +678,6 @@ void filter_combing_mask( hb_filter_private_t * pv ) for( x = 0; x < pv->width[k]-1; x++ ) { - h_count = v_count = 0; if( x == 0 ) { @@ -973,7 +969,6 @@ void detect_gamma_combed_segment( hb_filter_private_t * pv, int segment_start, i picked up from neuron2's Decomb plugin for AviSynth and tritical's IsCombedT and IsCombedTIVTC plugins. */ - int x, y, k, width, height; /* Comb scoring algorithm */ @@ -2452,6 +2447,8 @@ static int hb_decomb_work( hb_filter_object_t * filter, { hb_filter_private_t * pv = filter->private_data; hb_buffer_t * in = *buf_in; + hb_buffer_t * last = NULL, * out = NULL; + uint8_t duplicate = 0; if ( in->size <= 0 ) { @@ -2460,104 +2457,134 @@ static int hb_decomb_work( hb_filter_object_t * filter, return HB_FILTER_DONE; } - hb_avpicture_fill( &pv->pic_in, in ); - - /* Determine if top-field first layout */ - int tff; - if( pv->parity < 0 ) + do { - tff = !!(in->s.flags & PIC_FLAG_TOP_FIELD_FIRST); - } - else - { - tff = (pv->parity & 1) ^ 1; - } + hb_avpicture_fill( &pv->pic_in, in ); - /* Store current frame in yadif cache */ - store_ref( (const uint8_t**)pv->pic_in.data, pv ); + /* Determine if top-field first layout */ + int tff; + if( pv->parity < 0 ) + { + tff = !!(in->s.flags & PIC_FLAG_TOP_FIELD_FIRST); + } + else + { + tff = (pv->parity & 1) ^ 1; + } - /* 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 ); + /* Store current frame in yadif cache */ + if( !duplicate ) + { + store_ref( (const uint8_t**)pv->pic_in.data, pv ); + } - pv->buf_settings->s = in->s; - hb_buffer_move_subs( pv->buf_settings, in ); + /* 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 ); - pv->yadif_ready = 1; + pv->buf_settings->s = in->s; + hb_buffer_move_subs( pv->buf_settings, in ); - return HB_FILTER_DELAY; - } + pv->yadif_ready = 1; - /* Perform yadif filtering */ - int frame, out_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++ ) - { + return HB_FILTER_DELAY; + } -#if 0 - /* Perhaps skip the second run if the frame is uncombed? */ - if( frame && !pv->yadif_arguments[0].is_combed ) + /* deinterlace both fields if mcdeint is enabled without bob */ + int frame, out_frame, num_frames = 1; + if( ( pv->mode & (MODE_MCDEINT | MODE_BOB) ) == MODE_MCDEINT ) + num_frames = 2; + + /* Perform yadif filtering */ + for( frame = 0; frame < num_frames; frame++ ) { - break; - } -#endif - int parity = frame ^ tff ^ 1; -// This will be for bobbing #if 0 - if( pv->alternator ) + /* 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 ^ duplicate; + pv->tff = !parity; + + hb_buffer_t *b = pv->buf_out[!(frame^1)]; + hb_avpicture_fill( &pv->pic_out, b ); + + /* 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 ); + + /* 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 */ + b = pv->buf_out[(frame^1)]; + hb_avpicture_fill( &pv->pic_in, b ); + + mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv->width, pv->height, &pv->mcdeint ); + + out_frame = frame ^ 1; + } + else + { + out_frame = !(frame ^ 1); + } + } + + // Add to list of output buffers (should be at most 2) + if ( out == NULL ) { - parity = !parity; - pv->alternator = 0; + last = out = pv->buf_out[out_frame]; } else { - pv->alternator = 1; + last->next = pv->buf_out[out_frame]; + last = last->next; } -#endif - pv->tff = !parity; - - hb_buffer_t *b = pv->buf_out[!(frame^1)]; - hb_avpicture_fill( &pv->pic_out, b ); - - /* 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 ); - - /* 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 */ - b = pv->buf_out[(frame^1)]; - hb_avpicture_fill( &pv->pic_in, b ); - mcdeint_filter( pv->pic_in.data, pv->pic_out.data, parity, pv->width, pv->height, &pv->mcdeint ); + // Allocate a replacement for the buffer we just consumed + pv->buf_out[out_frame] = hb_video_buffer_init( pv->width[0], pv->height[0] ); - out_frame = frame ^ 1; - } - else + /* Copy buffered settings to output buffer settings */ + last->s = pv->buf_settings->s; + + if ( !duplicate ) { - out_frame = !(frame ^ 1); + hb_buffer_move_subs( last, pv->buf_settings ); } - } - *buf_out = pv->buf_out[out_frame]; - // Allocate a replacement for the buffer we just consumed - pv->buf_out[out_frame] = hb_video_buffer_init( pv->width[0], pv->height[0] ); - /* Copy buffered settings to output buffer settings */ - (*buf_out)->s = pv->buf_settings->s; - hb_buffer_move_subs( *buf_out, pv->buf_settings ); + /* if this frame was deinterlaced and bob mode is engaged, halve + the duration of the saved timestamp, and request a duplicate. */ + if( pv->mode & MODE_BOB && pv->yadif_arguments[0].is_combed == 1 ) + { + if ( !duplicate ) + { + last->s.stop -= (last->s.stop - last->s.start) / 2LL; + duplicate = 1; + } + else + { + last->s.start = out->s.stop; + last->s.new_chap = 0; + duplicate = 0; + } + } + } while ( duplicate ); /* Replace buffered settings with input buffer settings */ pv->buf_settings->s = in->s; hb_buffer_move_subs( pv->buf_settings, in ); + *buf_out = out; + return HB_FILTER_OK; } diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c index 029207805..4911f4bbc 100644 --- a/libhb/deinterlace.c +++ b/libhb/deinterlace.c @@ -21,7 +21,14 @@ #include "mpeg2dec/mpeg2.h" #include "mcdeint.h" -#define YADIF_MODE_DEFAULT -1 +// yadif_mode is a bit vector with the following flags +// Note that 2PASS should be enabled when using MCDEINT +#define MODE_YADIF_ENABLE 1 +#define MODE_YADIF_SPATIAL 2 +#define MODE_YADIF_2PASS 4 +#define MODE_YADIF_BOB 8 + +#define YADIF_MODE_DEFAULT 0 #define YADIF_PARITY_DEFAULT -1 #define MCDEINT_MODE_DEFAULT -1 @@ -155,7 +162,7 @@ static void yadif_filter_line( uint8_t *dst, YADIF_CHECK(-1) YADIF_CHECK(-2) }} }} YADIF_CHECK( 1) YADIF_CHECK( 2) }} }} - if( pv->yadif_mode < 2 ) + if( pv->yadif_mode & MODE_YADIF_SPATIAL ) { int b = (prev2[-2*refs] + next2[-2*refs])>>1; int f = (prev2[+2*refs] + next2[+2*refs])>>1; @@ -420,7 +427,7 @@ static int hb_deinterlace_init( hb_filter_object_t * filter, pv->cpu_count = hb_get_cpu_count(); /* Allocate yadif specific buffers */ - if( pv->yadif_mode >= 0 ) + if( pv->yadif_mode & MODE_YADIF_ENABLE ) { int i, j; for( i = 0; i < 3; i++ ) @@ -507,7 +514,7 @@ static void hb_deinterlace_close( hb_filter_object_t * filter ) } /* Cleanup yadif specific buffers */ - if( pv->yadif_mode >= 0 ) + if( pv->yadif_mode & MODE_YADIF_ENABLE ) { int i; for( i = 0; i<3*3; i++ ) @@ -556,6 +563,8 @@ static int hb_deinterlace_work( hb_filter_object_t * filter, AVPicture pic_out; hb_filter_private_t * pv = filter->private_data; hb_buffer_t * in = *buf_in; + hb_buffer_t * last = NULL, * out = NULL; + uint8_t duplicate = 0; if ( in->size <= 0 ) { @@ -564,99 +573,144 @@ static int hb_deinterlace_work( hb_filter_object_t * filter, return HB_FILTER_DONE; } - hb_avpicture_fill( &pic_in, in ); - - /* Use libavcodec deinterlace if yadif_mode < 0 */ - if( pv->yadif_mode < 0 ) + do { - hb_avpicture_fill( &pic_out, pv->buf_out[0] ); + hb_avpicture_fill( &pic_in, in ); - avpicture_deinterlace( &pic_out, &pic_in, pv->buf_out[0]->f.fmt, - pv->buf_out[0]->f.width, pv->buf_out[0]->f.height ); + /* Use libavcodec deinterlace if yadif_mode < 0 */ + if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) ) + { + hb_avpicture_fill( &pic_out, pv->buf_out[0] ); - pv->buf_out[0]->s = in->s; - hb_buffer_move_subs( pv->buf_out[0], in ); + avpicture_deinterlace( &pic_out, &pic_in, pv->buf_out[0]->f.fmt, + pv->buf_out[0]->f.width, pv->buf_out[0]->f.height ); - *buf_out = pv->buf_out[0]; + pv->buf_out[0]->s = in->s; + hb_buffer_move_subs( pv->buf_out[0], in ); - // Allocate a replacement for the buffer we just consumed - hb_buffer_t * b = pv->buf_out[0]; - pv->buf_out[0] = hb_video_buffer_init( b->f.width, b->f.height ); + *buf_out = pv->buf_out[0]; - return HB_FILTER_OK; - } + // Allocate a replacement for the buffer we just consumed + hb_buffer_t * b = pv->buf_out[0]; + pv->buf_out[0] = hb_video_buffer_init( b->f.width, b->f.height ); - /* Determine if top-field first layout */ - int tff; - if( pv->yadif_parity < 0 ) - { - tff = !!(in->s.flags & PIC_FLAG_TOP_FIELD_FIRST); - } - else - { - tff = (pv->yadif_parity & 1) ^ 1; - } - - /* Store current frame in yadif cache */ - yadif_store_ref( (const uint8_t**)pic_in.data, pv ); + return HB_FILTER_OK; + } - /* If yadif is not ready, store another ref and return HB_FILTER_DELAY */ - if( pv->yadif_ready == 0 ) - { - yadif_store_ref( (const uint8_t**)pic_in.data, pv ); + /* Determine if top-field first layout */ + int tff; + if( pv->yadif_parity < 0 ) + { + tff = !!(in->s.flags & PIC_FLAG_TOP_FIELD_FIRST); + } + else + { + tff = (pv->yadif_parity & 1) ^ 1; + } - pv->buf_settings->s = in->s; - hb_buffer_move_subs( pv->buf_settings, in ); + /* Store current frame in yadif cache */ + if (!duplicate) + { + yadif_store_ref( (const uint8_t**)pic_in.data, pv ); + } - pv->yadif_ready = 1; + /* If yadif is not ready, store another ref and return HB_FILTER_DELAY */ + if( pv->yadif_ready == 0 ) + { + yadif_store_ref( (const uint8_t**)pic_in.data, pv ); - return HB_FILTER_DELAY; - } + pv->buf_settings->s = in->s; + hb_buffer_move_subs( pv->buf_settings, in ); - /* Perform yadif and mcdeint filtering */ - int frame; - int out_frame; - hb_buffer_t * b; - for( frame = 0; frame <= (pv->yadif_mode & 1); frame++ ) - { - AVPicture pic_yadif_out; - int parity = frame ^ tff ^ 1; + pv->yadif_ready = 1; - b = pv->buf_out[!(frame^1)]; - hb_avpicture_fill( &pic_yadif_out, b ); + return HB_FILTER_DELAY; + } - yadif_filter( pic_yadif_out.data, parity, tff, pv ); + /* deinterlace both fields if mcdeint is enabled without bob */ + int frame, num_frames = 1; + if( ( pv->yadif_mode & MODE_YADIF_2PASS ) && + !( pv->yadif_mode & MODE_YADIF_BOB ) ) + { + num_frames = 2; + } - if( pv->mcdeint_mode >= 0 ) + /* Perform yadif and mcdeint filtering */ + int out_frame; + hb_buffer_t * b; + for( frame = 0; frame < num_frames; frame++ ) { - b = pv->buf_out[(frame^1)]; - hb_avpicture_fill( &pic_out, b ); + AVPicture pic_yadif_out; + int parity = frame ^ tff ^ 1 ^ duplicate; - mcdeint_filter( pic_out.data, pic_yadif_out.data, parity, - pv->width, pv->height, &pv->mcdeint ); + b = pv->buf_out[!(frame^1)]; + hb_avpicture_fill( &pic_yadif_out, b ); - out_frame = (frame^1); + yadif_filter( pic_yadif_out.data, parity, tff, pv ); + + if( pv->mcdeint_mode >= 0 ) + { + b = pv->buf_out[(frame^1)]; + hb_avpicture_fill( &pic_out, b ); + + mcdeint_filter( pic_out.data, pic_yadif_out.data, parity, + pv->width, pv->height, &pv->mcdeint ); + + out_frame = (frame^1); + } + else + { + out_frame = !(frame^1); + } + } + + // Add to list of output buffers (should be at most 2) + if ( out == NULL ) + { + last = out = pv->buf_out[out_frame]; } else { - out_frame = !(frame^1); + last->next = pv->buf_out[out_frame]; + last = last->next; } - } - *buf_out = pv->buf_out[out_frame]; - // Allocate a replacement for the buffer we just consumed - b = pv->buf_out[out_frame]; - pv->buf_out[out_frame] = hb_video_buffer_init( b->f.width, b->f.height ); + // Allocate a replacement for the buffer we just consumed + b = pv->buf_out[out_frame]; + pv->buf_out[out_frame] = hb_video_buffer_init( b->f.width, b->f.height ); + + /* Copy buffered settings to output buffer settings */ + last->s = pv->buf_settings->s; + + if ( !duplicate ) + { + hb_buffer_move_subs( last, pv->buf_settings ); + } - /* Copy buffered settings to output buffer settings */ - (*buf_out)->s = pv->buf_settings->s; - hb_buffer_move_subs( *buf_out, pv->buf_settings ); + /* if bob mode is engaged, halve the duration of the + * timestamp, and request a duplicate. */ + if( pv->yadif_mode & MODE_YADIF_BOB ) + { + if ( !duplicate ) + { + last->s.stop -= (last->s.stop - last->s.start) / 2LL; + duplicate = 1; + } + else + { + last->s.start = out->s.stop; + last->s.new_chap = 0; + duplicate = 0; + } + } + } while ( duplicate ); /* Replace buffered settings with input buffer settings */ pv->buf_settings->s = in->s; hb_buffer_move_subs( pv->buf_settings, in ); + *buf_out = out; + return HB_FILTER_OK; } - diff --git a/macosx/Controller.m b/macosx/Controller.m index 88a146ae0..9029e9b5c 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -3366,17 +3366,17 @@ bool one_burned = FALSE; else if ([fPictureController deinterlace] == 2) { /* Run old deinterlacer fd by default */ - hb_add_filter( job, filter, "-1" ); + hb_add_filter( job, filter, "0" ); } else if ([fPictureController deinterlace] == 3) { /* Yadif mode 0 (without spatial deinterlacing.) */ - hb_add_filter( job, filter, "2" ); + hb_add_filter( job, filter, "1" ); } else if ([fPictureController deinterlace] == 4) { /* Yadif (with spatial deinterlacing) */ - hb_add_filter( job, filter, "0" ); + hb_add_filter( job, filter, "3" ); } } @@ -3885,17 +3885,17 @@ bool one_burned = FALSE; else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 2) { /* Run old deinterlacer fd by default */ - hb_add_filter( job, filter, "-1" ); + hb_add_filter( job, filter, "0" ); } else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 3) { /* Yadif mode 0 (without spatial deinterlacing.) */ - hb_add_filter( job, filter, "2" ); + hb_add_filter( job, filter, "1" ); } else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 4) { /* Yadif (with spatial deinterlacing) */ - hb_add_filter( job, filter, "0" ); + hb_add_filter( job, filter, "3" ); } diff --git a/test/test.c b/test/test.c index 113bfe63b..cb23a6f4a 100644 --- a/test/test.c +++ b/test/test.c @@ -3451,15 +3451,19 @@ static int ParseOptions( int argc, char ** argv ) { if (!( strcmp( optarg, "fast" ) )) { - deinterlace_opt = "-1"; + deinterlace_opt = "0"; } else if (!( strcmp( optarg, "slow" ) )) { - deinterlace_opt = "2"; + deinterlace_opt = "1"; } else if (!( strcmp( optarg, "slower" ) )) { - deinterlace_opt = "0"; + deinterlace_opt = "3"; + } + else if (!( strcmp( optarg, "bob" ) )) + { + deinterlace_opt = "15"; } else { @@ -3507,7 +3511,18 @@ static int ParseOptions( int argc, char ** argv ) case '5': if( optarg != NULL ) { - decomb_opt = strdup( optarg ); + if (!( strcmp( optarg, "fast" ) )) + { + decomb_opt = "7:2:6:9:1:80"; + } + else if (!( strcmp( optarg, "bob" ) )) + { + decomb_opt = "455"; + } + else + { + decomb_opt = strdup( optarg ); + } } decomb = 1; break; |