diff options
Diffstat (limited to 'libhb/decomb.c')
-rw-r--r-- | libhb/decomb.c | 75 |
1 files changed, 65 insertions, 10 deletions
diff --git a/libhb/decomb.c b/libhb/decomb.c index df1838a7d..e83f0d5a6 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -630,6 +630,13 @@ static void yadif_filter_line( uint8_t *dst, int refs = pv->ref_stride[plane]; int x; + /* 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; + if( ( y < 3 ) || ( y > ( pv->height[plane] - 4 ) ) ) + edge = 1; + for( x = 0; x < w; x++) { /* Pixel above*/ @@ -654,7 +661,7 @@ static void yadif_filter_line( uint8_t *dst, int spatial_pred; /* Spatial pred is either a bilinear or cubic vertical interpolation. */ - if( pv->mode > 0 ) + if( pv->mode > 0 && !edge) { spatial_pred = cubic_interpolate( cur[-3*refs], cur[-refs], cur[+refs], cur[3*refs] ); } @@ -675,7 +682,7 @@ 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 )\ + if( pv->mode > 0 && !edge )\ {\ switch(j)\ {\ @@ -748,7 +755,7 @@ void yadif_decomb_filter_thread( void *thread_args_v ) int segment, segment_start, segment_stop; yadif_thread_arg_t *thread_args = thread_args_v; uint8_t **dst; - int parity, tff, y, w, h, ref_stride, is_combed; + int parity, tff, y, w, h, penultimate, ultimate, ref_stride, is_combed; pv = thread_args->pv; segment = thread_args->segment; @@ -794,6 +801,8 @@ void yadif_decomb_filter_thread( void *thread_args_v ) tff = yadif_work->tff; w = pv->width[plane]; h = pv->height[plane]; + penultimate = h - 2; + ultimate = h - 1; ref_stride = pv->ref_stride[plane]; segment_start = ( h / pv->cpu_count ) * segment; if( segment == pv->cpu_count - 1 ) @@ -810,6 +819,7 @@ void yadif_decomb_filter_thread( void *thread_args_v ) { if( ( pv->mode == 4 && is_combed ) || 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]; @@ -817,14 +827,59 @@ void yadif_decomb_filter_thread( void *thread_args_v ) blend_filter_line( dst2, cur, plane, y, pv ); } - else if( (y ^ parity) & 1 && is_combed == 1 ) + else if( ( ( y ^ parity ) & 1 ) && ( is_combed == 1 ) ) { - 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]; - - yadif_filter_line( dst2, prev, cur, next, plane, parity ^ tff, y, pv ); + /* This line gets yadif filtered. It is the bottom field + when TFF and vice-versa. It's the field that gets + filtered. Because yadif needs 2 lines above and below + the one being filtered, we need to mirror the edges. + When TFF, this means replacing the 2nd line with a + copy of the 1st, and the last with the second-to-last. */ + if( y > 1 && y < ( h -2 ) ) + { + /* This isn't the top or bottom, proceed as normal to yadif. */ + 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]; + + yadif_filter_line( dst2, + prev, + cur, + next, + plane, + parity ^ tff, + y, + pv ); + } + else if( y == 0 ) + { + /* BFF, so y0 = y1 */ + memcpy( &dst[plane][y*w], + &pv->ref[1][plane][1*ref_stride], + w * sizeof(uint8_t) ); + } + else if( y == 1 ) + { + /* TFF, so y1 = y0 */ + memcpy( &dst[plane][y*w], + &pv->ref[1][plane][0], + w * sizeof(uint8_t) ); + } + else if( y == penultimate ) + { + /* BFF, so penultimate y = ultimate y */ + memcpy( &dst[plane][y*w], + &pv->ref[1][plane][ultimate*ref_stride], + w * sizeof(uint8_t) ); + } + else if( y == ultimate ) + { + /* TFF, so ultimate y = penultimate y */ + memcpy( &dst[plane][y*w], + &pv->ref[1][plane][penultimate*ref_stride], + w * sizeof(uint8_t) ); + } } else { |