]> granicus.if.org Git - handbrake/commitdiff
filters: make job filter settings an hb_dict_t
authorJohn Stebbins <jstebbins.hb@gmail.com>
Sun, 21 Feb 2016 01:00:46 +0000 (18:00 -0700)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Wed, 9 Mar 2016 20:10:10 +0000 (13:10 -0700)
This simplifies accessing and changing filter parameters
programatically.  It also changes the custom filter string format to a
':' separated list of key/value pairs.

27 files changed:
gtk/src/hb-backend.c
gtk/src/queuehandler.c
libhb/avfilter.c
libhb/builtin_presets.h
libhb/common.c
libhb/common.h
libhb/cropscale.c
libhb/deblock.c
libhb/decomb.c
libhb/denoise.c
libhb/detelecine.c
libhb/hb.c
libhb/hb.h
libhb/hb_dict.c
libhb/hb_dict.h
libhb/hb_json.c
libhb/hbtypes.h [new file with mode: 0644]
libhb/libhb_presets.list
libhb/nlmeans.c
libhb/param.c
libhb/param.h
libhb/preset.c
libhb/preset_template.json
libhb/qsv_filter.c
libhb/vfr.c
libhb/work.c
test/test.c

index ccadcfbd4a1ea19e48c1ea37c8cc311259bd7dcb..2a8d79bb90271d98a9f016e3df2d3c30a0e30e64 100644 (file)
@@ -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);
index 8d13b499b3c8b75a5fe07f13a339faf87db1b66f..2365d0e04f56304f6bc240f60cffde8f58fc9bb8 100644 (file)
@@ -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);
 }
index c94a851da2e1515cbb975e2ffe95645ab3ac16e6..2e57f72d6a076111273deddf35dc2fa5426d79b4 100644 (file)
@@ -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++;
     }
 }
index 5ab646f1986e076ae92fd77b3718f89260becdc7..bbb6e1335eff0f3d08615ca1f80f57ba082e147d 100644 (file)
@@ -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";
index cf49a2b7261a43bed0c1f1ad0f22e1716d3e9261..ca74aeb165a4b5b3fe89b8358a4b2c75da6bcc0c 100644 (file)
@@ -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
  **********************************************************************
index daeeb7920a088de8976e5119b8ccc86eab1dd2da..d09c6e9a0c9833944c665572548d15050eba3a77 100644 (file)
@@ -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>
 #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
index 4c505ff2048d9a7259c3743a045e5464299ae62c..63475990e08afe093c3f61e367cd5cd2bd0f6616 100644 (file)
@@ -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;
index e48d89ced29301bdfbe5763574d303e4ab719a47..64cf277bb670f3572b5e189a9b53f3da10af5531 100644 (file)
@@ -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 )
     {
index b624031b481e2d6c7c28cee82f5783ffbb37d45e..cf0db0b6ec614666fc439f79628e6cce1b21e28a 100644 (file)
@@ -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));
index f66c987be418d11e00c9492d0b55a4d964d77f97..208d399a557ccbe6921120f6973033431148c6c5 100644 (file)
@@ -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 );
index d25c648034873d8a43b66c2df8e92535863d521b..dd5d26d423f11f1524ae87d70d027d09894342dc 100644 (file)
@@ -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;
index 88d90e18792586c3e4a857c945632cbb335134e2..5937ae1ba6b1c3a3b4aca26706c510d5dfac65bd 100644 (file)
@@ -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 )
@@ -1367,6 +1417,25 @@ void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter, const char * se
     hb_list_add( job->list_filter, filter );
 }
 
+/**
+ * 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.
index 3521e4d3ef1d1c3dfae9dd0e67e5ceda0a95ae68..f2dd6e9c4e81d701a3f67ae20ab26aaf3895a3a3 100644 (file)
@@ -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 * );
index cc0ee99fed3c01e029b888a4407568910c8a50af..5cc67c6293f472df513776451bb89ece09843a79 100644 (file)
@@ -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)
@@ -533,6 +746,26 @@ hb_value_array_append(hb_value_array_t *array, hb_value_t *value)
     json_array_append_new(array, 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)
 {
@@ -613,3 +846,4 @@ char * hb_dict_to_encopts(const hb_dict_t * dict)
 {
     return hb_value_get_string_xform(dict);
 }
+
index 5d44b86d94323dbbd33ca4539a02655ada9e2223..2309b8739cd02b7e286c4f92318599bf0bde7814 100644 (file)
@@ -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)
index ba889244a7a3529265176f901e14ab928dfba4da..39f7392f37a64c38c751fd78d91f5cbbf216274b 100644 (file)
@@ -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 (file)
index 0000000..42a82dd
--- /dev/null
@@ -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
index 4afc9409145790837f7f37e101445ea29706170e..cb46ba08493230162bbe60dbb89ba25de073d316 100644 (file)
@@ -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>
index ca661df2ea98236e7d4048192c2ab0efc9b57309..fd576efca4a64c18b2dcd0b8e68477b64dce50e6 100644 (file)
@@ -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
index e30c56b3e74a9954ad4f6d89b137cc210e8a158b..350f81773018a506d6df5c16b2910a53a7fd1c49 100644 (file)
@@ -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,        }
+    { 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;
+}
+
index 2256441e9b6eebfda691bb9b34806d6ee9e3a2f2..d61fd389c0a796dedd9b13031b9960c6caf55347 100644 (file)
@@ -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
index 1670b469b0f02f0f437c9e0c1e1ba826720c8b02..9b5f0616a3da56e1cc748aa7867c3d58385b2162 100644 (file)
@@ -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;
index 0140aed367fe076509b7032c7d4ea436423a91d4..da113f88ac682f18a874808c949dd4669ddcd181 100644 (file)
@@ -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,
index f168bb197770f8eb93ddbbecea7fe9499d393bd1..3d085815463cb5df360a73e32bcdc897a0b79370 100644 (file)
@@ -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;
 
index cc995ff5998a126c31dd30c886c3b31ae6fb57d6..d097a7ab14532e6f4bcaf0311293d2d3897a1c4e 100644 (file)
@@ -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;
 
index 6e3195e0b6b01369879942b7900023e5c84d892f..7a1460eecce7deec712f0a1e9b91e8a578a83bf2 100644 (file)
@@ -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);
             }
         }
     }
index 9cf49bbf2857dd1af4f287b9fac0cd9b6ef908e1..ca4062424cab4865f4151038795999c3f57836c8 100644 (file)
@@ -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>
 #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)
     {