summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gtk/src/hb-backend.c12
-rw-r--r--libhb/decomb.c187
-rw-r--r--libhb/deinterlace.c190
-rw-r--r--macosx/Controller.m12
-rw-r--r--test/test.c23
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;