summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2012-05-01 17:17:55 +0000
committerjstebbins <[email protected]>2012-05-01 17:17:55 +0000
commit3c2c830d58e7777d19b793fc7a6e08a921f0d12b (patch)
treed0db9229bd6d8c63a823aaafd366761022701b7a /libhb
parent31f5717ce0ab0e792342f193f5485bfe29790ffd (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
Diffstat (limited to 'libhb')
-rw-r--r--libhb/decomb.c187
-rw-r--r--libhb/deinterlace.c190
2 files changed, 229 insertions, 148 deletions
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;
}
-