diff options
author | John Stebbins <[email protected]> | 2015-11-09 13:37:32 -0800 |
---|---|---|
committer | John Stebbins <[email protected]> | 2016-02-15 12:38:13 -0700 |
commit | 7e5bbec56e9ee7b47d54d6e8ebfe912467479608 (patch) | |
tree | 60c78771e72419cf2afbc5653797ff3d62be16ca | |
parent | bced9cf423c41335de91922863940b60fb183b28 (diff) |
deinterlace: use avfilter yadif deinterlacer
-rw-r--r-- | gtk/src/hb-backend.c | 2 | ||||
-rw-r--r-- | libhb/avfilter.c | 13 | ||||
-rw-r--r-- | libhb/builtin_presets.h | 2 | ||||
-rw-r--r-- | libhb/deinterlace.c | 667 | ||||
-rw-r--r-- | libhb/libhb_presets.list | 2 | ||||
-rw-r--r-- | libhb/param.c | 92 | ||||
-rw-r--r-- | libhb/preset.c | 110 | ||||
-rw-r--r-- | test/test.c | 10 |
8 files changed, 216 insertions, 682 deletions
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index ce262335e..ccadcfbd4 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -200,7 +200,7 @@ static options_map_t d_deint_opts[] = { {N_("Off"), "off", HB_FILTER_INVALID, ""}, {N_("Decomb"), "decomb", HB_FILTER_DECOMB, ""}, - {N_("Deinterlace"), "deinterlace", HB_FILTER_DEINTERLACE, ""}, + {N_("Yadif"), "deinterlace", HB_FILTER_DEINTERLACE, ""}, }; combo_opts_t deint_opts = { diff --git a/libhb/avfilter.c b/libhb/avfilter.c index b145b7a0d..4c1f1d165 100644 --- a/libhb/avfilter.c +++ b/libhb/avfilter.c @@ -74,6 +74,18 @@ hb_filter_object_t hb_filter_rotate = .info = avfilter_info, }; +hb_filter_object_t hb_filter_deinterlace = +{ + .id = HB_FILTER_DEINTERLACE, + .enforce_order = 1, + .name = "avfilter", + .settings = NULL, + .init = avfilter_init, + .work = avfilter_work, + .close = avfilter_close, + .info = avfilter_info, +}; + static AVFilterContext * append_filter( hb_filter_private_t * pv, const char * name, const char * args) { @@ -429,6 +441,7 @@ void hb_avfilter_combine( hb_list_t * list ) { case HB_FILTER_AVFILTER: case HB_FILTER_ROTATE: + case HB_FILTER_DEINTERLACE: case HB_FILTER_PAD: if (avfilter != NULL) { diff --git a/libhb/builtin_presets.h b/libhb/builtin_presets.h index fa4236e3f..5ab646f19 100644 --- a/libhb/builtin_presets.h +++ b/libhb/builtin_presets.h @@ -858,6 +858,6 @@ const char hb_builtin_presets_json[] = " }, \n" " \"VersionMajor\": 11, \n" " \"VersionMicro\": 0, \n" -" \"VersionMinor\": 0\n" +" \"VersionMinor\": 1\n" " }\n" "}\n"; diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c deleted file mode 100644 index a402a5253..000000000 --- a/libhb/deinterlace.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - Copyright (C) 2006 Michael Niedermayer <[email protected]> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "hb.h" -#include "hbffmpeg.h" -#include "taskset.h" - -// yadif_mode is a bit vector with the following flags -#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 ABS(a) ((a) > 0 ? (a) : (-(a))) -#define MIN3(a,b,c) MIN(MIN(a,b),c) -#define MAX3(a,b,c) MAX(MAX(a,b),c) - -typedef struct yadif_arguments_s { - hb_buffer_t * dst; - int parity; - int tff; -} yadif_arguments_t; - -typedef struct deint_arguments_s { - hb_buffer_t * src; - hb_buffer_t * dst; -} deint_arguments_t; - -typedef struct deint_thread_arg_s { - hb_filter_private_t *pv; - int segment; -} deint_thread_arg_t; - -struct hb_filter_private_s -{ - int width; - int height; - - int yadif_mode; - int yadif_parity; - int yadif_ready; - - hb_buffer_t * yadif_ref[3]; - - int cpu_count; - int segments; - - int deint_nsegs; - - taskset_t deint_taskset; // Threads for fast deint - taskset_t yadif_taskset; // Threads for Yadif - - deint_arguments_t *deint_arguments; // Arguments to thread for work - yadif_arguments_t *yadif_arguments; // Arguments to thread for work -}; - -static int hb_deinterlace_init( hb_filter_object_t * filter, - hb_filter_init_t * init ); - -static int hb_deinterlace_work( hb_filter_object_t * filter, - hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ); - -static void hb_deinterlace_close( hb_filter_object_t * filter ); - -hb_filter_object_t hb_filter_deinterlace = -{ - .id = HB_FILTER_DEINTERLACE, - .enforce_order = 1, - .name = "Deinterlace", - .settings = NULL, - .init = hb_deinterlace_init, - .work = hb_deinterlace_work, - .close = hb_deinterlace_close, -}; - - -static void yadif_store_ref(hb_filter_private_t *pv, hb_buffer_t *b) -{ - - hb_buffer_close(&pv->yadif_ref[0]); - memmove(&pv->yadif_ref[0], &pv->yadif_ref[1], sizeof(hb_buffer_t *) * 2 ); - pv->yadif_ref[2] = b; -} - -static void yadif_filter_line( - hb_filter_private_t * pv, - uint8_t * dst, - uint8_t * prev, - uint8_t * cur, - uint8_t * next, - int width, - int stride, - int parity) -{ - uint8_t *prev2 = parity ? prev : cur ; - uint8_t *next2 = parity ? cur : next; - - int x; - for( x = 0; x < width; x++) - { - int c = cur[-stride]; - int d = (prev2[0] + next2[0])>>1; - int e = cur[+stride]; - int temporal_diff0 = ABS(prev2[0] - next2[0]); - int temporal_diff1 = ( ABS(prev[-stride] - c) + ABS(prev[+stride] - e) ) >> 1; - int temporal_diff2 = ( ABS(next[-stride] - c) + ABS(next[+stride] - e) ) >> 1; - int diff = MAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2); - int spatial_pred = (c+e)>>1; - int spatial_score = ABS(cur[-stride-1] - cur[+stride-1]) + ABS(c-e) + - ABS(cur[-stride+1] - cur[+stride+1]) - 1; - -#define YADIF_CHECK(j)\ - { int score = ABS(cur[-stride-1+j] - cur[+stride-1-j])\ - + ABS(cur[-stride +j] - cur[+stride -j])\ - + ABS(cur[-stride+1+j] - cur[+stride+1-j]);\ - if( score < spatial_score ){\ - spatial_score = score;\ - spatial_pred = (cur[-stride +j] + cur[+stride -j])>>1;\ - - YADIF_CHECK(-1) YADIF_CHECK(-2) }} }} - YADIF_CHECK( 1) YADIF_CHECK( 2) }} }} - - if( pv->yadif_mode & MODE_YADIF_SPATIAL ) - { - int b = (prev2[-2*stride] + next2[-2*stride])>>1; - int f = (prev2[+2*stride] + next2[+2*stride])>>1; - - int max = MAX3(d-e, d-c, MIN(b-c, f-e)); - int min = MIN3(d-e, d-c, MAX(b-c, f-e)); - - diff = MAX3( diff, min, -max ); - } - - if( spatial_pred > d + diff ) - { - spatial_pred = d + diff; - } - else if( spatial_pred < d - diff ) - { - spatial_pred = d - diff; - } - - dst[0] = spatial_pred; - - dst++; - cur++; - prev++; - next++; - prev2++; - next2++; - } -} - -typedef struct yadif_thread_arg_s { - hb_filter_private_t *pv; - int segment; -} yadif_thread_arg_t; - -/* - * deinterlace this segment of all three planes in a single thread. - */ -void yadif_filter_thread( void *thread_args_v ) -{ - yadif_arguments_t *yadif_work = NULL; - hb_filter_private_t * pv; - int run = 1; - int segment, segment_start, segment_stop; - yadif_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("Yadif Deinterlace thread started for segment %d", segment); - - while( run ) - { - /* - * 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. - */ - run = 0; - goto report_completion; - } - - yadif_work = &pv->yadif_arguments[segment]; - - if( yadif_work->dst == NULL ) - { - hb_error( "Thread started when no work available" ); - goto report_completion; - } - - /* - * Process all three planes, but only this segment of it. - */ - int pp; - for(pp = 0; pp < 3; pp++) - { - hb_buffer_t *dst = yadif_work->dst; - int w = dst->plane[pp].width; - int s = dst->plane[pp].stride; - int h = dst->plane[pp].height; - int yy; - int parity = yadif_work->parity; - int tff = yadif_work->tff; - int penultimate = h - 2; - - int segment_height = (h / pv->segments) & ~1; - segment_start = segment_height * segment; - if( segment == pv->segments - 1 ) - { - /* - * Final segment - */ - segment_stop = h; - } else { - segment_stop = segment_height * ( segment + 1 ); - } - - uint8_t *dst2 = &dst->plane[pp].data[segment_start * s]; - uint8_t *prev = &pv->yadif_ref[0]->plane[pp].data[segment_start * s]; - uint8_t *cur = &pv->yadif_ref[1]->plane[pp].data[segment_start * s]; - uint8_t *next = &pv->yadif_ref[2]->plane[pp].data[segment_start * s]; - for( yy = segment_start; yy < segment_stop; yy++ ) - { - if(((yy ^ parity) & 1)) - { - /* This 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( yy > 1 && yy < penultimate ) - { - /* This isn't the top or bottom, - * proceed as normal to yadif. */ - yadif_filter_line(pv, dst2, prev, cur, next, w, s, - parity ^ tff); - } - else - { - // parity == 0 (TFF), y1 = y0 - // parity == 1 (BFF), y0 = y1 - // parity == 0 (TFF), yu = yp - // parity == 1 (BFF), yp = yu - uint8_t *src = &pv->yadif_ref[1]->plane[pp].data[(yy^parity)*s]; - memcpy(dst2, src, w); - } - } - else - { - /* Preserve this field unfiltered */ - memcpy(dst2, cur, w); - } - dst2 += s; - prev += s; - cur += s; - next += s; - } - } - -report_completion: - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->yadif_taskset, segment ); - } -} - - -/* - * threaded yadif - each thread deinterlaces a single segment of all - * three planes. Where a segment is defined as the frame divided by - * the number of CPUs. - * - * This function blocks until the frame is deinterlaced. - */ -static void yadif_filter( hb_filter_private_t * pv, - hb_buffer_t * dst, int parity, int tff) -{ - - int segment; - - for( segment = 0; segment < pv->segments; segment++ ) - { - /* - * Setup the work for this plane. - */ - pv->yadif_arguments[segment].parity = parity; - pv->yadif_arguments[segment].tff = tff; - pv->yadif_arguments[segment].dst = dst; - } - - /* Allow the taskset threads to make one pass over the data. */ - taskset_cycle( &pv->yadif_taskset ); - - /* - * Entire frame is now deinterlaced. - */ -} - -/* - * deinterlace a frame in a single thread. - */ -void deint_filter_thread( void *thread_args_v ) -{ - deint_arguments_t *args = NULL; - hb_filter_private_t * pv; - int run = 1; - int segment; - deint_thread_arg_t *thread_args = thread_args_v; - - pv = thread_args->pv; - segment = thread_args->segment; - - hb_log("Fast Deinterlace thread started for segment %d", segment); - - while( run ) - { - /* - * Wait here until there is work to do. - */ - taskset_thread_wait4start( &pv->deint_taskset, segment ); - - - if( taskset_thread_stop( &pv->deint_taskset, segment ) ) - { - /* - * No more work to do, exit this thread. - */ - run = 0; - goto report_completion; - } - - args = &pv->deint_arguments[segment]; - - if( args->dst == NULL ) - { - // This can happen when flushing final buffers. - goto report_completion; - } - - /* - * Process all three planes, but only this segment of it. - */ - hb_deinterlace(args->dst, args->src); - -report_completion: - /* - * Finished this segment, let everyone know. - */ - taskset_thread_complete( &pv->deint_taskset, segment ); - } -} - -/* - * threaded fast deint - each thread deinterlaces a single frame. - * - * This function blocks until all frames are deinterlaced. - */ -static hb_buffer_t * deint_fast(hb_filter_private_t * pv, hb_buffer_t * in) -{ - - int ii; - hb_buffer_t *dst, *src; - hb_buffer_list_t list; - - hb_buffer_list_clear(&list); - if (in != NULL) - { - dst = hb_frame_buffer_init(in->f.fmt, in->f.width, in->f.height); - pv->deint_arguments[pv->deint_nsegs].src = in; - pv->deint_arguments[pv->deint_nsegs].dst = dst; - pv->deint_nsegs++; - } - if (in != NULL && pv->deint_nsegs < pv->segments) - { - return NULL; - } - - if (pv->deint_nsegs > 0) - { - /* Allow the taskset threads to make one pass over the data. */ - taskset_cycle( &pv->deint_taskset ); - } - - for (ii = 0; ii < pv->deint_nsegs; ii++) - { - src = pv->deint_arguments[ii].src; - dst = pv->deint_arguments[ii].dst; - pv->deint_arguments[ii].src = NULL; - pv->deint_arguments[ii].dst = NULL; - hb_buffer_list_append(&list, dst); - - dst->s = src->s; - hb_buffer_close(&src); - } - pv->deint_nsegs = 0; - - return hb_buffer_list_clear(&list); -} - -static int hb_deinterlace_init( hb_filter_object_t * filter, - hb_filter_init_t * init ) -{ - filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); - hb_filter_private_t * pv = filter->private_data; - - pv->width = init->geometry.width; - pv->height = init->geometry.height; - - pv->yadif_ready = 0; - pv->yadif_mode = YADIF_MODE_DEFAULT; - pv->yadif_parity = YADIF_PARITY_DEFAULT; - - if( filter->settings ) - { - sscanf( filter->settings, "%d:%d", - &pv->yadif_mode, - &pv->yadif_parity); - } - - pv->cpu_count = hb_get_cpu_count(); - - /* Allocate yadif specific buffers */ - if( pv->yadif_mode & MODE_YADIF_ENABLE ) - { - /* - * Setup yadif taskset. - */ - pv->segments = pv->cpu_count; - pv->yadif_arguments = malloc( sizeof( yadif_arguments_t ) * pv->segments ); - if( pv->yadif_arguments == NULL || - taskset_init( &pv->yadif_taskset, /*thread_count*/pv->segments, - sizeof( yadif_thread_arg_t ) ) == 0 ) - { - hb_error( "yadif could not initialize taskset" ); - } - - int ii; - for( ii = 0; ii < pv->segments; ii++ ) - { - yadif_thread_arg_t *thread_args; - - thread_args = taskset_thread_args( &pv->yadif_taskset, ii ); - - thread_args->pv = pv; - thread_args->segment = ii; - pv->yadif_arguments[ii].dst = NULL; - - if( taskset_thread_spawn( &pv->yadif_taskset, ii, - "yadif_filter_segment", - yadif_filter_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "yadif could not spawn thread" ); - } - } - } - else - { - /* - * Setup fast deint taskset. - */ - pv->segments = pv->cpu_count; - pv->deint_arguments = malloc( sizeof( deint_arguments_t ) * pv->segments ); - if( pv->deint_arguments == NULL || - taskset_init( &pv->deint_taskset, pv->segments, - sizeof( deint_thread_arg_t ) ) == 0 ) - { - hb_error( "deint could not initialize taskset" ); - } - - int ii; - for( ii = 0; ii < pv->segments; ii++ ) - { - deint_thread_arg_t *thread_args; - - thread_args = taskset_thread_args( &pv->deint_taskset, ii ); - - thread_args->pv = pv; - thread_args->segment = ii; - pv->deint_arguments[ii].dst = NULL; - - if( taskset_thread_spawn( &pv->deint_taskset, ii, - "deint_filter_segment", - deint_filter_thread, - HB_NORMAL_PRIORITY ) == 0 ) - { - hb_error( "deint could not spawn thread" ); - } - } - } - - return 0; -} - -static void hb_deinterlace_close( hb_filter_object_t * filter ) -{ - hb_filter_private_t * pv = filter->private_data; - - if( !pv ) - { - return; - } - - /* Cleanup yadif specific buffers */ - if( pv->yadif_mode & MODE_YADIF_ENABLE ) - { - taskset_fini( &pv->yadif_taskset ); - - int ii; - for(ii = 0; ii < 3; ii++) - { - hb_buffer_close(&pv->yadif_ref[ii]); - } - - free( pv->yadif_arguments ); - } - else - { - taskset_fini( &pv->deint_taskset ); - free( pv->deint_arguments ); - } - - free( pv ); - filter->private_data = NULL; -} - -static int hb_deinterlace_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; - - *buf_in = NULL; - hb_buffer_list_clear(&list); - if (in->s.flags & HB_BUF_FLAG_EOF) - { - if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) ) - { - // Flush final frames - hb_buffer_list_append(&list, deint_fast(pv, NULL)); - } - hb_buffer_list_append(&list, in); - - *buf_out = hb_buffer_list_clear(&list); - return HB_FILTER_DONE; - } - - /* Use fast deinterlace if yadif_mode < 0 */ - if( !( pv->yadif_mode & MODE_YADIF_ENABLE ) ) - { - *buf_out = deint_fast(pv, in); - return HB_FILTER_OK; - } - - /* Store current frame in yadif cache */ - yadif_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. - if (!pv->yadif_ready) - { - // If yadif is not ready, store another ref and return HB_FILTER_DELAY - yadif_store_ref(pv, hb_buffer_dup(in)); - pv->yadif_ready = 1; - // Wait for next - return HB_FILTER_DELAY; - } - - /* 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; - } - - /* deinterlace both fields if yadif 2 pass or bob */ - int frame, num_frames = 1; - if ((pv->yadif_mode & MODE_YADIF_2PASS) || - (pv->yadif_mode & MODE_YADIF_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; - - if (o_buf[idx] == NULL) - { - o_buf[idx] = hb_frame_buffer_init(in->f.fmt, - in->f.width, in->f.height); - } - yadif_filter(pv, o_buf[idx], parity, tff); - - // If bob, add both frames - // else, add only final frame - if (( pv->yadif_mode & MODE_YADIF_BOB ) || frame == num_frames - 1) - { - /* Copy buffered settings to output buffer settings */ - o_buf[idx]->s = pv->yadif_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; - } - } - hb_buffer_close(&o_buf[0]); - hb_buffer_close(&o_buf[1]); - - /* if bob mode is engaged, halve the duration of the - * timestamps. */ - if (pv->yadif_mode & MODE_YADIF_BOB) - { - 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; - } - - *buf_out = hb_buffer_list_clear(&list); - return HB_FILTER_OK; -} - diff --git a/libhb/libhb_presets.list b/libhb/libhb_presets.list index cc972f0f2..4afc94091 100644 --- a/libhb/libhb_presets.list +++ b/libhb/libhb_presets.list @@ -1,7 +1,7 @@ <resources> <section name="PresetTemplate"> <integer name="VersionMajor" value="11" /> - <integer name="VersionMinor" value="0" /> + <integer name="VersionMinor" value="1" /> <integer name="VersionMicro" value="0" /> <json name="Preset" file="preset_template.json" /> </section> diff --git a/libhb/param.c b/libhb/param.c index 8deaed3c3..3a9402021 100644 --- a/libhb/param.c +++ b/libhb/param.c @@ -67,13 +67,14 @@ static hb_filter_param_t decomb_presets[] = static hb_filter_param_t deinterlace_presets[] = { - { 1, "Custom", "custom", NULL }, - { 2, "Fast", "fast", "0:-1:-1:0:1" }, - { 3, "Slow", "slow", "1:-1:-1:0:1" }, - { 4, "Slower", "slower", "3:-1:-1:0:1" }, - { 5, "Bob", "bob", "15:-1:-1:0:1" }, - { 0, NULL, NULL, NULL }, - { 2, "Default", "default", "0:-1:-1:0:1" } + { 1, "Custom", "custom", NULL }, + { 3, "Default", "default", "3:-1" }, + { 2, "Skip Spatial Check", "skip-spatial", "1:-1" }, + { 5, "Bob", "bob", "7:-1" }, + { 0, NULL, NULL, NULL }, + { 2, "Fast", "fast", "1:-1:" }, + { 3, "Slow", "slow", "3:-1:" }, + { 4, "Slower", "slower", "3:-1:" } }; typedef struct @@ -104,7 +105,58 @@ static filter_param_map_t param_map[] = { HB_FILTER_INVALID, NULL, NULL, 0 } }; -/* Settings: +#define MODE_YADIF_ENABLE 1 +#define MODE_YADIF_SPATIAL 2 +#define MODE_YADIF_BOB 4 + +/* Deinterlace Settings + * mode:parity + * + * mode - yadif deinterlace mode + * parity - field parity + * + * Modes: + * 1 = Enabled + * 2 = Spatial + * 4 = Bob + * + * Parity: + * 0 = Top Field First + * 1 = Bottom Field First + * -1 = Automatic detection of field parity + */ +char * +generate_deinterlace_settings(const char * settings) +{ + char ** args; + char * result; + int ii, mode = 3, parity = -1; + + args = hb_str_vsplit(settings, ':'); + for (ii = 0; ii < 2 && args[ii]; ii++) + { + switch (ii) + { + case 0: + mode = strtol(args[ii], &result, 0); + break; + case 1: + parity = strtol(args[ii], &result, 0); + break; + } + } + if (!(mode & MODE_YADIF_ENABLE)) + { + return (char*)hb_filter_off; + } + int bob = !!(mode & MODE_YADIF_BOB); + int no_spatial = !(mode & MODE_YADIF_SPATIAL); + mode = bob | (no_spatial << 1); + + return hb_strdup_printf("yadif='mode=%d:parity=%d'", mode, parity); +} + +/* Rotate Settings: * degrees:mirror * * degrees - Rotation angle, may be one of 90, 180, or 270 @@ -700,12 +752,22 @@ hb_generate_filter_settings_by_index(int filter_id, int preset, filter_param = hb_strdup_printf("%d", preset); break; case HB_FILTER_DECOMB: - case HB_FILTER_DEINTERLACE: case HB_FILTER_DETELECINE: case HB_FILTER_HQDN3D: filter_param = generate_generic_settings_by_index(filter_id, preset, custom); break; + case HB_FILTER_DEINTERLACE: + { + char * s; + s = generate_generic_settings_by_index(filter_id, preset, custom); + if (s == NULL || hb_validate_filter_settings(filter_id, s)) + { + free(s); + return NULL; + } + return generate_deinterlace_settings(s); + } break; default: fprintf(stderr, "hb_generate_filter_settings: Unrecognized filter (%d).\n", @@ -754,11 +816,21 @@ hb_generate_filter_settings(int filter_id, const char *preset, const char *tune) filter_param = strdup(preset); break; case HB_FILTER_DECOMB: - case HB_FILTER_DEINTERLACE: case HB_FILTER_DETELECINE: case HB_FILTER_HQDN3D: filter_param = generate_generic_settings(filter_id, preset, tune); break; + case HB_FILTER_DEINTERLACE: + { + char * s; + s = generate_generic_settings(filter_id, preset, tune); + if (s == NULL || hb_validate_filter_settings(filter_id, s)) + { + free(s); + return NULL; + } + return generate_deinterlace_settings(s); + } break; default: fprintf(stderr, "hb_generate_filter_settings: Unrecognized filter (%d).\n", diff --git a/libhb/preset.c b/libhb/preset.c index bc84965e1..1670b469b 100644 --- a/libhb/preset.c +++ b/libhb/preset.c @@ -1969,6 +1969,79 @@ void hb_presets_clean(hb_value_t *preset) presets_clean(preset, hb_preset_template); } +static void import_deint_11_0_0(hb_value_t *preset) +{ + hb_value_t *val = hb_dict_get(preset, "PictureDeinterlaceFilter"); + if (val == NULL) + { + return; + } + const char * deint = hb_value_get_string(val); + if (deint == NULL) + { + // This really shouldn't happen for a valid preset + return; + } + if (strcasecmp(deint, "deinterlace")) + { + return; + } + val = hb_dict_get(preset, "PictureDeinterlacePreset"); + if (val == NULL) + { + hb_dict_set(preset, "PictureDeinterlacePreset", + hb_value_string("default")); + return; + } + deint = hb_value_get_string(val); + if (deint == NULL) + { + // This really shouldn't happen for a valid preset + return; + } + if (!strcasecmp(deint, "fast") || !strcasecmp(deint, "slow")) + { + // fast and slow -> skip-spatial + hb_dict_set(preset, "PictureDeinterlacePreset", + hb_value_string("skip-spatial")); + return; + } + else if (!strcasecmp(deint, "bob") || !strcasecmp(deint, "default")) + { + return; + } + else if (strcasecmp(deint, "custom")) + { + // not custom -> default + hb_dict_set(preset, "PictureDeinterlacePreset", + hb_value_string("default")); + return; + } + val = hb_dict_get(preset, "PictureDeinterlaceCustom"); + if (val == NULL) + { + hb_dict_set(preset, "PictureDeinterlacePreset", + hb_value_string("default")); + return; + } + // Translate custom values + deint = hb_value_get_string(val); + if (deint == NULL) + { + // This really shouldn't happen for a valid preset + return; + } + int bob, spatial, yadif, mode = 3, parity = -1; + sscanf(deint, "%d:%d", &mode, &parity); + yadif = !!(mode & 1); + spatial = !!(mode & 2); + bob = !!(mode & 8); + mode = yadif + (yadif && spatial) * 2 + bob * 4; + char * custom = hb_strdup_printf("%d:%d", mode, parity); + hb_dict_set(preset, "PictureDeinterlaceCustom", hb_value_string(custom)); + free(custom); +} + static void import_deint_10_0_0(hb_value_t *preset) { hb_value_t *val = hb_dict_get(preset, "PictureDecombDeinterlace"); @@ -2002,6 +2075,7 @@ static void import_deint_10_0_0(hb_value_t *preset) hb_value_string("default")); } } + import_deint_11_0_0(preset); } static const char* import_indexed_filter(int filter_id, int index) @@ -2277,6 +2351,11 @@ static void import_10_0_0(hb_value_t *preset) import_deint_10_0_0(preset); } +static void import_11_0_0(hb_value_t *preset) +{ + import_deint_11_0_0(preset); +} + static int preset_import(hb_value_t *preset, int major, int minor, int micro) { int result = 0; @@ -2294,6 +2373,11 @@ static int preset_import(hb_value_t *preset, int major, int minor, int micro) import_10_0_0(preset); result = 1; } + else if (major == 11 && minor == 0 && micro == 0) + { + import_11_0_0(preset); + result = 1; + } preset_clean(preset, hb_preset_template); } return result; @@ -2321,6 +2405,28 @@ int hb_presets_version(hb_value_t *preset, int *major, int *minor, int *micro) return -1; } +void hb_presets_update_version(hb_value_t *preset) +{ + if (hb_value_type(preset) == HB_VALUE_TYPE_DICT) + { + // Is this a single preset or a packaged collection of presets? + hb_value_t *val = hb_dict_get(preset, "PresetName"); + if (val == NULL) + { + val = hb_dict_get(preset, "VersionMajor"); + if (val != NULL) + { + hb_dict_set(preset, "VersionMajor", + hb_value_int(hb_preset_version_major)); + hb_dict_set(preset, "VersionMinor", + hb_value_int(hb_preset_version_minor)); + hb_dict_set(preset, "VersionMicro", + hb_value_int(hb_preset_version_micro)); + } + } + } +} + int hb_presets_import(hb_value_t *preset) { preset_import_context_t ctx; @@ -2329,6 +2435,10 @@ int hb_presets_import(hb_value_t *preset) ctx.result = 0; hb_presets_version(preset, &ctx.major, &ctx.minor, &ctx.micro); presets_do(do_preset_import, preset, (preset_do_context_t*)&ctx); + if (ctx.result) + { + hb_presets_update_version(preset); + } return ctx.result; } diff --git a/test/test.c b/test/test.c index a5179c702..47bdbe417 100644 --- a/test/test.c +++ b/test/test.c @@ -1262,7 +1262,13 @@ static void ShowHelp() "\n" "### Filters---------------------------------------------------------------\n\n" " -d, --deinterlace Unconditionally deinterlaces all frames\n" -" <fast/slow/slower/bob"); +" <"); +hb_filter_param_t * param = hb_filter_param_get_presets(HB_FILTER_DEINTERLACE); +// Skip "custom" +for (i = 1; param != NULL && param[i].name != NULL; i++) +{ + fprintf(out, "%s%s", i > 1 ? "/" : "", param[i].short_name); +} #ifdef USE_QSV if (hb_qsv_available()) { @@ -1271,7 +1277,7 @@ if (hb_qsv_available()) #endif fprintf( out, "> or omitted (default settings)\n" " or\n" -" <YM:FD> (default 0:-1)\n" +" <YM:FP> Yadif Mode:Field Parity (default 3:-1)\n" " --no-deinterlace Disable preset deinterlace filter\n" " -5, --decomb Selectively deinterlaces when it detects combing\n" " <fast/bob> or omitted (default settings)\n" |