diff options
author | John Stebbins <[email protected]> | 2016-02-20 18:00:46 -0700 |
---|---|---|
committer | John Stebbins <[email protected]> | 2016-03-09 13:10:10 -0700 |
commit | a44ccb49f182d4eeb122fbe675b28deb5c36b793 (patch) | |
tree | 6cc064cc24dacc2a80d41fb9543640c9004895af | |
parent | 96c02dd6f256f4a4e74f8962f56502d28e5e65a3 (diff) |
filters: make job filter settings an hb_dict_t
This simplifies accessing and changing filter parameters
programatically. It also changes the custom filter string format to a
':' separated list of key/value pairs.
-rw-r--r-- | gtk/src/hb-backend.c | 54 | ||||
-rw-r--r-- | gtk/src/queuehandler.c | 16 | ||||
-rw-r--r-- | libhb/avfilter.c | 416 | ||||
-rw-r--r-- | libhb/builtin_presets.h | 7 | ||||
-rw-r--r-- | libhb/common.c | 299 | ||||
-rw-r--r-- | libhb/common.h | 56 | ||||
-rw-r--r-- | libhb/cropscale.c | 35 | ||||
-rw-r--r-- | libhb/deblock.c | 24 | ||||
-rw-r--r-- | libhb/decomb.c | 115 | ||||
-rw-r--r-- | libhb/denoise.c | 106 | ||||
-rw-r--r-- | libhb/detelecine.c | 40 | ||||
-rw-r--r-- | libhb/hb.c | 77 | ||||
-rw-r--r-- | libhb/hb.h | 6 | ||||
-rw-r--r-- | libhb/hb_dict.c | 238 | ||||
-rw-r--r-- | libhb/hb_dict.h | 34 | ||||
-rw-r--r-- | libhb/hb_json.c | 11 | ||||
-rw-r--r-- | libhb/hbtypes.h | 49 | ||||
-rw-r--r-- | libhb/libhb_presets.list | 4 | ||||
-rw-r--r-- | libhb/nlmeans.c | 51 | ||||
-rw-r--r-- | libhb/param.c | 833 | ||||
-rw-r--r-- | libhb/param.h | 26 | ||||
-rw-r--r-- | libhb/preset.c | 332 | ||||
-rw-r--r-- | libhb/preset_template.json | 3 | ||||
-rw-r--r-- | libhb/qsv_filter.c | 37 | ||||
-rw-r--r-- | libhb/vfr.c | 27 | ||||
-rw-r--r-- | libhb/work.c | 36 | ||||
-rw-r--r-- | test/test.c | 308 |
27 files changed, 2213 insertions, 1027 deletions
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index ccadcfbd4..2a8d79bb9 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -3741,12 +3741,10 @@ ghb_validate_filters(GhbValue *settings, GtkWindow *parent) "PictureDeinterlaceFilter"); deint_preset = ghb_dict_get_string(settings, "PictureDeinterlacePreset"); - if (!strcasecmp(deint_preset, "custom")) - { - deint_custom = ghb_dict_get_string(settings, - "PictureDeinterlaceCustom"); - } - if (hb_validate_filter_preset(filter_id, deint_preset, deint_custom)) + deint_custom = ghb_dict_get_string(settings, + "PictureDeinterlaceCustom"); + if (hb_validate_filter_preset(filter_id, deint_preset, NULL, + deint_custom)) { if (deint_custom != NULL) { @@ -3780,12 +3778,9 @@ ghb_validate_filters(GhbValue *settings, GtkWindow *parent) int filter_id; filter_id = HB_FILTER_DETELECINE; - if (!strcasecmp(detel_preset, "custom")) - { - detel_custom = ghb_dict_get_string(settings, - "PictureDetelecineCustom"); - } - if (hb_validate_filter_preset(filter_id, detel_preset, detel_custom)) + detel_custom = ghb_dict_get_string(settings, "PictureDetelecineCustom"); + if (hb_validate_filter_preset(filter_id, detel_preset, NULL, + detel_custom)) { if (detel_custom != NULL) { @@ -3820,32 +3815,17 @@ ghb_validate_filters(GhbValue *settings, GtkWindow *parent) { denoise_tune = ghb_dict_get_string(settings, "PictureDenoiseTune"); } - if (!strcasecmp(denoise_preset, "custom")) + denoise_custom = ghb_dict_get_string(settings, "PictureDenoiseCustom"); + if (hb_validate_filter_preset(filter_id, denoise_preset, denoise_tune, + denoise_custom)) { - denoise_custom = ghb_dict_get_string(settings, - "PictureDenoiseCustom"); - } - if (hb_validate_filter_preset(filter_id, denoise_preset, - denoise_custom != NULL ? denoise_custom : denoise_tune)) - { - if (denoise_custom != NULL) - { - message = g_strdup_printf( - _("Invalid Denoise Settings:\n\n" - "Filter: %s\n" - "Preset: %s\n" - "Custom: %s\n"), denoise_filter, denoise_preset, - denoise_custom); - } - else - { - message = g_strdup_printf( - _("Invalid Denoise Settings:\n\n" - "Filter: %s\n" - "Preset: %s\n" - "Tune: %s\n"), denoise_filter, denoise_preset, - denoise_tune); - } + message = g_strdup_printf( + _("Invalid Denoise Settings:\n\n" + "Filter: %s\n" + "Preset: %s\n" + "Tune: %s\n" + "Custom: %s\n"), denoise_filter, denoise_preset, + denoise_tune, denoise_custom); ghb_message_dialog(parent, GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(message); diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c index 8d13b499b..2365d0e04 100644 --- a/gtk/src/queuehandler.c +++ b/gtk/src/queuehandler.c @@ -1071,7 +1071,6 @@ void ghb_finalize_job(GhbValue *settings) // Add scale filter since the above does not GhbValue *filter_list, *filter_dict; int width, height, crop[4]; - char *filter_str; filter_list = ghb_get_job_filter_list(settings); width = ghb_dict_get_int(settings, "scale_width"); @@ -1082,13 +1081,18 @@ void ghb_finalize_job(GhbValue *settings) crop[2] = ghb_dict_get_int(settings, "PictureLeftCrop"); crop[3] = ghb_dict_get_int(settings, "PictureRightCrop"); - filter_str = g_strdup_printf("%d:%d:%d:%d:%d:%d", - width, height, crop[0], crop[1], crop[2], crop[3]); + hb_dict_t * dict = ghb_dict_new(); + ghb_dict_set_int(dict, "width", width); + ghb_dict_set_int(dict, "height", height); + ghb_dict_set_int(dict, "crop-top", crop[0]); + ghb_dict_set_int(dict, "crop-bottom", crop[1]); + ghb_dict_set_int(dict, "crop-left", crop[2]); + ghb_dict_set_int(dict, "crop-right", crop[3]); + filter_dict = ghb_dict_new(); ghb_dict_set_int(filter_dict, "ID", HB_FILTER_CROP_SCALE); - ghb_dict_set_string(filter_dict, "Settings", filter_str); - hb_value_array_append(filter_list, filter_dict); - g_free(filter_str); + ghb_dict_set(filter_dict, "Settings", dict); + hb_add_filter2(filter_list, filter_dict); ghb_value_free(&preset); } diff --git a/libhb/avfilter.c b/libhb/avfilter.c index c94a851da..2e57f72d6 100644 --- a/libhb/avfilter.c +++ b/libhb/avfilter.c @@ -38,6 +38,13 @@ static int avfilter_work( hb_filter_object_t * filter, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ); static hb_filter_info_t * avfilter_info( hb_filter_object_t * filter ); + +static int null_init( hb_filter_object_t * filter, hb_filter_init_t * init ); +static void null_close( hb_filter_object_t * filter ); +static int null_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ); +static hb_filter_info_t * null_info( hb_filter_object_t * filter ); + hb_filter_object_t hb_filter_avfilter = { .id = HB_FILTER_AVFILTER, @@ -50,42 +57,81 @@ hb_filter_object_t hb_filter_avfilter = .info = avfilter_info, }; +const char pad_template[] = + "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:color=^"HB_ALL_REG"$:" + "x=^"HB_INT_REG"$:y=^"HB_INT_REG"$"; + hb_filter_object_t hb_filter_pad = { - .id = HB_FILTER_PAD, - .enforce_order = 1, - .name = "avfilter", - .settings = NULL, - .init = avfilter_init, - .work = avfilter_work, - .close = avfilter_close, - .info = avfilter_info, + .id = HB_FILTER_PAD, + .enforce_order = 1, + .name = "pad", + .settings = NULL, + .init = null_init, + .work = null_work, + .close = null_close, + .info = null_info, + .settings_template = pad_template, }; +const char rotate_template[] = + "angle=^(0|90|180|270)$:hflip=^"HB_BOOL_REG"$"; + hb_filter_object_t hb_filter_rotate = { - .id = HB_FILTER_ROTATE, - .enforce_order = 1, - .name = "avfilter", - .settings = NULL, - .init = avfilter_init, - .work = avfilter_work, - .close = avfilter_close, - .info = avfilter_info, + .id = HB_FILTER_ROTATE, + .enforce_order = 1, + .name = "rotate", + .settings = NULL, + .init = null_init, + .work = null_work, + .close = null_close, + .info = null_info, + .settings_template = rotate_template, }; +const char deint_template[] = + "mode=^"HB_INT_REG"$:parity=^([01])$"; + 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, + .id = HB_FILTER_DEINTERLACE, + .enforce_order = 1, + .name = "deinterlace", + .settings = NULL, + .init = null_init, + .work = null_work, + .close = null_close, + .info = null_info, + .settings_template = deint_template, }; +static int null_init( hb_filter_object_t * filter, hb_filter_init_t * init ) +{ + hb_log("null_init: It is an error to call this function."); + return 1; +} + +static void null_close( hb_filter_object_t * filter ) +{ + hb_log("null_close: It is an error to call this function."); + return; +} + +static int null_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) +{ + hb_log("null_work: It is an error to call this function."); + return HB_WORK_DONE; +} + +static hb_filter_info_t * null_info( hb_filter_object_t * filter ) +{ + hb_log("null_info: It is an error to call this function."); + return NULL; +} + + static AVFilterContext * append_filter( hb_filter_private_t * pv, const char * name, const char * args) { @@ -120,8 +166,11 @@ static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) char * filter_args; int result; AVFilterInOut * in = NULL, * out = NULL; + char * avfilter_settings = NULL; - if (filter->settings == NULL || filter->settings[0] == 0) + avfilter_settings = hb_filter_settings_string(HB_FILTER_AVFILTER, + filter->settings); + if (avfilter_settings == NULL) { hb_error("avfilter_init: no filter settings specified"); return 1; @@ -130,7 +179,7 @@ static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) pv = calloc(1, sizeof(struct hb_filter_private_s)); filter->private_data = pv; - pv->settings = strdup(filter->settings); + pv->settings = avfilter_settings; pv->graph = avfilter_graph_alloc(); if (pv->graph == NULL) { @@ -139,13 +188,18 @@ static int avfilter_init( hb_filter_object_t * filter, hb_filter_init_t * init ) } sws_flags = hb_strdup_printf("flags=%d", SWS_LANCZOS|SWS_ACCURATE_RND); - pv->graph->scale_sws_opts = sws_flags; - - result = avfilter_graph_parse2(pv->graph, filter->settings, &in, &out); + // avfilter_graph_free uses av_free to release scale_sws_opts. Due + // to the hacky implementation of av_free/av_malloc on windows, + // you must av_malloc anything that is av_free'd. + pv->graph->scale_sws_opts = av_malloc(strlen(sws_flags) + 1); + strcpy(pv->graph->scale_sws_opts, sws_flags); + free(sws_flags); + + result = avfilter_graph_parse2(pv->graph, avfilter_settings, &in, &out); if (result < 0 || in == NULL || out == NULL) { hb_error("avfilter_init: avfilter_graph_parse2 failed (%s)", - filter->settings); + avfilter_settings); goto fail; } @@ -343,6 +397,7 @@ static void fill_frame(hb_filter_private_t * pv, frame->height = buf->f.height; frame->format = buf->f.fmt; frame->interlaced_frame = !!buf->s.combed; + frame->top_field_first = !!(buf->s.flags & PIC_FLAG_TOP_FIELD_FIRST); } static hb_buffer_t* avframe_to_buffer(hb_filter_private_t * pv, AVFrame *frame) @@ -376,6 +431,27 @@ static hb_buffer_t* avframe_to_buffer(hb_filter_private_t * pv, AVFrame *frame) buf->s.start = av_rescale_q(frame->pts, pv->out_time_base, (AVRational){1, 90000}); + if (frame->top_field_first) + { + buf->s.flags |= PIC_FLAG_TOP_FIELD_FIRST; + } + if (!frame->interlaced_frame) + { + buf->s.flags |= PIC_FLAG_PROGRESSIVE_FRAME; + } + else + { + buf->s.combed = HB_COMB_HEAVY; + } + if (frame->repeat_pict == 1) + { + buf->s.flags |= PIC_FLAG_REPEAT_FIRST_FIELD; + } + if (frame->repeat_pict == 2) + { + buf->s.flags |= PIC_FLAG_REPEAT_FRAME; + } + return buf; } @@ -432,9 +508,241 @@ static int avfilter_work( hb_filter_object_t * filter, return HB_FILTER_OK; } +#define MODE_YADIF_ENABLE 1 +#define MODE_YADIF_SPATIAL 2 +#define MODE_YADIF_BOB 4 +#define MODE_YADIF_AUTO 8 + +/* Deinterlace Settings + * mode:parity + * + * mode - yadif deinterlace mode + * parity - field parity + * + * Modes: + * 1 = Enabled + * 2 = Spatial + * 4 = Bob + * 8 = Auto + * + * Parity: + * 0 = Top Field First + * 1 = Bottom Field First + * -1 = Automatic detection of field parity + */ +static hb_dict_t * +convert_deint_settings(const hb_dict_t * settings) +{ + int mode = 3, parity = -1; + + hb_dict_extract_int(&mode, settings, "mode"); + hb_dict_extract_int(&parity, settings, "parity"); + + if (!(mode & MODE_YADIF_ENABLE)) + { + return hb_value_null(); + } + int automatic = !!(mode & MODE_YADIF_AUTO); + int bob = !!(mode & MODE_YADIF_BOB); + int no_spatial = !(mode & MODE_YADIF_SPATIAL); + mode = bob | (no_spatial << 1); + + hb_dict_t * result = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + hb_dict_set(avsettings, "mode", hb_value_int(mode)); + if (automatic) + { + hb_dict_set(avsettings, "auto", hb_value_int(automatic)); + } + if (parity != -1) + { + hb_dict_set(avsettings, "parity", hb_value_int(parity)); + } + hb_dict_set(result, "yadif", avsettings); + + return result; +} + +/* Rotate Settings: + * degrees:mirror + * + * degrees - Rotation angle, may be one of 90, 180, or 270 + * mirror - Mirror image around x axis + * + * Examples: + * Mode 180:1 Mirror then rotate 180' + * Mode 0:1 Mirror + * Mode 180:0 Rotate 180' + * Mode 90:0 Rotate 90' + * Mode 270:0 Rotate 270' + * + * Legacy Mode Examples (also accepted): + * Mode 1: Flip vertically (y0 becomes yN and yN becomes y0) (aka 180:1) + * Mode 2: Flip horizontally (x0 becomes xN and xN becomes x0) (aka 0:1) + * Mode 3: Flip both horizontally and vertically (aka 180:0) + * Mode 4: Rotate 90' (aka 90:0) + * Mode 7: Flip horiz & vert plus Rotate 90' (aka 270:0) + */ +static hb_dict_t * +convert_rotate_settings(const hb_dict_t * settings) +{ + const char * trans = NULL; + int angle = 180, flip = 0, hflip = 0, vflip = 0; + + hb_dict_extract_int(&angle, settings, "angle"); + hb_dict_extract_bool(&flip, settings, "hflip"); + + const char * clock; + const char * cclock; + if (flip) + { + clock = "clock_flip"; + cclock = "cclock_flip"; + } + else + { + clock = "clock"; + cclock = "cclock"; + } + switch (angle) + { + case 0: + hflip = flip; + break; + case 90: + trans = clock; + break; + case 180: + vflip = 1; + hflip = !flip; + break; + case 270: + trans = cclock; + break; + default: + break; + } + if (trans != NULL) + { + hb_dict_t * result = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + hb_dict_set(avsettings, "dir", hb_value_string(trans)); + hb_dict_set(result, "transpose", avsettings); + + return result; + } + else if (hflip || vflip) + { + hb_dict_t * result = hb_value_array_init(); + hb_dict_t * avfilter; + if (vflip) + { + avfilter = hb_dict_init(); + hb_dict_set(avfilter, "vflip", hb_value_null()); + hb_value_array_append(result, avfilter); + } + if (hflip) + { + avfilter = hb_dict_init(); + hb_dict_set(avfilter, "hflip", hb_value_null()); + hb_value_array_append(result, avfilter); + } + return result; + } + else + { + return hb_value_null(); + } +} + +/* Pad presets and tunes + * + * There are currently no presets and tunes for pad + * The custom pad string is converted to an avformat filter graph string + */ +static hb_dict_t * +convert_pad_settings(const hb_dict_t * settings) +{ + int width = 0, height = 0, rgb = 0; + int x = -1, y = -1; + char * color = NULL; + + hb_dict_extract_int(&width, settings, "width"); + hb_dict_extract_int(&height, settings, "height"); + hb_dict_extract_string(&color, settings, "color"); + hb_dict_extract_int(&x, settings, "x"); + hb_dict_extract_int(&y, settings, "y"); + + if (color != NULL) + { + char * end; + rgb = strtol(color, &end, 0); + if (end == color) + { + // Not a numeric value, lookup by name + rgb = hb_rgb_lookup_by_name(color); + } + free(color); + color = hb_strdup_printf("0x%06x", rgb); + } + + char x_str[20]; + char y_str[20]; + if (x < 0) + { + snprintf(x_str, 20, "(out_w-in_w)/2"); + } + else + { + snprintf(x_str, 20, "%d", x); + } + if (y < 0) + { + snprintf(y_str, 20, "(out_h-in_h)/2"); + } + else + { + snprintf(y_str, 20, "%d", y); + } + hb_dict_t * result = hb_dict_init(); + hb_dict_t * avsettings = hb_dict_init(); + + hb_dict_set(avsettings, "width", hb_value_int(width)); + hb_dict_set(avsettings, "height", hb_value_int(height)); + hb_dict_set(avsettings, "x", hb_value_string(x_str)); + hb_dict_set(avsettings, "y", hb_value_string(y_str)); + if (color != NULL) + { + hb_dict_set(avsettings, "color", hb_value_string(color)); + } + hb_dict_set(result, "pad", avsettings); + + free(color); + + return result; +} + +static hb_dict_t * convert_settings(int filter_id, hb_dict_t * settings) +{ + switch (filter_id) + { + case HB_FILTER_ROTATE: + return convert_rotate_settings(settings); + case HB_FILTER_DEINTERLACE: + return convert_deint_settings(settings); + case HB_FILTER_PAD: + return convert_pad_settings(settings); + default: + return NULL; + } +} + void hb_avfilter_combine( hb_list_t * list ) { hb_filter_object_t * avfilter = NULL; + hb_value_t * settings = NULL; int ii; for (ii = 0; ii < hb_list_count(list);) @@ -443,30 +751,42 @@ void hb_avfilter_combine( hb_list_t * list ) switch (filter->id) { case HB_FILTER_AVFILTER: + { + settings = hb_value_dup(filter->settings); + } break; case HB_FILTER_ROTATE: case HB_FILTER_DEINTERLACE: case HB_FILTER_PAD: - if (avfilter != NULL) - { - // Chain filter together - char * settings; - settings = hb_strdup_printf("%s, %s", avfilter->settings, - filter->settings); - free(avfilter->settings); - avfilter->settings = settings; - hb_list_rem(list, filter); - hb_filter_close(&filter); - continue; - } - else - { - avfilter = filter; - avfilter->id = HB_FILTER_AVFILTER; - } - break; + { + settings = convert_settings(filter->id, filter->settings); + } break; default: avfilter = NULL; } + if (settings != NULL) + { + // Some filter values can result in no filter. + // E.g. rotate angle=0:hflip=0 + if (hb_value_type(settings) == HB_VALUE_TYPE_NULL) + { + hb_list_rem(list, filter); + hb_filter_close(&filter); + continue; + } + if (avfilter == NULL) + { + avfilter = hb_filter_init(HB_FILTER_AVFILTER); + avfilter->settings = hb_value_array_init(); + hb_list_insert(list, ii, avfilter); + ii++; + } + hb_list_rem(list, filter); + hb_filter_close(&filter); + + hb_value_array_concat(avfilter->settings, settings); + hb_value_free(&settings); + continue; + } ii++; } } diff --git a/libhb/builtin_presets.h b/libhb/builtin_presets.h index 5ab646f19..bbb6e1335 100644 --- a/libhb/builtin_presets.h +++ b/libhb/builtin_presets.h @@ -797,6 +797,7 @@ const char hb_builtin_presets_json[] = " \"PictureBottomCrop\": 0, \n" " \"PictureDARWidth\": 0, \n" " \"PictureDeblock\": 0, \n" +" \"PictureDeblockCustom\": \"qp=0:mode=2\", \n" " \"PictureDeinterlaceCustom\": \"\", \n" " \"PictureDeinterlaceFilter\": \"off\", \n" " \"PictureDeinterlacePreset\": \"default\", \n" @@ -818,7 +819,7 @@ const char hb_builtin_presets_json[] = " \"PicturePARHeight\": 720, \n" " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" -" \"PictureRotate\": \"0\", \n" +" \"PictureRotate\": \"angle=0:hflip=0\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 0, \n" " \"PresetDescription\": \"\", \n" @@ -856,8 +857,8 @@ const char hb_builtin_presets_json[] = " \"x264Option\": \"\", \n" " \"x264UseAdvancedOptions\": false\n" " }, \n" -" \"VersionMajor\": 11, \n" +" \"VersionMajor\": 12, \n" " \"VersionMicro\": 0, \n" -" \"VersionMinor\": 1\n" +" \"VersionMinor\": 0\n" " }\n" "}\n"; diff --git a/libhb/common.c b/libhb/common.c index cf49a2b72..ca74aeb16 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -3690,7 +3690,7 @@ hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ) hb_filter_object_t * filter_copy = malloc( sizeof( hb_filter_object_t ) ); memcpy( filter_copy, filter, sizeof( hb_filter_object_t ) ); if( filter->settings ) - filter_copy->settings = strdup( filter->settings ); + filter_copy->settings = hb_value_dup(filter->settings); return filter_copy; } @@ -3723,7 +3723,7 @@ hb_list_t *hb_filter_list_copy(const hb_list_t *src) * @param filter_id The type of filter to get. * @returns The requested filter object. */ -hb_filter_object_t * hb_filter_init( int filter_id ) +hb_filter_object_t * hb_filter_get( int filter_id ) { hb_filter_object_t * filter; switch( filter_id ) @@ -3798,7 +3798,12 @@ hb_filter_object_t * hb_filter_init( int filter_id ) filter = NULL; break; } - return hb_filter_copy( filter ); + return filter; +} + +hb_filter_object_t * hb_filter_init( int filter_id ) +{ + return hb_filter_copy(hb_filter_get(filter_id)); } /********************************************************************** @@ -3810,7 +3815,7 @@ void hb_filter_close( hb_filter_object_t ** _f ) { hb_filter_object_t * f = *_f; - free(f->settings); + hb_value_free(&f->settings); free( f ); *_f = NULL; @@ -3834,6 +3839,292 @@ void hb_filter_info_close( hb_filter_info_t ** _fi ) *_fi = NULL; } +static char * append_string(char * dst, const char * src) +{ + int dst_len = 0, src_len, len; + + if (src == NULL) + { + return dst; + } + + src_len = len = strlen(src) + 1; + if (dst != NULL) + { + dst_len = strlen(dst); + len += dst_len; + } + char * tmp = realloc(dst, len); + if (tmp == NULL) + { + // Failed to allocate required space + return dst; + } + dst = tmp; + memcpy(dst + dst_len, src, src_len); + return dst; +} + +static char * stringify_array(int filter_id, hb_value_array_t * array) +{ + char * result = strdup(""); + int ii; + int len = hb_value_array_len(array); + int first = 1; + + if (hb_value_array_len(array) == 0) + { + return result; + } + for (ii = 0; ii < len; ii++) + { + hb_value_t * val = hb_value_array_get(array, ii); + char * str = hb_filter_settings_string(filter_id, val); + if (str != NULL) + { + if (!first) + { + result = append_string(result, ","); + } + first = 0; + if (hb_value_type(val) == HB_VALUE_TYPE_DICT) + { + result = append_string(result, str); + } + else if (hb_value_type(val) == HB_VALUE_TYPE_ARRAY) + { + result = append_string(result, "["); + result = append_string(result, str); + result = append_string(result, "]"); + } + else + { + result = append_string(result, str); + } + free(str); + } + } + + return result; +} + +static char * stringify_dict(int filter_id, hb_dict_t * dict) +{ + char * result = strdup(""); + const char * key; + char ** keys = NULL; + hb_value_t * val; + hb_dict_iter_t iter; + int first = 1; + + if (hb_dict_elements(dict) == 0) + { + return result; + } + // Check for dict containing rational value + if (hb_dict_elements(dict) == 2) + { + hb_value_t *num_val = hb_dict_get(dict, "Num"); + hb_value_t *den_val = hb_dict_get(dict, "Den"); + if (num_val != NULL && den_val != NULL && + hb_value_type(num_val) == HB_VALUE_TYPE_INT && + hb_value_type(den_val) == HB_VALUE_TYPE_INT) + { + int num = hb_value_get_int(num_val); + int den = hb_value_get_int(den_val); + char * str = hb_strdup_printf("%d/%d", num, den); + result = append_string(result, str); + free(str); + return result; + } + } + hb_filter_object_t * filter = hb_filter_get(filter_id); + if (filter != NULL) + { + keys = hb_filter_get_keys(filter_id); + if (keys != NULL && keys[0] == NULL) + { + hb_str_vfree(keys); + keys = NULL; + } + } + + int done, ii = 0; + iter = hb_dict_iter_init(dict); + if (keys == NULL) + { + done = !hb_dict_iter_next_ex(dict, &iter, &key, NULL); + } + else + { + done = (key = keys[ii]) == NULL; + } + while (!done) + { + val = hb_dict_get(dict, key); + if (val != NULL) + { + if (!first) + { + result = append_string(result, ":"); + } + first = 0; + result = append_string(result, key); + int elements = 1; + + if (hb_value_type(val) == HB_VALUE_TYPE_NULL) + { + elements = 0; + } + else if (hb_value_type(val) == HB_VALUE_TYPE_DICT) + { + elements = hb_dict_elements(val); + } + else if (hb_value_type(val) == HB_VALUE_TYPE_ARRAY) + { + elements = hb_value_array_len(val); + } + if (elements != 0) + { + char * str = hb_filter_settings_string(filter_id, val); + if (str != NULL) + { + result = append_string(result, "="); + if (hb_value_type(val) == HB_VALUE_TYPE_DICT) + { + result = append_string(result, "'"); + result = append_string(result, str); + result = append_string(result, "'"); + } + else if (hb_value_type(val) == HB_VALUE_TYPE_ARRAY) + { + result = append_string(result, "["); + result = append_string(result, str); + result = append_string(result, "]"); + } + else + { + result = append_string(result, str); + } + free(str); + } + } + } + ii++; + if (keys == NULL) + { + done = !hb_dict_iter_next_ex(dict, &iter, &key, NULL); + } + else + { + done = (key = keys[ii]) == NULL; + } + } + hb_str_vfree(keys); + + return result; +} + +char * hb_filter_settings_string(int filter_id, hb_value_t * value) +{ + if (value == NULL || hb_value_type(value) == HB_VALUE_TYPE_NULL) + { + return strdup(""); + } + if (hb_value_type(value) == HB_VALUE_TYPE_DICT) + { + return stringify_dict(filter_id, value); + } + if (hb_value_type(value) == HB_VALUE_TYPE_ARRAY) + { + return stringify_array(filter_id, value); + } + return hb_value_get_string_xform(value); +} + +char * hb_filter_settings_string_json(int filter_id, const char * json) +{ + hb_value_t * value = hb_value_json(json); + char * result = hb_filter_settings_string(filter_id, value); + hb_value_free(&value); + + return result; +} + +hb_dict_t * hb_parse_filter_settings(const char * settings_str) +{ + hb_dict_t * dict = hb_dict_init(); + char ** settings_list = hb_str_vsplit(settings_str, ':'); + int ii; + + for (ii = 0; settings_list[ii] != NULL; ii++) + { + char * key, * value; + char ** settings_pair = hb_str_vsplit(settings_list[ii], '='); + if (settings_pair[0] == NULL || settings_pair[1] == NULL) + { + // Parse error. Not key=value pair. + hb_str_vfree(settings_list); + hb_str_vfree(settings_pair); + hb_value_free(&dict); + hb_log("hb_parse_filter_settings: Error parsing (%s)", + settings_str); + return NULL; + } + key = settings_pair[0]; + value = settings_pair[1]; + + int last = strlen(value) - 1; + // Check if value was quoted dictionary and remove quotes + // and parse the sub-dictionary. This should only happen + // for avfilter settings. + if (last > 0 && value[0] == '\'' && value[last] == '\'') + { + char * str = strdup(value + 1); + str[last - 1] = 0; + hb_dict_t * sub_dict = hb_parse_filter_settings(str); + free(str); + if (sub_dict == NULL) + { + // Parse error. Not key=value pair. + hb_str_vfree(settings_list); + hb_str_vfree(settings_pair); + hb_value_free(&dict); + hb_log("hb_parse_filter_settings: Error parsing (%s)", + settings_str); + return NULL; + } + hb_dict_case_set(dict, key, sub_dict); + } + // Check if value was quoted string and remove quotes + else if (last > 0 && value[0] == '"' && value[last] == '"') + { + char * str = strdup(value + 1); + str[last - 1] = 0; + hb_dict_case_set(dict, key, hb_value_string(str)); + free(str); + } + else + { + hb_dict_case_set(dict, key, hb_value_string(value)); + } + + hb_str_vfree(settings_pair); + } + hb_str_vfree(settings_list); + + return dict; +} + +char * hb_parse_filter_settings_json(const char * settings_str) +{ + hb_dict_t * dict = hb_parse_filter_settings(settings_str); + char * result = hb_value_get_json(dict); + hb_value_free(&dict); + + return result; +} + /********************************************************************** * hb_chapter_copy ********************************************************************** diff --git a/libhb/common.h b/libhb/common.h index daeeb7920..d09c6e9a0 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -10,6 +10,8 @@ #ifndef HB_COMMON_H #define HB_COMMON_H +#include "hbtypes.h" +#include "hb_dict.h" #include <math.h> #include <stdio.h> #include <stdlib.h> @@ -80,41 +82,6 @@ #define HB_MAX_WIDTH 20480 #define HB_MAX_HEIGHT 20480 -typedef struct hb_handle_s hb_handle_t; -typedef struct hb_hwd_s hb_hwd_t; -typedef struct hb_list_s hb_list_t; -typedef struct hb_buffer_list_s hb_buffer_list_t; -typedef struct hb_rate_s hb_rate_t; -typedef struct hb_dither_s hb_dither_t; -typedef struct hb_mixdown_s hb_mixdown_t; -typedef struct hb_encoder_s hb_encoder_t; -typedef struct hb_container_s hb_container_t; -typedef struct hb_rational_s hb_rational_t; -typedef struct hb_geometry_s hb_geometry_t; -typedef struct hb_geometry_settings_s hb_geometry_settings_t; -typedef struct hb_image_s hb_image_t; -typedef struct hb_job_s hb_job_t; -typedef struct hb_title_set_s hb_title_set_t; -typedef struct hb_title_s hb_title_t; -typedef struct hb_chapter_s hb_chapter_t; -typedef struct hb_audio_s hb_audio_t; -typedef struct hb_audio_config_s hb_audio_config_t; -typedef struct hb_subtitle_s hb_subtitle_t; -typedef struct hb_subtitle_config_s hb_subtitle_config_t; -typedef struct hb_attachment_s hb_attachment_t; -typedef struct hb_metadata_s hb_metadata_t; -typedef struct hb_coverart_s hb_coverart_t; -typedef struct hb_state_s hb_state_t; -typedef union hb_esconfig_u hb_esconfig_t; -typedef struct hb_work_private_s hb_work_private_t; -typedef struct hb_work_object_s hb_work_object_t; -typedef struct hb_filter_private_s hb_filter_private_t; -typedef struct hb_filter_object_s hb_filter_object_t; -typedef struct hb_buffer_s hb_buffer_t; -typedef struct hb_buffer_settings_s hb_buffer_settings_t; -typedef struct hb_image_format_s hb_image_format_t; -typedef struct hb_fifo_s hb_fifo_t; -typedef struct hb_lock_s hb_lock_t; typedef enum { HB_ERROR_NONE = 0, @@ -1223,7 +1190,7 @@ struct hb_filter_object_s int id; int enforce_order; char * name; - char * settings; + hb_dict_t * settings; #ifdef __LIBHB__ int (* init) ( hb_filter_object_t *, hb_filter_init_t * ); @@ -1233,6 +1200,8 @@ struct hb_filter_object_s void (* close) ( hb_filter_object_t * ); hb_filter_info_t * (* info) ( hb_filter_object_t * ); + const char * settings_template; + hb_fifo_t * fifo_in; hb_fifo_t * fifo_out; @@ -1286,11 +1255,18 @@ enum HB_FILTER_LAST = HB_FILTER_QSV }; +hb_filter_object_t * hb_filter_get( int filter_id ); hb_filter_object_t * hb_filter_init( int filter_id ); hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ); hb_list_t * hb_filter_list_copy(const hb_list_t *src); void hb_filter_close( hb_filter_object_t ** ); void hb_filter_info_close( hb_filter_info_t ** ); +hb_dict_t * hb_parse_filter_settings(const char * settings); +char * hb_parse_filter_settings_json(const char * settings_str); +char * hb_filter_settings_string(int filter_id, + hb_value_t * value); +char * hb_filter_settings_string_json(int filter_id, + const char * json); typedef void hb_error_handler_t( const char *errmsg ); @@ -1326,4 +1302,12 @@ const char * hb_x264_encopt_name( const char * name ); const char * hb_x265_encopt_name( const char * name ); #endif +#define HB_NEG_FLOAT_REG "(([-])?(([0-9]+([.,][0-9]+)?)|([.,][0-9]+))" +#define HB_FLOAT_REG "(([0-9]+([.,][0-9]+)?)|([.,][0-9]+))" +#define HB_NEG_INT_REG "(([-]?[0-9]+)" +#define HB_INT_REG "([0-9]+)" +#define HB_RATIONAL_REG "([0-9]+/[0-9]+)" +#define HB_BOOL_REG "(yes|no|true|false|[01])" +#define HB_ALL_REG "(.*)" + #endif diff --git a/libhb/cropscale.c b/libhb/cropscale.c index 4c505ff20..63475990e 100644 --- a/libhb/cropscale.c +++ b/libhb/cropscale.c @@ -43,16 +43,22 @@ static hb_filter_info_t * hb_crop_scale_info( hb_filter_object_t * filter ); static void hb_crop_scale_close( hb_filter_object_t * filter ); +static const char crop_scale_template[] = + "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:" + "crop-top=^"HB_INT_REG"$:crop-bottom=^"HB_INT_REG"$:" + "crop-left=^"HB_INT_REG"$:crop-right=^"HB_INT_REG"$"; + hb_filter_object_t hb_filter_crop_scale = { - .id = HB_FILTER_CROP_SCALE, - .enforce_order = 1, - .name = "Crop and Scale", - .settings = NULL, - .init = hb_crop_scale_init, - .work = hb_crop_scale_work, - .close = hb_crop_scale_close, - .info = hb_crop_scale_info, + .id = HB_FILTER_CROP_SCALE, + .enforce_order = 1, + .name = "Crop and Scale", + .settings = NULL, + .init = hb_crop_scale_init, + .work = hb_crop_scale_work, + .close = hb_crop_scale_close, + .info = hb_crop_scale_info, + .settings_template = crop_scale_template, }; static int hb_crop_scale_init( hb_filter_object_t * filter, @@ -81,12 +87,13 @@ static int hb_crop_scale_init( hb_filter_object_t * filter, } memcpy( pv->crop, init->crop, sizeof( int[4] ) ); - if( filter->settings ) - { - sscanf( filter->settings, "%d:%d:%d:%d:%d:%d", - &pv->width_out, &pv->height_out, - &pv->crop[0], &pv->crop[1], &pv->crop[2], &pv->crop[3] ); - } + hb_dict_extract_int(&pv->width_out, filter->settings, "width"); + hb_dict_extract_int(&pv->height_out, filter->settings, "height"); + hb_dict_extract_int(&pv->crop[0], filter->settings, "crop-top"); + hb_dict_extract_int(&pv->crop[1], filter->settings, "crop-bottom"); + hb_dict_extract_int(&pv->crop[2], filter->settings, "crop-left"); + hb_dict_extract_int(&pv->crop[3], filter->settings, "crop-right"); + // Set init values so the next stage in the pipline // knows what it will be getting init->pix_fmt = pv->pix_fmt; diff --git a/libhb/deblock.c b/libhb/deblock.c index e48d89ced..64cf277bb 100644 --- a/libhb/deblock.c +++ b/libhb/deblock.c @@ -58,15 +58,19 @@ static int hb_deblock_work( hb_filter_object_t * filter, static void hb_deblock_close( hb_filter_object_t * filter ); +static const char deblock_template[] = + "qp=^"HB_INT_REG"$:mode=^([012])$:disable=^"HB_BOOL_REG"$"; + hb_filter_object_t hb_filter_deblock = { - .id = HB_FILTER_DEBLOCK, - .enforce_order = 1, - .name = "Deblock (pp7)", - .settings = NULL, - .init = hb_deblock_init, - .work = hb_deblock_work, - .close = hb_deblock_close, + .id = HB_FILTER_DEBLOCK, + .enforce_order = 1, + .name = "Deblock (pp7)", + .settings = NULL, + .init = hb_deblock_init, + .work = hb_deblock_work, + .close = hb_deblock_close, + .settings_template = deblock_template, }; static inline void pp7_dct_a( DCTELEM * dst, uint8_t * src, int stride ) @@ -346,10 +350,8 @@ static int hb_deblock_init( hb_filter_object_t * filter, pv->pp7_mode = PP7_MODE_DEFAULT; pv->pp7_mpeg2 = 1; /*mpi->qscale_type;*/ - if( filter->settings ) - { - sscanf( filter->settings, "%d:%d", &pv->pp7_qp, &pv->pp7_mode ); - } + hb_dict_extract_int(&pv->pp7_mode, filter->settings, "mode"); + hb_dict_extract_int(&pv->pp7_qp, filter->settings, "qp"); if( pv->pp7_qp < 0 ) { diff --git a/libhb/decomb.c b/libhb/decomb.c index b624031b4..cf0db0b6e 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -118,7 +118,7 @@ typedef struct yadif_thread_arg_s { struct hb_filter_private_s { - // Decomb parameters + // Decomb detect parameters int mode; int filter_mode; int spatial_metric; @@ -127,6 +127,7 @@ struct hb_filter_private_s int block_threshold; int block_width; int block_height; + int * block_score; int comb_check_complete; int comb_check_nthreads; @@ -135,6 +136,16 @@ struct hb_filter_private_s float gamma_lut[256]; + /* Make buffers to store a comb masks. */ + hb_buffer_t * mask; + hb_buffer_t * mask_filtered; + hb_buffer_t * mask_temp; + int mask_box_x; + int mask_box_y; + uint8_t mask_box_color; + + // Deinterlace parameters + int parity; // EEDI2 parameters int magnitude_threshold; int variance_threshold; @@ -145,7 +156,6 @@ struct hb_filter_private_s int maximum_search_distance; int post_processing; - int parity; int tff; int yadif_ready; @@ -156,14 +166,6 @@ struct hb_filter_private_s hb_buffer_t * ref[3]; - /* Make buffers to store a comb masks. */ - hb_buffer_t * mask; - hb_buffer_t * mask_filtered; - hb_buffer_t * mask_temp; - int mask_box_x; - int mask_box_y; - uint8_t mask_box_color; - hb_buffer_t * eedi_half[4]; hb_buffer_t * eedi_full[5]; @@ -202,15 +204,26 @@ 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"$:" + "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"$:" + "search-distance=^"HB_INT_REG"$:postproc=^([0-3])$:parity=^([01])$"; + hb_filter_object_t hb_filter_decomb = { - .id = HB_FILTER_DECOMB, - .enforce_order = 1, - .name = "Decomb", - .settings = NULL, - .init = hb_decomb_init, - .work = hb_decomb_work, - .close = hb_decomb_close, + .id = HB_FILTER_DECOMB, + .enforce_order = 1, + .name = "Decomb", + .settings = NULL, + .init = hb_decomb_init, + .work = hb_decomb_work, + .close = hb_decomb_close, + .settings_template = decomb_template, }; // Borrowed from libav @@ -1976,8 +1989,8 @@ static int hb_decomb_init( hb_filter_object_t * filter, pv->yadif_ready = 0; - pv->mode = MODE_YADIF | MODE_BLEND | MODE_CUBIC | - MODE_GAMMA | MODE_FILTER; + 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; @@ -1997,26 +2010,44 @@ static int hb_decomb_init( hb_filter_object_t * filter, pv->parity = PARITY_DEFAULT; - if( filter->settings ) - { - sscanf( filter->settings, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", - &pv->mode, - &pv->spatial_metric, - &pv->motion_threshold, - &pv->spatial_threshold, - &pv->filter_mode, - &pv->block_threshold, - &pv->block_width, - &pv->block_height, - &pv->magnitude_threshold, - &pv->variance_threshold, - &pv->laplacian_threshold, - &pv->dilation_threshold, - &pv->erosion_threshold, - &pv->noise_threshold, - &pv->maximum_search_distance, - &pv->post_processing, - &pv->parity ); + if (filter->settings) + { + hb_value_t * dict = filter->settings; + + // 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) + { + hb_dict_extract_int(&pv->magnitude_threshold, dict, + "magnitude-thresh"); + hb_dict_extract_int(&pv->variance_threshold, dict, + "variance-thresh"); + hb_dict_extract_int(&pv->laplacian_threshold, dict, + "laplacian-thresh"); + hb_dict_extract_int(&pv->dilation_threshold, dict, + "dilation-thresh"); + hb_dict_extract_int(&pv->erosion_threshold, dict, + "erosion-thresh"); + hb_dict_extract_int(&pv->noise_threshold, dict, + "noise-thresh"); + hb_dict_extract_int(&pv->maximum_search_distance, dict, + "search-distance"); + hb_dict_extract_int(&pv->post_processing, dict, + "postproc"); + } } pv->cpu_count = hb_get_cpu_count(); @@ -2638,8 +2669,10 @@ static int hb_decomb_work( hb_filter_object_t * filter, 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->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)); diff --git a/libhb/denoise.c b/libhb/denoise.c index f66c987be..208d399a5 100644 --- a/libhb/denoise.c +++ b/libhb/denoise.c @@ -40,15 +40,22 @@ static int hb_denoise_work( hb_filter_object_t * filter, static void hb_denoise_close( hb_filter_object_t * filter ); +static const char denoise_template[] = + "y-spatial=^"HB_FLOAT_REG"$:cb-spatial=^"HB_FLOAT_REG"$:" + "cr-spatial=^"HB_FLOAT_REG"$:" + "y-temporal=^"HB_FLOAT_REG"$:cb-temporal=^"HB_FLOAT_REG"$:" + "cr-temporal=^"HB_FLOAT_REG"$"; + hb_filter_object_t hb_filter_denoise = { - .id = HB_FILTER_DENOISE, - .enforce_order = 1, - .name = "Denoise (hqdn3d)", - .settings = NULL, - .init = hb_denoise_init, - .work = hb_denoise_work, - .close = hb_denoise_close, + .id = HB_FILTER_DENOISE, + .enforce_order = 1, + .name = "Denoise (hqdn3d)", + .settings = NULL, + .init = hb_denoise_init, + .work = hb_denoise_work, + .close = hb_denoise_close, + .settings_template = denoise_template, }; static void hqdn3d_precalc_coef( short * ct, @@ -217,67 +224,34 @@ static int hb_denoise_init( hb_filter_object_t * filter, filter->private_data = calloc( sizeof(struct hb_filter_private_s), 1 ); hb_filter_private_t * pv = filter->private_data; - double spatial_luma = 0.0f, - spatial_chroma_b = 0.0f, - spatial_chroma_r = 0.0f, - temporal_luma = 0.0f, - temporal_chroma_b = 0.0f, - temporal_chroma_r = 0.0f; + double spatial_luma, spatial_chroma_b, spatial_chroma_r; + double temporal_luma, temporal_chroma_b, temporal_chroma_r; - if (filter->settings != NULL) + if (!hb_dict_extract_double(&spatial_luma, filter->settings, "y-spatial")) { - switch( sscanf( filter->settings, "%lf:%lf:%lf:%lf:%lf:%lf", - &spatial_luma, &spatial_chroma_b, &spatial_chroma_r, - &temporal_luma, &temporal_chroma_b, &temporal_chroma_r ) ) - { - case 0: - spatial_luma = HQDN3D_SPATIAL_LUMA_DEFAULT; - spatial_chroma_b = HQDN3D_SPATIAL_CHROMA_DEFAULT; - spatial_chroma_r = spatial_chroma_b; - temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT; - temporal_chroma_b = temporal_luma * - spatial_chroma_b / spatial_luma; - temporal_chroma_r = temporal_chroma_b; - break; - - case 1: - spatial_chroma_b = HQDN3D_SPATIAL_CHROMA_DEFAULT * - spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT; - spatial_chroma_r = spatial_chroma_b; - temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT * - spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT; - temporal_chroma_b = temporal_luma * - spatial_chroma_b / spatial_luma; - temporal_chroma_r = temporal_chroma_b; - break; - - case 2: - spatial_chroma_r = spatial_chroma_b; - temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT * - spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT; - temporal_chroma_b = temporal_luma * - spatial_chroma_b / spatial_luma; - temporal_chroma_r = temporal_chroma_b; - break; - - case 3: - temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT * - spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT; - temporal_chroma_b = temporal_luma * - spatial_chroma_b / spatial_luma; - temporal_chroma_r = temporal_chroma_b; - break; - - case 4: - temporal_chroma_b = temporal_luma * - spatial_chroma_b / spatial_luma; - temporal_chroma_r = temporal_chroma_b; - break; - - case 5: - temporal_chroma_r = temporal_chroma_b; - break; - } + spatial_luma = HQDN3D_SPATIAL_LUMA_DEFAULT; + } + if (!hb_dict_extract_double(&spatial_chroma_b, filter->settings, "cb-spatial")) + { + spatial_chroma_b = HQDN3D_SPATIAL_CHROMA_DEFAULT * + spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT; + } + if (!hb_dict_extract_double(&spatial_chroma_r, filter->settings, "cr-spatial")) + { + spatial_chroma_r = spatial_chroma_b; + } + if (!hb_dict_extract_double(&temporal_luma, filter->settings, "y-temporal")) + { + temporal_luma = HQDN3D_TEMPORAL_LUMA_DEFAULT * + spatial_luma / HQDN3D_SPATIAL_LUMA_DEFAULT; + } + if (!hb_dict_extract_double(&temporal_chroma_b, filter->settings, "cb-temporal")) + { + temporal_chroma_b = temporal_luma * spatial_chroma_b / spatial_luma; + } + if (!hb_dict_extract_double(&temporal_chroma_r, filter->settings, "cr-temporal")) + { + temporal_chroma_r = temporal_chroma_b; } hqdn3d_precalc_coef( pv->hqdn3d_coef[0], spatial_luma ); diff --git a/libhb/detelecine.c b/libhb/detelecine.c index d25c64803..dd5d26d42 100644 --- a/libhb/detelecine.c +++ b/libhb/detelecine.c @@ -103,15 +103,22 @@ static int hb_detelecine_work( hb_filter_object_t * filter, static void hb_detelecine_close( hb_filter_object_t * filter ); +static const char detelecine_template[] = + "skip-left=^"HB_INT_REG"$:skip-right=^"HB_INT_REG"$:" + "skip-top=^"HB_INT_REG"$:skip-bottom=^"HB_INT_REG"$:" + "strict-breaks=^"HB_BOOL_REG"$:plane=^([012])$:parity=^([01])$:" + "disable=^"HB_BOOL_REG"$"; + hb_filter_object_t hb_filter_detelecine = { - .id = HB_FILTER_DETELECINE, - .enforce_order = 1, - .name = "Detelecine (pullup)", - .settings = NULL, - .init = hb_detelecine_init, - .work = hb_detelecine_work, - .close = hb_detelecine_close, + .id = HB_FILTER_DETELECINE, + .enforce_order = 1, + .name = "Detelecine (pullup)", + .settings = NULL, + .init = hb_detelecine_init, + .work = hb_detelecine_work, + .close = hb_detelecine_close, + .settings_template = detelecine_template, }; /* @@ -826,17 +833,14 @@ static int hb_detelecine_init( hb_filter_object_t * filter, ctx->metric_plane = 0; ctx->parity = -1; - if( filter->settings ) - { - sscanf( filter->settings, "%d:%d:%d:%d:%d:%d:%d", - &ctx->junk_left, - &ctx->junk_right, - &ctx->junk_top, - &ctx->junk_bottom, - &ctx->strict_breaks, - &ctx->metric_plane, - &ctx->parity ); - } + // "Skip" array [top, bottom, left, right] + hb_dict_extract_int(&ctx->junk_top, filter->settings, "skip-top"); + hb_dict_extract_int(&ctx->junk_bottom, filter->settings, "skip-bottom"); + hb_dict_extract_int(&ctx->junk_left, filter->settings, "skip-left"); + hb_dict_extract_int(&ctx->junk_right, filter->settings, "skip-right"); + hb_dict_extract_int(&ctx->strict_breaks, filter->settings, "strict-breaks"); + hb_dict_extract_int(&ctx->metric_plane, filter->settings, "plane"); + hb_dict_extract_int(&ctx->parity, filter->settings, "parity"); ctx->format = PULLUP_FMT_Y; ctx->nplanes = 4; diff --git a/libhb/hb.c b/libhb/hb.c index 88d90e187..5937ae1ba 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -1334,13 +1334,63 @@ void hb_set_anamorphic_size2(hb_geometry_t *src_geo, * @param job Handle to hb_job_t * @param settings to give the filter */ -void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, const char * settings_in ) +void hb_add_filter2( hb_value_array_t * list, hb_dict_t * filter_dict ) { - char * settings = NULL; + int new_id = hb_dict_get_int(filter_dict, "ID"); - if ( settings_in != NULL ) + hb_filter_object_t * filter = hb_filter_get(new_id); + if (filter == NULL) { - settings = strdup( settings_in ); + hb_error("hb_add_filter2: Invalid filter ID %d", new_id); + hb_value_free(&filter_dict); + return; + } + if (filter->enforce_order) + { + // Find the position in the filter chain this filter belongs in + int ii, len; + + len = hb_value_array_len(list); + for( ii = 0; ii < len; ii++ ) + { + hb_value_t * f = hb_value_array_get(list, ii); + int id = hb_dict_get_int(f, "ID"); + if (id > new_id) + { + hb_value_array_insert(list, ii, filter_dict); + return; + } + else if ( id == new_id ) + { + // Don't allow the same filter to be added twice + hb_value_free(&filter_dict); + return; + } + } + } + // No position found or order not enforced for this filter + hb_value_array_append(list, filter_dict); +} + +/** + * Add a filter to a jobs filter list + * + * @param job Handle to hb_job_t + * @param settings to give the filter + */ +void hb_add_filter_dict( hb_job_t * job, hb_filter_object_t * filter, + const hb_dict_t * settings_in ) +{ + hb_dict_t * settings; + + // Always set filter->settings to a valid hb_dict_t + if (settings_in == NULL) + { + settings = hb_dict_init(); + } + else + { + settings = hb_value_dup(settings_in); } filter->settings = settings; if( filter->enforce_order ) @@ -1368,6 +1418,25 @@ void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, const char * se } /** + * Add a filter to a jobs filter list + * + * @param job Handle to hb_job_t + * @param settings to give the filter + */ +void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, + const char * settings_in ) +{ + hb_dict_t * settings = hb_parse_filter_settings(settings_in); + if (settings_in != NULL && settings == NULL) + { + hb_log("hb_add_filter: failed to parse filter settings!"); + return; + } + hb_add_filter_dict(job, filter, settings); + hb_value_free(&settings); +} + +/** * Returns the number of jobs in the queue. * @param h Handle to hb_handle_t. * @return Number of jobs. diff --git a/libhb/hb.h b/libhb/hb.h index 3521e4d3e..f2dd6e9c4 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -17,7 +17,6 @@ extern "C" { #include "common.h" #include "project.h" #include "compat.h" -#include "hb_dict.h" #include "hb_json.h" #include "preset.h" #include "plist.h" @@ -87,8 +86,11 @@ hb_image_t * hb_get_preview2(hb_handle_t * h, int title_idx, int picture, void hb_set_anamorphic_size2(hb_geometry_t *src_geo, hb_geometry_settings_t *geo, hb_geometry_t *result); +void hb_add_filter_dict( hb_job_t * job, hb_filter_object_t * filter, + const hb_dict_t * settings_in ); void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, - const char * settings ); + const char * settings ); +void hb_add_filter2( hb_value_array_t * list, hb_dict_t * filter ); /* Handling jobs */ int hb_count( hb_handle_t * ); diff --git a/libhb/hb_dict.c b/libhb/hb_dict.c index cc0ee99fe..5cc67c629 100644 --- a/libhb/hb_dict.c +++ b/libhb/hb_dict.c @@ -7,6 +7,7 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ +#include <ctype.h> #include <stdio.h> #include "hb.h" #include "hb_dict.h" @@ -49,6 +50,11 @@ void hb_value_free(hb_value_t **_value) *_value = NULL; } +hb_value_t * hb_value_null() +{ + return json_null(); +} + hb_value_t * hb_value_string(const char * value) { // json_string does not create a value for NULL strings. @@ -440,19 +446,226 @@ hb_dict_t * hb_dict_init() return json_object(); } +int hb_dict_elements(hb_dict_t * dict) +{ + return json_object_size(dict); +} + +static char * makelower(const char *key) +{ + int ii, len = strlen(key); + char * lower = malloc(len + 1); + + for (ii = 0; ii < len; ii++) + { + lower[ii] = tolower(key[ii]); + } + lower[ii] = '\0'; + return lower; +} + void hb_dict_set(hb_dict_t * dict, const char *key, hb_value_t *value) { json_object_set_new(dict, key, value); } +void hb_dict_case_set(hb_dict_t * dict, const char *key, hb_value_t *value) +{ + char * lower = makelower(key); + json_object_set_new(dict, lower, value); + free(lower); +} + int hb_dict_remove(hb_dict_t * dict, const char * key) { - return json_object_del(dict, key) == 0; + int result; + + // First try case sensitive lookup + result = json_object_del(dict, key) == 0; + if (!result) + { + // If not found, try case insensitive lookup + char * lower = makelower(key); + result = json_object_del(dict, lower) == 0; + free(lower); + } + return result; } hb_value_t * hb_dict_get(const hb_dict_t * dict, const char * key) { - return json_object_get(dict, key); + hb_value_t * result; + + // First try case sensitive lookup + result = json_object_get(dict, key); + if (result == NULL) + { + // If not found, try case insensitive lookup + char * lower = makelower(key); + result = json_object_get(dict, lower); + free(lower); + } + return result; +} + +// Dictionary extraction helpers +// +// Extract the given key from the dict and assign to dst *only* +// if key is found in dict. Values are converted to the requested +// data type. +// +// return: 1 - key is in dict +// 0 - key is not in dict +int hb_dict_extract_int(int *dst, const hb_dict_t * dict, const char * key) +{ + if (dict == NULL || key == NULL || dst == NULL) + { + return 0; + } + + hb_value_t *val = hb_dict_get(dict, key); + if (val == NULL) + { + return 0; + } + + *dst = hb_value_get_int(val); + return 1; +} + +int hb_dict_extract_double(double *dst, const hb_dict_t * dict, + const char * key) +{ + if (dict == NULL || key == NULL || dst == NULL) + { + return 0; + } + + hb_value_t *val = hb_dict_get(dict, key); + if (val == NULL) + { + return 0; + } + + *dst = hb_value_get_double(val); + return 1; +} + +int hb_dict_extract_bool(int *dst, const hb_dict_t * dict, const char * key) +{ + if (dict == NULL || key == NULL || dst == NULL) + { + return 0; + } + + hb_value_t *val = hb_dict_get(dict, key); + if (val == NULL) + { + return 0; + } + + *dst = hb_value_get_bool(val); + return 1; +} + +int hb_dict_extract_string(char **dst, const hb_dict_t * dict, const char * key) +{ + if (dict == NULL || key == NULL || dst == NULL) + { + return 0; + } + + hb_value_t *val = hb_dict_get(dict, key); + if (val == NULL) + { + return 0; + } + + *dst = hb_value_get_string_xform(val); + return 1; +} + +int hb_dict_extract_rational(hb_rational_t *dst, const hb_dict_t * dict, + const char * key) +{ + if (dict == NULL || key == NULL || dst == NULL) + { + return 0; + } + + hb_value_t *val = hb_dict_get(dict, key); + if (val == NULL) + { + return 0; + } + + if (hb_value_type(val) == HB_VALUE_TYPE_DICT) + { + hb_value_t * num_val = hb_dict_get(val, "Num"); + if (num_val == NULL) + { + return 0; + } + hb_value_t * den_val = hb_dict_get(val, "Num"); + if (den_val == NULL) + { + return 0; + } + + dst->num = hb_value_get_int(num_val); + dst->den = hb_value_get_int(den_val); + return 1; + } + else if (hb_value_type(val) == HB_VALUE_TYPE_STRING) + { + const char * str = hb_value_get_string(val); + char ** rational = hb_str_vsplit(str, '/'); + if (rational[0] != NULL && rational[1] != NULL && + isdigit(rational[0][0]) && isdigit(rational[1][0])) + { + char *num_end, *den_end; + + // found rational format value + int num = strtol(rational[0], &num_end, 0); + int den = strtol(rational[1], &den_end, 0); + // confirm that the 2 components were entirely numbers + if (num_end[0] == 0 && den_end[0] == 0) + { + dst->num = num; + dst->den = den; + hb_str_vfree(rational); + return 1; + } + } + hb_str_vfree(rational); + } + + return 0; +} + +int hb_dict_extract_int_array(int *dst, int count, + const hb_dict_t * dict, const char * key) +{ + if (dict == NULL || key == NULL || dst == NULL) + { + return 0; + } + + hb_value_t *val = hb_dict_get(dict, key); + if (hb_value_type(val) != HB_VALUE_TYPE_ARRAY) + { + return 0; + } + + int len = hb_value_array_len(val); + count = count < len ? count : len; + + int ii; + for (ii = 0; ii < count; ii++) + { + dst[ii] = hb_value_get_int(hb_value_array_get(val, ii)); + } + return 1; } hb_dict_iter_t hb_dict_iter_init(const hb_dict_t *dict) @@ -534,6 +747,26 @@ hb_value_array_append(hb_value_array_t *array, hb_value_t *value) } void +hb_value_array_concat(hb_value_array_t *array, hb_value_t *value) +{ + if (hb_value_type(value) == HB_VALUE_TYPE_ARRAY) + { + int ii; + int len = hb_value_array_len(value); + + for (ii = 0; ii < len; ii++) + { + hb_value_t * val = hb_value_array_get(value, ii); + json_array_append_new(array, hb_value_dup(val)); + } + } + else + { + json_array_append_new(array, hb_value_dup(value)); + } +} + +void hb_value_array_remove(hb_value_array_t *array, int index) { json_array_remove(array, index); @@ -613,3 +846,4 @@ char * hb_dict_to_encopts(const hb_dict_t * dict) { return hb_value_get_string_xform(dict); } + diff --git a/libhb/hb_dict.h b/libhb/hb_dict.h index 5d44b86d9..2309b8739 100644 --- a/libhb/hb_dict.h +++ b/libhb/hb_dict.h @@ -9,6 +9,7 @@ #if !defined(HB_DICT_H) #define HB_DICT_H +#include "hbtypes.h" #include <jansson.h> #define HB_VALUE_TYPE_DICT JSON_OBJECT @@ -37,13 +38,35 @@ typedef void* hb_dict_iter_t; hb_dict_t * hb_dict_init(void); /* free dictionary and release references to all values it contains */ void hb_dict_free(hb_dict_t ** dict_ptr); +/* return number of member elements in the dictionary */ +int hb_dict_elements(hb_dict_t * dict); /* add value to dictionary. dictionary takes ownership of value */ void hb_dict_set(hb_dict_t * dict, const char * key, hb_value_t * value); +void hb_dict_case_set(hb_dict_t * dict, const char *key, + hb_value_t *value); /* remove value from dictionary. releases reference to value */ int hb_dict_remove(hb_dict_t * dict, const char * key); /* get value from dictionary. value has borrowed reference */ hb_value_t * hb_dict_get(const hb_dict_t * dict, const char * key); +int hb_dict_extract_int(int *dst, + const hb_dict_t * dict, + const char * key); +int hb_dict_extract_double(double *dst, + const hb_dict_t * dict, + const char * key); +int hb_dict_extract_bool(int *dst, + const hb_dict_t * dict, + const char * key); +int hb_dict_extract_string(char **dst, + const hb_dict_t * dict, + const char * key); +int hb_dict_extract_rational(hb_rational_t *dst, + const hb_dict_t * dict, + const char * key); +int hb_dict_extract_int_array(int *dst, int count, + const hb_dict_t * dict, + const char * key); /* dict iterator * hb_dict_iter_init(dict) returns an iter to the first key/value in the dict @@ -81,6 +104,10 @@ void hb_value_array_remove(hb_value_array_t *array, int index); /* clears dst and performs a deep copy */ void hb_value_array_copy(hb_value_array_t *dst, const hb_value_array_t *src, int count); +/* appends copy of value to array. if value is an array, appends a copy of + * each element to array */ +void hb_value_array_concat(hb_value_array_t *array, + hb_value_t *value); size_t hb_value_array_len(const hb_value_array_t *array); /* hb_value_t */ @@ -92,6 +119,7 @@ void hb_value_decref(hb_value_t *value); void hb_value_free(hb_value_t **value); /* Create new hb_value_t */ +hb_value_t * hb_value_null(); hb_value_t * hb_value_string(const char *value); hb_value_t * hb_value_int(json_int_t value); hb_value_t * hb_value_double(double value); @@ -125,4 +153,10 @@ int hb_value_write_json(hb_value_t *value, const char *path); hb_dict_t * hb_encopts_to_dict(const char * encopts, int encoder); char * hb_dict_to_encopts(const hb_dict_t * dict); +/* convenience macros */ +#define hb_dict_get_string(dict, key) hb_value_get_string(hb_dict_get(dict, key)) +#define hb_dict_get_int(dict, key) hb_value_get_int(hb_dict_get(dict, key)) +#define hb_dict_get_double(dict, key) hb_value_get_double(hb_dict_get(dict, key)) +#define hb_dict_get_bool(dict, key) hb_value_get_bool(hb_dict_get(dict, key)) + #endif // !defined(HB_DICT_H) diff --git a/libhb/hb_json.c b/libhb/hb_json.c index ba889244a..39f7392f3 100644 --- a/libhb/hb_json.c +++ b/libhb/hb_json.c @@ -608,7 +608,7 @@ hb_dict_t* hb_job_to_dict( const hb_job_t * job ) if (filter->settings != NULL) { hb_dict_set(filter_dict, "Settings", - hb_value_string(filter->settings)); + hb_value_dup(filter->settings)); } hb_value_array_append(filter_list, filter_dict); @@ -1070,10 +1070,10 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict ) { filter_dict = hb_value_array_get(filter_list, ii); int filter_id = -1; - char *filter_settings = NULL; - result = json_unpack_ex(filter_dict, &error, 0, "{s:i, s?s}", + hb_value_t *filter_settings = NULL; + result = json_unpack_ex(filter_dict, &error, 0, "{s:i, s?o}", "ID", unpack_i(&filter_id), - "Settings", unpack_s(&filter_settings)); + "Settings", unpack_o(&filter_settings)); if (result < 0) { hb_error("hb_dict_to_job: failed to find filter settings: %s", @@ -1084,7 +1084,7 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict ) { hb_filter_object_t *filter; filter = hb_filter_init(filter_id); - hb_add_filter(job, filter, filter_settings); + hb_add_filter_dict(job, filter, filter_settings); } } } @@ -1696,4 +1696,3 @@ hb_image_t* hb_json_to_image(char *json_image) return image; } - diff --git a/libhb/hbtypes.h b/libhb/hbtypes.h new file mode 100644 index 000000000..42a82dd27 --- /dev/null +++ b/libhb/hbtypes.h @@ -0,0 +1,49 @@ +/* hbtypes.h + + Copyright (c) 2003-2016 HandBrake Team + This file is part of the HandBrake source code + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License v2. + For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +#ifndef HB_TYPES_H +#define HB_TYPES_H + +typedef struct hb_handle_s hb_handle_t; +typedef struct hb_hwd_s hb_hwd_t; +typedef struct hb_list_s hb_list_t; +typedef struct hb_buffer_list_s hb_buffer_list_t; +typedef struct hb_rate_s hb_rate_t; +typedef struct hb_dither_s hb_dither_t; +typedef struct hb_mixdown_s hb_mixdown_t; +typedef struct hb_encoder_s hb_encoder_t; +typedef struct hb_container_s hb_container_t; +typedef struct hb_rational_s hb_rational_t; +typedef struct hb_geometry_s hb_geometry_t; +typedef struct hb_geometry_settings_s hb_geometry_settings_t; +typedef struct hb_image_s hb_image_t; +typedef struct hb_job_s hb_job_t; +typedef struct hb_title_set_s hb_title_set_t; +typedef struct hb_title_s hb_title_t; +typedef struct hb_chapter_s hb_chapter_t; +typedef struct hb_audio_s hb_audio_t; +typedef struct hb_audio_config_s hb_audio_config_t; +typedef struct hb_subtitle_s hb_subtitle_t; +typedef struct hb_subtitle_config_s hb_subtitle_config_t; +typedef struct hb_attachment_s hb_attachment_t; +typedef struct hb_metadata_s hb_metadata_t; +typedef struct hb_coverart_s hb_coverart_t; +typedef struct hb_state_s hb_state_t; +typedef union hb_esconfig_u hb_esconfig_t; +typedef struct hb_work_private_s hb_work_private_t; +typedef struct hb_work_object_s hb_work_object_t; +typedef struct hb_filter_private_s hb_filter_private_t; +typedef struct hb_filter_object_s hb_filter_object_t; +typedef struct hb_buffer_s hb_buffer_t; +typedef struct hb_buffer_settings_s hb_buffer_settings_t; +typedef struct hb_image_format_s hb_image_format_t; +typedef struct hb_fifo_s hb_fifo_t; +typedef struct hb_lock_s hb_lock_t; + +#endif // HB_TYPES_H diff --git a/libhb/libhb_presets.list b/libhb/libhb_presets.list index 4afc94091..cb46ba084 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="1" /> + <integer name="VersionMajor" value="12" /> + <integer name="VersionMinor" value="0" /> <integer name="VersionMicro" value="0" /> <json name="Preset" file="preset_template.json" /> </section> diff --git a/libhb/nlmeans.c b/libhb/nlmeans.c index ca661df2e..fd576efca 100644 --- a/libhb/nlmeans.c +++ b/libhb/nlmeans.c @@ -154,15 +154,27 @@ static void nlmeans_close(hb_filter_object_t *filter); static void nlmeans_filter_thread(void *thread_args_v); +static const char nlmeans_template[] = + "y-strength=^"HB_FLOAT_REG"$:y-origin-tune=^"HB_FLOAT_REG"$:" + "y-patch-size=^"HB_INT_REG"$:y-range=^"HB_INT_REG"$:" + "y-frame-count=^"HB_INT_REG"$:y-prefilter=^"HB_INT_REG"$:" + "cb-strength=^"HB_FLOAT_REG"$:cb-origin-tune=^"HB_FLOAT_REG"$:" + "cb-patch-size=^"HB_INT_REG"$:cb-range=^"HB_INT_REG"$:" + "cb-frame-count=^"HB_INT_REG"$:cb-prefilter=^"HB_INT_REG"$:" + "cr-strength=^"HB_FLOAT_REG"$:cr-origin-tune=^"HB_FLOAT_REG"$:" + "cr-patch-size=^"HB_INT_REG"$:cr-range=^"HB_INT_REG"$:" + "cr-frame-count=^"HB_INT_REG"$:cr-prefilter=^"HB_INT_REG"$"; + hb_filter_object_t hb_filter_nlmeans = { - .id = HB_FILTER_NLMEANS, - .enforce_order = 1, - .name = "Denoise (nlmeans)", - .settings = NULL, - .init = nlmeans_init, - .work = nlmeans_work, - .close = nlmeans_close, + .id = HB_FILTER_NLMEANS, + .enforce_order = 1, + .name = "Denoise (nlmeans)", + .settings = NULL, + .init = nlmeans_init, + .work = nlmeans_work, + .close = nlmeans_close, + .settings_template = nlmeans_template, }; static void nlmeans_border(uint8_t *src, @@ -792,10 +804,27 @@ static int nlmeans_init(hb_filter_object_t *filter, // Read user parameters if (filter->settings != NULL) { - sscanf(filter->settings, "%lf:%lf:%d:%d:%d:%d:%lf:%lf:%d:%d:%d:%d:%lf:%lf:%d:%d:%d:%d", - &pv->strength[0], &pv->origin_tune[0], &pv->patch_size[0], &pv->range[0], &pv->nframes[0], &pv->prefilter[0], - &pv->strength[1], &pv->origin_tune[1], &pv->patch_size[1], &pv->range[1], &pv->nframes[1], &pv->prefilter[1], - &pv->strength[2], &pv->origin_tune[2], &pv->patch_size[2], &pv->range[2], &pv->nframes[2], &pv->prefilter[2]); + hb_dict_t * dict = filter->settings; + hb_dict_extract_double(&pv->strength[0], dict, "y-strength"); + hb_dict_extract_double(&pv->origin_tune[0], dict, "y-origin-tune"); + hb_dict_extract_int(&pv->patch_size[0], dict, "y-patch-size"); + hb_dict_extract_int(&pv->range[0], dict, "y-range"); + hb_dict_extract_int(&pv->nframes[0], dict, "y-frame-count"); + hb_dict_extract_int(&pv->prefilter[0], dict, "y-prefilter"); + + hb_dict_extract_double(&pv->strength[1], dict, "cb-strength"); + hb_dict_extract_double(&pv->origin_tune[1], dict, "cb-origin-tune"); + hb_dict_extract_int(&pv->patch_size[1], dict, "cb-patch-size"); + hb_dict_extract_int(&pv->range[1], dict, "cb-range"); + hb_dict_extract_int(&pv->nframes[1], dict, "cb-frame-count"); + hb_dict_extract_int(&pv->prefilter[1], dict, "cb-prefilter"); + + hb_dict_extract_double(&pv->strength[2], dict, "cr-strength"); + hb_dict_extract_double(&pv->origin_tune[2], dict, "cr-origin-tune"); + hb_dict_extract_int(&pv->patch_size[2], dict, "cr-patch-size"); + hb_dict_extract_int(&pv->range[2], dict, "cr-range"); + hb_dict_extract_int(&pv->nframes[2], dict, "cr-frame-count"); + hb_dict_extract_int(&pv->prefilter[2], dict, "cr-prefilter"); } // Cascade values diff --git a/libhb/param.c b/libhb/param.c index e30c56b3e..350f81773 100644 --- a/libhb/param.c +++ b/libhb/param.c @@ -8,13 +8,12 @@ * http://www.gnu.org/licenses/gpl-2.0.html */ +#include "hb_dict.h" #include "param.h" #include "common.h" #include "colormap.h" #include <regex.h> -const char hb_filter_off[] = "off"; - static hb_filter_param_t nlmeans_presets[] = { { 1, "Custom", "custom", NULL }, @@ -38,43 +37,69 @@ static hb_filter_param_t nlmeans_tunes[] = static hb_filter_param_t hqdn3d_presets[] = { { 1, "Custom", "custom", NULL }, - { 5, "Ultralight", "ultralight", "1:0.7:0.7:1:2:2" }, - { 2, "Light", "light", "2:1:1:2:3:3" }, - { 3, "Medium", "medium", "3:2:2:2:3:3" }, - { 4, "Strong", "strong", "7:7:7:5:5:5" }, + { 5, "Ultralight", "ultralight", + "y-spatial=1:cb-spatial=0.7:cr-spatial=0.7:" + "y-temporal=1:cb-temporal=2:cr-temporal=2" + }, + { 2, "Light", "light", + "y-spatial=2:cb-spatial=1:cr-spatial=1:" + "y-temporal=2:cb-temporal=3:cr-temporal=3" + }, + { 3, "Medium", "medium", + "y-spatial=3:cb-spatial=2:cr-spatial=2:" + "y-temporal=2:cb-temporal=3:cr-temporal=3" + }, + { 4, "Strong", "strong", + "y-spatial=7:cb-spatial=7:cr-spatial=7:" + "y-temporal=5:cb-temporal=5:cr-temporal=5" + }, { 0, NULL, NULL, NULL }, // Legacy and aliases go below the NULL - { 2, "Weak", "weak", "2:1:1:2:3:3" }, - { 2, "Default", "default", "2:1:1:2:3:3" }, + { 2, "Weak", "weak", + "y-spatial=2:cb-spatial=1:cr-spatial=1:" + "y-temporal=2:cb-temporal=3:cr-temporal=3" + }, + { 2, "Default", "default", + "y-spatial=2:cb-spatial=1:cr-spatial=1:" + "y-temporal=2:cb-temporal=3:cr-temporal=3" + }, }; static hb_filter_param_t detelecine_presets[] = { - { 0, "Off", "off", hb_filter_off }, + { 0, "Off", "off", "disable=1" }, { 1, "Custom", "custom", NULL }, - { 2, "Default", "default", "" }, + { 2, "Default", "default", + "skip-top=4:skip-bottom=4:skip-left=1:skip-right=1:plane=0" + }, { 0, NULL, NULL, NULL } }; static hb_filter_param_t decomb_presets[] = { { 1, "Custom", "custom", NULL }, - { 2, "Default", "default", "" }, - { 3, "Fast", "fast", "7:2:6:9:1:80" }, - { 4, "Bob", "bob", "455" }, + { 2, "Default", "default", + "mode=391:spatial-metric=2:motion-thresh=3:spatial-thresh=3:" + "filter-mode=2:block-thresh=40" + }, + { 3, "Fast", "fast", + "mode=7:motion-thresh=6:spatial-thresh=9:" + "filter-mode=1:block-thresh=80" + }, + { 4, "Bob", "bob", "mode=455" }, { 0, NULL, NULL, NULL } }; static hb_filter_param_t deinterlace_presets[] = { - { 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", "1:-1:" }, - { 4, "Slower", "slower", "3:-1:" } + { 1, "Custom", "custom", NULL }, + { 3, "Default", "default", "mode=3" }, + { 2, "Skip Spatial Check", "skip-spatial", "mode=1" }, + { 5, "Bob", "bob", "mode=7" }, + { 0, NULL, NULL, NULL }, + { 2, "Fast", "fast", "mode=1" }, + { 3, "Slow", "slow", "mode=1" }, + { 4, "Slower", "slower", "mode=3" } }; typedef struct @@ -90,7 +115,7 @@ static filter_param_map_t param_map[] = { HB_FILTER_NLMEANS, nlmeans_presets, nlmeans_tunes, sizeof(nlmeans_presets) / sizeof(hb_filter_param_t) }, - { HB_FILTER_HQDN3D, hqdn3d_presets, NULL, + { HB_FILTER_HQDN3D, hqdn3d_presets, NULL, sizeof(hqdn3d_presets) / sizeof(hb_filter_param_t) }, { HB_FILTER_DETELECINE, detelecine_presets, NULL, @@ -102,257 +127,9 @@ static filter_param_map_t param_map[] = { HB_FILTER_DEINTERLACE, deinterlace_presets, NULL, sizeof(deinterlace_presets) / sizeof(hb_filter_param_t) }, - { HB_FILTER_INVALID, NULL, NULL, 0 } + { HB_FILTER_INVALID, NULL, NULL, 0 } }; -#define MODE_YADIF_ENABLE 1 -#define MODE_YADIF_SPATIAL 2 -#define MODE_YADIF_BOB 4 -#define MODE_YADIF_AUTO 8 - -/* Deinterlace Settings - * mode:parity - * - * mode - yadif deinterlace mode - * parity - field parity - * - * Modes: - * 1 = Enabled - * 2 = Spatial - * 4 = Bob - * 8 = Auto - * - * 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 automatic = !!(mode & MODE_YADIF_AUTO); - 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:auto=%d:parity=%d'", - mode, automatic, parity); -} - -/* Rotate Settings: - * degrees:mirror - * - * degrees - Rotation angle, may be one of 90, 180, or 270 - * mirror - Mirror image around x axis - * - * Examples: - * Mode 180:1 Mirror then rotate 180' - * Mode 0:1 Mirror - * Mode 180:0 Rotate 180' - * Mode 90:0 Rotate 90' - * Mode 270:0 Rotate 270' - * - * Legacy Mode Examples (also accepted): - * Mode 1: Flip vertically (y0 becomes yN and yN becomes y0) (aka 180:1) - * Mode 2: Flip horizontally (x0 becomes xN and xN becomes x0) (aka 0:1) - * Mode 3: Flip both horizontally and vertically (aka 180:0) - * Mode 4: Rotate 90' (aka 90:0) - * Mode 7: Flip horiz & vert plus Rotate 90' (aka 270:0) - */ -char * -generate_rotate_settings(const char * preset, const char * tune) -{ - char ** args; - const char * trans = NULL; - char * result; - int ii, angle = 180, flip = 0, hflip = 0, vflip = 0; - - args = hb_str_vsplit(preset, ':'); - for (ii = 0; ii < 2 && args[ii]; ii++) - { - switch (ii) - { - case 0: - angle = strtol(args[ii], &result, 0); - break; - case 1: - flip = strtol(args[ii], &result, 0); - break; - default: - break; - } - } - hb_str_vfree(args); - if (angle < 8 && ii == 1) - { - // Legacy value - switch (angle) - { - case 1: - vflip = 1; - break; - case 2: - hflip = 1; - break; - case 3: - vflip = hflip = 1; - break; - case 4: - trans = "clock"; - break; - case 5: - trans = "cclock_flip"; - break; - case 6: - trans = "clock_flip"; - break; - case 7: - trans = "cclock"; - break; - default: - break; - } - } - else - { - const char * clock; - const char * cclock; - if (flip) - { - clock = "clock_flip"; - cclock = "cclock_flip"; - } - else - { - clock = "clock"; - cclock = "cclock"; - } - switch (angle) - { - case 0: - hflip = flip; - break; - case 90: - trans = clock; - break; - case 180: - vflip = hflip = 1; - break; - case 270: - trans = cclock; - break; - default: - break; - } - } - if (trans != NULL) - { - return hb_strdup_printf("transpose='dir=%s'", trans); - } - else if (vflip || hflip) - { - return hb_strdup_printf("%s%s%s", - vflip ? "vflip" : "", - hflip ? ", " : "", - hflip ? "hflip" : ""); - } - else - { - return (char*)hb_filter_off; - } -} - -/* Pad presets and tunes - * - * There are currently no presets and tunes for pad - * The custom pad string is converted to an avformat filter graph string - */ -char * -generate_pad_settings(const char * preset, const char * tune) -{ - int width = 0, height = 0, rgb = 0; - int x = -1, y = -1, ii; - char ** args; - char * result; - - args = hb_str_vsplit(preset, ':'); - for (ii = 0; ii < 5 && args[ii]; ii++) - { - if (args[ii][0] == 0 || !strcasecmp("auto", args[ii])) - continue; - switch (ii) - { - case 0: - width = strtol(args[ii], &result, 0); - break; - case 1: - height = strtol(args[ii], &result, 0); - break; - case 2: - rgb = strtol(args[ii], &result, 0); - if (result == args[ii]) - { - // Not a numeric value, lookup by name - rgb = hb_rgb_lookup_by_name(args[2]); - } - break; - case 3: - x = strtol(args[ii], &result, 0); - break; - case 4: - y = strtol(args[ii], &result, 0); - break; - default: - break; - } - } - hb_str_vfree(args); - - char x_str[20]; - char y_str[20]; - if (x < 0) - { - snprintf(x_str, 20, "(out_w-in_w)/2"); - } - else - { - snprintf(x_str, 20, "%d", x); - } - if (y < 0) - { - snprintf(y_str, 20, "(out_h-in_h)/2"); - } - else - { - snprintf(y_str, 20, "%d", y); - } - result = hb_strdup_printf( - "pad='width=%d:height=%d:x=%s:y=%s:color=0x%06x'", - width, height, x_str, y_str, rgb); - return result; -} - /* NL-means presets and tunes * * Presets adjust strength: @@ -368,16 +145,18 @@ generate_pad_settings(const char * preset, const char * tune) * highmotion - like film but avoids color smearing with stronger settings * animation - cel animation such as cartoons, anime */ -static char * generate_nlmeans_settings(const char *preset, const char *tune) +static hb_dict_t * generate_nlmeans_settings(const char *preset, + const char *tune, + const char *custom) { - char *opt = NULL; + hb_dict_t * settings; if (preset == NULL) return NULL; - if (!strcasecmp(preset, "custom") && tune != NULL) + if (preset == NULL || !strcasecmp(preset, "custom")) { - return strdup(tune); + return hb_parse_filter_settings(custom); } if (!strcasecmp(preset, "ultralight") || !strcasecmp(preset, "light") || @@ -513,31 +292,38 @@ static char * generate_nlmeans_settings(const char *preset, const char *tune) return NULL; } - opt = hb_strdup_printf("%lf:%lf:%d:%d:%d:%d:%lf:%lf:%d:%d:%d:%d", - strength[0], origin_tune[0], patch_size[0], - range[0], frames[0], prefilter[0], - strength[1], origin_tune[1], patch_size[1], - range[1], frames[1], prefilter[1]); - - + settings = hb_dict_init(); + hb_dict_set(settings, "y-strength", hb_value_double(strength[0])); + hb_dict_set(settings, "y-origin-tune", hb_value_double(origin_tune[0])); + hb_dict_set(settings, "y-patch-size", hb_value_int(patch_size[0])); + hb_dict_set(settings, "y-range", hb_value_int(range[0])); + hb_dict_set(settings, "y-frame-count", hb_value_int(frames[0])); + hb_dict_set(settings, "y-prefilter", hb_value_int(prefilter[0])); + + hb_dict_set(settings, "cb-strength", hb_value_double(strength[1])); + hb_dict_set(settings, "cb-origin-tune", hb_value_double(origin_tune[1])); + hb_dict_set(settings, "cb-patch-size", hb_value_int(patch_size[1])); + hb_dict_set(settings, "cb-range", hb_value_int(range[1])); + hb_dict_set(settings, "cb-frame-count", hb_value_int(frames[1])); + hb_dict_set(settings, "cb-prefilter", hb_value_int(prefilter[1])); } else { - opt = strdup(preset); + settings = hb_parse_filter_settings(preset); if (tune != NULL) { fprintf(stderr, "Custom nlmeans parameters specified; ignoring nlmeans tune (%s).\n", tune); } } - return opt; + return settings; } int hb_validate_param_string(const char *regex_pattern, const char *param_string) { regex_t regex_temp; - if (regcomp(®ex_temp, regex_pattern, REG_EXTENDED) == 0) + if (regcomp(®ex_temp, regex_pattern, REG_EXTENDED|REG_ICASE) == 0) { if (regexec(®ex_temp, param_string, 0, NULL, 0) == 0) { @@ -547,66 +333,109 @@ int hb_validate_param_string(const char *regex_pattern, const char *param_string } else { - fprintf(stderr, "hb_validate_param_string: Error compiling regex for pattern (%s).\n", param_string); + hb_log("hb_validate_param_string: Error compiling regex for pattern (%s).\n", param_string); } regfree(®ex_temp); return 1; } -int hb_validate_filter_settings(int filter_id, const char *filter_param) +int hb_validate_filter_settings(int filter_id, const hb_dict_t * settings) { - if (filter_param == NULL) - return 0; + hb_filter_object_t * filter; + hb_dict_t * settings_template; + hb_dict_iter_t iter; - // Regex matches "number" followed by one or more ":number", where number is int or float - const char *hb_colon_separated_params_regex = "^(((([\\-])?[0-9]+([.,][0-9]+)?)|(([\\-])?[.,][0-9]+))((:((([\\-])?[0-9]+([,.][0-9]+)?)|(([\\-])?[,.][0-9]+)))+)?)$"; - const char *hb_pad_regex = "^([0-9]*|auto)(:([0-9]*|auto)(:([a-zA-Z0-9]*|auto)(:([0-9]*|auto)(:([0-9]*|auto))?)?)?)?$"; + if (settings == NULL) + return 0; - const char *regex_pattern = NULL; + // Verify that all keys in settings are in the filter settings template + filter = hb_filter_get(filter_id); + if (filter == NULL) + { + hb_log("hb_validate_filter_settings: Unrecognized filter (%d).\n", + filter_id); + return 1; + } + if (filter->settings_template == NULL) + { + // filter has no template to verify settings against + return 0; + } + settings_template = hb_parse_filter_settings(filter->settings_template); + if (settings_template == NULL) + { + hb_log("hb_validate_filter_settings: invalid template!"); + return 0; + } - switch (filter_id) + for (iter = hb_dict_iter_init(settings); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(settings, iter)) { - case HB_FILTER_PAD: - regex_pattern = hb_pad_regex; - break; - case HB_FILTER_ROTATE: - case HB_FILTER_DEBLOCK: - case HB_FILTER_DETELECINE: - case HB_FILTER_DECOMB: - case HB_FILTER_DEINTERLACE: - case HB_FILTER_NLMEANS: - case HB_FILTER_HQDN3D: - if (filter_param[0] == 0) + const char * key; + hb_value_t * val; + + key = hb_dict_iter_key(iter); + + // Check if key found in settings is also found in the template + val = hb_dict_get(settings_template, key); + if (val == NULL) + { + // Key is missing from template, indicate invalid settings + hb_log("Invalid filter key (%s) for filter %s", + key, filter->name); + return 1; + } + + // If a string value is found, and it is non-empty, + // it is a regex pattern for allowed values. + const char * regex_pattern = hb_value_get_string(val); + if (regex_pattern != NULL && regex_pattern[0] != 0) + { + char * param; + param = hb_value_get_string_xform(hb_dict_get(settings, key)); + if (hb_validate_param_string(regex_pattern, param) != 0) { - return 0; + hb_log("Invalid filter value (%s) for key %s filter %s", + param, key, filter->name); + free(param); + return 1; } - regex_pattern = hb_colon_separated_params_regex; - break; - default: - fprintf(stderr, "hb_validate_filter_settings: Unrecognized filter (%d).\n", - filter_id); - return 1; - break; + free(param); + } } + hb_value_free(&settings_template); - if (hb_validate_param_string(regex_pattern, filter_param) == 0) - { - return 0; - } - return 1; + return 0; +} + +int hb_validate_filter_settings_json(int filter_id, const char * json) +{ + hb_value_t * value = hb_value_json(json); + int result = hb_validate_filter_settings(filter_id, value); + hb_value_free(&value); + + return result; } static hb_filter_param_t* filter_param_get_presets_internal(int filter_id, int *count) { int ii; + + if (count != NULL) + { + *count = 0; + } for (ii = 0; param_map[ii].filter_id != HB_FILTER_INVALID; ii++) { if (param_map[ii].filter_id == filter_id) { if (count != NULL) + { *count = param_map[ii].count; + } return param_map[ii].presets; } } @@ -619,13 +448,17 @@ filter_param_get_tunes_internal(int filter_id, int *count) int ii; if (count != NULL) + { *count = 0; + } for (ii = 0; param_map[ii].filter_id != HB_FILTER_INVALID; ii++) { if (param_map[ii].filter_id == filter_id) { if (count != NULL) + { *count = param_map[ii].count; + } return param_map[ii].tunes; } } @@ -651,127 +484,80 @@ filter_param_get_entry(hb_filter_param_t *table, const char *name, int count) return NULL; } -static hb_filter_param_t* -filter_param_get_entry_by_index(hb_filter_param_t *table, int index, int count) +static hb_dict_t * +generate_generic_settings(int filter_id, const char *preset, const char *custom) { - if (table == NULL) - return NULL; + int preset_count; + hb_filter_param_t *preset_table; + hb_filter_param_t *preset_entry; - int ii; - for (ii = 0; ii < count; ii++) + if (preset == NULL || !strcasecmp(preset, "custom")) { - if (table[ii].name != NULL && table[ii].index == index) - { - return &table[ii]; - } + return hb_parse_filter_settings(custom); } - return NULL; -} - -static char * -generate_generic_settings(int filter_id, const char *preset, const char *tune) -{ - char *opt = NULL; - int preset_count, tune_count; - hb_filter_param_t *preset_table, *tune_table; - hb_filter_param_t *preset_entry, *tune_entry; preset_table = filter_param_get_presets_internal(filter_id, &preset_count); - tune_table = filter_param_get_tunes_internal(filter_id, &tune_count); preset_entry = filter_param_get_entry(preset_table, preset, preset_count); - tune_entry = filter_param_get_entry(tune_table, tune, tune_count); - if (preset_entry != NULL) - { - if (!strcasecmp(preset, "custom") && tune != NULL) - { - opt = strdup(tune); - } - else if (preset_entry->settings == hb_filter_off) - { - return (char*)hb_filter_off; - } - else if (preset_entry->settings != NULL) - { - opt = hb_strdup_printf("%s%s%s", preset_entry->settings, - tune_entry != NULL ? ":" : "", - tune_entry != NULL ? tune_entry->settings : ""); - } - } - else if (preset != NULL) + if (preset_entry != NULL && preset_entry->settings != NULL) { - return strdup(preset); + return hb_parse_filter_settings(preset_entry->settings); } - return opt; + return NULL; } -// Legacy: old presets store filter falues as indexes :( -static char * -generate_generic_settings_by_index(int filter_id, int preset, - const char *custom) +static hb_value_t * +generate_deblock_settings(const char * preset, const char * custom) { - char *opt = NULL; - int preset_count; - hb_filter_param_t *preset_table; - hb_filter_param_t *preset_entry; + hb_dict_t * settings = NULL; - preset_table = filter_param_get_presets_internal(filter_id, &preset_count); - preset_entry = filter_param_get_entry_by_index(preset_table, preset, - preset_count); - if (preset_entry != NULL) + // Deblock "presets" are just the QP value. 0 disables. + if ((preset == NULL || !strcasecmp(preset, "custom"))) { - if (!strcasecmp(preset_entry->short_name, "custom") && custom != NULL) - { - opt = strdup(custom); - } - else if (preset_entry->settings == hb_filter_off) - { - return (char*)hb_filter_off; - } - else if (preset_entry->settings != NULL) + settings = hb_parse_filter_settings(custom); + } + else + { + settings = hb_dict_init(); + int qp = strtol(preset, NULL, 0); + if (qp < 5) { - opt = hb_strdup_printf("%s", preset_entry->settings); + hb_dict_set(settings, "disable", hb_value_bool(1)); } + hb_dict_set(settings, "qp", hb_value_int(qp)); } - return opt; + + return settings; } -char * -hb_generate_filter_settings_by_index(int filter_id, int preset, - const char *custom) +hb_value_t * +hb_generate_filter_settings(int filter_id, const char *preset, const char *tune, + const char *custom) { - char *filter_param = NULL; + hb_value_t * settings = NULL; switch (filter_id) { + case HB_FILTER_DEBLOCK: + settings = generate_deblock_settings(preset, custom); + break; + case HB_FILTER_PAD: case HB_FILTER_ROTATE: - if (preset <= 0) - filter_param = (char*)hb_filter_off; - else - filter_param = hb_strdup_printf("%d", preset); + case HB_FILTER_CROP_SCALE: + case HB_FILTER_VFR: + case HB_FILTER_RENDER_SUB: + case HB_FILTER_GRAYSCALE: + case HB_FILTER_QSV: + settings = hb_parse_filter_settings(custom); break; - case HB_FILTER_DEBLOCK: - if (preset < 5) - filter_param = (char*)hb_filter_off; - else - filter_param = hb_strdup_printf("%d", preset); + case HB_FILTER_NLMEANS: + settings = generate_nlmeans_settings(preset, tune, custom); break; case HB_FILTER_DECOMB: 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; + settings = generate_generic_settings(filter_id, preset, custom); + break; default: fprintf(stderr, "hb_generate_filter_settings: Unrecognized filter (%d).\n", @@ -779,83 +565,47 @@ hb_generate_filter_settings_by_index(int filter_id, int preset, break; } - if (filter_param == hb_filter_off) - return filter_param; - - if (filter_param != NULL && - hb_validate_filter_settings(filter_id, filter_param) == 0) + if (settings != NULL && + hb_validate_filter_settings(filter_id, settings) == 0) { - return filter_param; + return settings; } - free(filter_param); + hb_value_free(&settings); return NULL; } char * -hb_generate_filter_settings(int filter_id, const char *preset, const char *tune) +hb_generate_filter_settings_json(int filter_id, const char *preset, + const char *tune, const char *custom) { - char *filter_param = NULL; + hb_value_t * settings; - switch (filter_id) + settings = hb_generate_filter_settings(filter_id, preset, tune, custom); + if (settings == NULL) { - case HB_FILTER_PAD: - if (preset == NULL) return NULL; - if (!strcasecmp(preset, "off")) return (char*)hb_filter_off; - if (hb_validate_filter_settings(filter_id, preset)) return NULL; - - return generate_pad_settings(preset, tune); - case HB_FILTER_ROTATE: - if (preset == NULL) return NULL; - if (!strcasecmp(preset, "off")) return (char*)hb_filter_off; - if (hb_validate_filter_settings(filter_id, preset)) return NULL; - - return generate_rotate_settings(preset, tune); - case HB_FILTER_NLMEANS: - filter_param = generate_nlmeans_settings(preset, tune); - break; - case HB_FILTER_DEBLOCK: - if (atoi(preset) < 5) - filter_param = (char*)hb_filter_off; - else - filter_param = strdup(preset); - break; - case HB_FILTER_DECOMB: - 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", - filter_id); - break; + return NULL; } - if (filter_param == hb_filter_off) - return filter_param; + char * result = hb_value_get_json(settings); + hb_value_free(&settings); + return result; +} - if (filter_param != NULL && - hb_validate_filter_settings(filter_id, filter_param) == 0) +int hb_validate_filter_string(int filter_id, const char * filter_str) +{ + hb_dict_t * settings = hb_parse_filter_settings(filter_str); + if (settings == NULL) { - return filter_param; + return 1; } - free(filter_param); - return NULL; + int result = hb_validate_filter_settings(filter_id, settings); + hb_value_free(&settings); + return result; } int -hb_validate_filter_preset(int filter_id, const char *preset, const char *tune) +hb_validate_filter_preset(int filter_id, const char *preset, const char *tune, + const char *custom) { if (preset == NULL && tune == NULL) return 1; @@ -868,41 +618,25 @@ hb_validate_filter_preset(int filter_id, const char *preset, const char *tune) preset_entry = filter_param_get_entry(preset_table, preset, preset_count); if (preset_entry == NULL || preset_entry->name == NULL) return 1; - if (tune != NULL) + if (!strcasecmp(preset, "custom") && custom != NULL) { - if (!strcasecmp(preset, "custom") && tune != NULL) + hb_dict_t * settings = hb_parse_filter_settings(custom); + if (settings == NULL) { - return hb_validate_filter_settings(filter_id, tune); - } - tune_table = filter_param_get_tunes_internal(filter_id, &tune_count); - tune_entry = filter_param_get_entry(tune_table, tune, tune_count); - if (tune_entry == NULL) return 1; + } + int result = hb_validate_filter_settings(filter_id, settings); + hb_value_free(&settings); + return result; } - return 0; -} - -int -hb_validate_filter_preset_by_index(int filter_id, int preset, const char *tune) -{ - int preset_count, tune_count; - hb_filter_param_t *preset_table, *tune_table; - hb_filter_param_t *preset_entry, *tune_entry; - - preset_table = filter_param_get_presets_internal(filter_id, &preset_count); - preset_entry = filter_param_get_entry_by_index(preset_table, preset, preset_count); - if (preset_entry == NULL || preset_entry->name == NULL) - return 1; if (tune != NULL) { - if (!strcasecmp(preset_entry->short_name, "custom") && tune != NULL) - { - return hb_validate_filter_settings(filter_id, tune); - } tune_table = filter_param_get_tunes_internal(filter_id, &tune_count); tune_entry = filter_param_get_entry(tune_table, tune, tune_count); if (tune_entry == NULL) + { return 1; + } } return 0; } @@ -953,3 +687,114 @@ hb_filter_param_t* hb_filter_param_get_tunes(int filter_id) return filter_param_get_tunes_internal(filter_id, NULL); } +// Get json array of filter preset name and short_name +char * hb_filter_get_presets_json(int filter_id) +{ + hb_value_array_t * array = hb_value_array_init(); + int ii, count = 0; + hb_filter_param_t * table; + + table = filter_param_get_presets_internal(filter_id, NULL); + + for (count = 0; table[count].name != NULL; count++); + for (ii = 0; ii < count; ii++) + { + hb_dict_t * dict = hb_dict_init(); + hb_dict_set(dict, "short_name", hb_value_string(table[ii].short_name)); + hb_dict_set(dict, "name", hb_value_string(table[ii].name)); + hb_value_array_append(array, dict); + } + + char * result = hb_value_get_json(array); + hb_value_free(&array); + return result; +} + +// Get json array of filter tune name and short_name +char * hb_filter_get_tunes_json(int filter_id) +{ + hb_value_array_t * array = hb_value_array_init(); + int ii, count = 0; + hb_filter_param_t * table; + + table = filter_param_get_tunes_internal(filter_id, NULL); + + for (count = 0; table[count].name != NULL; count++); + for (ii = 0; ii < count; ii++) + { + hb_dict_t * dict = hb_dict_init(); + hb_dict_set(dict, "short_name", hb_value_string(table[ii].short_name)); + hb_dict_set(dict, "name", hb_value_string(table[ii].name)); + hb_value_array_append(array, dict); + } + + char * result = hb_value_get_json(array); + hb_value_free(&array); + return result; +} + +char ** hb_filter_get_presets_short_name(int filter_id) +{ + int ii, count = 0; + hb_filter_param_t * table; + + table = filter_param_get_presets_internal(filter_id, NULL); + + for (count = 0; table[count].name != NULL; count++); + char ** result = calloc(count + 1, sizeof(char*)); + for (ii = 0; ii < count; ii++) + { + result[ii] = strdup(table[ii].short_name); + } + result[ii] = NULL; + + return result; +} + +char ** hb_filter_get_presets_name(int filter_id) +{ + int ii, count = 0; + hb_filter_param_t * table; + + table = filter_param_get_presets_internal(filter_id, NULL); + + for (count = 0; table[count].name != NULL; count++); + char ** result = calloc(count + 1, sizeof(char*)); + for (ii = 0; ii < count; ii++) + { + result[ii] = strdup(table[ii].name); + } + result[ii] = NULL; + + return result; +} + +char ** hb_filter_get_keys(int filter_id) +{ + hb_filter_object_t * filter = hb_filter_get(filter_id); + + if (filter == NULL || filter->settings_template == NULL) + { + return NULL; + } + + char ** tmpl = hb_str_vsplit(filter->settings_template, ':'); + int ii, count = 0; + + for (ii = 0; tmpl[ii] != NULL; ii++) + { + count++; + } + char ** result = calloc(count + 1, sizeof(char*)); + for (ii = 0; tmpl[ii] != NULL; ii++) + { + char ** pair = hb_str_vsplit(tmpl[ii], '='); + result[ii] = strdup(pair[0]); + hb_str_vfree(pair); + } + result[ii] = NULL; + hb_str_vfree(tmpl); + + return result; +} + diff --git a/libhb/param.h b/libhb/param.h index 2256441e9..d61fd389c 100644 --- a/libhb/param.h +++ b/libhb/param.h @@ -9,8 +9,6 @@ #ifndef HB_PARAM_H #define HB_PARAM_H -extern const char hb_filter_off[]; - typedef struct hb_filter_param_s hb_filter_param_t; struct hb_filter_param_s @@ -21,18 +19,24 @@ struct hb_filter_param_s const char *settings; }; -char * hb_generate_filter_settings(int filter_id, - const char *preset, const char *tune); -char * hb_generate_filter_settings_by_index(int filter_id, int preset, - const char *custom); +hb_dict_t * hb_generate_filter_settings(int filter_id, const char *preset, + const char *tune, const char *custom); +char * hb_generate_filter_settings_json(int filter_id, const char *preset, + const char *tune, const char *custom); -int hb_validate_filter_preset(int filter_id, - const char *preset, const char *tune); -int hb_validate_filter_settings(int filter_id, const char *filter_param); -int hb_validate_param_string(const char *regex_pattern, - const char *param_string); +int hb_validate_filter_preset(int filter_id, const char *preset, + const char *tune, const char *custom); +int hb_validate_filter_settings(int filter_id, const hb_dict_t *settings); +int hb_validate_filter_settings_json(int filter_id, const char * json); +int hb_validate_filter_string(int filter_id, const char * filter_str); hb_filter_param_t * hb_filter_param_get_presets(int filter_id); hb_filter_param_t * hb_filter_param_get_tunes(int filter_id); +char ** hb_filter_get_keys(int filter_id); +char ** hb_filter_get_presets_short_name(int filter_id); +char ** hb_filter_get_presets_name(int filter_id); +char * hb_filter_get_presets_json(int filter_id); +char * hb_filter_get_tunes_json(int filter_id); + #endif // HB_PARAM_H diff --git a/libhb/preset.c b/libhb/preset.c index 1670b469b..9b5f0616a 100644 --- a/libhb/preset.c +++ b/libhb/preset.c @@ -1072,8 +1072,8 @@ static int get_video_framerate(hb_value_t *rate_value) int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) { - hb_value_t *filters_dict, *filter_list, *filter_dict; - char *filter_str; + hb_value_t * filters_dict, * filter_list, * filter_dict; + hb_dict_t * filter_settings; int clock_min, clock_max, clock; hb_video_framerate_get_limits(&clock_min, &clock_max, &clock); @@ -1091,30 +1091,26 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) const char *custom; custom = hb_value_get_string(hb_dict_get(preset, "PictureDetelecineCustom")); - if (hb_value_type(detel_val) == HB_VALUE_TYPE_STRING) - { - filter_str = hb_generate_filter_settings( - HB_FILTER_DETELECINE, hb_value_get_string(detel_val), custom); - } - else - { - filter_str = hb_generate_filter_settings_by_index( - HB_FILTER_DETELECINE, hb_value_get_int(detel_val), custom); - } - if (filter_str == NULL) + filter_settings = hb_generate_filter_settings( + HB_FILTER_DETELECINE, hb_value_get_string(detel_val), NULL, custom); + + if (filter_settings == NULL) { char *s = hb_value_get_string_xform(detel_val); hb_error("Invalid detelecine filter settings (%s)", s); free(s); return -1; } - else if (filter_str != hb_filter_off) + else if (!hb_dict_get_bool(filter_settings, "disable")) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DETELECINE)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); } } @@ -1143,20 +1139,23 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) hb_error("Invalid deinterlace filter (%s)", deint_filter); return -1; } - filter_str = hb_generate_filter_settings( - filter_id, deint_preset, deint_custom); - if (filter_str == NULL) + filter_settings = hb_generate_filter_settings( + filter_id, deint_preset, NULL, deint_custom); + if (filter_settings == NULL) { hb_error("Invalid deinterlace filter preset (%s)", deint_preset); return -1; } - else if (filter_str != hb_filter_off) + else if (!hb_dict_get_bool(filter_settings, "disable")) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(filter_id)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); } } @@ -1171,21 +1170,19 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) if (denoise != 0) { int filter_id = denoise == 1 ? HB_FILTER_NLMEANS : HB_FILTER_HQDN3D; - const char *denoise_preset, *denoise_tune; + const char *denoise_preset, *denoise_tune, *denoise_custom; denoise_preset = hb_value_get_string( hb_dict_get(preset, "PictureDenoisePreset")); if (denoise_preset != NULL) { - if (strcasecmp(denoise_preset, "custom")) - denoise_tune = hb_value_get_string( - hb_dict_get(preset, "PictureDenoiseTune")); - else - denoise_tune = hb_value_get_string( - hb_dict_get(preset, "PictureDenoiseCustom")); + denoise_tune = hb_value_get_string( + hb_dict_get(preset, "PictureDenoiseTune")); + denoise_custom = hb_value_get_string( + hb_dict_get(preset, "PictureDenoiseCustom")); - filter_str = hb_generate_filter_settings( - filter_id, denoise_preset, denoise_tune); - if (filter_str == NULL) + filter_settings = hb_generate_filter_settings(filter_id, + denoise_preset, denoise_tune, denoise_custom); + if (filter_settings == NULL) { hb_error("Invalid denoise filter settings (%s%s%s)", denoise_preset, @@ -1193,14 +1190,16 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) denoise_tune ? denoise_tune : ""); return -1; } - else if (filter_str != hb_filter_off) + else if (!hb_dict_get_bool(filter_settings, "disable")) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(filter_id)); - hb_dict_set(filter_dict, "Settings", - hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); } } } @@ -1210,20 +1209,25 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) hb_dict_get(preset, "PictureDeblock")); if (deblock != NULL) { - filter_str = hb_generate_filter_settings(HB_FILTER_DEBLOCK, - deblock, NULL); - if (filter_str == NULL) + const char * deblock_custom = hb_value_get_string( + hb_dict_get(preset, "PictureDeblockCustom")); + filter_settings = hb_generate_filter_settings(HB_FILTER_DEBLOCK, + deblock, NULL, deblock_custom); + if (filter_settings == NULL) { hb_error("Invalid deblock filter settings (%s)", deblock); return -1; } - else if (filter_str != hb_filter_off) + else if (!hb_dict_get_bool(filter_settings, "disable")) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DEBLOCK)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); } } free(deblock); @@ -1233,20 +1237,23 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) hb_dict_get(preset, "PictureRotate")); if (rotate != NULL) { - filter_str = hb_generate_filter_settings(HB_FILTER_ROTATE, - rotate, NULL); - if (filter_str == NULL) + filter_settings = hb_generate_filter_settings(HB_FILTER_ROTATE, + NULL, NULL, rotate); + if (filter_settings == NULL) { hb_error("Invalid rotate filter settings (%s)", rotate); return -1; } - else if (filter_str != hb_filter_off) + else if (!hb_dict_get_bool(filter_settings, "disable")) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_ROTATE)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); } } free(rotate); @@ -1256,41 +1263,44 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_GRAYSCALE)); - hb_value_array_append(filter_list, filter_dict); - } - - hb_value_t *fr_value = hb_dict_get(preset, "VideoFramerate"); - int vrate_den = get_video_framerate(fr_value); - if (vrate_den < 0) - { - char *str = hb_value_get_string_xform(fr_value); - hb_error("Invalid video framerate (%s)", str); - free(str); - return -1; + hb_add_filter2(filter_list, filter_dict); } // Pad filter - char *pad = hb_value_get_string_xform( - hb_dict_get(preset, "PicturePad")); + char *pad = hb_value_get_string_xform(hb_dict_get(preset, "PicturePad")); if (pad != NULL) { - filter_str = hb_generate_filter_settings(HB_FILTER_PAD, pad, NULL); - if (filter_str == NULL) + filter_settings = hb_generate_filter_settings(HB_FILTER_PAD, + NULL, NULL, pad); + if (filter_settings == NULL) { hb_error("Invalid pad filter settings (%s)", pad); return -1; } - else if (filter_str != hb_filter_off) + else if (!hb_dict_get_bool(filter_settings, "disable")) { filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_PAD)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); } } free(pad); + hb_value_t *fr_value = hb_dict_get(preset, "VideoFramerate"); + int vrate_den = get_video_framerate(fr_value); + if (vrate_den < 0) + { + char *str = hb_value_get_string_xform(fr_value); + hb_error("Invalid video framerate (%s)", str); + free(str); + return -1; + } + int fr_mode; hb_value_t *fr_mode_value = hb_dict_get(preset, "VideoFramerateMode"); fr_mode = hb_value_type(fr_mode_value) == HB_VALUE_TYPE_STRING ? ( @@ -1298,16 +1308,29 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) !strcasecmp(hb_value_get_string(fr_mode_value), "pfr") ? 2 : 0) : hb_value_get_int(fr_mode_value); + filter_settings = hb_dict_init(); if (vrate_den == 0) - filter_str = hb_strdup_printf("%d", fr_mode); + { + hb_dict_set(filter_settings, "mode", hb_value_int(fr_mode)); + } else - filter_str = hb_strdup_printf("%d:%d:%d", fr_mode, clock, vrate_den); + { + char *str = hb_strdup_printf("%d/%d", clock, vrate_den); + hb_dict_set(filter_settings, "mode", hb_value_int(fr_mode)); + hb_dict_set(filter_settings, "rate", hb_value_string(str)); + free(str); + } + if (hb_validate_filter_settings(HB_FILTER_VFR, filter_settings)) + { + hb_error("hb_preset_apply_filters: Internal error, invalid VFR"); + hb_value_free(&filter_settings); + return -1; + } filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_VFR)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - hb_value_array_append(filter_list, filter_dict); - free(filter_str); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); return 0; } @@ -1623,19 +1646,26 @@ int hb_preset_apply_title(hb_handle_t *h, int title_index, par_dict = NULL; hb_dict_t *filter_dict; - char *filter_str; - - // Setup scale filter - filter_str = hb_strdup_printf("%d:%d:%d:%d:%d:%d", - resultGeo.width, resultGeo.height, - geo.crop[0], geo.crop[1], - geo.crop[2], geo.crop[3]); + hb_dict_t *filter_settings; + + filter_settings = hb_dict_init(); + hb_dict_set(filter_settings, "width", hb_value_int(resultGeo.width)); + hb_dict_set(filter_settings, "height", hb_value_int(resultGeo.height)); + hb_dict_set(filter_settings, "crop-top", hb_value_int(geo.crop[0])); + hb_dict_set(filter_settings, "crop-bottom", hb_value_int(geo.crop[1])); + hb_dict_set(filter_settings, "crop-left", hb_value_int(geo.crop[2])); + hb_dict_set(filter_settings, "crop-right", hb_value_int(geo.crop[3])); + if (hb_validate_filter_settings(HB_FILTER_CROP_SCALE, filter_settings)) + { + hb_error("hb_preset_apply_title: Internal error, invalid CROP_SCALE"); + hb_value_free(&filter_settings); + goto fail; + } filter_dict = hb_dict_init(); hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_CROP_SCALE)); - hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); - free(filter_str); - hb_value_array_append(filter_list, filter_dict); + hb_dict_set(filter_dict, "Settings", filter_settings); + hb_add_filter2(filter_list, filter_dict); // Audio settings if (hb_preset_job_add_audio(h, title_index, preset, job_dict) != 0) @@ -1969,6 +1999,95 @@ void hb_presets_clean(hb_value_t *preset) presets_clean(preset, hb_preset_template); } +static void import_custom_11_1_0(hb_value_t * preset, int filter_id, + const char * key) +{ + const char *str = hb_dict_get_string(preset, key); + if (str == NULL) + { + return; + } + hb_filter_object_t * filter = hb_filter_get(filter_id); + if (filter == NULL) + { + hb_log("import_custom_11_1_0: invalid filter id %d\n", filter_id); + return; + } + if (filter->settings_template == NULL) + { + return; + } + char ** values = hb_str_vsplit(str, ':'); + char ** tmpl = hb_str_vsplit(filter->settings_template, ':'); + int ii; + + hb_dict_t * dict = hb_dict_init(); + for (ii = 0; values[ii] != NULL; ii++) + { + if (tmpl[ii] == NULL) + { + // Incomplete template? + break; + } + char ** pair = hb_str_vsplit(tmpl[ii], '='); + if (pair[0] != NULL) + { + hb_dict_set(dict, pair[0], hb_value_string(values[ii])); + } + hb_str_vfree(pair); + } + hb_str_vfree(tmpl); + hb_str_vfree(values); + + char * result = hb_filter_settings_string(filter_id, dict); + hb_dict_set(preset, key, hb_value_string(result)); + free(result); +} + +static void import_filters_11_1_0(hb_value_t *preset) +{ + hb_value_t *val = hb_dict_get(preset, "PictureDeinterlaceFilter"); + if (val != NULL) + { + const char * str = hb_value_get_string(val); + if (str != NULL) + { + if (strcasecmp(str, "deinterlace")) + { + import_custom_11_1_0(preset, HB_FILTER_DEINTERLACE, + "PictureDeinterlaceCustom"); + } + else if (strcasecmp(str, "decomb")) + { + import_custom_11_1_0(preset, HB_FILTER_DECOMB, + "PictureDeinterlaceCustom"); + } + } + } + val = hb_dict_get(preset, "PictureDenoiseFilter"); + if (val != NULL) + { + const char * str = hb_value_get_string(val); + if (str != NULL) + { + if (strcasecmp(str, "hqdn3d")) + { + import_custom_11_1_0(preset, HB_FILTER_HQDN3D, + "PictureDenoiseCustom"); + } + else if (strcasecmp(str, "nlmeans")) + { + import_custom_11_1_0(preset, HB_FILTER_NLMEANS, + "PictureDenoiseCustom"); + } + } + } + import_custom_11_1_0(preset, HB_FILTER_DETELECINE, + "PictureDetelecineCustom"); + import_custom_11_1_0(preset, HB_FILTER_ROTATE, + "PictureRotate"); +} + static void import_deint_11_0_0(hb_value_t *preset) { hb_value_t *val = hb_dict_get(preset, "PictureDeinterlaceFilter"); @@ -2075,7 +2194,6 @@ 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) @@ -2127,7 +2245,6 @@ static void import_deint_0_0_0(hb_value_t *preset) hb_dict_set(preset, "PictureDeinterlace", hb_value_string("off")); } } - import_deint_10_0_0(preset); } static void import_detel_0_0_0(hb_value_t *preset) @@ -2336,24 +2453,38 @@ static void import_video_0_0_0(hb_value_t *preset) } } -static void import_0_0_0(hb_value_t *preset) +static void import_11_1_0(hb_value_t *preset) { - import_video_0_0_0(preset); - import_pic_0_0_0(preset); - import_audio_0_0_0(preset); - import_deint_0_0_0(preset); - import_detel_0_0_0(preset); - import_denoise_0_0_0(preset); + import_filters_11_1_0(preset); +} + +static void import_11_0_0(hb_value_t *preset) +{ + import_deint_11_0_0(preset); + + // Import next... + import_11_1_0(preset); } static void import_10_0_0(hb_value_t *preset) { import_deint_10_0_0(preset); + + // Import next... + import_11_0_0(preset); } -static void import_11_0_0(hb_value_t *preset) +static void import_0_0_0(hb_value_t *preset) { - import_deint_11_0_0(preset); + import_video_0_0_0(preset); + import_pic_0_0_0(preset); + import_audio_0_0_0(preset); + import_deint_0_0_0(preset); + import_detel_0_0_0(preset); + import_denoise_0_0_0(preset); + + // Import next... + import_10_0_0(preset); } static int preset_import(hb_value_t *preset, int major, int minor, int micro) @@ -2378,6 +2509,11 @@ static int preset_import(hb_value_t *preset, int major, int minor, int micro) import_11_0_0(preset); result = 1; } + else if (major == 11 && minor == 1 && micro == 0) + { + import_11_1_0(preset); + result = 1; + } preset_clean(preset, hb_preset_template); } return result; diff --git a/libhb/preset_template.json b/libhb/preset_template.json index 0140aed36..da113f88a 100644 --- a/libhb/preset_template.json +++ b/libhb/preset_template.json @@ -46,6 +46,7 @@ "PictureTopCrop": 0, "PictureDARWidth": 0, "PictureDeblock": 0, + "PictureDeblockCustom": "qp=0:mode=2", "PictureDeinterlaceCustom": "", "PictureDeinterlaceFilter": "off", "PictureDeinterlacePreset": "default", @@ -62,7 +63,7 @@ "PicturePAR": "loose", "PicturePARWidth": 853, "PicturePARHeight": 720, - "PictureRotate": "0", + "PictureRotate": "angle=0:hflip=0", "PictureWidth": 0, "PictureHeight": 0, "PictureForceHeight": 0, diff --git a/libhb/qsv_filter.c b/libhb/qsv_filter.c index f168bb197..3d0858154 100644 --- a/libhb/qsv_filter.c +++ b/libhb/qsv_filter.c @@ -71,16 +71,23 @@ static hb_filter_info_t * hb_qsv_filter_info( hb_filter_object_t * filter ); static void hb_qsv_filter_close( hb_filter_object_t * filter ); +static const char qsv_filter_template[] = + "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:" + "crop-top=^"HB_INT_REG"$:crop-bottom=^"HB_INT_REG"$:" + "crop-left=^"HB_INT_REG"$:crop-right=^"HB_INT_REG"$:" + "deinterlace=^([01])$"; + hb_filter_object_t hb_filter_qsv = { - .id = HB_FILTER_QSV, - .enforce_order = 1, - .name = "Quick Sync Video VPP", - .settings = NULL, - .init = hb_qsv_filter_init, - .work = hb_qsv_filter_work, - .close = hb_qsv_filter_close, - .info = hb_qsv_filter_info, + .id = HB_FILTER_QSV, + .enforce_order = 1, + .name = "Quick Sync Video VPP", + .settings = NULL, + .init = hb_qsv_filter_init, + .work = hb_qsv_filter_work, + .close = hb_qsv_filter_close, + .info = hb_qsv_filter_info, + .settings_template = qsv_filter_template, }; static int filter_init( av_qsv_context* qsv, hb_filter_private_t * pv ){ @@ -346,13 +353,13 @@ static int hb_qsv_filter_init( hb_filter_object_t * filter, pv->height_out = init->geometry.height; memcpy( pv->crop, init->crop, sizeof( int[4] ) ); - if (filter->settings != NULL) - { - sscanf(filter->settings, "%d:%d:%d:%d:%d:%d_dei:%d", - &pv->width_out, &pv->height_out, - &pv->crop[0], &pv->crop[1], &pv->crop[2], &pv->crop[3], - &pv->deinterlace); - } + hb_dict_extract_int(&pv->width_out, filter->settings, "width"); + hb_dict_extract_int(&pv->height_out, filter->settings, "height"); + hb_dict_extract_int(pv->crop[0], filter->settings, "crop-top"); + hb_dict_extract_int(pv->crop[1], filter->settings, "crop-bottom"); + hb_dict_extract_int(pv->crop[2], filter->settings, "crop-left"); + hb_dict_extract_int(pv->crop[3], filter->settings, "crop-right"); + hb_dict_extract_bool(&pv->deinterlace, filter->settings, "deinterlace"); pv->job = init->job; diff --git a/libhb/vfr.c b/libhb/vfr.c index cc995ff59..d097a7ab1 100644 --- a/libhb/vfr.c +++ b/libhb/vfr.c @@ -48,16 +48,20 @@ static int hb_vfr_work( hb_filter_object_t * filter, static void hb_vfr_close( hb_filter_object_t * filter ); static hb_filter_info_t * hb_vfr_info( hb_filter_object_t * filter ); +static const char hb_vfr_template[] = + "mode=^([012])$:rate=^"HB_RATIONAL_REG"$"; + hb_filter_object_t hb_filter_vfr = { - .id = HB_FILTER_VFR, - .enforce_order = 1, - .name = "Framerate Shaper", - .settings = NULL, - .init = hb_vfr_init, - .work = hb_vfr_work, - .close = hb_vfr_close, - .info = hb_vfr_info, + .id = HB_FILTER_VFR, + .enforce_order = 1, + .name = "Framerate Shaper", + .settings = NULL, + .init = hb_vfr_init, + .work = hb_vfr_work, + .close = hb_vfr_close, + .info = hb_vfr_info, + .settings_template = hb_vfr_template, }; // Create gamma lookup table. @@ -301,11 +305,8 @@ static int hb_vfr_init(hb_filter_object_t *filter, hb_filter_init_t *init) pv->cfr = init->cfr; pv->input_vrate = pv->vrate = init->vrate; - if (filter->settings != NULL) - { - sscanf(filter->settings, "%d:%d:%d", - &pv->cfr, &pv->vrate.num, &pv->vrate.den); - } + hb_dict_extract_int(&pv->cfr, filter->settings, "mode"); + hb_dict_extract_rational(&pv->vrate, filter->settings, "rate"); pv->job = init->job; diff --git a/libhb/work.c b/libhb/work.c index 6e3195e0b..7a1460eec 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -381,11 +381,14 @@ void hb_display_job_info(hb_job_t *job) for( i = 0; i < hb_list_count( job->list_filter ); i++ ) { hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); - if( filter->settings && *filter->settings ) - hb_log(" + %s (%s)", filter->name, filter->settings); + char * settings = hb_filter_settings_string(filter->id, + filter->settings); + if (settings != NULL) + hb_log(" + %s (%s)", filter->name, settings); else hb_log(" + %s (default settings)", filter->name); - if( filter->info ) + free(settings); + if (filter->info) { hb_filter_info_t * info; @@ -899,7 +902,7 @@ static int sanitize_subtitles( hb_job_t * job ) // not required to add the subtitle rendering filter since // we will always try to do it here. hb_filter_object_t *filter = hb_filter_init(HB_FILTER_RENDER_SUB); - hb_add_filter(job, filter, NULL); + hb_add_filter_dict(job, filter, NULL); } return 0; @@ -1273,9 +1276,9 @@ static int sanitize_qsv( hb_job_t * job ) { // we need filters to copy to system memory and back filter = hb_filter_init(HB_FILTER_QSV_PRE); - hb_add_filter(job, filter, NULL); + hb_add_filter_dict(job, filter, NULL); filter = hb_filter_init(HB_FILTER_QSV_POST); - hb_add_filter(job, filter, NULL); + hb_add_filter_dict(job, filter, NULL); } if (vpp_settings[0] != job->title->geometry.width || vpp_settings[1] != job->title->geometry.height || @@ -1286,17 +1289,18 @@ static int sanitize_qsv( hb_job_t * job ) vpp_settings[6] >= 1 /* deinterlace */) { // we need the VPP filter - char *settings = hb_strdup_printf("%d:%d:%d:%d:%d:%d_dei:%d", - vpp_settings[0], - vpp_settings[1], - vpp_settings[2], - vpp_settings[3], - vpp_settings[4], - vpp_settings[5], - vpp_settings[6]); + hb_dict_t * dict = hb_dict_init(); + hb_dict_set(dict, "width", hb_value_int(vpp_settings[0])); + hb_dict_set(dict, "height", hb_value_int(vpp_settings[1])); + hb_dict_set(dict, "crop-top", hb_value_int(vpp_settings[2])); + hb_dict_set(dict, "crop-bottom", hb_value_int(vpp_settings[3])); + hb_dict_set(dict, "crop-left", hb_value_int(vpp_settings[4])); + hb_dict_set(dict, "crop-right", hb_value_int(vpp_settings[5])); + hb_dict_set(dict, "deinterlace", hb_value_int(vpp_settings[6])); + filter = hb_filter_init(HB_FILTER_QSV); - hb_add_filter(job, filter, settings); - free(settings); + hb_add_filter_dict(job, filter, dict); + hb_value_free(&dict); } } } diff --git a/test/test.c b/test/test.c index 9cf49bbf2..ca4062424 100644 --- a/test/test.c +++ b/test/test.c @@ -7,6 +7,7 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> @@ -41,6 +42,14 @@ #include <IOKit/storage/IODVDMedia.h> #endif +#define NLMEANS_DEFAULT_PRESET "medium" +#define DEINTERLACE_DEFAULT_PRESET "default" +#define DECOMB_DEFAULT_PRESET "default" +#define DETELECINE_DEFAULT_PRESET "default" +#define HQDN3D_DEFAULT_PRESET "medium" +#define ROTATE_DEFAULT "angle=180:hflip=0" +#define DEBLOCK_DEFAULT "qp=5" + /* Options */ static int debug = HB_DEBUG_ALL; static int update = 0; @@ -897,6 +906,170 @@ void SigHandler( int i_signal ) /**************************************************************************** * ShowHelp: ****************************************************************************/ +static void showFilterPresets(FILE* const out, int filter_id) +{ + char ** names = hb_filter_get_presets_short_name(filter_id); + char * slash = "", * newline; + int ii, count = 0, linelen = 0; + +#ifdef USE_QSV +if (filter_id == HB_FILTER_DEINTERLACE && hb_qsv_available()) +{ + count = 1; +} +#endif + + // Count number of entries we want to display + for (ii = 0; names[ii] != NULL; ii++) + { + if (!strcasecmp(names[ii], "custom") || // skip custom + !strcasecmp(names[ii], "off") || // skip off + !strcasecmp(names[ii], "default")) // skip default + continue; + count++; + } + + // If there are no entries, display nothing. + if (count == 0) + { + return; + } + fprintf(out, " Presets:\n" + " <"); + for (ii = 0; names[ii] != NULL; ii++) + { + if (!strcasecmp(names[ii], "custom") || // skip custom + !strcasecmp(names[ii], "off") || // skip off + !strcasecmp(names[ii], "default")) // skip default + continue; + int len = strlen(names[ii]) + 1; + if (linelen + len > 48) + { + newline = "\n "; + linelen = 0; + } + else + { + newline = ""; + } + fprintf(out, "%s%s%s", slash, newline, names[ii]); + linelen += len; + slash = "/"; + } +#ifdef USE_QSV +if (filter_id == HB_FILTER_DEINTERLACE && hb_qsv_available()) +{ + fprintf(out, "/qsv"); +} +#endif + fprintf(out, ">\n"); + hb_str_vfree(names); +} + +static void showFilterKeys(FILE* const out, int filter_id) +{ + char ** keys = hb_filter_get_keys(filter_id); + char * colon = "", * newline; + int ii, linelen = 0; + + fprintf(out, " Custom Format:\n" + " <"); + for (ii = 0; keys[ii] != NULL; ii++) + { + int c = tolower(keys[ii][0]); + int len = strlen(keys[ii]) + 3; + if (linelen + len > 48) + { + newline = "\n "; + linelen = 0; + } + else + { + newline = ""; + } + fprintf(out, "%s%s%s=%c", colon, newline, keys[ii], c); + linelen += len; + colon = ":"; + } + fprintf(out, ">\n"); + hb_str_vfree(keys); +} + +static void showFilterDefault(FILE* const out, int filter_id) +{ + const char * preset = "default"; + + fprintf(out, " Default:\n" + " <"); + switch (filter_id) + { + case HB_FILTER_NLMEANS: + preset = NLMEANS_DEFAULT_PRESET; + break; + case HB_FILTER_DEINTERLACE: + preset = DEINTERLACE_DEFAULT_PRESET; + break; + case HB_FILTER_DECOMB: + preset = DECOMB_DEFAULT_PRESET; + break; + case HB_FILTER_DETELECINE: + preset = DETELECINE_DEFAULT_PRESET; + break; + case HB_FILTER_HQDN3D: + preset = HQDN3D_DEFAULT_PRESET; + break; + default: + break; + } + switch (filter_id) + { + case HB_FILTER_DEINTERLACE: + case HB_FILTER_NLMEANS: + case HB_FILTER_DECOMB: + case HB_FILTER_DETELECINE: + case HB_FILTER_HQDN3D: + { + hb_dict_t * settings; + settings = hb_generate_filter_settings(filter_id, preset, + NULL, NULL); + char * str = hb_filter_settings_string(filter_id, settings); + hb_value_free(&settings); + + char ** split = hb_str_vsplit(str, ':'); + char * colon = "", * newline; + int ii, linelen = 0; + + for (ii = 0; split[ii] != NULL; ii++) + { + int len = strlen(split[ii]) + 1; + if (linelen + len > 48) + { + newline = "\n "; + linelen = 0; + } + else + { + newline = ""; + } + fprintf(out, "%s%s%s", colon, newline, split[ii]); + linelen += len; + colon = ":"; + } + hb_str_vfree(split); + free(str); + } break; + case HB_FILTER_ROTATE: + fprintf(out, "%s", ROTATE_DEFAULT); + break; + case HB_FILTER_DEBLOCK: + fprintf(out, "%s", DEBLOCK_DEFAULT); + break; + default: + break; + } + fprintf(out, ">\n"); +} + static void ShowHelp() { int i, clock_min, clock_max, clock; @@ -1261,64 +1434,61 @@ static void ShowHelp() " (default: detected from source)\n" "\n" "### Filters---------------------------------------------------------------\n\n" -" -d, --deinterlace Unconditionally deinterlaces all frames\n" -" <"); -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()) -{ - fprintf(out, "/qsv"); -} -#endif - fprintf( out, "> or omitted (default settings)\n" - " or\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" -" or\n" -" <MO:ME:MT:ST:BT:BX:BY:MG:VA:LA:DI:ER:NO:MD:PP:FD>\n" -" (default: 7:2:6:9:80:16:16:10:20:20:4:2:50:24:1:-1)\n" -" --no-decomb Disable preset decomb filter\n" +" -d, --deinterlace Unconditionally deinterlaces all frames\n"); + showFilterPresets(out, HB_FILTER_DEINTERLACE); + showFilterKeys(out, HB_FILTER_DEINTERLACE); + showFilterDefault(out, HB_FILTER_DEINTERLACE); + fprintf( out, +" --no-deinterlace Disable preset deinterlace filter\n" +" -5, --decomb Selectively deinterlaces when it detects combing\n"); + showFilterPresets(out, HB_FILTER_DECOMB); + showFilterKeys(out, HB_FILTER_DECOMB); + showFilterDefault(out, HB_FILTER_DECOMB); + fprintf( out, +" --no-decomb Disable preset decomb filter\n" " -9, --detelecine Detelecine (ivtc) video with pullup filter\n" " Note: this filter drops duplicate frames to\n" " restore the pre-telecine framerate, unless you\n" " specify a constant framerate\n" -" (--rate 29.97 --cfr)\n" -" <L:R:T:B:SB:MP:FD> (default 1:1:4:4:0:0:-1)\n" -" --no-detelecine Disable preset detelecine filter\n" -" -8, --hqdn3d Denoise video with hqdn3d filter\n" -" <ultralight/light/medium/strong> or omitted (default settings)\n" -" or\n" -" <SL:SCb:SCr:TL:TCb:TCr>\n" -" (default: 4:3:3:6:4.5:4.5)\n" -" --no-hqdn3d Disable preset hqdn3d filter\n" -" --denoise Legacy alias for '--hqdn3d'\n" -" --nlmeans Denoise video with nlmeans filter\n" -" <ultralight/light/medium/strong> or omitted\n" -" or\n" -" <SY:OTY:PSY:RY:FY:PY:Sb:OTb:PSb:Rb:Fb:Pb:Sr:OTr:PSr:Rr:Fr:Pr>\n" -" (default 8:1:7:3:2:0)\n" +" (--rate 29.97 --cfr)\n"); + showFilterPresets(out, HB_FILTER_DETELECINE); + showFilterKeys(out, HB_FILTER_DETELECINE); + showFilterDefault(out, HB_FILTER_DETELECINE); + fprintf( out, +" --no-detelecine Disable preset detelecine filter\n" +" -8, --hqdn3d Denoise video with hqdn3d filter\n"); + showFilterPresets(out, HB_FILTER_HQDN3D); + showFilterKeys(out, HB_FILTER_HQDN3D); + showFilterDefault(out, HB_FILTER_HQDN3D); + fprintf( out, +" --no-hqdn3d Disable preset hqdn3d filter\n" +" --denoise Legacy alias for '--hqdn3d'\n" +" --nlmeans Denoise video with nlmeans filter\n"); + showFilterPresets(out, HB_FILTER_NLMEANS); + showFilterKeys(out, HB_FILTER_NLMEANS); + showFilterDefault(out, HB_FILTER_NLMEANS); + fprintf( out, + " --no-nlmeans Disable preset nlmeans filter\n" " --nlmeans-tune Tune nlmeans filter to content type\n" " Note: only works in conjunction with presets\n" " ultralight/light/medium/strong.\n" -" <none/film/grain/highmotion/animation> or omitted (default none)\n" -" -7, --deblock Deblock video with pp7 filter\n" -" <QP:M> (default 5:2)\n" -" --no-deblock Disable preset deblock filter\n" -" --rotate Rotate image or flip its axes.\n" -" <angle>:<mirror> Angle rotates clockwise, can be one of:\n" +" Tunes:\n" +" <none/film/grain/highmotion/animation>\n" +" -7, --deblock Deblock video with pp7 filter\n"); + showFilterKeys(out, HB_FILTER_DEBLOCK); + showFilterDefault(out, HB_FILTER_DEBLOCK); + fprintf( out, +" --no-deblock Disable preset deblock filter\n" +" --rotate Rotate image or flip its axes.\n" +" angle rotates clockwise, can be one of:\n" " 0, 90, 180, 270\n" -" Mirror flips the image on the x axis.\n" -" Default: 180:0 (rotate 180 degrees)\n" +" hflip flips the image on the x axis.\n"); + showFilterKeys(out, HB_FILTER_ROTATE); + showFilterDefault(out, HB_FILTER_ROTATE); + fprintf( out, " -g, --grayscale Grayscale encoding\n" -" --no-grayscale Disable preset 'grayscale'\n" +" --no-grayscale Disable preset 'grayscale'\n" "\n" "### Subtitle Options------------------------------------------------------\n\n" " --subtitle-lang-list Specifiy a comma separated list of subtitle\n" @@ -2092,7 +2262,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - deinterlace = strdup("default"); + deinterlace = strdup(DEINTERLACE_DEFAULT_PRESET); } break; case '7': @@ -2103,7 +2273,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - deblock = strdup("5"); + deblock = strdup(DEBLOCK_DEFAULT); } break; case '8': @@ -2114,7 +2284,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - hqdn3d = strdup("default"); + hqdn3d = strdup(HQDN3D_DEFAULT_PRESET); } break; case FILTER_NLMEANS: @@ -2125,7 +2295,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - nlmeans = strdup("medium"); + nlmeans = strdup(NLMEANS_DEFAULT_PRESET); } break; case FILTER_NLMEANS_TUNE: @@ -2140,7 +2310,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - detelecine = strdup("default"); + detelecine = strdup(DETELECINE_DEFAULT_PRESET); } break; case '5': @@ -2151,7 +2321,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - decomb = strdup("default"); + decomb = strdup(DECOMB_DEFAULT_PRESET); } break; case 'g': @@ -2165,7 +2335,7 @@ static int ParseOptions( int argc, char ** argv ) } else { - rotate = strdup("180:0"); + rotate = strdup(ROTATE_DEFAULT); } break; case KEEP_DISPLAY_ASPECT: @@ -2428,7 +2598,7 @@ static int ParseOptions( int argc, char ** argv ) "Incompatible options --deblock and --no-deblock\n"); return -1; } - if (hb_validate_filter_settings(HB_FILTER_DEBLOCK, deblock)) + if (hb_validate_filter_string(HB_FILTER_DEBLOCK, deblock)) { fprintf(stderr, "Invalid deblock option %s\n", deblock); return -1; @@ -2444,13 +2614,13 @@ static int ParseOptions( int argc, char ** argv ) return -1; } if (!hb_validate_filter_preset(HB_FILTER_DETELECINE, - detelecine, NULL)) + detelecine, NULL, NULL)) { // Nothing to do, but must validate preset before // attempting to validate custom settings to prevent potential // false positive } - else if (!hb_validate_filter_settings(HB_FILTER_DETELECINE, detelecine)) + else if (!hb_validate_filter_string(HB_FILTER_DETELECINE, detelecine)) { detelecine_custom = 1; } @@ -2469,7 +2639,7 @@ static int ParseOptions( int argc, char ** argv ) "Incompatible options --pad and --no-pad\n"); return -1; } - else if (hb_validate_filter_settings(HB_FILTER_PAD, pad)) + else if (hb_validate_filter_string(HB_FILTER_PAD, pad)) { fprintf(stderr, "Invalid pad option %s\n", pad); return -1; @@ -2485,13 +2655,13 @@ static int ParseOptions( int argc, char ** argv ) return -1; } if (!hb_validate_filter_preset(HB_FILTER_DEINTERLACE, - deinterlace, NULL)) + deinterlace, NULL, NULL)) { // Nothing to do, but must validate preset before // attempting to validate custom settings to prevent potential // false positive } - else if (!hb_validate_filter_settings(HB_FILTER_DEINTERLACE, deinterlace)) + else if (!hb_validate_filter_string(HB_FILTER_DEINTERLACE, deinterlace)) { deinterlace_custom = 1; } @@ -2510,13 +2680,13 @@ static int ParseOptions( int argc, char ** argv ) "Incompatible options --decomb and --no-decomb\n"); return -1; } - if (!hb_validate_filter_preset(HB_FILTER_DECOMB, decomb, NULL)) + if (!hb_validate_filter_preset(HB_FILTER_DECOMB, decomb, NULL, NULL)) { // Nothing to do, but must validate preset before // attempting to validate custom settings to prevent potential // false positive } - else if (!hb_validate_filter_settings(HB_FILTER_DECOMB, decomb)) + else if (!hb_validate_filter_string(HB_FILTER_DECOMB, decomb)) { decomb_custom = 1; } @@ -2535,13 +2705,13 @@ static int ParseOptions( int argc, char ** argv ) "Incompatible options --hqdn3d and --no-hqdn3d\n"); return -1; } - if (!hb_validate_filter_preset(HB_FILTER_HQDN3D, hqdn3d, NULL)) + if (!hb_validate_filter_preset(HB_FILTER_HQDN3D, hqdn3d, NULL, NULL)) { // Nothing to do, but must validate preset before // attempting to validate custom settings to prevent potential // false positive } - else if (!hb_validate_filter_settings(HB_FILTER_HQDN3D, hqdn3d)) + else if (!hb_validate_filter_string(HB_FILTER_HQDN3D, hqdn3d)) { hqdn3d_custom = 1; } @@ -2560,13 +2730,14 @@ static int ParseOptions( int argc, char ** argv ) "Incompatible options --nlmeans and --no-nlmeans\n"); return -1; } - if (!hb_validate_filter_preset(HB_FILTER_NLMEANS, nlmeans, nlmeans_tune)) + if (!hb_validate_filter_preset(HB_FILTER_NLMEANS, nlmeans, + nlmeans_tune, NULL)) { // Nothing to do, but must validate preset before // attempting to validate custom settings to prevent potential // false positive } - else if (!hb_validate_filter_settings(HB_FILTER_NLMEANS, nlmeans)) + else if (!hb_validate_filter_string(HB_FILTER_NLMEANS, nlmeans)) { nlmeans_custom = 1; } @@ -3457,7 +3628,8 @@ static hb_dict_t * PreparePreset(const char *preset_name) } if (deblock != NULL) { - hb_dict_set(preset, "PictureDeblock", hb_value_string(deblock)); + hb_dict_set(preset, "PictureDeblock", hb_value_string("custom")); + hb_dict_set(preset, "PictureDeblockCustom", hb_value_string(deblock)); } if (rotate != NULL) { |