diff options
author | jstebbins <[email protected]> | 2013-12-02 21:25:41 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2013-12-02 21:25:41 +0000 |
commit | 87ba2a39cc223742796170d87a8563c2e64910d8 (patch) | |
tree | 12348638a37e6ec22aefeecc0b9cdbfd03332e16 /libhb/decomb.c | |
parent | 6f68c72ba9055ced110782e250ae824ff076a23e (diff) |
libhb: remove use of avpicture_deinterlace
This function is being remove from libav. so replace it's functionality
with a threaded implementation of our own.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5911 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/decomb.c')
-rw-r--r-- | libhb/decomb.c | 218 |
1 files changed, 137 insertions, 81 deletions
diff --git a/libhb/decomb.c b/libhb/decomb.c index 74ea8ec94..efad5179c 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -189,6 +189,12 @@ struct hb_filter_private_s taskset_t eedi2_taskset; // Threads for eedi2 - one per plane }; +typedef struct +{ + int tap[5]; + int normalize; +} filter_param_t; + static int hb_decomb_init( hb_filter_object_t * filter, hb_filter_init_t * init ); @@ -209,20 +215,36 @@ hb_filter_object_t hb_filter_decomb = .close = hb_decomb_close, }; -int cubic_interpolate_pixel( int y0, int y1, int y2, int y3 ) +// Borrowed from libav +#define times4(x) x, x, x, x +#define times1024(x) times4(times4(times4(times4(times4(x))))) + +static const uint8_t hb_crop_table[256 + 2 * 1024] = { +times1024(0x00), +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, +0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, +0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, +0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, +0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, +0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, +0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, +0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, +0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, +times1024(0xFF) +}; + +static inline 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 ); - result /= 40; - - if( result > 255 ) - { - result = 255; - } - else if( result < 0 ) - { - result = 0; - } + result = hb_crop_table[(result / 40) + 1024]; return result; } @@ -288,7 +310,7 @@ static void cubic_interpolate_line( } } -void draw_mask_box( hb_filter_private_t * pv ) +static void draw_mask_box( hb_filter_private_t * pv ) { int x = pv->mask_box_x; int y = pv->mask_box_y; @@ -323,9 +345,9 @@ void draw_mask_box( hb_filter_private_t * pv ) } } -void apply_mask_line( uint8_t * srcp, - uint8_t * mskp, - int width ) +static void apply_mask_line( uint8_t * srcp, + uint8_t * mskp, + int width ) { int x; @@ -342,7 +364,7 @@ void apply_mask_line( uint8_t * srcp, } } -void apply_mask(hb_filter_private_t * pv, hb_buffer_t * b) +static void apply_mask(hb_filter_private_t * pv, hb_buffer_t * b) { /* draw_boxes */ draw_mask_box( pv ); @@ -391,30 +413,24 @@ static void store_ref(hb_filter_private_t * pv, hb_buffer_t * b) pv->ref[2] = b; } -int blend_filter_pixel( int up2, int up1, int current, int down1, int down2 ) +static inline int blend_filter_pixel(filter_param_t *filter, int up2, int up1, int current, int down1, int down2) { /* Low-pass 5-tap filter */ int result = 0; - result += -up2; - result += up1 * 2; - result += current * 6; - result += down1 *2; - result += -down2; - result /= 8; - if( result > 255 ) - { - result = 255; - } - if( result < 0 ) - { - result = 0; - } + result += up2 * filter->tap[0]; + result += up1 * filter->tap[1]; + result += current * filter->tap[2]; + result += down1 * filter->tap[3]; + result += down2 * filter->tap[4]; + result >>= filter->normalize; + result = hb_crop_table[result + 1024]; return result; } -static void blend_filter_line( uint8_t *dst, +static void blend_filter_line(filter_param_t *filter, + uint8_t *dst, uint8_t *cur, int width, int height, @@ -468,15 +484,15 @@ static void blend_filter_line( uint8_t *dst, for( x = 0; x < w; x++) { - dst[0] = blend_filter_pixel( cur[up2], cur[up1], cur[0], - cur[down1], cur[down2] ); - + /* Low-pass 5-tap filter */ + dst[0] = blend_filter_pixel(filter, cur[up2], cur[up1], cur[0], + cur[down1], cur[down2] ); dst++; cur++; } } -void reset_combing_results( hb_filter_private_t * pv ) +static void reset_combing_results( hb_filter_private_t * pv ) { pv->comb_check_complete = 0; int ii; @@ -486,7 +502,7 @@ void reset_combing_results( hb_filter_private_t * pv ) } } -int check_combing_results( hb_filter_private_t * pv ) +static int check_combing_results( hb_filter_private_t * pv ) { int threshold = pv->block_threshold; int send_to_blend = 0; @@ -523,7 +539,7 @@ int check_combing_results( hb_filter_private_t * pv ) } } -void check_filtered_combing_mask( hb_filter_private_t * pv, int segment, int start, int stop ) +static void check_filtered_combing_mask( hb_filter_private_t * pv, int segment, int start, int stop ) { /* Go through the mask in X*Y blocks. If any of these windows have threshold or more combed pixels, consider the whole @@ -591,7 +607,7 @@ void check_filtered_combing_mask( hb_filter_private_t * pv, int segment, int sta } } -void check_combing_mask( hb_filter_private_t * pv, int segment, int start, int stop ) +static void check_combing_mask( hb_filter_private_t * pv, int segment, int start, int stop ) { /* Go through the mask in X*Y blocks. If any of these windows have threshold or more combed pixels, consider the whole @@ -670,7 +686,7 @@ void check_combing_mask( hb_filter_private_t * pv, int segment, int start, int s } } -void build_gamma_lut( hb_filter_private_t * pv ) +static void build_gamma_lut( hb_filter_private_t * pv ) { int i; for( i = 0; i < 256; i++ ) @@ -679,12 +695,7 @@ void build_gamma_lut( hb_filter_private_t * pv ) } } -float scale_gamma( int pixel, hb_filter_private_t * pv ) -{ - return pv->gamma_lut[pixel]; -} - -void detect_gamma_combed_segment( hb_filter_private_t * pv, int segment_start, int segment_stop ) +static void detect_gamma_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 @@ -756,7 +767,6 @@ void detect_gamma_combed_segment( hb_filter_private_t * pv, int segment_start, i fabs( pv->gamma_lut[prev[down_1]] - pv->gamma_lut[cur[down_1]] ) > mthresh ) motion++; -// hb_log("prev->cur motion: %f, mthresh: %f", fabs( scale_gamma( prev[0] ) - scale_gamma( cur[0] ) ), mthresh); } else { @@ -794,7 +804,7 @@ void detect_gamma_combed_segment( hb_filter_private_t * pv, int segment_start, i } -void detect_combed_segment( hb_filter_private_t * pv, int segment_start, int segment_stop ) +static 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 @@ -931,7 +941,7 @@ void detect_combed_segment( hb_filter_private_t * pv, int segment_start, int seg // This function calls all the eedi2 filters in sequence for a given plane. // It outputs the final interpolated image to pv->eedi_full[DST2PF]. -void eedi2_interpolate_plane( hb_filter_private_t * pv, int plane ) +static void eedi2_interpolate_plane( hb_filter_private_t * pv, int plane ) { /* We need all these pointers. No, seriously. I swear. It's not a joke. They're used. @@ -1011,7 +1021,7 @@ void eedi2_interpolate_plane( hb_filter_private_t * pv, int plane ) /* * eedi2 interpolate this plane in a single thread. */ -void eedi2_filter_thread( void *thread_args_v ) +static void eedi2_filter_thread( void *thread_args_v ) { hb_filter_private_t * pv; int plane; @@ -1041,7 +1051,7 @@ void eedi2_filter_thread( void *thread_args_v ) * Process plane */ eedi2_interpolate_plane( pv, plane ); - + /* * Finished this segment, let everyone know. */ @@ -1053,7 +1063,7 @@ void eedi2_filter_thread( void *thread_args_v ) // Sets up the input field planes for EEDI2 in pv->eedi_half[SRCPF] // and then runs eedi2_filter_thread for each plane. -void eedi2_planer( hb_filter_private_t * pv ) +static void eedi2_planer( hb_filter_private_t * pv ) { /* Copy the first field from the source to a half-height frame. */ int pp; @@ -1076,7 +1086,7 @@ void eedi2_planer( hb_filter_private_t * pv ) } -void mask_dilate_thread( void *thread_args_v ) +static void mask_dilate_thread( void *thread_args_v ) { hb_filter_private_t * pv; int segment, segment_start, segment_stop; @@ -1100,7 +1110,7 @@ void mask_dilate_thread( void *thread_args_v ) * No more work to do, exit this thread. */ break; - } + } int xx, yy, pp; @@ -1178,7 +1188,7 @@ void mask_dilate_thread( void *thread_args_v ) taskset_thread_complete( &pv->mask_dilate_taskset, segment ); } -void mask_erode_thread( void *thread_args_v ) +static void mask_erode_thread( void *thread_args_v ) { hb_filter_private_t * pv; int segment, segment_start, segment_stop; @@ -1202,7 +1212,7 @@ void mask_erode_thread( void *thread_args_v ) * No more work to do, exit this thread. */ break; - } + } int xx, yy, pp; @@ -1280,7 +1290,7 @@ void mask_erode_thread( void *thread_args_v ) taskset_thread_complete( &pv->mask_erode_taskset, segment ); } -void mask_filter_thread( void *thread_args_v ) +static void mask_filter_thread( void *thread_args_v ) { hb_filter_private_t * pv; int segment, segment_start, segment_stop; @@ -1304,7 +1314,7 @@ void mask_filter_thread( void *thread_args_v ) * No more work to do, exit this thread. */ break; - } + } int xx, yy, pp; @@ -1383,7 +1393,7 @@ void mask_filter_thread( void *thread_args_v ) taskset_thread_complete( &pv->mask_filter_taskset, segment ); } -void decomb_check_thread( void *thread_args_v ) +static void decomb_check_thread( void *thread_args_v ) { hb_filter_private_t * pv; int segment, segment_start, segment_stop; @@ -1407,7 +1417,7 @@ void decomb_check_thread( void *thread_args_v ) * No more work to do, exit this thread. */ break; - } + } segment_start = thread_args->segment_start[0]; segment_stop = segment_start + thread_args->segment_height[0]; @@ -1433,7 +1443,7 @@ void decomb_check_thread( void *thread_args_v ) /* * comb detect this segment of all three planes in a single thread. */ -void decomb_filter_thread( void *thread_args_v ) +static void decomb_filter_thread( void *thread_args_v ) { hb_filter_private_t * pv; int segment, segment_start, segment_stop; @@ -1457,7 +1467,7 @@ void decomb_filter_thread( void *thread_args_v ) * No more work to do, exit this thread. */ break; - } + } /* * Process segment (for now just from luma) @@ -1487,14 +1497,14 @@ void decomb_filter_thread( void *thread_args_v ) taskset_thread_complete( &pv->decomb_filter_taskset, segment ); } -int comb_segmenter( hb_filter_private_t * pv ) +static int comb_segmenter( hb_filter_private_t * pv ) { /* * Now that all data for decomb detection is ready for * our threads, fire them off and wait for their completion. */ taskset_cycle( &pv->decomb_filter_taskset ); - + if( pv->mode & MODE_FILTER ) { taskset_cycle( &pv->mask_filter_taskset ); @@ -1682,12 +1692,20 @@ static void yadif_filter_line( /* * deinterlace this segment of all three planes in a single thread. */ -void yadif_decomb_filter_thread( void *thread_args_v ) +static void yadif_decomb_filter_thread( void *thread_args_v ) { yadif_arguments_t *yadif_work = NULL; hb_filter_private_t * pv; int segment, segment_start, segment_stop; yadif_thread_arg_t *thread_args = thread_args_v; + filter_param_t filter; + + filter.tap[0] = -1; + filter.tap[1] = 2; + filter.tap[2] = 6; + filter.tap[3] = 2; + filter.tap[4] = -1; + filter.normalize = 3; pv = thread_args->pv; segment = thread_args->segment; @@ -1700,14 +1718,14 @@ void yadif_decomb_filter_thread( void *thread_args_v ) * Wait here until there is work to do. */ taskset_thread_wait4start( &pv->yadif_taskset, segment ); - + if( taskset_thread_stop( &pv->yadif_taskset, segment ) ) { /* * No more work to do, exit this thread. */ break; - } + } yadif_work = &pv->yadif_arguments[segment]; @@ -1747,7 +1765,7 @@ void yadif_decomb_filter_thread( void *thread_args_v ) for( yy = start; yy < segment_stop; yy += 2 ) { /* This line gets blend filtered, not yadif filtered. */ - blend_filter_line(dst2, cur, width, height, stride, yy); + blend_filter_line(&filter, dst2, cur, width, height, stride, yy); dst2 += stride * 2; cur += stride * 2; } @@ -1961,7 +1979,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, pv->yadif_ready = 0; - pv->mode = MODE_YADIF | MODE_BLEND | MODE_CUBIC | + pv->mode = MODE_YADIF | MODE_BLEND | MODE_CUBIC | MODE_GAMMA | MODE_FILTER; pv->filter_mode = FILTER_ERODE_DILATE; pv->spatial_metric = 2; @@ -2037,7 +2055,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, init->pix_fmt, init->width, init->height); } } - + /* * Setup yadif taskset. */ @@ -2103,7 +2121,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, for( ii = 0; ii < pv->cpu_count; ii++ ) { decomb_thread_arg_t *thread_args; - + thread_args = taskset_thread_args( &pv->decomb_filter_taskset, ii ); thread_args->pv = pv; thread_args->segment = ii; @@ -2161,7 +2179,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, for( ii = 0; ii < pv->comb_check_nthreads; ii++ ) { decomb_thread_arg_t *thread_args, *decomb_prev_thread_args = NULL; - + thread_args = taskset_thread_args( &pv->decomb_check_taskset, ii ); thread_args->pv = pv; thread_args->segment = ii; @@ -2218,7 +2236,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, for( ii = 0; ii < pv->cpu_count; ii++ ) { decomb_thread_arg_t *thread_args; - + thread_args = taskset_thread_args( &pv->mask_filter_taskset, ii ); thread_args->pv = pv; thread_args->segment = ii; @@ -2269,7 +2287,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, for( ii = 0; ii < pv->cpu_count; ii++ ) { decomb_thread_arg_t *thread_args; - + thread_args = taskset_thread_args( &pv->mask_erode_taskset, ii ); thread_args->pv = pv; thread_args->segment = ii; @@ -2318,7 +2336,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, for( ii = 0; ii < pv->cpu_count; ii++ ) { decomb_thread_arg_t *thread_args; - + thread_args = taskset_thread_args( &pv->mask_dilate_taskset, ii ); thread_args->pv = pv; thread_args->segment = ii; @@ -2410,7 +2428,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, } } } - + return 0; } @@ -2444,7 +2462,7 @@ static void hb_decomb_close( hb_filter_object_t * filter ) taskset_fini( &pv->eedi2_taskset ); } - + /* Cleanup reference buffers. */ int ii; for (ii = 0; ii < 3; ii++) @@ -2480,14 +2498,14 @@ static void hb_decomb_close( hb_filter_object_t * filter ) if (pv->cxy) eedi2_aligned_free(pv->cxy); if (pv->tmpc) eedi2_aligned_free(pv->tmpc); } - + free(pv->block_score); /* * free memory for yadif structs */ free( pv->yadif_arguments ); - + free( pv ); filter->private_data = NULL; } @@ -2539,12 +2557,12 @@ static int hb_decomb_work( hb_filter_object_t * filter, { num_frames = 2; } - + // Will need up to 2 buffers simultaneously int idx = 0; hb_buffer_t * o_buf[2] = {NULL,}; - /* Perform yadif filtering */ + /* Perform yadif filtering */ for( frame = 0; frame < num_frames; frame++ ) { int parity = frame ^ tff ^ 1; @@ -2626,3 +2644,41 @@ static int hb_decomb_work( hb_filter_object_t * filter, return HB_FILTER_OK; } + +void hb_deinterlace(hb_buffer_t *dst, hb_buffer_t *src) +{ + int pp; + filter_param_t filter; + + filter.tap[0] = -1; + filter.tap[1] = 4; + filter.tap[2] = 2; + filter.tap[3] = 4; + filter.tap[4] = -1; + filter.normalize = 3; + + for (pp = 0; pp < 3; pp++) + { + int yy; + int width = src->plane[pp].width; + int stride = src->plane[pp].stride; + int height = src->plane[pp].height; + + // Filter parity lines + uint8_t *pdst = &dst->plane[pp].data[0]; + uint8_t *psrc = &src->plane[pp].data[0]; + + /* These will be useful if we ever do temporal blending. */ + for( yy = 0; yy < height; yy += 2 ) + { + /* This line gets blend filtered, not yadif filtered. */ + memcpy(pdst, psrc, width); + pdst += stride; + psrc += stride; + blend_filter_line(&filter, pdst, psrc, width, height, stride, yy); + pdst += stride; + psrc += stride; + } + } +} + |