From 5a24d1b2f7b9414e76ceaa4b23eb3661ac8ce828 Mon Sep 17 00:00:00 2001
From: jstebbins <jstebbins.hb@gmail.com>
Date: Sat, 4 Apr 2015 14:43:39 +0000
Subject: [PATCH] libhb: Add filter preset/tune lookup and setting validation
 for more filter types

All filters except for crop_scale now have preset/tune support and basic
validation.

This code could also be used by the other frontends to simplify some things.
For example, it can be used to query libhb for a list of available presets
and tunes for each filter.


git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@7050 b64f7644-9d1e-0410-96f1-a4d463321fa5
---
 libhb/common.h |   4 -
 libhb/hb.h     |   1 +
 libhb/param.c  | 446 +++++++++++++++++++++++++++++++++++++++++++++----
 libhb/param.h  |  38 +++++
 4 files changed, 453 insertions(+), 36 deletions(-)
 create mode 100644 libhb/param.h

diff --git a/libhb/common.h b/libhb/common.h
index 1014b8c14..60ef9cc82 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -1238,10 +1238,6 @@ 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 ** );
-char * hb_generate_filter_settings(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);
 
 typedef void hb_error_handler_t( const char *errmsg );
 
diff --git a/libhb/hb.h b/libhb/hb.h
index 8f85fa5e9..2da5e81c0 100644
--- a/libhb/hb.h
+++ b/libhb/hb.h
@@ -18,6 +18,7 @@ extern "C" {
 #include "common.h"
 #include "hb_dict.h"
 #include "hb_json.h"
+#include "param.h"
 
 /* hb_init()
    Initializes a libhb session (launches his own thread, detects CPUs,
diff --git a/libhb/param.c b/libhb/param.c
index b85f25a55..29315e44d 100644
--- a/libhb/param.c
+++ b/libhb/param.c
@@ -8,9 +8,103 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  */
 
-#include "hb.h"
+#include "param.h"
+#include "common.h"
 #include <regex.h>
 
+const char hb_filter_off[] = "off";
+
+static hb_filter_param_t nlmeans_presets[] =
+{
+    { 1, "Custom",      "custom",     NULL              },
+    { 5, "Ultralight",  "ultralight", NULL              },
+    { 2, "Light",       "light",      NULL              },
+    { 3, "Medium",      "medium",     NULL              },
+    { 4, "Strong",      "strong",     NULL              },
+    { 0, NULL,          NULL,         NULL              }
+};
+
+static hb_filter_param_t nlmeans_tunes[] =
+{
+    { 0, "None",        "none",       NULL              },
+    { 1, "Film",        "film",       NULL              },
+    { 2, "Grain",       "grain",      NULL              },
+    { 3, "High Motion", "highmotion", NULL              },
+    { 4, "Animation",   "animation",  NULL              },
+    { 0, NULL,          NULL,         NULL              }
+};
+
+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"     },
+    { 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"     },
+};
+
+static hb_filter_param_t detelecine_presets[] =
+{
+    { 0, "Off",         "off",        hb_filter_off     },
+    { 1, "Custom",      "custom",     NULL              },
+    { 2, "Default",     "default",    ""                },
+    { 0, NULL,          NULL,         NULL              }
+};
+
+static hb_filter_param_t decomb_presets[] =
+{
+    { 0, "Off",         "off",        hb_filter_off     },
+    { 1, "Custom",      "custom",     NULL              },
+    { 2, "Default",     "default",    ""                },
+    { 3, "Fast",        "fast",       "7:2:6:9:1:80"    },
+    { 4, "Bob",         "bob",        "455"             },
+    { 0, NULL,          NULL,         NULL              }
+};
+
+static hb_filter_param_t deinterlace_presets[] =
+{
+    { 0, "Off",         "off",        hb_filter_off     },
+    { 1, "Custom",      "custom",     NULL              },
+    { 2, "Fast",        "fast",       "0:-1:-1:0:1"     },
+    { 3, "Slow",        "slow",       "1:-1:-1:0:1"     },
+    { 4, "Slower",      "slower",     "3:-1:-1:0:1"     },
+    { 5, "Bob",         "bob",        "15:-1:-1:0:1"    },
+    { 0,  NULL,         NULL,         NULL              },
+    { 2, "Default",     "default",    "0:-1:-1:0:1"     }
+};
+
+typedef struct
+{
+    int                filter_id;
+    hb_filter_param_t *presets;
+    hb_filter_param_t *tunes;
+    int                count;
+} filter_param_map_t;
+
+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,
+      sizeof(hqdn3d_presets) / sizeof(hb_filter_param_t)         },
+
+    { HB_FILTER_DETELECINE,  detelecine_presets,  NULL,
+      sizeof(detelecine_presets) / sizeof(hb_filter_param_t)     },
+
+    { HB_FILTER_DECOMB,      decomb_presets,      NULL,
+      sizeof(decomb_presets) / sizeof(hb_filter_param_t)         },
+
+    { HB_FILTER_DEINTERLACE, deinterlace_presets, NULL,
+      sizeof(deinterlace_presets) / sizeof(hb_filter_param_t)    },
+
+    { HB_FILTER_INVALID,     NULL,                NULL, 0        }
+};
+
 /* NL-means presets and tunes
  *
  * Presets adjust strength:
@@ -33,6 +127,10 @@ static char * generate_nlmeans_settings(const char *preset, const char *tune)
     if (preset == NULL)
         return NULL;
 
+    if (!strcasecmp(preset, "custom") && tune != NULL)
+    {
+        return strdup(tune);
+    }
     if (!strcasecmp(preset, "ultralight") ||
         !strcasecmp(preset, "light") ||
         !strcasecmp(preset, "medium") ||
@@ -187,31 +285,6 @@ static char * generate_nlmeans_settings(const char *preset, const char *tune)
     return opt;
 }
 
-/* HQDN3D presets
- *
- * Presets adjust strength:
- * ultralight - visually transparent
- * light
- * medium
- * strong
- */
-static char * generate_hqdn3d_settings(const char *preset, const char *tune)
-{
-    if (preset == NULL)
-        return NULL;
-
-    if (!strcasecmp(preset, "strong"))
-        return strdup("7:7:7:5:5:5");
-    else if (!strcasecmp(preset, "medium"))
-        return strdup("3:2:2:2:3:3");
-    else if (!strcasecmp(preset, "light") || !strcasecmp(preset, "weak"))
-        return strdup("2:1:1:2:3:3");
-    else if (!strcasecmp(preset, "ultralight"))
-        return strdup("1:0.7:0.7:1:2:2");
-    else
-        return strdup(preset);
-}
-
 int hb_validate_param_string(const char *regex_pattern, const char *param_string)
 {
     regex_t regex_temp;
@@ -235,6 +308,9 @@ int hb_validate_param_string(const char *regex_pattern, const char *param_string
 
 int hb_validate_filter_settings(int filter_id, const char *filter_param)
 {
+    if (filter_param == NULL)
+        return 0;
+
     // Regex matches "number" followed by one or more ":number", where number is uint or ufloat
     const char *hb_colon_separated_params_regex = "^((([0-9]+([.][0-9]+)?)|([.][0-9]+))((:(([0-9]+([.][0-9]+)?)|([.][0-9]+)))+)?)$";
 
@@ -242,9 +318,14 @@ int hb_validate_filter_settings(int filter_id, const char *filter_param)
 
     switch (filter_id)
     {
+        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 == NULL)
+            if (filter_param[0] == 0)
             {
                 return 0;
             }
@@ -264,7 +345,188 @@ int hb_validate_filter_settings(int filter_id, const char *filter_param)
     return 1;
 }
 
-char * hb_generate_filter_settings(int filter_id, const char *preset, const char *tune)
+static hb_filter_param_t*
+filter_param_get_presets_internal(int filter_id, int *count)
+{
+    int ii;
+    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;
+        }
+    }
+    return NULL;
+}
+
+static hb_filter_param_t*
+filter_param_get_tunes_internal(int filter_id, int *count)
+{
+    int ii;
+    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;
+        }
+    }
+    return NULL;
+}
+
+static hb_filter_param_t*
+filter_param_get_entry(hb_filter_param_t *table, const char *name, int count)
+{
+    if (table == NULL || name == NULL)
+        return NULL;
+
+    int ii;
+    for (ii = 0; ii < count; ii++)
+    {
+        if ((table[ii].name != NULL && !strcasecmp(name, table[ii].name)) ||
+            (table[ii].short_name != NULL &&
+             !strcasecmp(name, table[ii].short_name)))
+        {
+            return &table[ii];
+        }
+    }
+    return NULL;
+}
+
+static hb_filter_param_t*
+filter_param_get_entry_by_index(hb_filter_param_t *table, int index, int count)
+{
+    if (table == NULL)
+        return NULL;
+
+    int ii;
+    for (ii = 0; ii < count; ii++)
+    {
+        if (table[ii].name != NULL && table[ii].index == index)
+        {
+            return &table[ii];
+        }
+    }
+    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", preset_entry->settings,
+                    tune_entry != NULL ? tune_entry->settings : "");
+        }
+    }
+    else if (preset != NULL)
+    {
+        return strdup(preset);
+    }
+    return opt;
+}
+
+// Legacy: old presets store filter falues as indexes :(
+static char *
+generate_generic_settings_by_index(int filter_id, int preset,
+                                   const char *custom)
+{
+    char *opt = NULL;
+    int preset_count;
+    hb_filter_param_t *preset_table;
+    hb_filter_param_t *preset_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)
+    {
+        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)
+        {
+            opt = hb_strdup_printf("%s", preset_entry->settings);
+        }
+    }
+    return opt;
+}
+
+char *
+hb_generate_filter_settings_by_index(int filter_id, int preset,
+                                     const char *custom)
+{
+    char *filter_param = NULL;
+
+    switch (filter_id)
+    {
+        case HB_FILTER_ROTATE:
+            if (preset <= 0)
+                filter_param = (char*)hb_filter_off;
+            else
+                filter_param = hb_strdup_printf("%d", preset);
+            break;
+        case HB_FILTER_DEBLOCK:
+            if (preset < 5)
+                filter_param = (char*)hb_filter_off;
+            else
+                filter_param = hb_strdup_printf("%d", preset);
+            break;
+        case HB_FILTER_DECOMB:
+        case HB_FILTER_DEINTERLACE:
+        case HB_FILTER_DETELECINE:
+        case HB_FILTER_HQDN3D:
+            filter_param = generate_generic_settings_by_index(filter_id,
+                                                              preset, custom);
+            break;
+        default:
+            fprintf(stderr,
+                    "hb_generate_filter_settings: Unrecognized filter (%d).\n",
+                    filter_id);
+            break;
+    }
+
+    if (filter_param == hb_filter_off)
+        return filter_param;
+
+    if (filter_param != NULL &&
+        hb_validate_filter_settings(filter_id, filter_param) == 0)
+    {
+        return filter_param;
+    }
+    free(filter_param);
+    return NULL;
+}
+
+char *
+hb_generate_filter_settings(int filter_id, const char *preset, const char *tune)
 {
     char *filter_param = NULL;
 
@@ -273,19 +535,139 @@ char * hb_generate_filter_settings(int filter_id, const char *preset, const char
         case HB_FILTER_NLMEANS:
             filter_param = generate_nlmeans_settings(preset, tune);
             break;
+        case HB_FILTER_ROTATE:
+            if (atoi(preset) == 0)
+                filter_param = (char*)hb_filter_off;
+            else
+                filter_param = strdup(preset);
+            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_DEINTERLACE:
+        case HB_FILTER_DETELECINE:
         case HB_FILTER_HQDN3D:
-            filter_param = generate_hqdn3d_settings(preset, tune);
+            filter_param = generate_generic_settings(filter_id, preset, tune);
             break;
         default:
-            fprintf(stderr, "hb_generate_filter_settings: Unrecognized filter (%d).\n",
-                   filter_id);
+            fprintf(stderr,
+                    "hb_generate_filter_settings: Unrecognized filter (%d).\n",
+                    filter_id);
             break;
     }
 
-    if (hb_validate_filter_settings(filter_id, filter_param) == 0)
+    if (filter_param == hb_filter_off)
+        return filter_param;
+
+    if (filter_param != NULL &&
+        hb_validate_filter_settings(filter_id, filter_param) == 0)
     {
         return filter_param;
     }
+    free(filter_param);
     return NULL;
 }
 
+int
+hb_validate_filter_preset(int filter_id, const char *preset, const char *tune)
+{
+    if (preset == NULL && tune == NULL)
+        return 1;
+
+    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(preset_table, preset, preset_count);
+    if (preset_entry == NULL || preset_entry->name == NULL)
+        return 1;
+    if (tune != NULL)
+    {
+        if (!strcasecmp(preset, "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;
+}
+
+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;
+}
+
+int
+hb_filter_preset_index(int filter_id, const char *preset)
+{
+    if (preset == NULL)
+        return -1;
+
+    int preset_count;
+    hb_filter_param_t *preset_table;
+    hb_filter_param_t *preset_entry;
+
+    preset_table = filter_param_get_presets_internal(filter_id, &preset_count);
+    preset_entry = filter_param_get_entry(preset_table, preset, preset_count);
+    if (preset_entry == NULL)
+        return -1;
+    return preset_entry->index;
+}
+
+int
+hb_filter_tune_index(int filter_id, const char *tune)
+{
+    if (tune == NULL)
+        return -1;
+
+    int tune_count;
+    hb_filter_param_t *tune_table;
+    hb_filter_param_t *tune_entry;
+
+    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 tune_entry->index;
+}
+
+hb_filter_param_t* hb_filter_param_get_presets(int filter_id)
+{
+    return filter_param_get_presets_internal(filter_id, NULL);
+}
+
+hb_filter_param_t* hb_filter_param_get_tunes(int filter_id)
+{
+    return filter_param_get_tunes_internal(filter_id, NULL);
+}
+
diff --git a/libhb/param.h b/libhb/param.h
new file mode 100644
index 000000000..733c2b30b
--- /dev/null
+++ b/libhb/param.h
@@ -0,0 +1,38 @@
+/* param.h
+
+   Copyright (c) 2003-2015 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_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
+{
+    int         index;
+    const char *name;
+    const char *short_name;
+    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);
+
+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);
+
+hb_filter_param_t * hb_filter_param_get_presets(int filter_id);
+hb_filter_param_t * hb_filter_param_get_tunes(int filter_id);
+
+#endif // HB_PARAM_H
-- 
2.40.0