diff options
Diffstat (limited to 'libhb/decomb.c')
-rw-r--r-- | libhb/decomb.c | 1736 |
1 files changed, 174 insertions, 1562 deletions
diff --git a/libhb/decomb.c b/libhb/decomb.c index cf0db0b6e..a91dffc7f 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -13,8 +13,13 @@ /***** Parameters: - Mode : Spatial metric : Motion thresh : Spatial thresh : Mask Filter Mode : - Block thresh : Block width : Block height + Mode: + 1 = yadif + 2 = blend + 4 = cubic interpolation + 8 = EEDI2 interpolation + 16 = Deinterlace each field to a separate frame + 32 = Selectively deinterlace based on comb detection Appended for EEDI2: Magnitude thresh : Variance thresh : Laplacian thresh : Dilation thresh : @@ -24,24 +29,9 @@ Plus: Parity Defaults: - 391:2:3:3:2:40:16:16:10:20:20:4:2:50:24:1:-1 + 7:10:20:20:4:2:50:24:1:-1 -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_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 - -#define FILTER_CLASSIC 1 -#define FILTER_ERODE_DILATE 2 /***** These modes can be layered. For example, Yadif (1) + EEDI2 (8) = 9, @@ -60,8 +50,6 @@ which will feed EEDI2 interpolations to yadif. 10: Switch between EEDI2 and blend 11: Switch between EEDI2->yadif and blend ...okay I'm getting bored now listing all these different modes -32: Passes through the combing mask for every combed frame (white for combed pixels, otherwise black) -33+: Overlay the combing mask for every combed frame on top of the filtered output (white for combed pixels) 12-15: EEDI2 will override cubic interpolation *****/ @@ -70,6 +58,7 @@ which will feed EEDI2 interpolations to yadif. #include "hbffmpeg.h" #include "eedi2.h" #include "taskset.h" +#include "decomb.h" #define PARITY_DEFAULT -1 @@ -92,7 +81,7 @@ struct yadif_arguments_s { hb_buffer_t *dst; int parity; int tff; - int is_combed; + int mode; }; typedef struct yadif_arguments_s yadif_arguments_t; @@ -102,13 +91,6 @@ typedef struct eedi2_thread_arg_s { int plane; } eedi2_thread_arg_t; -typedef struct decomb_thread_arg_s { - hb_filter_private_t *pv; - int segment; - int segment_start[3]; - int segment_height[3]; -} decomb_thread_arg_t; - typedef struct yadif_thread_arg_s { hb_filter_private_t *pv; int segment; @@ -118,23 +100,8 @@ typedef struct yadif_thread_arg_s { struct hb_filter_private_s { - // Decomb detect parameters + // Decomb parameters int mode; - int filter_mode; - int spatial_metric; - int motion_threshold; - int spatial_threshold; - int block_threshold; - int block_width; - int block_height; - - int * block_score; - int comb_check_complete; - int comb_check_nthreads; - int skip_comb_check; - int is_combed; - - float gamma_lut[256]; /* Make buffers to store a comb masks. */ hb_buffer_t * mask; @@ -144,49 +111,45 @@ struct hb_filter_private_s int mask_box_y; uint8_t mask_box_color; - // Deinterlace parameters - int parity; // EEDI2 parameters - int magnitude_threshold; - int variance_threshold; - int laplacian_threshold; - int dilation_threshold; - int erosion_threshold; - int noise_threshold; - int maximum_search_distance; - int post_processing; - - int tff; + int magnitude_threshold; + int variance_threshold; + int laplacian_threshold; + int dilation_threshold; + int erosion_threshold; + int noise_threshold; + int maximum_search_distance; + int post_processing; - int yadif_ready; + // Deinterlace parameters + int parity; + int tff; - int deinterlaced_frames; - int blended_frames; - int unfiltered_frames; + int yadif_ready; - hb_buffer_t * ref[3]; + int deinterlaced; + int blended; + int unfiltered; + int frames; + hb_buffer_t * ref[3]; - hb_buffer_t * eedi_half[4]; - hb_buffer_t * eedi_full[5]; - int * cx2; - int * cy2; - int * cxy; - int * tmpc; + hb_buffer_t * eedi_half[4]; + hb_buffer_t * eedi_full[5]; + int * cx2; + int * cy2; + int * cxy; + int * tmpc; - int cpu_count; - int segment_height[3]; + int cpu_count; + int segment_height[3]; - taskset_t yadif_taskset; // Threads for Yadif - one per CPU - yadif_arguments_t *yadif_arguments; // Arguments to thread for work + taskset_t yadif_taskset; // Threads for Yadif - one per CPU + yadif_arguments_t * yadif_arguments; // Arguments to thread for work - taskset_t decomb_filter_taskset; // Threads for comb detection - taskset_t decomb_check_taskset; // Threads for comb check - taskset_t mask_filter_taskset; // Threads for decomb mask filter - taskset_t mask_erode_taskset; // Threads for decomb mask erode - taskset_t mask_dilate_taskset; // Threads for decomb mask dilate + taskset_t eedi2_taskset; // Threads for eedi2 - one per plane - taskset_t eedi2_taskset; // Threads for eedi2 - one per plane + hb_buffer_list_t out_list; }; typedef struct @@ -205,10 +168,7 @@ static int hb_decomb_work( hb_filter_object_t * filter, static void hb_decomb_close( hb_filter_object_t * filter ); static const char decomb_template[] = - "mode=^"HB_INT_REG"$:spatial-metric=^([012])$:" - "motion-thresh=^"HB_INT_REG"$:spatial-thresh=^"HB_INT_REG"$:" - "filter-mode=^([012])$:block-thresh=^"HB_INT_REG"$:" - "block-width=^"HB_INT_REG"$:block-height=^"HB_INT_REG"$:" + "mode=^"HB_INT_REG"$:" "magnitude-thresh=^"HB_INT_REG"$:variance-thresh=^"HB_INT_REG"$:" "laplacian-thresh=^"HB_INT_REG"$:dilation-thresh=^"HB_INT_REG"$:" "erosion-thresh=^"HB_INT_REG"$:noise-thresh=^"HB_INT_REG"$:" @@ -321,102 +281,6 @@ static void cubic_interpolate_line( } } -static void draw_mask_box( hb_filter_private_t * pv ) -{ - int x = pv->mask_box_x; - int y = pv->mask_box_y; - int box_width = pv->block_width; - int box_height = pv->block_height; - int stride; - uint8_t * mskp; - - if (pv->mode & MODE_FILTER) - { - mskp = pv->mask_filtered->plane[0].data; - stride = pv->mask_filtered->plane[0].stride; - } - else - { - mskp = pv->mask->plane[0].data; - stride = pv->mask->plane[0].stride; - } - - - int block_x, block_y; - for( block_x = 0; block_x < box_width; block_x++) - { - mskp[y*stride+x+block_x] = 128; - mskp[(y+box_height)*stride+x+block_x] = 128; - } - - for( block_y = 0; block_y < box_height; block_y++) - { - mskp[stride*(y+block_y)+x] = 128; - mskp[stride*(y+block_y) + x + box_width] = 128; - } -} - -static void apply_mask_line( uint8_t * srcp, - uint8_t * mskp, - int width ) -{ - int x; - - for( x = 0; x < width; x++ ) - { - if( mskp[x] == 1 ) - { - srcp[x] = 255; - } - if( mskp[x] == 128 ) - { - srcp[x] = 128; - } - } -} - -static void apply_mask(hb_filter_private_t * pv, hb_buffer_t * b) -{ - /* draw_boxes */ - draw_mask_box( pv ); - - int pp, yy; - hb_buffer_t * m; - - if (pv->mode & MODE_FILTER) - { - m = pv->mask_filtered; - } - else - { - m = pv->mask; - } - for (pp = 0; pp < 3; pp++) - { - uint8_t * dstp = b->plane[pp].data; - uint8_t * mskp = m->plane[pp].data; - - for( yy = 0; yy < m->plane[pp].height; yy++ ) - { - if (!(pv->mode & MODE_COMPOSITE) && pp == 0) - { - memcpy(dstp, mskp, m->plane[pp].width); - } - else if (!(pv->mode & MODE_COMPOSITE)) - { - memset(dstp, 128, m->plane[pp].width); - } - if (pp == 0) - { - apply_mask_line(dstp, mskp, m->plane[pp].width); - } - - dstp += b->plane[pp].stride; - mskp += m->plane[pp].stride; - } - } -} - static void store_ref(hb_filter_private_t * pv, hb_buffer_t * b) { hb_buffer_close(&pv->ref[0]); @@ -503,452 +367,6 @@ static void blend_filter_line(filter_param_t *filter, } } -static void reset_combing_results( hb_filter_private_t * pv ) -{ - pv->comb_check_complete = 0; - int ii; - for (ii = 0; ii < pv->comb_check_nthreads; ii++) - { - pv->block_score[ii] = 0; - } -} - -static int check_combing_results( hb_filter_private_t * pv ) -{ - int threshold = pv->block_threshold; - int send_to_blend = 0; - - int ii; - for (ii = 0; ii < pv->comb_check_nthreads; ii++) - { - if( pv->block_score[ii] >= ( threshold / 2 ) ) - { - if (pv->block_score[ii] <= threshold) - { - /* Blend video content that scores between - ( threshold / 2 ) and threshold. */ - send_to_blend = 1; - pv->mask_box_color = 2; - } - else if( pv->block_score[ii] > threshold ) - { - /* Yadif deinterlace video content above the threshold. */ - pv->mask_box_color = 1; - return 1; - } - } - } - - if( send_to_blend ) - { - return 2; - } - else - { - /* Consider this frame to be uncombed. */ - return 0; - } -} - -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 - frame to be combed and send it on to be deinterlaced. */ - - /* Block mask threshold -- The number of pixels - in a block_width * block_height window of - he mask that need to show combing for the - whole frame to be seen as such. */ - int threshold = pv->block_threshold; - int block_width = pv->block_width; - int block_height = pv->block_height; - int block_x, block_y; - int block_score = 0; - uint8_t * mask_p; - int x, y, pp; - - for( pp = 0; pp < 1; pp++ ) - { - int stride = pv->mask_filtered->plane[pp].stride; - int width = pv->mask_filtered->plane[pp].width; - - pv->mask_box_x = -1; - pv->mask_box_y = -1; - pv->mask_box_color = 0; - - for( y = start; y < ( stop - block_height + 1 ); y = y + block_height ) - { - for( x = 0; x < ( width - block_width ); x = x + block_width ) - { - block_score = 0; - - for( block_y = 0; block_y < block_height; block_y++ ) - { - int my = y + block_y; - mask_p = &pv->mask_filtered->plane[pp].data[my*stride + x]; - - for( block_x = 0; block_x < block_width; block_x++ ) - { - block_score += mask_p[0]; - mask_p++; - } - } - - if (pv->comb_check_complete) - { - // Some other thread found coming before this one - return; - } - - if( block_score >= ( threshold / 2 ) ) - { - pv->mask_box_x = x; - pv->mask_box_y = y; - - pv->block_score[segment] = block_score; - if( block_score > threshold ) - { - pv->comb_check_complete = 1; - return; - } - } - } - } - } -} - -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 - frame to be combed and send it on to be deinterlaced. */ - - /* Block mask threshold -- The number of pixels - in a block_width * block_height window of - he mask that need to show combing for the - whole frame to be seen as such. */ - int threshold = pv->block_threshold; - int block_width = pv->block_width; - int block_height = pv->block_height; - int block_x, block_y; - int block_score = 0; - uint8_t * mask_p; - int x, y, pp; - - for( pp = 0; pp < 1; pp++ ) - { - int stride = pv->mask->plane[pp].stride; - int width = pv->mask->plane[pp].width; - - for (y = start; y < (stop - block_height + 1); y = y + block_height) - { - for (x = 0; x < (width - block_width); x = x + block_width) - { - block_score = 0; - - for( block_y = 0; block_y < block_height; block_y++ ) - { - int mask_y = y + block_y; - mask_p = &pv->mask->plane[pp].data[mask_y * stride + x]; - - for( block_x = 0; block_x < block_width; block_x++ ) - { - /* We only want to mark a pixel in a block as combed - if the adjacent pixels are as well. Got to - handle the sides separately. */ - if( (x + block_x) == 0 ) - { - block_score += mask_p[0] & mask_p[1]; - } - else if( (x + block_x) == (width -1) ) - { - block_score += mask_p[-1] & mask_p[0]; - } - else - { - block_score += mask_p[-1] & mask_p[0] & mask_p[1]; - } - - mask_p++; - } - } - - if (pv->comb_check_complete) - { - // Some other thread found coming before this one - return; - } - - if( block_score >= ( threshold / 2 ) ) - { - pv->mask_box_x = x; - pv->mask_box_y = y; - - pv->block_score[segment] = block_score; - if( block_score > threshold ) - { - pv->comb_check_complete = 1; - return; - } - } - } - } - } -} - -static void build_gamma_lut( hb_filter_private_t * pv ) -{ - int i; - for( i = 0; i < 256; i++ ) - { - pv->gamma_lut[i] = pow( ( (float)i / (float)255 ), 2.2f ); - } -} - -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 - AviSynth and tritical's IsCombedT and - IsCombedTIVTC plugins. */ - - /* Comb scoring algorithm */ - /* Motion threshold */ - float mthresh = (float)pv->motion_threshold / (float)255; - /* Spatial threshold */ - float athresh = (float)pv->spatial_threshold / (float)255; - float athresh6 = 6 *athresh; - - /* One pas for Y, one pass for U, one pass for V */ - int pp; - for( pp = 0; pp < 1; pp++ ) - { - int x, y; - int stride = pv->ref[0]->plane[pp].stride; - int width = pv->ref[0]->plane[pp].width; - int height = pv->ref[0]->plane[pp].height; - - /* Comb detection has to start at y = 2 and end at - y = height - 2, because it needs to examine - 2 pixels above and 2 below the current pixel. */ - if( segment_start < 2 ) - segment_start = 2; - if( segment_stop > height - 2 ) - segment_stop = height - 2; - - for( y = segment_start; y < segment_stop; y++ ) - { - /* These are just to make the buffer locations easier to read. */ - int up_2 = -2 * stride ; - int up_1 = -1 * stride; - int down_1 = stride; - int down_2 = 2 * stride; - - /* We need to examine a column of 5 pixels - in the prev, cur, and next frames. */ - uint8_t * prev = &pv->ref[0]->plane[pp].data[y * stride]; - uint8_t * cur = &pv->ref[1]->plane[pp].data[y * stride]; - uint8_t * next = &pv->ref[2]->plane[pp].data[y * stride]; - uint8_t * mask = &pv->mask->plane[pp].data[y * stride]; - - memset(mask, 0, stride); - - for( x = 0; x < width; x++ ) - { - float up_diff, down_diff; - up_diff = pv->gamma_lut[cur[0]] - pv->gamma_lut[cur[up_1]]; - down_diff = pv->gamma_lut[cur[0]] - pv->gamma_lut[cur[down_1]]; - - if( ( up_diff > athresh && down_diff > athresh ) || - ( up_diff < -athresh && down_diff < -athresh ) ) - { - /* The pixel above and below are different, - and they change in the same "direction" too.*/ - int motion = 0; - if( mthresh > 0 ) - { - /* Make sure there's sufficient motion between frame t-1 to frame t+1. */ - if( fabs( pv->gamma_lut[prev[0]] - pv->gamma_lut[cur[0]] ) > mthresh && - fabs( pv->gamma_lut[cur[up_1]] - pv->gamma_lut[next[up_1]] ) > mthresh && - fabs( pv->gamma_lut[cur[down_1]] - pv->gamma_lut[next[down_1]] ) > mthresh ) - motion++; - if( fabs( pv->gamma_lut[next[0]] - pv->gamma_lut[cur[0]] ) > mthresh && - fabs( pv->gamma_lut[prev[up_1]] - pv->gamma_lut[cur[up_1]] ) > mthresh && - fabs( pv->gamma_lut[prev[down_1]] - pv->gamma_lut[cur[down_1]] ) > mthresh ) - motion++; - - } - else - { - /* User doesn't want to check for motion, - so move on to the spatial check. */ - motion = 1; - } - - if( motion || ( pv->deinterlaced_frames==0 && pv->blended_frames==0 && pv->unfiltered_frames==0) ) - { - - /* Tritical's noise-resistant combing scorer. - The check is done on a bob+blur convolution. */ - float combing = fabs( pv->gamma_lut[cur[up_2]] - + ( 4 * pv->gamma_lut[cur[0]] ) - + pv->gamma_lut[cur[down_2]] - - ( 3 * ( pv->gamma_lut[cur[up_1]] - + pv->gamma_lut[cur[down_1]] ) ) ); - /* If the frame is sufficiently combed, - then mark it down on the mask as 1. */ - if( combing > athresh6 ) - { - mask[0] = 1; - } - } - } - - cur++; - prev++; - next++; - mask++; - } - } - } -} - - -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 - AviSynth and tritical's IsCombedT and - IsCombedTIVTC plugins. */ - - /* Comb scoring algorithm */ - int spatial_metric = pv->spatial_metric; - /* Motion threshold */ - int mthresh = pv->motion_threshold; - /* Spatial threshold */ - int athresh = pv->spatial_threshold; - int athresh_squared = athresh * athresh; - int athresh6 = 6 * athresh; - - /* One pas for Y, one pass for U, one pass for V */ - int pp; - for( pp = 0; pp < 1; pp++ ) - { - int x, y; - int stride = pv->ref[0]->plane[pp].stride; - int width = pv->ref[0]->plane[pp].width; - int height = pv->ref[0]->plane[pp].height; - - /* Comb detection has to start at y = 2 and end at - y = height - 2, because it needs to examine - 2 pixels above and 2 below the current pixel. */ - if( segment_start < 2 ) - segment_start = 2; - if( segment_stop > height - 2 ) - segment_stop = height - 2; - - for( y = segment_start; y < segment_stop; y++ ) - { - /* These are just to make the buffer locations easier to read. */ - int up_2 = -2 * stride ; - int up_1 = -1 * stride; - int down_1 = stride; - int down_2 = 2 * stride; - - /* We need to examine a column of 5 pixels - in the prev, cur, and next frames. */ - uint8_t * prev = &pv->ref[0]->plane[pp].data[y * stride]; - uint8_t * cur = &pv->ref[1]->plane[pp].data[y * stride]; - uint8_t * next = &pv->ref[2]->plane[pp].data[y * stride]; - uint8_t * mask = &pv->mask->plane[pp].data[y * stride]; - - memset(mask, 0, stride); - - for( x = 0; x < width; x++ ) - { - int up_diff = cur[0] - cur[up_1]; - int down_diff = cur[0] - cur[down_1]; - - if( ( up_diff > athresh && down_diff > athresh ) || - ( up_diff < -athresh && down_diff < -athresh ) ) - { - /* The pixel above and below are different, - and they change in the same "direction" too.*/ - int motion = 0; - if( mthresh > 0 ) - { - /* Make sure there's sufficient motion between frame t-1 to frame t+1. */ - if( abs( prev[0] - cur[0] ) > mthresh && - abs( cur[up_1] - next[up_1] ) > mthresh && - abs( cur[down_1] - next[down_1] ) > mthresh ) - motion++; - if( abs( next[0] - cur[0] ) > mthresh && - abs( prev[up_1] - cur[up_1] ) > mthresh && - abs( prev[down_1] - cur[down_1] ) > mthresh ) - motion++; - } - else - { - /* User doesn't want to check for motion, - so move on to the spatial check. */ - motion = 1; - } - - if( motion || ( pv->deinterlaced_frames==0 && pv->blended_frames==0 && pv->unfiltered_frames==0) ) - { - /* That means it's time for the spatial check. - We've got several options here. */ - if( spatial_metric == 0 ) - { - /* Simple 32detect style comb detection */ - if( ( abs( cur[0] - cur[down_2] ) < 10 ) && - ( abs( cur[0] - cur[down_1] ) > 15 ) ) - { - mask[0] = 1; - } - } - else if( spatial_metric == 1 ) - { - /* This, for comparison, is what IsCombed uses. - It's better, but still noise senstive. */ - int combing = ( cur[up_1] - cur[0] ) * - ( cur[down_1] - cur[0] ); - - if( combing > athresh_squared ) - { - mask[0] = 1; - } - } - else if( spatial_metric == 2 ) - { - /* Tritical's noise-resistant combing scorer. - The check is done on a bob+blur convolution. */ - int combing = abs( cur[up_2] - + ( 4 * cur[0] ) - + cur[down_2] - - ( 3 * ( cur[up_1] - + cur[down_1] ) ) ); - - /* If the frame is sufficiently combed, - then mark it down on the mask as 1. */ - if( combing > athresh6 ) - { - mask[0] = 1; - } - } - } - } - - cur++; - prev++; - next++; - mask++; - } - } - } -} - // This function calls all the eedi2 filters in sequence for a given plane. // It outputs the final interpolated image to pv->eedi_full[DST2PF]. static void eedi2_interpolate_plane( hb_filter_private_t * pv, int plane ) @@ -1095,446 +513,6 @@ static void eedi2_planer( hb_filter_private_t * pv ) taskset_cycle( &pv->eedi2_taskset ); } - -static void mask_dilate_thread( void *thread_args_v ) -{ - hb_filter_private_t * pv; - int segment, segment_start, segment_stop; - decomb_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("mask dilate thread started for segment %d", segment); - - while (1) - { - /* - * Wait here until there is work to do. - */ - taskset_thread_wait4start( &pv->mask_dilate_taskset, segment ); - - if (taskset_thread_stop(&pv->mask_dilate_taskset, segment)) - { - /* - * No more work to do, exit this thread. - */ - break; - } - - int xx, yy, pp; - - int count; - int dilation_threshold = 4; - - for( pp = 0; pp < 1; pp++ ) - { - int width = pv->mask_filtered->plane[pp].width; - int height = pv->mask_filtered->plane[pp].height; - int stride = pv->mask_filtered->plane[pp].stride; - - int start, stop, p, c, n; - segment_start = thread_args->segment_start[pp]; - segment_stop = segment_start + thread_args->segment_height[pp]; - - if (segment_start == 0) - { - start = 1; - p = 0; - c = 1; - n = 2; - } - else - { - start = segment_start; - p = segment_start - 1; - c = segment_start; - n = segment_start + 1; - } - - if (segment_stop == height) - { - stop = height -1; - } - else - { - stop = segment_stop; - } - - uint8_t *curp = &pv->mask_filtered->plane[pp].data[p * stride + 1]; - uint8_t *cur = &pv->mask_filtered->plane[pp].data[c * stride + 1]; - uint8_t *curn = &pv->mask_filtered->plane[pp].data[n * stride + 1]; - uint8_t *dst = &pv->mask_temp->plane[pp].data[c * stride + 1]; - - for( yy = start; yy < stop; yy++ ) - { - for( xx = 1; xx < width - 1; xx++ ) - { - if (cur[xx]) - { - dst[xx] = 1; - continue; - } - - count = curp[xx-1] + curp[xx] + curp[xx+1] + - cur [xx-1] + cur [xx+1] + - curn[xx-1] + curn[xx] + curn[xx+1]; - - dst[xx] = count >= dilation_threshold; - } - curp += stride; - cur += stride; - curn += stride; - dst += stride; - } - } - - taskset_thread_complete( &pv->mask_dilate_taskset, segment ); - } - - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->mask_dilate_taskset, segment ); -} - -static void mask_erode_thread( void *thread_args_v ) -{ - hb_filter_private_t * pv; - int segment, segment_start, segment_stop; - decomb_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("mask erode thread started for segment %d", segment); - - while (1) - { - /* - * Wait here until there is work to do. - */ - taskset_thread_wait4start( &pv->mask_erode_taskset, segment ); - - if( taskset_thread_stop( &pv->mask_erode_taskset, segment ) ) - { - /* - * No more work to do, exit this thread. - */ - break; - } - - int xx, yy, pp; - - int count; - int erosion_threshold = 2; - - for( pp = 0; pp < 1; pp++ ) - { - int width = pv->mask_filtered->plane[pp].width; - int height = pv->mask_filtered->plane[pp].height; - int stride = pv->mask_filtered->plane[pp].stride; - - int start, stop, p, c, n; - segment_start = thread_args->segment_start[pp]; - segment_stop = segment_start + thread_args->segment_height[pp]; - - if (segment_start == 0) - { - start = 1; - p = 0; - c = 1; - n = 2; - } - else - { - start = segment_start; - p = segment_start - 1; - c = segment_start; - n = segment_start + 1; - } - - if (segment_stop == height) - { - stop = height -1; - } - else - { - stop = segment_stop; - } - - uint8_t *curp = &pv->mask_temp->plane[pp].data[p * stride + 1]; - uint8_t *cur = &pv->mask_temp->plane[pp].data[c * stride + 1]; - uint8_t *curn = &pv->mask_temp->plane[pp].data[n * stride + 1]; - uint8_t *dst = &pv->mask_filtered->plane[pp].data[c * stride + 1]; - - for( yy = start; yy < stop; yy++ ) - { - for( xx = 1; xx < width - 1; xx++ ) - { - if( cur[xx] == 0 ) - { - dst[xx] = 0; - continue; - } - - count = curp[xx-1] + curp[xx] + curp[xx+1] + - cur [xx-1] + cur [xx+1] + - curn[xx-1] + curn[xx] + curn[xx+1]; - - dst[xx] = count >= erosion_threshold; - } - curp += stride; - cur += stride; - curn += stride; - dst += stride; - } - } - - taskset_thread_complete( &pv->mask_erode_taskset, segment ); - } - - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->mask_erode_taskset, segment ); -} - -static void mask_filter_thread( void *thread_args_v ) -{ - hb_filter_private_t * pv; - int segment, segment_start, segment_stop; - decomb_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("mask filter thread started for segment %d", segment); - - while (1) - { - /* - * Wait here until there is work to do. - */ - taskset_thread_wait4start( &pv->mask_filter_taskset, segment ); - - if( taskset_thread_stop( &pv->mask_filter_taskset, segment ) ) - { - /* - * No more work to do, exit this thread. - */ - break; - } - - int xx, yy, pp; - - for( pp = 0; pp < 1; pp++ ) - { - int width = pv->mask->plane[pp].width; - int height = pv->mask->plane[pp].height; - int stride = pv->mask->plane[pp].stride; - - int start, stop, p, c, n; - segment_start = thread_args->segment_start[pp]; - segment_stop = segment_start + thread_args->segment_height[pp]; - - if (segment_start == 0) - { - start = 1; - p = 0; - c = 1; - n = 2; - } - else - { - start = segment_start; - p = segment_start - 1; - c = segment_start; - n = segment_start + 1; - } - - if (segment_stop == height) - { - stop = height - 1; - } - else - { - stop = segment_stop; - } - - uint8_t *curp = &pv->mask->plane[pp].data[p * stride + 1]; - uint8_t *cur = &pv->mask->plane[pp].data[c * stride + 1]; - uint8_t *curn = &pv->mask->plane[pp].data[n * stride + 1]; - uint8_t *dst = (pv->filter_mode == FILTER_CLASSIC ) ? - &pv->mask_filtered->plane[pp].data[c * stride + 1] : - &pv->mask_temp->plane[pp].data[c * stride + 1] ; - - for( yy = start; yy < stop; yy++ ) - { - for( xx = 1; xx < width - 1; xx++ ) - { - int h_count, v_count; - - h_count = cur[xx-1] & cur[xx] & cur[xx+1]; - v_count = curp[xx] & cur[xx] & curn[xx]; - - if (pv->filter_mode == FILTER_CLASSIC) - { - dst[xx] = h_count; - } - else - { - dst[xx] = h_count & v_count; - } - } - curp += stride; - cur += stride; - curn += stride; - dst += stride; - } - } - - taskset_thread_complete( &pv->mask_filter_taskset, segment ); - } - - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->mask_filter_taskset, segment ); -} - -static void decomb_check_thread( void *thread_args_v ) -{ - hb_filter_private_t * pv; - int segment, segment_start, segment_stop; - decomb_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("decomb check thread started for segment %d", segment); - - while (1) - { - /* - * Wait here until there is work to do. - */ - taskset_thread_wait4start( &pv->decomb_check_taskset, segment ); - - if( taskset_thread_stop( &pv->decomb_check_taskset, segment ) ) - { - /* - * 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]; - - if( pv->mode & MODE_FILTER ) - { - check_filtered_combing_mask(pv, segment, segment_start, segment_stop); - } - else - { - check_combing_mask(pv, segment, segment_start, segment_stop); - } - - taskset_thread_complete( &pv->decomb_check_taskset, segment ); - } - - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->decomb_check_taskset, segment ); -} - -/* - * comb detect this segment of all three planes in a single thread. - */ -static void decomb_filter_thread( void *thread_args_v ) -{ - hb_filter_private_t * pv; - int segment, segment_start, segment_stop; - decomb_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("decomb filter thread started for segment %d", segment); - - while (1) - { - /* - * Wait here until there is work to do. - */ - taskset_thread_wait4start( &pv->decomb_filter_taskset, segment ); - - if( taskset_thread_stop( &pv->decomb_filter_taskset, segment ) ) - { - /* - * No more work to do, exit this thread. - */ - break; - } - - /* - * Process segment (for now just from luma) - */ - int pp; - for( pp = 0; pp < 1; pp++) - { - segment_start = thread_args->segment_start[pp]; - segment_stop = segment_start + thread_args->segment_height[pp]; - - if( pv->mode & MODE_GAMMA ) - { - detect_gamma_combed_segment( pv, segment_start, segment_stop ); - } - else - { - detect_combed_segment( pv, segment_start, segment_stop ); - } - } - - taskset_thread_complete( &pv->decomb_filter_taskset, segment ); - } - - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->decomb_filter_taskset, segment ); -} - -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 ); - if( pv->filter_mode == FILTER_ERODE_DILATE ) - { - taskset_cycle( &pv->mask_erode_taskset ); - taskset_cycle( &pv->mask_dilate_taskset ); - taskset_cycle( &pv->mask_erode_taskset ); - } - //return check_filtered_combing_mask( pv ); - } - else - { - //return check_combing_mask( pv ); - } - reset_combing_results(pv); - taskset_cycle( &pv->decomb_check_taskset ); - return check_combing_results(pv); -} - /* EDDI: Edge Directed Deinterlacing Interpolation Checks 4 different slopes to see if there is more similarity along a diagonal than there was vertically. If a diagonal is more similar, then it indicates @@ -1546,7 +524,7 @@ static int comb_segmenter( hb_filter_private_t * pv ) + ABS(cur[-stride+1+j] - cur[+stride+1-j]);\ if( score < spatial_score ){\ spatial_score = score;\ - if( ( pv->mode & MODE_CUBIC ) && !vertical_edge )\ + if( ( pv->mode & MODE_DECOMB_CUBIC ) && !vertical_edge )\ {\ switch(j)\ {\ @@ -1590,7 +568,7 @@ static void yadif_filter_line( uint8_t *next2 = parity ? cur : next; int x; - int eedi2_mode = ( pv->mode & MODE_EEDI2 ); + int eedi2_mode = ( pv->mode & MODE_DECOMB_EEDI2 ); /* We can replace spatial_pred with this interpolation*/ uint8_t * eedi2_guess = NULL; @@ -1639,7 +617,7 @@ static void yadif_filter_line( ABS(cur[-stride+1] - cur[+stride+1]) - 1; /* Spatial pred is either a bilinear or cubic vertical interpolation. */ - if( ( pv->mode & MODE_CUBIC ) && !vertical_edge) + if( ( pv->mode & MODE_DECOMB_CUBIC ) && !vertical_edge) { spatial_pred = cubic_interpolate_pixel( cur[-3*stride], cur[-stride], cur[+stride], cur[3*stride] ); } @@ -1649,10 +627,10 @@ static void yadif_filter_line( } // YADIF_CHECK requires a margin to avoid invalid memory access. - // In MODE_CUBIC, margin needed is 2 + ABS(param). + // In MODE_DECOMB_CUBIC, margin needed is 2 + ABS(param). // Else, the margin needed is 1 + ABS(param). int margin = 2; - if (pv->mode & MODE_CUBIC) + if (pv->mode & MODE_DECOMB_CUBIC) margin = 3; if (x >= margin && x <= width - (margin + 1)) @@ -1743,9 +721,9 @@ static void yadif_decomb_filter_thread( void *thread_args_v ) * Process all three planes, but only this segment of it. */ hb_buffer_t *dst; - int parity, tff, is_combed; + int parity, tff, mode; - is_combed = pv->yadif_arguments[segment].is_combed; + mode = pv->yadif_arguments[segment].mode; dst = yadif_work->dst; tff = yadif_work->tff; parity = yadif_work->parity; @@ -1769,7 +747,7 @@ static void yadif_decomb_filter_thread( void *thread_args_v ) uint8_t *cur = &pv->ref[1]->plane[pp].data[start * stride]; uint8_t *next = &pv->ref[2]->plane[pp].data[start * stride]; - if( is_combed == 2 ) + if (mode == MODE_DECOMB_BLEND) { /* These will be useful if we ever do temporal blending. */ for( yy = start; yy < segment_stop; yy += 2 ) @@ -1780,7 +758,7 @@ static void yadif_decomb_filter_thread( void *thread_args_v ) cur += stride * 2; } } - else if (pv->mode == MODE_CUBIC && is_combed) + else if (mode == MODE_DECOMB_CUBIC) { for( yy = start; yy < segment_stop; yy += 2 ) { @@ -1790,7 +768,7 @@ static void yadif_decomb_filter_thread( void *thread_args_v ) cur += stride * 2; } } - else if ((pv->mode & MODE_YADIF) && is_combed == 1) + else if (mode & MODE_DECOMB_YADIF) { for( yy = start; yy < segment_stop; yy += 2 ) { @@ -1856,70 +834,47 @@ static void yadif_filter( hb_filter_private_t * pv, int tff) { /* If we're running comb detection, do it now, otherwise default to true. */ - int is_combed; + int is_combed = HB_COMB_HEAVY; + int mode = 0; - if (!pv->skip_comb_check) + if (pv->mode & MODE_DECOMB_SELECTIVE) { - is_combed = pv->spatial_metric >= 0 ? comb_segmenter( pv ) : 1; - } - else - { - is_combed = pv->is_combed; + is_combed = pv->ref[1]->s.combed; } - /* The comb detector suggests three different values: - 0: Don't comb this frame. - 1: Deinterlace this frame. - 2: Blend this frame. - Since that might conflict with the filter's mode, - it may be necesary to adjust this value. */ - if( is_combed == 1 && (pv->mode == MODE_BLEND) ) - { - /* All combed frames are getting blended */ - is_combed = 2; - } - else if( is_combed == 2 && !( pv->mode & MODE_BLEND ) ) + // Pick a mode based on the comb detect state and selected decomb modes + if ((pv->mode & MODE_DECOMB_BLEND) && is_combed == HB_COMB_LIGHT ) { - /* Blending is disabled, so force interpolation of these frames. */ - is_combed = 1; + mode = MODE_DECOMB_BLEND; } - if( is_combed == 1 && - ( pv->mode & MODE_BLEND ) && - !( pv->mode & ( MODE_YADIF | MODE_EEDI2 | MODE_CUBIC ) ) ) + else if (is_combed != HB_COMB_NONE) { - /* Deinterlacers are disabled, blending isn't, so blend these frames. */ - is_combed = 2; - } - else if( is_combed && - !( pv->mode & ( MODE_BLEND | MODE_YADIF | MODE_EEDI2 | MODE_CUBIC | MODE_MASK ) ) ) - { - /* No deinterlacer or mask chosen, pass the frame through. */ - is_combed = 0; + mode = pv->mode & ~MODE_DECOMB_SELECTIVE; } - if( is_combed == 1 ) + if (mode == MODE_DECOMB_BLEND) { - pv->deinterlaced_frames++; + pv->blended++; } - else if( is_combed == 2 ) + else if (mode != 0) { - pv->blended_frames++; + pv->deinterlaced++; } else { - pv->unfiltered_frames++; + pv->unfiltered++; } + pv->frames++; - if( is_combed == 1 && ( pv->mode & MODE_EEDI2 ) ) + if (mode & MODE_DECOMB_EEDI2) { /* Generate an EEDI2 interpolation */ eedi2_planer( pv ); } - pv->is_combed = is_combed; - if( is_combed ) + if (mode != 0) { - if( ( pv->mode & MODE_EEDI2 ) && !( pv->mode & MODE_YADIF ) && is_combed == 1 ) + if ((mode & MODE_DECOMB_EEDI2 ) && !(mode & MODE_DECOMB_YADIF)) { // Just pass through the EEDI2 interpolation int pp; @@ -1954,7 +909,7 @@ static void yadif_filter( hb_filter_private_t * pv, pv->yadif_arguments[segment].parity = parity; pv->yadif_arguments[segment].tff = tff; pv->yadif_arguments[segment].dst = dst; - pv->yadif_arguments[segment].is_combed = is_combed; + pv->yadif_arguments[segment].mode = mode; } /* @@ -1970,7 +925,7 @@ static void yadif_filter( hb_filter_private_t * pv, else { /* Just passing through... */ - pv->yadif_arguments[0].is_combed = is_combed; // 0 + pv->yadif_arguments[0].mode = mode; // 0 hb_buffer_copy(dst, pv->ref[1]); } } @@ -1980,35 +935,25 @@ static int hb_decomb_init( hb_filter_object_t * filter, { filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); hb_filter_private_t * pv = filter->private_data; - - build_gamma_lut( pv ); - - pv->deinterlaced_frames = 0; - pv->blended_frames = 0; - pv->unfiltered_frames = 0; - - pv->yadif_ready = 0; - - pv->mode = MODE_YADIF | MODE_BLEND | MODE_CUBIC | - MODE_GAMMA | MODE_FILTER; - pv->filter_mode = FILTER_ERODE_DILATE; - pv->spatial_metric = 2; - pv->motion_threshold = 3; - pv->spatial_threshold = 3; - pv->block_threshold = 40; - pv->block_width = 16; - pv->block_height = 16; - - pv->magnitude_threshold = 10; - pv->variance_threshold = 20; - pv->laplacian_threshold = 20; - pv->dilation_threshold = 4; - pv->erosion_threshold = 2; - pv->noise_threshold = 50; + hb_buffer_list_clear(&pv->out_list); + + pv->deinterlaced = 0; + pv->blended = 0; + pv->unfiltered = 0; + pv->frames = 0; + pv->yadif_ready = 0; + + pv->mode = MODE_DECOMB_YADIF | MODE_DECOMB_BLEND | + MODE_DECOMB_CUBIC; + pv->magnitude_threshold = 10; + pv->variance_threshold = 20; + pv->laplacian_threshold = 20; + pv->dilation_threshold = 4; + pv->erosion_threshold = 2; + pv->noise_threshold = 50; pv->maximum_search_distance = 24; - pv->post_processing = 1; - - pv->parity = PARITY_DEFAULT; + pv->post_processing = 1; + pv->parity = PARITY_DEFAULT; if (filter->settings) { @@ -2016,20 +961,10 @@ static int hb_decomb_init( hb_filter_object_t * filter, // Get comb detection settings hb_dict_extract_int(&pv->mode, dict, "mode"); - hb_dict_extract_int(&pv->spatial_metric, dict, "spatial-metric"); - hb_dict_extract_int(&pv->motion_threshold, dict, - "motion-thresh"); - hb_dict_extract_int(&pv->spatial_threshold, dict, - "spatial-thresh"); - hb_dict_extract_int(&pv->filter_mode, dict, "filter-mode"); - hb_dict_extract_int(&pv->block_threshold, dict, - "block-thresh"); - hb_dict_extract_int(&pv->block_width, dict, "block-width"); - hb_dict_extract_int(&pv->block_height, dict, "block-height"); // Get deinterlace settings hb_dict_extract_int(&pv->parity, dict, "parity"); - if (pv->mode & MODE_EEDI2) + if (pv->mode & MODE_DECOMB_EEDI2) { hb_dict_extract_int(&pv->magnitude_threshold, dict, "magnitude-thresh"); @@ -2060,19 +995,8 @@ static int hb_decomb_init( hb_filter_object_t * filter, pv->segment_height[1] = hb_image_height(init->pix_fmt, pv->segment_height[0], 1); pv->segment_height[2] = hb_image_height(init->pix_fmt, pv->segment_height[0], 2); - /* Allocate buffers to store comb masks. */ - pv->mask = hb_frame_buffer_init(init->pix_fmt, - init->geometry.width, init->geometry.height); - pv->mask_filtered = hb_frame_buffer_init(init->pix_fmt, - init->geometry.width, init->geometry.height); - pv->mask_temp = hb_frame_buffer_init(init->pix_fmt, - init->geometry.width, init->geometry.height); - memset(pv->mask->data, 0, pv->mask->size); - memset(pv->mask_filtered->data, 0, pv->mask_filtered->size); - memset(pv->mask_temp->data, 0, pv->mask_temp->size); - int ii; - if( pv->mode & MODE_EEDI2 ) + if( pv->mode & MODE_DECOMB_EEDI2 ) { /* Allocate half-height eedi2 buffers */ for( ii = 0; ii < 4; ii++ ) @@ -2141,276 +1065,7 @@ static int hb_decomb_init( hb_filter_object_t * filter, yadif_prev_thread_args = thread_args; } - /* - * Create comb detection taskset. - */ - if( taskset_init( &pv->decomb_filter_taskset, pv->cpu_count, - sizeof( decomb_thread_arg_t ) ) == 0 ) - { - hb_error( "decomb could not initialize taskset" ); - } - - decomb_thread_arg_t *decomb_prev_thread_args = NULL; - 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; - - int pp; - for (pp = 0; pp < 3; pp++) - { - if (decomb_prev_thread_args != NULL) - { - thread_args->segment_start[pp] = - decomb_prev_thread_args->segment_start[pp] + - decomb_prev_thread_args->segment_height[pp]; - } - if( ii == pv->cpu_count - 1 ) - { - /* - * Final segment - */ - thread_args->segment_height[pp] = - hb_image_height(init->pix_fmt, init->geometry.height, pp) - - thread_args->segment_start[pp]; - } else { - thread_args->segment_height[pp] = pv->segment_height[pp]; - } - } - - if( taskset_thread_spawn( &pv->decomb_filter_taskset, ii, - "decomb_filter_segment", - decomb_filter_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "decomb could not spawn thread" ); - } - - decomb_prev_thread_args = thread_args; - } - - pv->comb_check_nthreads = init->geometry.height / pv->block_height; - - if (pv->comb_check_nthreads > pv->cpu_count) - pv->comb_check_nthreads = pv->cpu_count; - - pv->block_score = calloc(pv->comb_check_nthreads, sizeof(int)); - - /* - * Create comb check taskset. - */ - if( taskset_init( &pv->decomb_check_taskset, pv->comb_check_nthreads, - sizeof( decomb_thread_arg_t ) ) == 0 ) - { - hb_error( "decomb check could not initialize taskset" ); - } - - decomb_prev_thread_args = NULL; - for( ii = 0; ii < pv->comb_check_nthreads; ii++ ) - { - decomb_thread_arg_t *thread_args; - - thread_args = taskset_thread_args( &pv->decomb_check_taskset, ii ); - thread_args->pv = pv; - thread_args->segment = ii; - - int pp; - for (pp = 0; pp < 3; pp++) - { - if (decomb_prev_thread_args != NULL) - { - thread_args->segment_start[pp] = - decomb_prev_thread_args->segment_start[pp] + - decomb_prev_thread_args->segment_height[pp]; - } - - // Make segment hight a multiple of block_height - int h = hb_image_height(init->pix_fmt, init->geometry.height, pp) / pv->comb_check_nthreads; - h = h / pv->block_height * pv->block_height; - if (h == 0) - h = pv->block_height; - - if (ii == pv->comb_check_nthreads - 1) - { - /* - * Final segment - */ - thread_args->segment_height[pp] = - hb_image_height(init->pix_fmt, init->geometry.height, pp) - - thread_args->segment_start[pp]; - } else { - thread_args->segment_height[pp] = h; - } - } - - if( taskset_thread_spawn( &pv->decomb_check_taskset, ii, - "decomb_check_segment", - decomb_check_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "decomb check could not spawn thread" ); - } - - decomb_prev_thread_args = thread_args; - } - - if( pv->mode & MODE_FILTER ) - { - if( taskset_init( &pv->mask_filter_taskset, pv->cpu_count, - sizeof( decomb_thread_arg_t ) ) == 0 ) - { - hb_error( "maske filter could not initialize taskset" ); - } - - decomb_prev_thread_args = NULL; - 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; - - int pp; - for (pp = 0; pp < 3; pp++) - { - if (decomb_prev_thread_args != NULL) - { - thread_args->segment_start[pp] = - decomb_prev_thread_args->segment_start[pp] + - decomb_prev_thread_args->segment_height[pp]; - } - - if( ii == pv->cpu_count - 1 ) - { - /* - * Final segment - */ - thread_args->segment_height[pp] = - hb_image_height(init->pix_fmt, init->geometry.height, pp) - - thread_args->segment_start[pp]; - } else { - thread_args->segment_height[pp] = pv->segment_height[pp]; - } - } - - if( taskset_thread_spawn( &pv->mask_filter_taskset, ii, - "mask_filter_segment", - mask_filter_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "mask filter could not spawn thread" ); - } - - decomb_prev_thread_args = thread_args; - } - - if( pv->filter_mode == FILTER_ERODE_DILATE ) - { - if( taskset_init( &pv->mask_erode_taskset, pv->cpu_count, - sizeof( decomb_thread_arg_t ) ) == 0 ) - { - hb_error( "mask erode could not initialize taskset" ); - } - - decomb_prev_thread_args = NULL; - 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; - - int pp; - for (pp = 0; pp < 3; pp++) - { - if (decomb_prev_thread_args != NULL) - { - thread_args->segment_start[pp] = - decomb_prev_thread_args->segment_start[pp] + - decomb_prev_thread_args->segment_height[pp]; - } - - if( ii == pv->cpu_count - 1 ) - { - /* - * Final segment - */ - thread_args->segment_height[pp] = - hb_image_height(init->pix_fmt, init->geometry.height, pp) - - thread_args->segment_start[pp]; - } else { - thread_args->segment_height[pp] = pv->segment_height[pp]; - } - } - - if( taskset_thread_spawn( &pv->mask_erode_taskset, ii, - "mask_erode_segment", - mask_erode_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "mask erode could not spawn thread" ); - } - - decomb_prev_thread_args = thread_args; - } - - if( taskset_init( &pv->mask_dilate_taskset, pv->cpu_count, - sizeof( decomb_thread_arg_t ) ) == 0 ) - { - hb_error( "mask dilate could not initialize taskset" ); - } - - decomb_prev_thread_args = NULL; - 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; - - int pp; - for (pp = 0; pp < 3; pp++) - { - if (decomb_prev_thread_args != NULL) - { - thread_args->segment_start[pp] = - decomb_prev_thread_args->segment_start[pp] + - decomb_prev_thread_args->segment_height[pp]; - } - - if( ii == pv->cpu_count - 1 ) - { - /* - * Final segment - */ - thread_args->segment_height[pp] = - hb_image_height(init->pix_fmt, init->geometry.height, pp) - - thread_args->segment_start[pp]; - } else { - thread_args->segment_height[pp] = pv->segment_height[pp]; - } - } - - if( taskset_thread_spawn( &pv->mask_dilate_taskset, ii, - "mask_dilate_segment", - mask_dilate_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "mask dilate could not spawn thread" ); - } - - decomb_prev_thread_args = thread_args; - } - } - } - - if( pv->mode & MODE_EEDI2 ) + if( pv->mode & MODE_DECOMB_EEDI2 ) { /* * Create eedi2 taskset. @@ -2477,28 +1132,16 @@ static void hb_decomb_close( hb_filter_object_t * filter ) return; } - hb_log("decomb: deinterlaced %i | blended %i | unfiltered %i | total %i", pv->deinterlaced_frames, pv->blended_frames, pv->unfiltered_frames, pv->deinterlaced_frames + pv->blended_frames + pv->unfiltered_frames); + hb_log("decomb: deinterlaced %i | blended %i | unfiltered %i | total %i", + pv->deinterlaced, pv->blended, pv->unfiltered, pv->frames); taskset_fini( &pv->yadif_taskset ); - taskset_fini( &pv->decomb_filter_taskset ); - taskset_fini( &pv->decomb_check_taskset ); - if( pv->mode & MODE_FILTER ) - { - taskset_fini( &pv->mask_filter_taskset ); - if( pv->filter_mode == FILTER_ERODE_DILATE ) - { - taskset_fini( &pv->mask_erode_taskset ); - taskset_fini( &pv->mask_dilate_taskset ); - } - } - - if( pv->mode & MODE_EEDI2 ) + if( pv->mode & MODE_DECOMB_EEDI2 ) { taskset_fini( &pv->eedi2_taskset ); } - /* Cleanup reference buffers. */ int ii; for (ii = 0; ii < 3; ii++) @@ -2506,12 +1149,7 @@ static void hb_decomb_close( hb_filter_object_t * filter ) hb_buffer_close(&pv->ref[ii]); } - /* Cleanup combing masks. */ - hb_buffer_close(&pv->mask); - hb_buffer_close(&pv->mask_filtered); - hb_buffer_close(&pv->mask_temp); - - if( pv->mode & MODE_EEDI2 ) + if( pv->mode & MODE_DECOMB_EEDI2 ) { /* Cleanup eedi-half buffers */ int ii; @@ -2527,7 +1165,7 @@ static void hb_decomb_close( hb_filter_object_t * filter ) } } - if( pv->post_processing > 1 && ( pv->mode & MODE_EEDI2 ) ) + if( pv->post_processing > 1 && ( pv->mode & MODE_DECOMB_EEDI2 ) ) { if (pv->cx2) eedi2_aligned_free(pv->cx2); if (pv->cy2) eedi2_aligned_free(pv->cy2); @@ -2535,8 +1173,6 @@ static void hb_decomb_close( hb_filter_object_t * filter ) if (pv->tmpc) eedi2_aligned_free(pv->tmpc); } - free(pv->block_score); - /* * free memory for yadif structs */ @@ -2568,26 +1204,92 @@ static void fill_stride(hb_buffer_t * buf) } } +static void process_frame( hb_filter_private_t * pv ) +{ + if ((pv->mode & MODE_DECOMB_SELECTIVE) && + pv->ref[1]->s.combed == HB_COMB_NONE) + { + // Input buffer is not combed. Just make a dup of it. + hb_buffer_t * buf = hb_buffer_dup(pv->ref[1]); + hb_buffer_list_append(&pv->out_list, buf); + pv->frames++; + pv->unfiltered++; + } + else + { + /* Determine if top-field first layout */ + int tff; + if (pv->parity < 0) + { + tff = !!(pv->ref[1]->s.flags & PIC_FLAG_TOP_FIELD_FIRST); + } + else + { + tff = (pv->parity & 1) ^ 1; + } + + /* deinterlace both fields if bob */ + int frame, num_frames = 1; + if (pv->mode & MODE_DECOMB_BOB) + { + num_frames = 2; + } + + // Will need up to 2 buffers simultaneously + + /* Perform yadif filtering */ + for (frame = 0; frame < num_frames; frame++) + { + hb_buffer_t * buf; + int parity = frame ^ tff ^ 1; + + // tff for eedi2 + pv->tff = !parity; + + buf = hb_frame_buffer_init(pv->ref[1]->f.fmt, + pv->ref[1]->f.width, + pv->ref[1]->f.height); + yadif_filter(pv, buf, parity, tff); + + /* Copy buffered settings to output buffer settings */ + buf->s = pv->ref[1]->s; + + hb_buffer_list_append(&pv->out_list, buf); + } + + /* if this frame was deinterlaced and bob mode is engaged, halve + the duration of the saved timestamps. */ + if (pv->mode & MODE_DECOMB_BOB) + { + hb_buffer_t *first = hb_buffer_list_head(&pv->out_list); + hb_buffer_t *second = hb_buffer_list_tail(&pv->out_list); + first->s.stop -= (first->s.stop - first->s.start) / 2LL; + second->s.start = first->s.stop; + second->s.new_chap = 0; + } + } +} + static int hb_decomb_work( hb_filter_object_t * filter, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_filter_private_t * pv = filter->private_data; hb_buffer_t * in = *buf_in; - hb_buffer_list_t list; - hb_buffer_list_clear(&list); + // Input buffer is always consumed. + *buf_in = NULL; if (in->s.flags & HB_BUF_FLAG_EOF) { - *buf_out = in; - *buf_in = NULL; + // Duplicate last frame and process refs + store_ref(pv, hb_buffer_dup(pv->ref[2])); + process_frame(pv); + hb_buffer_list_append(&pv->out_list, in); + *buf_out = hb_buffer_list_clear(&pv->out_list); return HB_FILTER_DONE; } - /* Store current frame in yadif cache */ - *buf_in = NULL; fill_stride(in); - store_ref(pv, in); // yadif requires 3 buffers, prev, cur, and next. For the first // frame, there can be no prev, so we duplicate the first frame. @@ -2595,106 +1297,16 @@ static int hb_decomb_work( hb_filter_object_t * filter, { // If yadif is not ready, store another ref and return HB_FILTER_DELAY store_ref(pv, hb_buffer_dup(in)); + store_ref(pv, in); pv->yadif_ready = 1; // Wait for next return HB_FILTER_DELAY; } - /* 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; - } - - /* deinterlace both fields if bob */ - int frame, num_frames = 1; - if (pv->mode & MODE_BOB) - { - num_frames = 2; - } - - // Will need up to 2 buffers simultaneously - int idx = 0; - hb_buffer_t * o_buf[2] = {NULL,}; - - /* Perform yadif filtering */ - for( frame = 0; frame < num_frames; frame++ ) - { - int parity = frame ^ tff ^ 1; - - /* Skip the second run if the frame is uncombed */ - if (frame && pv->is_combed == 0) - { - break; - } - - // tff for eedi2 - pv->tff = !parity; - - if (o_buf[idx] == NULL) - { - o_buf[idx] = hb_video_buffer_init(in->f.width, in->f.height); - } - - if (frame) - pv->skip_comb_check = 1; - else - pv->skip_comb_check = 0; - - yadif_filter(pv, o_buf[idx], parity, tff); - - // If bob, add all frames to output - // else, if not combed, add frame to output - // else if final iteration, add frame to output - if ((pv->mode & MODE_BOB) || - pv->is_combed == 0 || - frame == num_frames - 1) - { - /* Copy buffered settings to output buffer settings */ - o_buf[idx]->s = pv->ref[1]->s; - - o_buf[idx]->next = NULL; - hb_buffer_list_append(&list, o_buf[idx]); - - // Indicate that buffer was consumed - o_buf[idx] = NULL; - - idx ^= 1; - - if ((pv->mode & MODE_MASK) && pv->spatial_metric >= 0 ) - { - if (pv->mode == MODE_MASK || - ((pv->mode & MODE_MASK) && - (pv->mode & MODE_FILTER)) || - ((pv->mode & MODE_MASK) && - (pv->mode & MODE_GAMMA)) || - pv->is_combed) - { - apply_mask(pv, hb_buffer_list_tail(&list)); - } - } - } - } - hb_buffer_close(&o_buf[0]); - hb_buffer_close(&o_buf[1]); - - /* if this frame was deinterlaced and bob mode is engaged, halve - the duration of the saved timestamps. */ - if ((pv->mode & MODE_BOB) && pv->is_combed) - { - hb_buffer_t *first = hb_buffer_list_head(&list); - hb_buffer_t *second = hb_buffer_list_tail(&list); - first->s.stop -= (first->s.stop - first->s.start) / 2LL; - second->s.start = first->s.stop; - second->s.new_chap = 0; - } + store_ref(pv, in); + process_frame(pv); - *buf_out = hb_buffer_list_clear(&list); + *buf_out = hb_buffer_list_clear(&pv->out_list); return HB_FILTER_OK; } |