diff options
author | Bradley Sepos <[email protected]> | 2017-05-23 19:22:37 -0400 |
---|---|---|
committer | Bradley Sepos <[email protected]> | 2017-05-30 14:00:27 -0400 |
commit | fcbc09c44a7ae5c43319df08bf449e097fe083b2 (patch) | |
tree | 76ef3c0cf9f169d468be84dcfc050352e9047bf7 /libhb | |
parent | 1af79e413bd7e8d6e75604690942d6dddeb4ec97 (diff) |
libhb: Add Unsharp sharpening filter.
Closes #525.
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/common.c | 4 | ||||
-rw-r--r-- | libhb/common.h | 1 | ||||
-rw-r--r-- | libhb/internal.h | 1 | ||||
-rw-r--r-- | libhb/param.c | 157 | ||||
-rw-r--r-- | libhb/preset.c | 46 | ||||
-rw-r--r-- | libhb/preset_builtin.h | 254 | ||||
-rw-r--r-- | libhb/unsharp.c | 274 |
7 files changed, 736 insertions, 1 deletions
diff --git a/libhb/common.c b/libhb/common.c index 11928e519..c8a2f22f7 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -3959,6 +3959,10 @@ hb_filter_object_t * hb_filter_get( int filter_id ) filter = &hb_filter_crop_scale; break; + case HB_FILTER_UNSHARP: + filter = &hb_filter_unsharp; + break; + case HB_FILTER_AVFILTER: filter = &hb_filter_avfilter; break; diff --git a/libhb/common.h b/libhb/common.h index 266f13fe2..562bbc362 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -1270,6 +1270,7 @@ enum HB_FILTER_NLMEANS, HB_FILTER_RENDER_SUB, HB_FILTER_CROP_SCALE, + HB_FILTER_UNSHARP, HB_FILTER_ROTATE, HB_FILTER_GRAYSCALE, HB_FILTER_PAD, diff --git a/libhb/internal.h b/libhb/internal.h index 4aaba97ba..0cffbdff4 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -465,6 +465,7 @@ extern hb_filter_object_t hb_filter_crop_scale; extern hb_filter_object_t hb_filter_rotate; extern hb_filter_object_t hb_filter_grayscale; extern hb_filter_object_t hb_filter_pad; +extern hb_filter_object_t hb_filter_unsharp; extern hb_filter_object_t hb_filter_avfilter; #ifdef USE_QSV diff --git a/libhb/param.c b/libhb/param.c index 456ba4d24..ae8d99618 100644 --- a/libhb/param.c +++ b/libhb/param.c @@ -70,6 +70,26 @@ static hb_filter_param_t hqdn3d_presets[] = }, }; +static hb_filter_param_t unsharp_presets[] = +{ + { 1, "Custom", "custom", NULL }, + { 2, "Ultralight", "ultralight", NULL }, + { 3, "Light", "light", NULL }, + { 4, "Medium", "medium", NULL }, + { 5, "Strong", "strong", NULL }, + { 6, "Stronger", "stronger", NULL }, + { 0, NULL, NULL, NULL } +}; + +static hb_filter_param_t unsharp_tunes[] = +{ + { 0, "None", "none", NULL }, + { 1, "Fine", "fine", NULL }, + { 2, "Medium", "medium", NULL }, + { 3, "Coarse", "coarse", NULL }, + { 0, NULL, NULL, NULL } +}; + static hb_filter_param_t detelecine_presets[] = { { 0, "Off", "off", "disable=1" }, @@ -141,6 +161,9 @@ static filter_param_map_t param_map[] = { HB_FILTER_HQDN3D, hqdn3d_presets, NULL, sizeof(hqdn3d_presets) / sizeof(hb_filter_param_t) }, + { HB_FILTER_UNSHARP, unsharp_presets, unsharp_tunes, + sizeof(unsharp_presets) / sizeof(hb_filter_param_t) }, + { HB_FILTER_DETELECINE, detelecine_presets, NULL, sizeof(detelecine_presets) / sizeof(hb_filter_param_t) }, @@ -408,6 +431,137 @@ static hb_dict_t * generate_nlmeans_settings(const char *preset, return settings; } +static hb_dict_t * generate_unsharp_settings(const char *preset, + const char *tune, + const char *custom) +{ + hb_dict_t * settings; + + if (preset == NULL) + return NULL; + + if (preset == NULL || !strcasecmp(preset, "custom")) + { + return hb_parse_filter_settings(custom); + } + if (!strcasecmp(preset, "ultralight") || + !strcasecmp(preset, "light") || + !strcasecmp(preset, "medium") || + !strcasecmp(preset, "strong") || + !strcasecmp(preset, "stronger")) + { + double strength[2]; + int size[2]; + + if (tune == NULL || !strcasecmp(tune, "none")) + { + strength[0] = strength[1] = 0.25; + size[0] = size[1] = 7; + if (!strcasecmp(preset, "ultralight")) + { + strength[0] = strength[1] = 0.05; + } + else if (!strcasecmp(preset, "light")) + { + strength[0] = strength[1] = 0.15; + } + else if (!strcasecmp(preset, "strong")) + { + strength[0] = strength[1] = 0.5; + } + else if (!strcasecmp(preset, "stronger")) + { + strength[0] = strength[1] = 0.8; + } + } + else if (!strcasecmp(tune, "fine")) + { + strength[0] = 0.4; strength[1] = 0.25; + size[0] = size[1] = 3; + if (!strcasecmp(preset, "ultralight")) + { + strength[0] = 0.15; strength[1] = 0.1; + } + else if (!strcasecmp(preset, "light")) + { + strength[0] = 0.25; strength[1] = 0.15; + } + else if (!strcasecmp(preset, "strong")) + { + strength[0] = 0.8; strength[1] = 0.5; + } + else if (!strcasecmp(preset, "stronger")) + { + strength[0] = 0.8; strength[1] = 0.5; + } + } + else if (!strcasecmp(tune, "medium")) + { + strength[0] = 0.275; strength[1] = 0.165; + size[0] = 7; size[1] = 5; + if (!strcasecmp(preset, "ultralight")) + { + strength[0] = 0.055; strength[1] = 0.033; + } + else if (!strcasecmp(preset, "light")) + { + strength[0] = 0.165; strength[1] = 0.1; + } + else if (!strcasecmp(preset, "strong")) + { + strength[0] = 0.55; strength[1] = 0.33; + } + else if (!strcasecmp(preset, "stronger")) + { + strength[0] = 0.9; strength[1] = 0.6; + } + } + else if (!strcasecmp(tune, "coarse")) + { + strength[0] = 0.275; strength[1] = 0.165; + size[0] = 13; size[1] = 9; + if (!strcasecmp(preset, "ultralight")) + { + strength[0] = 0.055; strength[1] = 0.033; + } + else if (!strcasecmp(preset, "light")) + { + strength[0] = 0.165; strength[1] = 0.1; + } + else if (!strcasecmp(preset, "strong")) + { + strength[0] = 0.55; strength[1] = 0.33; + } + else if (!strcasecmp(preset, "stronger")) + { + strength[0] = 0.9; strength[1] = 0.6; + } + } + else + { + fprintf(stderr, "Unrecognized unsharp tune (%s).\n", tune); + return NULL; + } + + settings = hb_dict_init(); + hb_dict_set(settings, "y-strength", hb_value_double(strength[0])); + hb_dict_set(settings, "y-size", hb_value_int(size[0])); + + hb_dict_set(settings, "cb-strength", hb_value_double(strength[1])); + hb_dict_set(settings, "cb-size", hb_value_int(size[1])); + } + else + { + settings = hb_parse_filter_settings(preset); + if (tune != NULL) + { + fprintf(stderr, "Custom unsharp parameters specified; ignoring unsharp tune (%s).\n", tune); + } + } + + return settings; +} + int hb_validate_param_string(const char *regex_pattern, const char *param_string) { regex_t regex_temp; @@ -668,6 +822,9 @@ hb_generate_filter_settings(int filter_id, const char *preset, const char *tune, case HB_FILTER_NLMEANS: settings = generate_nlmeans_settings(preset, tune, custom); break; + case HB_FILTER_UNSHARP: + settings = generate_unsharp_settings(preset, tune, custom); + break; case HB_FILTER_COMB_DETECT: case HB_FILTER_DECOMB: case HB_FILTER_DETELECINE: diff --git a/libhb/preset.c b/libhb/preset.c index 5741362fc..08f7d186c 100644 --- a/libhb/preset.c +++ b/libhb/preset.c @@ -1371,6 +1371,52 @@ int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict) } } + // Sharpen filter + const char *sharpen_filter, *sharpen_preset, *sharpen_tune, *sharpen_custom; + sharpen_filter = hb_value_get_string(hb_dict_get(preset, + "PictureSharpenFilter")); + sharpen_preset = hb_value_get_string(hb_dict_get(preset, + "PictureSharpenPreset")); + sharpen_tune = hb_value_get_string(hb_dict_get(preset, + "PictureSharpenTune")); + sharpen_custom = hb_value_get_string(hb_dict_get(preset, + "PictureSharpenCustom")); + if (sharpen_filter != NULL && sharpen_preset != NULL && + strcasecmp(sharpen_filter, "off")) + { + int filter_id; + if (!strcasecmp(sharpen_filter, "unsharp")) + { + filter_id = HB_FILTER_UNSHARP; + } + else + { + hb_error("Invalid sharpen filter (%s)", sharpen_filter); + return -1; + } + filter_settings = hb_generate_filter_settings(filter_id, + sharpen_preset, sharpen_tune, sharpen_custom); + if (filter_settings == NULL) + { + hb_error("Invalid sharpen filter settings (%s%s%s)", + sharpen_preset, + sharpen_tune ? "," : "", + sharpen_tune ? sharpen_tune : ""); + return -1; + } + 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", filter_settings); + hb_add_filter2(filter_list, filter_dict); + } + else + { + hb_value_free(&filter_settings); + } + } + // Deblock filter char *deblock = hb_value_get_string_xform( hb_dict_get(preset, "PictureDeblock")); diff --git a/libhb/preset_builtin.h b/libhb/preset_builtin.h index 356f8b431..296e0d5ad 100644 --- a/libhb/preset_builtin.h +++ b/libhb/preset_builtin.h @@ -63,6 +63,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"Small H.264 video (up to 1080p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -159,6 +163,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"Small H.264 video (up to 720p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -255,6 +263,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"Small H.264 video (up to 576p25) and AAC stereo audio, in an MP4 container.\", \n" @@ -351,6 +363,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"Small H.264 video (up to 480p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -447,6 +463,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -543,6 +563,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -639,6 +663,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 576p25) and AAC stereo audio, in an MP4 container.\", \n" @@ -735,6 +763,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 480p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -845,6 +877,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"High quality H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -955,6 +991,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"High quality H.264 video (up to 720p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1065,6 +1105,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"High quality H.264 video (up to 576p25), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1175,6 +1219,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"High quality H.264 video (up to 480p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1285,6 +1333,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"Super high quality H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1395,6 +1447,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"Super high quality H.264 video (up to 720p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1505,6 +1561,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"Super high quality H.264 video (up to 576p25), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1615,6 +1675,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"Super high quality H.264 video (up to 480p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container.\", \n" @@ -1718,6 +1782,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"Encode up to 3 minutes of video in large size for Gmail (25 MB or less). H.264 video (up to 720p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -1814,6 +1882,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"Encode up to 5 minutes of video in medium size for Gmail (25 MB or less). H.264 video (up to 480p30) and AAC stereo audio, in an MP4 container.\", \n" @@ -1910,6 +1982,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 384, \n" " \"PresetDescription\": \"Encode up to 10 minutes of video in small size for Gmail (25 MB or less). H.264 video (up to 288p30) and AAC mono audio, in an MP4 container.\", \n" @@ -2013,6 +2089,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30) and AAC stereo audio, in an MP4 container. Compatible with Android devices.\", \n" @@ -2109,6 +2189,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30) and AAC stereo audio, in an MP4 container. Compatible with Android devices.\", \n" @@ -2205,6 +2289,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 576p25) and AAC stereo audio, in an MP4 container. Compatible with Android devices.\", \n" @@ -2301,6 +2389,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 480p30) and AAC stereo audio, in an MP4 container. Compatible with Android devices.\", \n" @@ -2411,6 +2503,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p60), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Apple iPad Pro; iPad Air; iPad mini 2nd, 3rd Generation and later; Apple TV 4th Generation and later.\", \n" @@ -2521,6 +2617,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Apple iPhone 5, 5S, 6, 6s, and later; iPod touch 6th Generation and later; iPad Pro; iPad Air; iPad 3rd, 4th Generation and later; iPad mini; Apple TV 3rd Generation and later.\", \n" @@ -2631,6 +2731,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Apple iPhone 4 and later; iPod touch 4th, 5th Generation and later; Apple TV 2nd Generation and later.\", \n" @@ -2741,6 +2845,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 960, \n" " \"PresetDescription\": \"H.264 video (up to 540p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Apple iPhone 1st Generation, 3G, 3GS, and later; iPod touch 1st, 2nd, 3rd Generation and later; iPod Classic; Apple TV 1st Generation and later.\", \n" @@ -2837,6 +2945,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 320, \n" " \"PresetDescription\": \"H.264 video (up to 240p30) and AAC stereo audio, in an MP4 container. Compatible with Apple iPod 5th Generation and later.\", \n" @@ -2947,6 +3059,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Google Chromecast.\", \n" @@ -3057,6 +3173,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) audio, in an MP4 container. Compatible with Amazon Fire TV.\", \n" @@ -3167,6 +3287,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Playstation 3 and 4.\", \n" @@ -3263,6 +3387,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30) and AAC stereo audio, in an MP4 container. Compatible with Playstation Vita TV.\", \n" @@ -3359,6 +3487,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 960, \n" " \"PresetDescription\": \"H.264 video (up to 540p30) and AAC stereo audio, in an MP4 container. Compatible with Playstation Vita.\", \n" @@ -3472,6 +3604,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 3840, \n" " \"PresetDescription\": \"H.265 video (up to 2160p60), AAC stereo audio, and surround audio, in an MKV container. Compatible with Roku 4.\", \n" @@ -3585,6 +3721,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 3840, \n" " \"PresetDescription\": \"H.265 video (up to 2160p30), AAC stereo audio, and surround audio, in an MKV container. Compatible with Roku 4.\", \n" @@ -3695,6 +3835,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Roku 1080p models.\", \n" @@ -3805,6 +3949,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Roku 720p models.\", \n" @@ -3901,6 +4049,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 576p25) and AAC stereo audio, in an MP4 container. Compatible with Roku standard definition models.\", \n" @@ -3997,6 +4149,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 480p30) and AAC stereo audio, in an MP4 container. Compatible with Roku standard definition models.\", \n" @@ -4093,6 +4249,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30) and AAC stereo audio, in an MP4 container. Compatible with Windows Mobile devices with Qualcomm Snapdragon 800 (MSM8974), S4 (MSM8x30, MSM8960), and better CPUs.\", \n" @@ -4189,6 +4349,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30) and AAC stereo audio, in an MP4 container. Compatible with Windows Mobile devices with Qualcomm Snapdragon S4 (MSM8x27), S2 (MSM8x55), S1 (MSM8x50), and better CPUs.\", \n" @@ -4285,6 +4449,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 960, \n" " \"PresetDescription\": \"H.264 video (up to 540p30) and AAC stereo audio, in an MP4 container. Compatible with Windows Mobile devices with Qualcomm Snapdragon 200 (MSM8210, MSM8212) and better CPUs.\", \n" @@ -4381,6 +4549,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 480p30) and AAC stereo audio, in an MP4 container. Compatible with Windows Mobile devices with Qualcomm Snapdragon S1 (MSM7x27a) and better CPUs.\", \n" @@ -4491,6 +4663,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Xbox One.\", \n" @@ -4601,6 +4777,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30), AAC stereo audio, and Dolby Digital (AC-3) surround audio, in an MP4 container. Compatible with Xbox 360.\", \n" @@ -4704,6 +4884,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.264 video (up to 1080p30) and AAC stereo audio, in an MKV container.\", \n" @@ -4800,6 +4984,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.264 video (up to 720p30) and AAC stereo audio, in an MKV container.\", \n" @@ -4896,6 +5084,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 576p25) and AAC stereo audio, in an MKV container.\", \n" @@ -4992,6 +5184,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.264 video (up to 480p30) and AAC stereo audio, in an MKV container.\", \n" @@ -5088,6 +5284,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"H.265 video (up to 1080p30) and AAC stereo audio, in an MKV container.\", \n" @@ -5184,6 +5384,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"H.265 video (up to 720p30) and AAC stereo audio, in an MKV container.\", \n" @@ -5280,6 +5484,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.265 video (up to 576p25) and AAC stereo audio, in an MKV container.\", \n" @@ -5376,6 +5584,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"H.265 video (up to 480p30) and AAC stereo audio, in an MKV container.\", \n" @@ -5470,6 +5682,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"VP8 video (up to 1080p30) and Vorbis stereo audio, in an MKV container.\", \n" @@ -5564,6 +5780,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"VP8 video (up to 720p30) and Vorbis stereo audio, in an MKV container.\", \n" @@ -5658,6 +5878,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"VP8 video (up to 576p25) and Vorbis stereo audio, in an MKV container.\", \n" @@ -5752,6 +5976,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"VP8 video (up to 480p30) and Vorbis stereo audio, in an MKV container.\", \n" @@ -5846,6 +6074,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1920, \n" " \"PresetDescription\": \"VP9 video (up to 1080p30) and Opus stereo audio, in an MKV container.\", \n" @@ -5940,6 +6172,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 1280, \n" " \"PresetDescription\": \"VP9 video (up to 720p30) and Opus stereo audio, in an MKV container.\", \n" @@ -6034,6 +6270,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"VP9 video (up to 576p25) and Opus stereo audio, in an MKV container.\", \n" @@ -6128,6 +6368,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 720, \n" " \"PresetDescription\": \"VP9 video (up to 480p30) and Opus stereo audio, in an MKV container.\", \n" @@ -6985,6 +7229,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 0, \n" " \"PresetDescription\": \"\", \n" @@ -7097,6 +7345,10 @@ const char hb_builtin_presets_json[] = " \"PicturePARWidth\": 853, \n" " \"PictureRightCrop\": 0, \n" " \"PictureRotate\": \"angle=0:hflip=0\", \n" +" \"PictureSharpenCustom\": \"\", \n" +" \"PictureSharpenFilter\": \"off\", \n" +" \"PictureSharpenPreset\": \"medium\", \n" +" \"PictureSharpenTune\": \"none\", \n" " \"PictureTopCrop\": 0, \n" " \"PictureWidth\": 0, \n" " \"PresetDescription\": \"\", \n" @@ -7133,7 +7385,7 @@ const char hb_builtin_presets_json[] = " \"x264Option\": \"\", \n" " \"x264UseAdvancedOptions\": false\n" " }, \n" -" \"VersionMajor\": 24, \n" +" \"VersionMajor\": 25, \n" " \"VersionMicro\": 0, \n" " \"VersionMinor\": 0\n" " }\n" diff --git a/libhb/unsharp.c b/libhb/unsharp.c new file mode 100644 index 000000000..2d5a1d577 --- /dev/null +++ b/libhb/unsharp.c @@ -0,0 +1,274 @@ +/* unsharp.c + + Copyright (c) 2002 RĂ©mi Guyomarch <rguyom at pobox.com> + Copyright (c) 2003-2017 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 + */ + +#include "hb.h" + +#define UNSHARP_STRENGTH_LUMA_DEFAULT 0.25 +#define UNSHARP_SIZE_LUMA_DEFAULT 7 +#define UNSHARP_STRENGTH_CHROMA_DEFAULT 0.25 +#define UNSHARP_SIZE_CHROMA_DEFAULT 7 +#define UNSHARP_SIZE_MIN 3 +#define UNSHARP_SIZE_MAX 63 + +typedef struct +{ + double strength; // strength + int size; // pixel context region width (must be odd) + + int steps; + int amount; + int scalebits; + int32_t halfscale; + uint32_t * SC[UNSHARP_SIZE_MAX - 1]; +} unsharp_plane_context_t; + +struct hb_filter_private_s +{ + unsharp_plane_context_t plane_ctx[3]; +}; + +static int hb_unsharp_init(hb_filter_object_t *filter, + hb_filter_init_t *init); + +static int hb_unsharp_work(hb_filter_object_t *filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out); + +static void hb_unsharp_close(hb_filter_object_t *filter); + +static const char hb_unsharp_template[] = + "y-strength=^"HB_FLOAT_REG"$:y-size=^"HB_INT_REG"$:" + "cb-strength=^"HB_FLOAT_REG"$:cb-size=^"HB_INT_REG"$:" + "cr-strength=^"HB_FLOAT_REG"$:cr-size=^"HB_INT_REG"$"; + +hb_filter_object_t hb_filter_unsharp = +{ + .id = HB_FILTER_UNSHARP, + .enforce_order = 1, + .name = "Sharpen (unsharp)", + .settings = NULL, + .init = hb_unsharp_init, + .work = hb_unsharp_work, + .close = hb_unsharp_close, + .settings_template = hb_unsharp_template, +}; + +static void hb_unsharp(const uint8_t *src, + uint8_t *dst, + const int width, + const int height, + const int stride, + unsharp_plane_context_t * ctx) +{ + uint32_t **SC = ctx->SC; + uint32_t SR[UNSHARP_SIZE_MAX - 1], + Tmp1, + Tmp2; + const uint8_t *src2 = src; // avoid gcc warning + int32_t res; + int x, y, z; + int amount = ctx->amount; + int steps = ctx->steps; + int scalebits = ctx->scalebits; + int32_t halfscale = ctx->halfscale; + + if (!amount) + { + if (src != dst) + { + memcpy(dst, src, stride*height); + } + + return; + } + + for (y = 0; y < 2 * steps; y++) + { + memset(SC[y], 0, sizeof(SC[y][0]) * (width + 2 * steps)); + } + + for (y = -steps; y < height + steps; y++) + { + if (y < height) + { + src2 = src; + } + + memset(SR, 0, sizeof(SR[0]) * (2 * steps - 1)); + + for (x = -steps; x < width + steps; x++) + { + Tmp1 = x <= 0 ? src2[0] : x >= width ? src2[width - 1] : src2[x]; + + for (z = 0; z < steps * 2; z += 2) + { + Tmp2 = SR[z + 0] + Tmp1; SR[z + 0] = Tmp1; + Tmp1 = SR[z + 1] + Tmp2; SR[z + 1] = Tmp2; + } + + for (z = 0; z < steps * 2; z += 2) + { + Tmp2 = SC[z + 0][x + steps] + Tmp1; SC[z + 0][x + steps] = Tmp1; + Tmp1 = SC[z + 1][x + steps] + Tmp2; SC[z + 1][x + steps] = Tmp2; + } + + if (x >= steps && y >= steps) + { + const uint8_t * srx = src - steps * stride + x - steps; + uint8_t * dsx = dst - steps * stride + x - steps; + + res = (int32_t)*srx + ((((int32_t)*srx - + (int32_t)((Tmp1 + halfscale) >> scalebits)) * amount) >> 16); + *dsx = res > 255 ? 255 : res < 0 ? 0 : (uint8_t)res; + } + } + + if (y >= 0) + { + dst += stride; + src += stride; + } + } +} + +static int hb_unsharp_init(hb_filter_object_t *filter, + hb_filter_init_t *init) +{ + filter->private_data = calloc(sizeof(struct hb_filter_private_s), 1); + hb_filter_private_t * pv = filter->private_data; + + // Mark parameters unset + for (int c = 0; c < 3; c++) + { + pv->plane_ctx[c].strength = -1; + pv->plane_ctx[c].size = -1; + } + + // Read user parameters + if (filter->settings != NULL) + { + hb_dict_t * dict = filter->settings; + hb_dict_extract_double(&pv->plane_ctx[0].strength, dict, "y-strength"); + hb_dict_extract_int(&pv->plane_ctx[0].size, dict, "y-size"); + + hb_dict_extract_double(&pv->plane_ctx[1].strength, dict, "cb-strength"); + hb_dict_extract_int(&pv->plane_ctx[1].size, dict, "cb-size"); + + hb_dict_extract_double(&pv->plane_ctx[2].strength, dict, "cr-strength"); + hb_dict_extract_int(&pv->plane_ctx[2].size, dict, "cr-size"); + } + + // Cascade values + // Cr not set; inherit Cb. Cb not set; inherit Y. Y not set; defaults. + for (int c = 1; c < 3; c++) + { + unsharp_plane_context_t * prev_ctx = &pv->plane_ctx[c - 1]; + unsharp_plane_context_t * ctx = &pv->plane_ctx[c]; + + if (ctx->strength == -1) ctx->strength = prev_ctx->strength; + if (ctx->size == -1) ctx->size = prev_ctx->size; + } + + for (int c = 0; c < 3; c++) + { + unsharp_plane_context_t * ctx = &pv->plane_ctx[c]; + int w = hb_image_width(init->pix_fmt, init->geometry.width, c); + + // Replace unset values with defaults + if (ctx->strength == -1) + { + ctx->strength = c ? UNSHARP_STRENGTH_CHROMA_DEFAULT : + UNSHARP_STRENGTH_LUMA_DEFAULT; + } + if (ctx->size == -1) + { + ctx->size = c ? UNSHARP_SIZE_CHROMA_DEFAULT : + UNSHARP_SIZE_LUMA_DEFAULT; + } + + // Sanitize + if (ctx->strength < 0) ctx->strength = 0; + if (ctx->strength > 1.5) ctx->strength = 1.5; + if (ctx->size % 2 == 0) ctx->size--; + if (ctx->size < UNSHARP_SIZE_MIN) ctx->size = UNSHARP_SIZE_MIN; + if (ctx->size > UNSHARP_SIZE_MAX) ctx->size = UNSHARP_SIZE_MAX; + + ctx->amount = ctx->strength * 65536.0; + ctx->steps = ctx->size / 2; + ctx->scalebits = ctx->steps * 4; + ctx->halfscale = 1 << (ctx->scalebits - 1); + + int z; + for (z = 0; z < 2 * ctx->steps; z++) + { + ctx->SC[z] = malloc(sizeof(*(ctx->SC[z])) * (w + 2 * ctx->steps)); + } + } + + return 0; +} + +static void hb_unsharp_close(hb_filter_object_t * filter) +{ + hb_filter_private_t *pv = filter->private_data; + + if (pv == NULL) + { + return; + } + + int c, z; + for (c = 0; c < 3; c++) + { + unsharp_plane_context_t * ctx = &pv->plane_ctx[c]; + for (z = 0; z < ctx->steps; z++) + { + free(ctx->SC[z]); + ctx->SC[z] = NULL; + } + } + + free(pv); + filter->private_data = NULL; +} + +static int hb_unsharp_work(hb_filter_object_t *filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out) +{ + hb_filter_private_t *pv = filter->private_data; + hb_buffer_t *in = *buf_in, *out; + + if (in->s.flags & HB_BUF_FLAG_EOF) + { + *buf_out = in; + *buf_in = NULL; + return HB_FILTER_DONE; + } + + out = hb_frame_buffer_init(in->f.fmt, in->f.width, in->f.height); + + int c; + for (c = 0; c < 3; c++) + { + unsharp_plane_context_t * ctx = &pv->plane_ctx[c]; + hb_unsharp(in->plane[c].data, + out->plane[c].data, + in->plane[c].width, + in->plane[c].height, + in->plane[c].stride, + ctx); + } + + out->s = in->s; + *buf_out = out; + + return HB_FILTER_OK; +} |