summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2016-02-20 18:00:46 -0700
committerJohn Stebbins <[email protected]>2016-03-09 13:10:10 -0700
commita44ccb49f182d4eeb122fbe675b28deb5c36b793 (patch)
tree6cc064cc24dacc2a80d41fb9543640c9004895af
parent96c02dd6f256f4a4e74f8962f56502d28e5e65a3 (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.c54
-rw-r--r--gtk/src/queuehandler.c16
-rw-r--r--libhb/avfilter.c416
-rw-r--r--libhb/builtin_presets.h7
-rw-r--r--libhb/common.c299
-rw-r--r--libhb/common.h56
-rw-r--r--libhb/cropscale.c35
-rw-r--r--libhb/deblock.c24
-rw-r--r--libhb/decomb.c115
-rw-r--r--libhb/denoise.c106
-rw-r--r--libhb/detelecine.c40
-rw-r--r--libhb/hb.c77
-rw-r--r--libhb/hb.h6
-rw-r--r--libhb/hb_dict.c238
-rw-r--r--libhb/hb_dict.h34
-rw-r--r--libhb/hb_json.c11
-rw-r--r--libhb/hbtypes.h49
-rw-r--r--libhb/libhb_presets.list4
-rw-r--r--libhb/nlmeans.c51
-rw-r--r--libhb/param.c833
-rw-r--r--libhb/param.h26
-rw-r--r--libhb/preset.c332
-rw-r--r--libhb/preset_template.json3
-rw-r--r--libhb/qsv_filter.c37
-rw-r--r--libhb/vfr.c27
-rw-r--r--libhb/work.c36
-rw-r--r--test/test.c308
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(&regex_temp, regex_pattern, REG_EXTENDED) == 0)
+ if (regcomp(&regex_temp, regex_pattern, REG_EXTENDED|REG_ICASE) == 0)
{
if (regexec(&regex_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(&regex_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)
{