summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gtk/src/hb-backend.c22
-rw-r--r--gtk/src/internal_defaults.json11
-rw-r--r--gtk/src/presets.c177
-rw-r--r--gtk/src/queuehandler.c30
-rw-r--r--gtk/src/standard_presets.json52
-rw-r--r--libhb/builtin_presets.h965
-rw-r--r--libhb/common.c21
-rw-r--r--libhb/hb.c5
-rw-r--r--libhb/hb.h3
-rw-r--r--libhb/hb_dict.c5
-rw-r--r--libhb/hb_dict.h1
-rw-r--r--libhb/lang.c8
-rw-r--r--libhb/lang.h2
-rw-r--r--libhb/libhb_presets.list9
-rw-r--r--libhb/module.defs6
-rw-r--r--libhb/plist.c678
-rw-r--r--libhb/plist.h13
-rw-r--r--libhb/preset.c2198
-rw-r--r--libhb/preset.h84
-rw-r--r--libhb/preset_builtin.json855
-rw-r--r--libhb/preset_template.json104
-rw-r--r--scripts/create_resources.py161
-rw-r--r--scripts/quotestring.py62
-rw-r--r--test/test.c5269
24 files changed, 7796 insertions, 2945 deletions
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index f02ec32e7..836f4d714 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -119,10 +119,10 @@ combo_opts_t when_complete_opts =
static options_map_t d_par_opts[] =
{
- {N_("Off"), "0", 0, "0"},
- {N_("Strict"), "1", 1, "1"},
- {N_("Loose"), "2", 2, "2"},
- {N_("Custom"), "3", 3, "3"},
+ {N_("Off"), "off", 0, "0"},
+ {N_("Strict"), "strict", 1, "1"},
+ {N_("Loose"), "loose", 2, "2"},
+ {N_("Custom"), "custom", 3, "3"},
};
combo_opts_t par_opts =
{
@@ -1242,9 +1242,9 @@ ghb_audio_samplerate_opts_set(GtkComboBox *combo)
gtk_list_store_set(store, &iter,
0, str,
1, TRUE,
- 2, "source",
+ 2, "auto",
3, 0.0,
- 4, "source",
+ 4, "auto",
-1);
g_free(str);
@@ -1285,7 +1285,7 @@ ghb_audio_samplerate_get_short_name(int rate)
const char *name;
name = hb_audio_samplerate_get_name(rate);
if (name == NULL)
- name = "source";
+ name = "auto";
return name;
}
@@ -1293,7 +1293,7 @@ const hb_rate_t*
ghb_lookup_audio_samplerate(const char *name)
{
// Check for special "Same as source" value
- if (!strncmp(name, "source", 8))
+ if (!strncmp(name, "auto", 8))
return &sas_rate;
// First find an enabled rate
@@ -1354,9 +1354,9 @@ video_framerate_opts_set(GtkBuilder *builder, const gchar *name)
gtk_list_store_set(store, &iter,
0, _("Same as source"),
1, TRUE,
- 2, "source",
+ 2, "auto",
3, 0.0,
- 4, "source",
+ 4, "auto",
-1);
const hb_rate_t *rate;
@@ -1394,7 +1394,7 @@ const hb_rate_t*
ghb_lookup_video_framerate(const char *name)
{
// Check for special "Same as source" value
- if (!strncmp(name, "source", 8))
+ if (!strncmp(name, "auto", 8))
return &sas_rate;
// First find an enabled rate
diff --git a/gtk/src/internal_defaults.json b/gtk/src/internal_defaults.json
index 76e78c6ff..0d4fd7657 100644
--- a/gtk/src/internal_defaults.json
+++ b/gtk/src/internal_defaults.json
@@ -12,7 +12,7 @@
"AudioTrackGainSlider": 0.0,
"AudioTrackDRCSlider": 0.0,
"AudioMixdown": "dpl2",
- "AudioSamplerate": "source",
+ "AudioSamplerate": "auto",
"AudioTrackName": "",
"angle_count": 1,
"angle": 1,
@@ -105,7 +105,6 @@
"window_height": 1
},
"Presets": {
- "PresetBuildNumber": "",
"PictureAutoCrop": true,
"ChapterMarkers": true,
"FileFormat": "mp4",
@@ -129,12 +128,12 @@
"PictureDenoiseCustom": "",
"PictureDetelecine": "off",
"PictureDetelecineCustom": "",
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PicturePARWidth": 853,
"PicturePARHeight": 720,
"PictureHeight": 0,
"PictureWidth": 0,
- "VideoFramerate": "source",
+ "VideoFramerate": "auto",
"VideoFramerateMode": "vfr",
"VideoGrayScale": false,
"Mp4HttpOptimize": false,
@@ -151,7 +150,7 @@
"AudioCopyMask": [
"copy:ac3"
],
- "AudioEncoderFallback": "ffac3",
+ "AudioEncoderFallback": "ac3",
"AudioLanguageList": [
"und"
],
@@ -164,7 +163,7 @@
"AudioTrackGainSlider": 0.0,
"AudioTrackDRCSlider": 0.0,
"AudioMixdown": "dpl2",
- "AudioSamplerate": "source"
+ "AudioSamplerate": "auto"
}
],
"AudioSecondaryEncoderMode": true,
diff --git a/gtk/src/presets.c b/gtk/src/presets.c
index 2354bc618..5c2825c7e 100644
--- a/gtk/src/presets.c
+++ b/gtk/src/presets.c
@@ -1973,39 +1973,6 @@ value_map_t decomb_xlat[] =
};
static GhbValue*
-export_value_xlat2(value_map_t *value_map, GhbValue *lin_val, GhbType mac_type)
-{
- GhbValue *gval;
-
- if (lin_val == NULL) return NULL;
- gint ii;
- gchar *str;
- GhbValue *sval;
-
- str = ghb_value_get_string_xform(lin_val);
- for (ii = 0; value_map[ii].mac_val; ii++)
- {
- if (strcmp(str, value_map[ii].lin_val) == 0)
- {
- sval = ghb_string_value_new(value_map[ii].mac_val);
- g_free(str);
- gval = ghb_value_xform(sval, mac_type);
- if (gval == NULL)
- {
- g_warning("can't transform");
- ghb_value_free(&sval);
- return NULL;
- }
- ghb_value_free(&sval);
- return gval;
- }
- }
- g_debug("Can't map value: (%s)", str);
- g_free(str);
- return NULL;
-}
-
-static GhbValue*
export_value_video_framerate(GhbValue *lin_val)
{
GhbValue *sval = NULL;
@@ -2045,7 +2012,7 @@ export_value_mixdown(GhbValue *lin_val)
const gchar *mix;
str = ghb_value_get_string(lin_val);
- mix = hb_mixdown_get_name(hb_mixdown_get_from_name(str));
+ mix = hb_mixdown_get_short_name(hb_mixdown_get_from_name(str));
if (mix != NULL)
sval = ghb_string_value_new(mix);
@@ -2060,7 +2027,7 @@ export_value_video_encoder(GhbValue *lin_val)
const gchar *enc;
str = ghb_value_get_string(lin_val);
- enc = hb_video_encoder_get_name(hb_video_encoder_get_from_name(str));
+ enc = hb_video_encoder_get_short_name(hb_video_encoder_get_from_name(str));
if (enc != NULL)
sval = ghb_string_value_new(enc);
@@ -2075,7 +2042,7 @@ export_value_audio_encoder(GhbValue *lin_val)
const gchar *enc;
str = ghb_value_get_string(lin_val);
- enc = hb_audio_encoder_get_name(hb_audio_encoder_get_from_name(str));
+ enc = hb_audio_encoder_get_short_name(hb_audio_encoder_get_from_name(str));
if (enc != NULL)
sval = ghb_string_value_new(enc);
@@ -2090,7 +2057,7 @@ export_value_container(GhbValue *lin_val)
const gchar *mux;
str = ghb_value_get_string(lin_val);
- mux = hb_container_get_name(hb_container_get_from_name(str));
+ mux = hb_container_get_short_name(hb_container_get_from_name(str));
if (mux != NULL)
sval = ghb_string_value_new(mux);
@@ -2104,6 +2071,12 @@ export_value_xlat(GhbValue *dict)
GhbValue *lin_val, *gval;
const gchar *key;
+ // Convert PictureModulus to correct data type
+ key = "PictureModulus";
+ lin_val = ghb_dict_get(dict, key);
+ gval = ghb_value_xform(lin_val, GHB_INT);
+ if (gval)
+ ghb_dict_set(dict, key, gval);
key = "VideoEncoder";
lin_val = ghb_dict_get(dict, key);
gval = export_value_video_encoder(lin_val);
@@ -2119,28 +2092,6 @@ export_value_xlat(GhbValue *dict)
gval = export_value_video_framerate(lin_val);
if (gval)
ghb_dict_set(dict, key, gval);
- key = "PictureDetelecine";
- lin_val = ghb_dict_get(dict, key);
- gval = export_value_xlat2(detel_xlat, lin_val, GHB_INT);
- if (gval)
- ghb_dict_set(dict, key, gval);
- key = "PictureDecomb";
- lin_val = ghb_dict_get(dict, key);
- gval = export_value_xlat2(decomb_xlat, lin_val, GHB_INT);
- if (gval)
- ghb_dict_set(dict, key, gval);
- key = "PictureDeinterlace";
- lin_val = ghb_dict_get(dict, key);
- gval = export_value_xlat2(deint_xlat, lin_val, GHB_INT);
- if (gval)
- ghb_dict_set(dict, key, gval);
-#if 0
- key = "PictureDenoisePreset";
- lin_val = ghb_dict_get(dict, key);
- gval = export_value_xlat2(denoise_xlat, lin_val, GHB_INT);
- if (gval)
- ghb_dict_set(dict, key, gval);
-#endif
gint count, ii;
GhbValue *alist;
@@ -2803,6 +2754,41 @@ export_xlat_preset(GhbValue *dict)
}
}
+ GhbValue *copy_mask = ghb_array_new();
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowMP3Pass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:mp3"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowAACPass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:aac"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowAC3Pass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:ac3"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowDTSPass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:dts"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowDTSHDPass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:dtshd"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowEAC3Pass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:eac3"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowFLACPass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:flac"));
+ }
+ if (ghb_value_get_bool(ghb_dict_get(dict, "AudioAllowTRUEHDPass")))
+ {
+ ghb_array_append(copy_mask, ghb_string_value_new("copy:truehd"));
+ }
+ ghb_dict_set(dict, "AudioCopyMask", copy_mask);
+
if (ghb_value_get_bool(ghb_dict_get(dict, "x264UseAdvancedOptions")))
{
ghb_dict_remove(dict, "VideoPreset");
@@ -2841,31 +2827,50 @@ export_xlat_preset(GhbValue *dict)
export_value_xlat(dict);
}
+static void export_xlat_presets(GhbValue *presets);
+
+static void
+export_xlat_dict(GhbValue *dict)
+{
+ gboolean folder;
+ folder = ghb_value_get_bool(ghb_dict_get(dict, "Folder"));
+ if (folder)
+ {
+ GhbValue *nested;
+
+ nested = ghb_dict_get(dict, "ChildrenArray");
+ export_xlat_presets(nested);
+ }
+ else
+ {
+ export_xlat_preset(dict);
+ }
+}
+
static void
export_xlat_presets(GhbValue *presets)
{
gint count, ii;
GhbValue *dict;
- gboolean folder;
if (presets == NULL) return;
- count = ghb_array_len(presets);
- for (ii = 0; ii < count; ii++)
+ if (ghb_value_type(presets) == GHB_DICT)
{
- dict = ghb_array_get(presets, ii);
- folder = ghb_value_get_bool(ghb_dict_get(dict, "Folder"));
- if (folder)
- {
- GhbValue *nested;
-
- nested = ghb_dict_get(dict, "ChildrenArray");
- export_xlat_presets(nested);
- }
- else
+ export_xlat_dict(presets);
+ }
+ else if (ghb_value_type(presets) == GHB_ARRAY)
+ {
+ count = ghb_array_len(presets);
+ for (ii = 0; ii < count; ii++)
{
- export_xlat_preset(dict);
+ dict = ghb_array_get(presets, ii);
+ export_xlat_dict(dict);
}
}
+ else
+ {
+ g_warning("export_xlat_presets: Invalid presets format");
+ }
}
static guint prefs_timeout_id = 0;
@@ -2933,8 +2938,6 @@ ghb_presets_reload(signal_user_data_t *ud)
std_dict = ghb_array_get(std_presets, ii);
copy_dict = ghb_value_dup(std_dict);
- ghb_dict_set(copy_dict, "PresetBuildNumber",
- ghb_int_value_new(hb_get_build(NULL)));
ghb_presets_insert(presetsPlist, copy_dict, &indices, 1);
presets_list_insert(ud, &indices, 1);
}
@@ -3009,8 +3012,6 @@ replace_standard_presets(GhbValue *presetsArray)
std_dict = ghb_array_get(std_presets, ii);
copy_dict = ghb_value_dup(std_dict);
- ghb_dict_set(copy_dict, "PresetBuildNumber",
- ghb_int_value_new(hb_get_build(NULL)));
ghb_presets_insert(presetsArray, copy_dict, &indices, 1);
}
ghb_value_free(&std_presets);
@@ -3026,7 +3027,6 @@ update_standard_presets(signal_user_data_t *ud, GhbValue *presetsArray)
{
GhbValue *dict;
const GhbValue *gval;
- gint64 build;
gint type;
dict = ghb_array_get(presetsArray, ii);
@@ -3041,6 +3041,10 @@ update_standard_presets(signal_user_data_t *ud, GhbValue *presetsArray)
type = ghb_value_get_int(gval);
if (type == 0)
{
+ // TODO: check preset version
+#if 0
+ gint64 build;
+
gval = ghb_dict_get(dict, "PresetBuildNumber");
if (gval == NULL)
{
@@ -3056,6 +3060,7 @@ update_standard_presets(signal_user_data_t *ud, GhbValue *presetsArray)
replace_standard_presets(presetsArray);
return 1;
}
+#endif
}
}
return 0;
@@ -3134,7 +3139,6 @@ settings_save(signal_user_data_t *ud, const GhbValue *path)
}
current_preset = dict;
ghb_dict_set_int(dict, "Type", PRESETS_CUSTOM);
- ghb_dict_set_int(dict, "PresetBuildNumber", hb_get_build(NULL));
ghb_dict_set(dict, "PresetName", ghb_string_value_new(name));
if (replace)
@@ -3499,7 +3503,7 @@ preset_export_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
{
exportDir = ".";
}
- filename = g_strdup_printf("%s.plist", name);
+ filename = g_strdup_printf("%s.json", name);
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), exportDir);
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename);
g_free(filename);
@@ -3515,7 +3519,7 @@ preset_export_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
gtk_widget_hide(dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
- GhbValue *export, *dict, *array;
+ GhbValue *export, *dict;
gchar *dir;
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
@@ -3524,14 +3528,9 @@ preset_export_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
dict = presets_get_dict(presetsPlist, indices, len);
export = ghb_value_dup(dict);
- array = ghb_array_new();
- ghb_array_append(array, export);
- presets_clear_default(array);
- presets_customize(array);
- export_xlat_presets(array);
-
- store_plist(filename, array);
- ghb_value_free(&array);
+ export_xlat_presets(export);
+ hb_preset_write_json(export, filename);
+ ghb_value_free(&export);
exportDir = ghb_dict_get_string(ud->prefs, "ExportDirectory");
dir = g_path_get_dirname(filename);
diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c
index 67ce7dca4..876d49ec9 100644
--- a/gtk/src/queuehandler.c
+++ b/gtk/src/queuehandler.c
@@ -236,13 +236,14 @@ add_to_queue_list(signal_user_data_t *ud, GhbValue *settings, GtkTreeIter *piter
// Next line in the display (Picture settings)
// Picture: Source: W x H, Output W x H (Animorphic), Display W x H
- int width, height, pic_par;
+ const char *pic_par;
+ int width, height;
int crop[4];
gboolean keep_aspect;
width = ghb_dict_get_int(settings, "scale_width");
height = ghb_dict_get_int(settings, "scale_height");
- pic_par = ghb_dict_get_int(settings, "PicturePAR");
+ pic_par = ghb_dict_get_string(settings, "PicturePAR");
keep_aspect = ghb_dict_get_bool(settings, "PictureKeepRatio");
crop[0] = ghb_dict_get_int(settings, "PictureTopCrop");
crop[1] = ghb_dict_get_int(settings, "PictureBottomCrop");
@@ -250,9 +251,7 @@ add_to_queue_list(signal_user_data_t *ud, GhbValue *settings, GtkTreeIter *piter
crop[3] = ghb_dict_get_int(settings, "PictureRightCrop");
gchar *aspect_desc;
- switch (pic_par)
- {
- case 0:
+ if (pic_par == NULL || !strcasecmp(pic_par, "off"))
{
if (keep_aspect)
{
@@ -262,27 +261,18 @@ add_to_queue_list(signal_user_data_t *ud, GhbValue *settings, GtkTreeIter *piter
{
aspect_desc = _("(Aspect Lost)");
}
- } break;
-
- case 1:
- {
- aspect_desc = _("(Anamorphic)");
- } break;
-
- case 2:
+ }
+ else if (!strcasecmp(pic_par, "strict") || !strcasecmp(pic_par, "loose"))
{
aspect_desc = _("(Anamorphic)");
- } break;
-
- case 3:
+ }
+ else if (!strcasecmp(pic_par, "custom"))
{
aspect_desc = _("(Custom Anamorphic)");
- } break;
-
- default:
+ }
+ else
{
aspect_desc = "";
- } break;
}
gint source_width, source_height;
diff --git a/gtk/src/standard_presets.json b/gtk/src/standard_presets.json
index 160a09d82..41c7be767 100644
--- a/gtk/src/standard_presets.json
+++ b/gtk/src/standard_presets.json
@@ -50,7 +50,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 720,
@@ -58,7 +58,7 @@
"PresetName": "Universal",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -117,7 +117,7 @@
"PictureKeepRatio": 1,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 0,
+ "PicturePAR": "off",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 320,
@@ -125,7 +125,7 @@
"PresetName": "iPod",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -184,7 +184,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 960,
@@ -192,7 +192,7 @@
"PresetName": "iPhone & iPod touch",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -251,7 +251,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 1280,
@@ -259,7 +259,7 @@
"PresetName": "iPad",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -327,7 +327,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 960,
@@ -335,7 +335,7 @@
"PresetName": "AppleTV",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -403,7 +403,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 1280,
@@ -411,7 +411,7 @@
"PresetName": "AppleTV 2",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -479,7 +479,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 1920,
@@ -487,7 +487,7 @@
"PresetName": "AppleTV 3",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -546,7 +546,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 720,
@@ -554,7 +554,7 @@
"PresetName": "Android",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -613,7 +613,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 1280,
@@ -621,7 +621,7 @@
"PresetName": "Android Tablet",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -680,7 +680,7 @@
"PictureKeepRatio": 1,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 0,
+ "PicturePAR": "off",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 1280,
@@ -688,7 +688,7 @@
"PresetName": "Windows Phone 8",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -710,7 +710,6 @@
],
"Default": 0,
"Folder": true,
- "PresetBuildNumber": 2013061301,
"PresetName": "Devices",
"Type": 0
},
@@ -756,7 +755,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 0,
@@ -764,7 +763,7 @@
"PresetName": "Normal",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -832,7 +831,7 @@
"PictureKeepRatio": 0,
"PictureLeftCrop": 0,
"PictureModulus": 2,
- "PicturePAR": 2,
+ "PicturePAR": "loose",
"PictureRightCrop": 0,
"PictureTopCrop": 0,
"PictureWidth": 0,
@@ -840,7 +839,7 @@
"PresetName": "High Profile",
"Subtitles": "None",
"Type": 0,
- "UsesPictureFilters": 1,
+ "UsesPictureFilters": true,
"UsesPictureSettings": 1,
"VideoAvgBitrate": "2500",
"VideoEncoder": "H.264 (x264)",
@@ -862,8 +861,7 @@
],
"Default": 0,
"Folder": true,
- "PresetBuildNumber": 2013061301,
"PresetName": "Regular",
"Type": 0
}
-] \ No newline at end of file
+]
diff --git a/libhb/builtin_presets.h b/libhb/builtin_presets.h
new file mode 100644
index 000000000..b0b3e5cd8
--- /dev/null
+++ b/libhb/builtin_presets.h
@@ -0,0 +1,965 @@
+const char hb_builtin_presets_json[] =
+"{\n"
+" \"PresetBuiltin\": [\n"
+" {\n"
+" \"ChildrenArray\": [\n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }, \n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"copy:ac3\", \n"
+" \"AudioMixdown\": \"none\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 576, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 720, \n"
+" \"PresetDescription\": \"HandBrake's settings for compatibility with all Apple devices (including the iPod 6G and later). Includes Dolby Digital audio for surround sound.\", \n"
+" \"PresetName\": \"Universal\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.0\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"fast\", \n"
+" \"VideoProfile\": \"baseline\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 1, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 240, \n"
+" \"PictureKeepRatio\": 1, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"off\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 320, \n"
+" \"PresetDescription\": \"HandBrake's settings for playback on the iPod with Video (all generations).\", \n"
+" \"PresetName\": \"iPod\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"1.3\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"baseline\", \n"
+" \"VideoQualitySlider\": 22.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 640, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 960, \n"
+" \"PresetDescription\": \"HandBrake's settings for handheld iOS devices (iPhone 4, iPod touch 3G and later).\", \n"
+" \"PresetName\": \"iPhone & iPod touch\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.1\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"high\", \n"
+" \"VideoQualitySlider\": 22.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 720, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 1280, \n"
+" \"PresetDescription\": \"HandBrake's settings for playback on the iPad (all generations).\", \n"
+" \"PresetName\": \"iPad\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.1\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"high\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }, \n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"copy:ac3\", \n"
+" \"AudioMixdown\": \"none\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 720, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 960, \n"
+" \"PresetDescription\": \"HandBrake's settings for the original AppleTV. Includes Dolby Digital audio for surround sound. Also compatible with iOS devices released since 2009.\", \n"
+" \"PresetName\": \"AppleTV\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.1\", \n"
+" \"VideoOptionExtra\": \"qpmin=4:cabac=0:ref=2:b-pyramid=none:weightb=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"high\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }, \n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"copy:ac3\", \n"
+" \"AudioMixdown\": \"none\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 720, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 1280, \n"
+" \"PresetDescription\": \"HandBrake's settings for the second-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV.\", \n"
+" \"PresetName\": \"AppleTV 2\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.1\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"high\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }, \n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"copy:ac3\", \n"
+" \"AudioMixdown\": \"none\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 3, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 1080, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 1920, \n"
+" \"PresetDescription\": \"HandBrake's settings for the third-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV. May stutter on the second-generation AppleTV.\", \n"
+" \"PresetName\": \"AppleTV 3\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"4.0\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"high\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"128\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 0, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 576, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 720, \n"
+" \"PresetDescription\": \"HandBrake's settings for midrange devices running Android 2.3 or later.\", \n"
+" \"PresetName\": \"Android\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.0\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"main\", \n"
+" \"VideoQualitySlider\": 22.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"128\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 0, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 720, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 1280, \n"
+" \"PresetDescription\": \"HandBrake's preset for tablets running Android 2.3 or later.\", \n"
+" \"PresetName\": \"Android Tablet\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.1\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"main\", \n"
+" \"VideoQualitySlider\": 22.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"128\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 0, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 720, \n"
+" \"PictureKeepRatio\": 1, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"off\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 1280, \n"
+" \"PresetDescription\": \"HandBrake's preset for Windows Phone 8 devices\", \n"
+" \"PresetName\": \"Windows Phone 8\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"30\", \n"
+" \"VideoFramerateMode\": \"pfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"3.1\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"main\", \n"
+" \"VideoQualitySlider\": 22.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }\n"
+" ], \n"
+" \"Default\": 0, \n"
+" \"Folder\": true, \n"
+" \"PresetName\": \"Devices\", \n"
+" \"Type\": 0\n"
+" }, \n"
+" {\n"
+" \"ChildrenArray\": [\n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 1, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 0, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 0, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 0, \n"
+" \"PresetDescription\": \"HandBrake's normal, default settings.\", \n"
+" \"PresetName\": \"Normal\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"auto\", \n"
+" \"VideoFramerateMode\": \"vfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"4.0\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"veryfast\", \n"
+" \"VideoProfile\": \"main\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }, \n"
+" {\n"
+" \"AudioAllowAACPass\": 1, \n"
+" \"AudioAllowAC3Pass\": 1, \n"
+" \"AudioAllowDTSHDPass\": 1, \n"
+" \"AudioAllowDTSPass\": 1, \n"
+" \"AudioAllowMP3Pass\": 1, \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"aac\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }, \n"
+" {\n"
+" \"AudioBitrate\": \"160\", \n"
+" \"AudioEncoder\": \"copy:ac3\", \n"
+" \"AudioMixdown\": \"none\", \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrack\": 1, \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0\n"
+" }\n"
+" ], \n"
+" \"ChapterMarkers\": 1, \n"
+" \"Default\": 0, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": 0, \n"
+" \"Mp4iPodCompatible\": 0, \n"
+" \"PictureAutoCrop\": 1, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": 2, \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": 1, \n"
+" \"PictureDeinterlace\": 0, \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDetelecine\": 0, \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureHeight\": 0, \n"
+" \"PictureKeepRatio\": 0, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 0, \n"
+" \"PresetDescription\": \"HandBrake's general-purpose preset for High Profile H.264 video.\", \n"
+" \"PresetName\": \"High Profile\", \n"
+" \"Type\": 0, \n"
+" \"UsesPictureFilters\": 1, \n"
+" \"UsesPictureSettings\": 1, \n"
+" \"VideoAvgBitrate\": \"2500\", \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"auto\", \n"
+" \"VideoFramerateMode\": \"vfr\", \n"
+" \"VideoGrayScale\": 0, \n"
+" \"VideoLevel\": \"4.1\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"high\", \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoTune\": \"\", \n"
+" \"VideoTurboTwoPass\": 0, \n"
+" \"VideoTwoPass\": 0, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": 0\n"
+" }\n"
+" ], \n"
+" \"Default\": 0, \n"
+" \"Folder\": true, \n"
+" \"PresetName\": \"Regular\", \n"
+" \"Type\": 0\n"
+" }\n"
+" ], \n"
+" \"PresetTemplate\": {\n"
+" \"Preset\": {\n"
+" \"AudioAllowAACPass\": false, \n"
+" \"AudioAllowAC3Pass\": true, \n"
+" \"AudioAllowDTSHDPass\": false, \n"
+" \"AudioAllowDTSPass\": false, \n"
+" \"AudioAllowEAC3Pass\": false, \n"
+" \"AudioAllowFLACPass\": false, \n"
+" \"AudioAllowMP3Pass\": false, \n"
+" \"AudioAllowTRUEHDPass\": false, \n"
+" \"AudioCopyMask\": [], \n"
+" \"AudioEncoderFallback\": \"ac3\", \n"
+" \"AudioLanguageList\": [\n"
+" \"und\"\n"
+" ], \n"
+" \"AudioList\": [\n"
+" {\n"
+" \"AudioBitrate\": \"192\", \n"
+" \"AudioCompressionLevel\": -1.0, \n"
+" \"AudioDitherMethod\": \"auto\", \n"
+" \"AudioEncoder\": \"copy:ac3\", \n"
+" \"AudioMixdown\": \"dpl2\", \n"
+" \"AudioNormalizeMixLevel\": false, \n"
+" \"AudioSamplerate\": \"auto\", \n"
+" \"AudioTrackDRCSlider\": 0.0, \n"
+" \"AudioTrackGainSlider\": 0.0, \n"
+" \"AudioTrackQuality\": -1.0, \n"
+" \"AudioTrackQualityEnable\": false\n"
+" }\n"
+" ], \n"
+" \"AudioSecondaryEncoderMode\": true, \n"
+" \"AudioTrackSelectionBehavior\": \"first\", \n"
+" \"ChapterMarkers\": true, \n"
+" \"Default\": false, \n"
+" \"FileFormat\": \"mp4\", \n"
+" \"Folder\": false, \n"
+" \"Mp4HttpOptimize\": false, \n"
+" \"Mp4iPodCompatible\": false, \n"
+" \"PictureAutoCrop\": true, \n"
+" \"PictureBottomCrop\": 0, \n"
+" \"PictureDARWidth\": 0, \n"
+" \"PictureDeblock\": 0, \n"
+" \"PictureDecomb\": \"off\", \n"
+" \"PictureDecombCustom\": \"\", \n"
+" \"PictureDecombDeinterlace\": true, \n"
+" \"PictureDeinterlace\": \"off\", \n"
+" \"PictureDeinterlaceCustom\": \"\", \n"
+" \"PictureDenoiseCustom\": \"\", \n"
+" \"PictureDenoiseFilter\": \"off\", \n"
+" \"PictureDenoisePreset\": \"medium\", \n"
+" \"PictureDenoiseTune\": \"none\", \n"
+" \"PictureDetelecine\": \"off\", \n"
+" \"PictureDetelecineCustom\": \"\", \n"
+" \"PictureForceHeight\": 0, \n"
+" \"PictureForceWidth\": 0, \n"
+" \"PictureHeight\": 0, \n"
+" \"PictureItuPAR\": false, \n"
+" \"PictureKeepRatio\": true, \n"
+" \"PictureLeftCrop\": 0, \n"
+" \"PictureLooseCrop\": false, \n"
+" \"PictureModulus\": 2, \n"
+" \"PicturePAR\": \"loose\", \n"
+" \"PicturePARHeight\": 720, \n"
+" \"PicturePARWidth\": 853, \n"
+" \"PictureRightCrop\": 0, \n"
+" \"PictureRotate\": 0, \n"
+" \"PictureTopCrop\": 0, \n"
+" \"PictureWidth\": 0, \n"
+" \"PresetDescription\": \"\", \n"
+" \"PresetName\": \"Name Missing\", \n"
+" \"SubtitleAddCC\": false, \n"
+" \"SubtitleAddForeignAudioSearch\": false, \n"
+" \"SubtitleAddForeignAudioSubtitle\": false, \n"
+" \"SubtitleBurnBDSub\": false, \n"
+" \"SubtitleBurnBehavior\": \"none\", \n"
+" \"SubtitleBurnDVDSub\": false, \n"
+" \"SubtitleLanguageList\": [], \n"
+" \"SubtitleTrackSelectionBehavior\": \"none\", \n"
+" \"Type\": 1, \n"
+" \"UsesPictureFilters\": true, \n"
+" \"UsesPictureSettings\": 2, \n"
+" \"VideoAvgBitrate\": 1800, \n"
+" \"VideoColorMatrixCode\": 0, \n"
+" \"VideoEncoder\": \"x264\", \n"
+" \"VideoFramerate\": \"auto\", \n"
+" \"VideoFramerateMode\": \"vfr\", \n"
+" \"VideoGrayScale\": false, \n"
+" \"VideoHWDecode\": false, \n"
+" \"VideoLevel\": \"auto\", \n"
+" \"VideoOptionExtra\": \"\", \n"
+" \"VideoPreset\": \"medium\", \n"
+" \"VideoProfile\": \"auto\", \n"
+" \"VideoQSVAsyncDepth\": 4, \n"
+" \"VideoQSVDecode\": false, \n"
+" \"VideoQualitySlider\": 20.0, \n"
+" \"VideoQualityType\": 2, \n"
+" \"VideoScaler\": \"swscale\", \n"
+" \"VideoTune\": \"none\", \n"
+" \"VideoTurboTwoPass\": false, \n"
+" \"VideoTwoPass\": false, \n"
+" \"x264Option\": \"\", \n"
+" \"x264UseAdvancedOptions\": false\n"
+" }, \n"
+" \"VersionMajor\": 10, \n"
+" \"VersionMicro\": 0, \n"
+" \"VersionMinor\": 0\n"
+" }\n"
+"}\n";
diff --git a/libhb/common.c b/libhb/common.c
index 7bb3f2a56..8a7b72522 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -262,6 +262,9 @@ hb_encoder_internal_t hb_audio_encoders[] =
{ { "Vorbis (vorbis)", "libvorbis", NULL, HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_VORBIS, },
{ { "FLAC (ffmpeg)", "ffflac", NULL, HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, },
{ { "FLAC (24-bit)", "ffflac24", NULL, HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, },
+ // generic names
+ { { "AAC", "aac", NULL, 0, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AAC, },
+ { { "HE-AAC", "haac", NULL, 0, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AAC_HE, },
// actual encoders
{ { "AAC (CoreAudio)", "ca_aac", "AAC (Apple AudioToolbox)", HB_ACODEC_CA_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, },
{ { "HE-AAC (CoreAudio)", "ca_haac", "HE-AAC (Apple AudioToolbox)", HB_ACODEC_CA_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_HE, },
@@ -1793,7 +1796,7 @@ int hb_video_encoder_get_default(int muxer)
}
fail:
- return 0;
+ return HB_VCODEC_INVALID;
}
hb_encoder_t * hb_video_encoder_get_from_codec(int codec)
@@ -1826,7 +1829,7 @@ int hb_video_encoder_get_from_name(const char *name)
}
fail:
- return 0;
+ return HB_VCODEC_INVALID;
}
const char* hb_video_encoder_get_name(int encoder)
@@ -1937,10 +1940,10 @@ int hb_audio_encoder_get_fallback_for_passthru(int passthru)
}
// passthru tracks are often the second audio from the same source track
- // if we don't have an encoder matching the passthru codec, return 0
+ // if we don't have an encoder matching the passthru codec, return INVALID
// dropping the track, as well as ensuring that there is at least one
// audio track in the output is then up to the UIs
- return 0;
+ return HB_ACODEC_INVALID;
}
int hb_audio_encoder_get_default(int muxer)
@@ -1974,7 +1977,7 @@ int hb_audio_encoder_get_default(int muxer)
}
fail:
- return 0;
+ return HB_ACODEC_INVALID;
}
hb_encoder_t* hb_audio_encoder_get_from_codec(int codec)
@@ -1988,7 +1991,7 @@ hb_encoder_t* hb_audio_encoder_get_from_codec(int codec)
}
}
- return 0;
+ return NULL;
}
int hb_audio_encoder_get_from_name(const char *name)
@@ -2007,7 +2010,7 @@ int hb_audio_encoder_get_from_name(const char *name)
}
fail:
- return 0;
+ return HB_ACODEC_INVALID;
}
const char* hb_audio_encoder_get_name(int encoder)
@@ -2302,7 +2305,7 @@ int hb_container_get_from_name(const char *name)
}
fail:
- return 0;
+ return HB_MUX_INVALID;
}
int hb_container_get_from_extension(const char *extension)
@@ -2320,7 +2323,7 @@ int hb_container_get_from_extension(const char *extension)
}
fail:
- return 0;
+ return HB_MUX_INVALID;
}
const char* hb_container_get_name(int format)
diff --git a/libhb/hb.c b/libhb/hb.c
index 7a7429153..f4ec2308f 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -1655,6 +1655,9 @@ int hb_global_init()
*/
hb_buffer_pool_init();
+ // Initialize the builtin presets hb_dict_t
+ hb_presets_builtin_init();
+
return result;
}
@@ -1667,6 +1670,8 @@ void hb_global_close()
DIR * dir;
struct dirent * entry;
+ hb_presets_free();
+
/* Find and remove temp folder */
memset( dirname, 0, 1024 );
hb_get_temporary_directory( dirname );
diff --git a/libhb/hb.h b/libhb/hb.h
index 38418ac3b..215455cda 100644
--- a/libhb/hb.h
+++ b/libhb/hb.h
@@ -14,11 +14,12 @@
extern "C" {
#endif
-#include "project.h"
#include "common.h"
+#include "project.h"
#include "compat.h"
#include "hb_dict.h"
#include "hb_json.h"
+#include "preset.h"
#include "param.h"
/* hb_init()
diff --git a/libhb/hb_dict.c b/libhb/hb_dict.c
index 7fd12b565..866803f58 100644
--- a/libhb/hb_dict.c
+++ b/libhb/hb_dict.c
@@ -21,6 +21,11 @@ hb_value_type_t hb_value_type(const hb_value_t *value)
return type;
}
+int hb_value_is_number(const hb_value_t *value)
+{
+ return json_is_number(value);
+}
+
hb_value_t * hb_value_dup(const hb_value_t *value)
{
if (value == NULL) return NULL;
diff --git a/libhb/hb_dict.h b/libhb/hb_dict.h
index 52898e413..2a4f71cfe 100644
--- a/libhb/hb_dict.h
+++ b/libhb/hb_dict.h
@@ -84,6 +84,7 @@ size_t hb_value_array_len(const hb_value_array_t *array);
/* hb_value_t */
int hb_value_type(const hb_value_t *value);
+int hb_value_is_number(const hb_value_t *value);
hb_value_t * hb_value_dup(const hb_value_t *value);
void hb_value_incref(hb_value_t *value);
void hb_value_decref(hb_value_t *value);
diff --git a/libhb/lang.c b/libhb/lang.c
index f40520a23..34466da34 100644
--- a/libhb/lang.c
+++ b/libhb/lang.c
@@ -202,10 +202,16 @@ static const iso639_lang_t languages[] =
static const int lang_count = sizeof(languages) / sizeof(languages[0]);
-iso639_lang_t * lang_lookup( const char * str )
+const iso639_lang_t * lang_lookup( const char * str )
{
iso639_lang_t * lang;
+ // We use "Any" as a synonym for undefined
+ if (!strcasecmp("any", str))
+ {
+ return &languages[0];
+ }
+
for (lang = (iso639_lang_t*) languages; lang->eng_name; lang++)
{
if ((lang->iso639_1 != NULL && !strcasecmp(lang->iso639_1, str)) ||
diff --git a/libhb/lang.h b/libhb/lang.h
index 21aab70af..7e7b82bd5 100644
--- a/libhb/lang.h
+++ b/libhb/lang.h
@@ -24,7 +24,7 @@ typedef struct iso639_lang_t
extern "C" {
#endif
/* find language, match any of names in lang struct */
-iso639_lang_t * lang_lookup( const char * str );
+const iso639_lang_t * lang_lookup( const char * str );
/* find language associated with ISO-639-1 language code */
iso639_lang_t * lang_for_code( int code );
diff --git a/libhb/libhb_presets.list b/libhb/libhb_presets.list
new file mode 100644
index 000000000..3742b1d40
--- /dev/null
+++ b/libhb/libhb_presets.list
@@ -0,0 +1,9 @@
+<resources>
+ <section name="PresetTemplate">
+ <integer name="VersionMajor" value="10" />
+ <integer name="VersionMinor" value="0" />
+ <integer name="VersionMicro" value="0" />
+ <json name="Preset" file="preset_template.json" />
+ </section>
+ <json name="PresetBuiltin" file="preset_builtin.json" />
+</resources>
diff --git a/libhb/module.defs b/libhb/module.defs
index 3d7d55ee3..f98930dd5 100644
--- a/libhb/module.defs
+++ b/libhb/module.defs
@@ -47,6 +47,12 @@ endif
LIBHB.GCC.D += __LIBHB__ USE_PTHREAD
LIBHB.GCC.I += $(LIBHB.build/) $(CONTRIB.build/)include
+ifneq (,$(filter $(BUILD.system),darwin cygwin mingw))
+LIBHB.GCC.I += $(CONTRIB.build/)include/libxml2
+else
+LIBHB.GCC.I += /usr/include/libxml2
+endif
+
ifeq ($(BUILD.system),cygwin)
LIBHB.GCC.D += SYS_CYGWIN
else ifeq ($(BUILD.system),darwin)
diff --git a/libhb/plist.c b/libhb/plist.c
new file mode 100644
index 000000000..f61014537
--- /dev/null
+++ b/libhb/plist.c
@@ -0,0 +1,678 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include "libxml/parser.h"
+
+#include "common.h"
+#include "hb_dict.h"
+#include "plist.h"
+
+#define BUF_SZ (128*1024)
+
+static char *preamble =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n";
+static char *postfix =
+ "</plist>\n";
+
+typedef struct queue_item_s queue_item_t;
+struct queue_item_s
+{
+ void *value;
+ queue_item_t *next;
+};
+
+typedef struct
+{
+ queue_item_t *head;
+} queue_t;
+
+queue_t * queue_new()
+{
+ return calloc(1, sizeof(queue_t));
+}
+
+void queue_free(queue_t **_q)
+{
+ queue_t *q = *_q;
+ if (q == NULL)
+ return;
+
+ queue_item_t *n, *i = q->head;
+ while (i != NULL)
+ {
+ n = i->next;
+ free(i);
+ i = n;
+ }
+ free(q);
+ *_q = NULL;
+}
+
+void queue_push_head(queue_t *q, void *v)
+{
+ queue_item_t *i = calloc(1, sizeof(queue_item_t));
+ i->value = v;
+ i->next = q->head;
+ q->head = i;
+}
+
+void * queue_peek_head(queue_t *q)
+{
+ if (q->head != NULL)
+ return q->head->value;
+ return NULL;
+}
+
+void * queue_pop_head(queue_t *q)
+{
+ void *result;
+ queue_item_t *i;
+
+ if (q->head == NULL)
+ return NULL;
+
+ i = q->head;
+ result = i->value;
+ q->head = i->next;
+ free(i);
+
+ return result;
+}
+
+int queue_is_empty(queue_t *q)
+{
+ return q->head == NULL;
+}
+
+char * markup_escape_text(const char *str)
+{
+ int ii, jj;
+ int len = strlen(str);
+ int step = 40;
+ int alloc = len + step;
+ char *markup = malloc(alloc);
+
+ for (ii = 0, jj = 0; ii < len; ii++)
+ {
+ if (jj > alloc - 8)
+ {
+ alloc += step;
+ char *tmp = realloc(markup, alloc);
+ if (tmp == NULL)
+ {
+ markup[jj] = 0;
+ return markup;
+ }
+ markup = tmp;
+ }
+ switch (str[ii])
+ {
+ case '<':
+ markup[jj++] = '&';
+ markup[jj++] = 'l';
+ markup[jj++] = 't';
+ markup[jj++] = ';';
+ break;
+ case '>':
+ markup[jj++] = '&';
+ markup[jj++] = 'g';
+ markup[jj++] = 't';
+ markup[jj++] = ';';
+ break;
+ case '\'':
+ markup[jj++] = '&';
+ markup[jj++] = 'a';
+ markup[jj++] = 'p';
+ markup[jj++] = 'o';
+ markup[jj++] = 's';
+ markup[jj++] = ';';
+ break;
+ case '"':
+ markup[jj++] = '&';
+ markup[jj++] = 'q';
+ markup[jj++] = 'u';
+ markup[jj++] = 'o';
+ markup[jj++] = 't';
+ markup[jj++] = ';';
+ break;
+ case '&':
+ markup[jj++] = '&';
+ markup[jj++] = 'a';
+ markup[jj++] = 'm';
+ markup[jj++] = 'p';
+ markup[jj++] = ';';
+ break;
+ default:
+ markup[jj++] = str[ii];
+ break;
+ }
+ markup[jj] = 0;
+ }
+ return markup;
+}
+
+enum
+{
+ P_NONE = 0,
+ P_PLIST,
+ P_KEY,
+ P_ARRAY,
+ P_DICT,
+ P_INTEGER,
+ P_REAL,
+ P_STRING,
+ P_DATE,
+ P_TRUE,
+ P_FALSE,
+ P_DATA,
+};
+
+typedef struct
+{
+ char *tag;
+ int id;
+} tag_map_t;
+
+static tag_map_t tag_map[] =
+{
+ {"plist", P_PLIST},
+ {"key", P_KEY},
+ {"array", P_ARRAY},
+ {"dict", P_DICT},
+ {"integer", P_INTEGER},
+ {"real", P_REAL},
+ {"string", P_STRING},
+ {"date", P_DATE},
+ {"true", P_TRUE},
+ {"false", P_FALSE},
+ {"data", P_DATA},
+};
+#define TAG_MAP_SZ (sizeof(tag_map)/sizeof(tag_map_t))
+
+typedef struct
+{
+ char *key;
+ char *value;
+ hb_value_t *plist;
+ queue_t *stack;
+ queue_t *tag_stack;
+ int closed_top;
+} parse_data_t;
+
+static void
+start_element(
+ void *ud,
+ const xmlChar *xname,
+ const xmlChar **attr_names)
+{
+ char *name = (char*)xname;
+ parse_data_t *pd = (parse_data_t*)ud;
+ union
+ {
+ int id;
+ void * pid;
+ } id;
+ int ii;
+
+ // Check to see if the first element found has been closed
+ // If so, ignore any junk following it.
+ if (pd->closed_top)
+ return;
+
+ for (ii = 0; ii < TAG_MAP_SZ; ii++)
+ {
+ if (strcmp(name, tag_map[ii].tag) == 0)
+ {
+ id.id = tag_map[ii].id;
+ break;
+ }
+ }
+ if (ii == TAG_MAP_SZ)
+ {
+ hb_error("Unrecognized start tag (%s)", name);
+ return;
+ }
+ if (pd->value)
+ {
+ free(pd->value);
+ pd->value = NULL;
+ }
+ queue_push_head(pd->tag_stack, id.pid);
+ hb_value_type_t gtype = 0;
+ hb_value_t *gval = NULL;
+ hb_value_t *current = queue_peek_head(pd->stack);
+ switch (id.id)
+ {
+ case P_PLIST:
+ { // Ignore
+ } break;
+ case P_KEY:
+ {
+ if (pd->key) free(pd->key);
+ pd->key = NULL;
+ } break;
+ case P_DICT:
+ {
+ gval = hb_dict_init();
+ queue_push_head(pd->stack, gval);
+ } break;
+ case P_ARRAY:
+ {
+ gval = hb_value_array_init();
+ queue_push_head(pd->stack, gval);
+ } break;
+ case P_INTEGER:
+ {
+ } break;
+ case P_REAL:
+ {
+ } break;
+ case P_STRING:
+ {
+ } break;
+ case P_DATE:
+ {
+ } break;
+ case P_TRUE:
+ {
+ } break;
+ case P_FALSE:
+ {
+ } break;
+ case P_DATA:
+ {
+ } break;
+ }
+ // Add the element to the current container
+ if (gval)
+ { // There's an element to add
+ if (current == NULL)
+ {
+ pd->plist = gval;
+ return;
+ }
+ gtype = hb_value_type(current);
+ if (gtype == HB_VALUE_TYPE_ARRAY)
+ {
+ hb_value_array_append(current, gval);
+ }
+ else if (gtype == HB_VALUE_TYPE_DICT)
+ {
+ if (pd->key == NULL)
+ {
+ hb_error("No key for dictionary item");
+ hb_value_free(&gval);
+ }
+ else
+ {
+ hb_dict_set(current, pd->key, gval);
+ }
+ }
+ else
+ {
+ hb_error("Invalid container type. This shouldn't happen");
+ }
+ }
+}
+
+static void
+end_element(
+ void *ud,
+ const xmlChar *xname)
+{
+ char *name = (char*)xname;
+ parse_data_t *pd = (parse_data_t*)ud;
+ int id;
+ union
+ {
+ int id;
+ void * pid;
+ } start_id;
+ int ii;
+
+ // Check to see if the first element found has been closed
+ // If so, ignore any junk following it.
+ if (pd->closed_top)
+ return;
+
+ for (ii = 0; ii < TAG_MAP_SZ; ii++)
+ {
+ if (strcmp(name, tag_map[ii].tag) == 0)
+ {
+ id = tag_map[ii].id;
+ break;
+ }
+ }
+ if (ii == TAG_MAP_SZ)
+ {
+ hb_error("Unrecognized start tag (%s)", name);
+ return;
+ }
+ start_id.pid = queue_pop_head(pd->tag_stack);
+ if (start_id.id != id)
+ hb_error("start tag != end tag: (%s %d) %d", name, id, id);
+
+ hb_value_t *gval = NULL;
+ hb_value_t *current = queue_peek_head(pd->stack);
+ hb_value_type_t gtype = 0;
+ const char *value;
+ if (pd->value != NULL)
+ value = pd->value;
+ else
+ value = "";
+ switch (id)
+ {
+ case P_PLIST:
+ { // Ignore
+ } break;
+ case P_KEY:
+ {
+ if (pd->key) free(pd->key);
+ pd->key = strdup(value);
+ return;
+ } break;
+ case P_DICT:
+ {
+ queue_pop_head(pd->stack);
+ } break;
+ case P_ARRAY:
+ {
+ queue_pop_head(pd->stack);
+ } break;
+ case P_INTEGER:
+ {
+ uint64_t val = strtoll(value, NULL, 0);
+ gval = hb_value_int(val);
+ } break;
+ case P_REAL:
+ {
+ double val = strtod(value, NULL);
+ gval = hb_value_double(val);
+ } break;
+ case P_STRING:
+ {
+ gval = hb_value_string(value);
+ } break;
+ case P_TRUE:
+ {
+ gval = hb_value_bool(1);
+ } break;
+ case P_FALSE:
+ {
+ gval = hb_value_bool(0);
+ } break;
+ default:
+ {
+ hb_error("Unhandled plist type %d", id);
+ } break;
+ }
+ if (gval)
+ {
+ // Get the top of the data structure stack and if it's an array
+ // or dict, add the current element
+ if (current == NULL)
+ {
+ pd->plist = gval;
+ pd->closed_top = 1;
+ return;
+ }
+ gtype = hb_value_type(current);
+ if (gtype == HB_VALUE_TYPE_ARRAY)
+ {
+ hb_value_array_append(current, gval);
+ }
+ else if (gtype == HB_VALUE_TYPE_DICT)
+ {
+ if (pd->key == NULL)
+ {
+ hb_error("No key for dictionary item");
+ hb_value_free(&gval);
+ }
+ else
+ {
+ hb_dict_set(current, pd->key, gval);
+ }
+ }
+ else
+ {
+ hb_error("Invalid container type. This shouldn't happen");
+ }
+ }
+ if (queue_is_empty(pd->stack))
+ pd->closed_top = 1;
+}
+
+static void
+text_data(
+ void *ud,
+ const xmlChar *xtext,
+ int len)
+{
+ char *text = (char*)xtext;
+ parse_data_t *pd = (parse_data_t*)ud;
+ if (pd->value) free(pd->value);
+ pd->value = malloc(len + 1);
+ strncpy(pd->value, text, len);
+ pd->value[len] = 0;
+}
+
+static void
+parse_warning(void *ud, const char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ hb_valog(0, "Plist parse warning: ", msg, args);
+ va_end(args);
+}
+
+static void
+parse_error(void *ud, const char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ hb_valog(0, "Plist parse error: ", msg, args);
+ va_end(args);
+}
+
+hb_value_t*
+hb_plist_parse(const char *buf, size_t len)
+{
+ xmlSAXHandler parser;
+ parse_data_t pd;
+
+ pd.stack = queue_new();
+ pd.tag_stack = queue_new();
+ pd.key = NULL;
+ pd.value = NULL;
+ pd.plist = NULL;
+ pd.closed_top = 0;
+
+ memset(&parser, 0, sizeof(parser));
+ parser.initialized = XML_SAX2_MAGIC;
+ parser.startElement = start_element;
+ parser.endElement = end_element;
+ parser.characters = text_data;
+ parser.warning = parse_warning;
+ parser.error = parse_error;
+ int result = xmlSAXUserParseMemory(&parser, &pd, buf, len);
+ if (result != 0)
+ {
+ hb_error("Plist parse failed");
+ return NULL;
+ }
+ xmlCleanupParser();
+
+ if (pd.key) free(pd.key);
+ if (pd.value) free(pd.value);
+ queue_free(&pd.stack);
+ queue_free(&pd.tag_stack);
+
+ return pd.plist;
+}
+
+hb_value_t*
+hb_plist_parse_file(const char *filename)
+{
+ char *buffer;
+ size_t size;
+ hb_value_t *gval;
+ FILE *fd;
+
+ fd = fopen(filename, "r");
+ if (fd == NULL)
+ {
+ // File doesn't exist
+ return NULL;
+ }
+ fseek(fd, 0, SEEK_END);
+ size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ buffer = malloc(size+1);
+ size = fread(buffer, 1, size, fd);
+ buffer[size] = 0;
+ gval = hb_plist_parse(buffer, size);
+ free(buffer);
+ fclose(fd);
+ return gval;
+}
+
+static void
+indent_fprintf(FILE *file, int indent, const char *fmt, ...)
+{
+ va_list ap;
+
+ for (; indent; indent--)
+ putc('\t', file);
+ va_start(ap, fmt);
+ vfprintf(file, fmt, ap);
+ va_end(ap);
+}
+
+static void
+gval_write(FILE *file, hb_value_t *gval)
+{
+ static int indent = 0;
+ int ii;
+ hb_value_type_t gtype;
+
+ if (gval == NULL) return;
+ gtype = hb_value_type(gval);
+ if (gtype == HB_VALUE_TYPE_ARRAY)
+ {
+ hb_value_t *val;
+ int count;
+
+ indent_fprintf(file, indent, "<array>\n");
+ indent++;
+ count = hb_value_array_len(gval);
+ for (ii = 0; ii < count; ii++)
+ {
+ val = hb_value_array_get(gval, ii);
+ gval_write(file, val);
+ }
+ indent--;
+ indent_fprintf(file, indent, "</array>\n");
+ }
+ else if (gtype == HB_VALUE_TYPE_DICT)
+ {
+ const char *key;
+ hb_value_t *val;
+ hb_dict_iter_t iter;
+
+ indent_fprintf(file, indent, "<dict>\n");
+ indent++;
+
+ for (iter = hb_dict_iter_init(gval);
+ iter != HB_DICT_ITER_DONE;
+ iter = hb_dict_iter_next(gval, iter))
+ {
+ key = hb_dict_iter_key(iter);
+ val = hb_dict_iter_value(iter);
+ indent_fprintf(file, indent, "<key>%s</key>\n", key);
+ gval_write(file, val);
+ }
+
+ indent--;
+ indent_fprintf(file, indent, "</dict>\n");
+ }
+ else if (gtype == HB_VALUE_TYPE_BOOL)
+ {
+ char *tag;
+ if (hb_value_get_bool(gval))
+ {
+ tag = "true";
+ }
+ else
+ {
+ tag = "false";
+ }
+ indent_fprintf(file, indent, "<%s />\n", tag);
+ }
+ else if (gtype == HB_VALUE_TYPE_DOUBLE)
+ {
+ double val = hb_value_get_double(gval);
+ indent_fprintf(file, indent, "<real>%.17g</real>\n", val);
+ }
+ else if (gtype == HB_VALUE_TYPE_INT)
+ {
+ int64_t val = hb_value_get_int(gval);
+ indent_fprintf(file, indent, "<integer>%"PRId64"</integer>\n", val);
+ }
+ else if (gtype == HB_VALUE_TYPE_STRING)
+ {
+ const char *str = hb_value_get_string(gval);
+ char *esc = markup_escape_text(str);
+ indent_fprintf(file, indent, "<string>%s</string>\n", esc);
+ free(esc);
+ }
+ else
+ {
+ // Try to make anything thats unrecognized into a string
+ hb_error("Unhandled data type %d", gtype);
+ }
+}
+
+void
+hb_plist_write(FILE *file, hb_value_t *gval)
+{
+ fprintf(file, "%s", preamble);
+ gval_write(file, gval);
+ fprintf(file, "%s", postfix);
+}
+
+void
+hb_plist_write_file(const char *filename, hb_value_t *gval)
+{
+ FILE *file;
+
+ file = fopen(filename, "w");
+ if (file == NULL)
+ return;
+
+ hb_plist_write(file, gval);
+ fclose(file);
+}
+
+
+#if defined(PL_TEST)
+int
+main(int argc, char *argv[])
+{
+ hb_value_t *gval;
+
+ file = fopen(argv[1], "r");
+ gval = hb_plist_parse_file(file);
+ if (argc > 2)
+ hb_plist_write_file(argv[2], gval);
+ else
+ hb_plist_write(stdout, gval);
+ if (file) fclose (file);
+ return 0;
+}
+#endif
diff --git a/libhb/plist.h b/libhb/plist.h
new file mode 100644
index 000000000..901aeb4b0
--- /dev/null
+++ b/libhb/plist.h
@@ -0,0 +1,13 @@
+#if !defined(_HB_PLIST_H_)
+#define _HB_PLIST_H_
+
+#include <stdio.h>
+#include "hb_dict.h"
+
+hb_value_t * hb_plist_parse(const char *buf, size_t len);
+hb_value_t * hb_plist_parse_file(const char *filename);
+void hb_plist_write(FILE *file, hb_value_t *val);
+void hb_plist_write_file(const char *filename, hb_value_t *val);
+
+#endif // _HB_PLIST_H_
+
diff --git a/libhb/preset.c b/libhb/preset.c
new file mode 100644
index 000000000..3fef7c686
--- /dev/null
+++ b/libhb/preset.c
@@ -0,0 +1,2198 @@
+/* hb_preset.c
+
+ 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
+ */
+
+#include "builtin_presets.h"
+#include "hb.h"
+#include "hb_dict.h"
+#include "plist.h"
+
+#if defined(SYS_LINUX)
+#define HB_PRESET_PLIST_FILE "ghb/presets"
+#define HB_PRESET_JSON_FILE "ghb/presets.json"
+#elif defined(SYS_MINGW)
+#define HB_PRESET_PLIST_FILE "HandBrake\\user_presets.xml"
+#define HB_PRESET_JSON_FILE "HandBrake\\user_presets.json"
+#elif defined(SYS_DARWIN)
+#define HB_PRESET_PLIST_FILE "HandBrake/UserPresets.plist"
+#endif
+
+int hb_preset_version_major;
+int hb_preset_version_minor;
+int hb_preset_version_micro;
+
+static hb_value_t *hb_preset_template = NULL;
+static hb_value_t *hb_presets = NULL;
+static hb_value_t *hb_presets_custom = NULL;
+static hb_value_t *hb_presets_builtin = NULL;
+
+static int get_job_mux(hb_dict_t *job_dict)
+{
+ int mux;
+
+ hb_dict_t *dest_dict = hb_dict_get(job_dict, "Destination");
+ hb_value_t *mux_value = hb_dict_get(dest_dict, "Mux");
+ if (hb_value_type(mux_value) == HB_VALUE_TYPE_STRING)
+ {
+ mux = hb_container_get_from_name(hb_value_get_string(mux_value));
+ if (mux == 0)
+ mux = hb_container_get_from_extension(
+ hb_value_get_string(mux_value));
+ }
+ else
+ {
+ mux = hb_value_get_int(mux_value);
+ }
+ hb_container_t *container = hb_container_get_from_format(mux);
+ if (container == NULL)
+ {
+ char *str = hb_value_get_string_xform(mux_value);
+ hb_error("Invalid container (%s)", str);
+ free(str);
+ return HB_MUX_INVALID;
+ }
+ return mux;
+}
+
+static int get_audio_copy_mask(hb_dict_t * preset)
+{
+ int mask = HB_ACODEC_PASS_FLAG;
+
+ hb_value_array_t *copy_mask_array = hb_dict_get(preset, "AudioCopyMask");
+ if (copy_mask_array != NULL)
+ {
+ int count = hb_value_array_len(copy_mask_array);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ int codec;
+ hb_value_t *value;
+ value = hb_value_array_get(copy_mask_array, ii);
+ if (hb_value_type(value) == HB_VALUE_TYPE_STRING)
+ {
+ char *tmp = NULL;
+ const char * s = hb_value_get_string(value);
+ // Only codecs that start with 'copy:' can be copied
+ if (strncmp(s, "copy:", 5))
+ {
+ s = tmp = hb_strdup_printf("copy:%s", s);
+ }
+ codec = hb_audio_encoder_get_from_name(s);
+ if (codec == 0)
+ {
+ hb_error("Invalid audio codec in autopassthru copy mask (%s)", s);
+ hb_error("Codec name is invalid or can not be copied");
+ free(tmp);
+ return HB_ACODEC_INVALID;
+ }
+ free(tmp);
+ }
+ else
+ {
+ codec = hb_value_get_int(value);
+ }
+ mask |= codec;
+ }
+ }
+ else
+ {
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowMP3Pass")) *
+ HB_ACODEC_MP3;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowAACPass")) *
+ HB_ACODEC_FFAAC;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowAC3Pass")) *
+ HB_ACODEC_AC3;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowDTSPass")) *
+ HB_ACODEC_DCA;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowDTSHDPass")) *
+ HB_ACODEC_DCA_HD;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowEAC3Pass")) *
+ HB_ACODEC_FFEAC3;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowFLACPass")) *
+ HB_ACODEC_FFFLAC;
+ mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowTRUEHDPass")) *
+ HB_ACODEC_FFTRUEHD;
+ }
+ return mask;
+}
+
+static hb_dict_t * source_audio_track_used(hb_dict_t *track_dict, int track)
+{
+ // Kind of hacky, but keys must be strings
+ char key[8];
+ snprintf(key, sizeof(key), "%d", track);
+
+ hb_dict_t *used = hb_dict_get(track_dict, key);
+ if (used == NULL)
+ {
+ used = hb_dict_init();
+ hb_dict_set(track_dict, key, used);
+ }
+ return used;
+}
+
+// Find a source audio track matching given language
+static int find_audio_track(const hb_title_t *title,
+ const char *lang, int start)
+{
+ hb_audio_config_t * audio;
+ int ii, count;
+
+ count = hb_list_count(title->list_audio);
+ for (ii = start; ii < count; ii++)
+ {
+ audio = hb_list_audio_config_item(title->list_audio, ii);
+ // Ignore secondary audio types
+ if ((audio->lang.type == HB_AUDIO_TYPE_NONE ||
+ audio->lang.type == HB_AUDIO_TYPE_NORMAL) &&
+ (!strcmp(lang, audio->lang.iso639_2) || !strcmp(lang, "und")))
+ {
+ return ii;
+ }
+ }
+ return -1;
+}
+
+static int validate_audio_encoders(hb_dict_t *preset)
+{
+ hb_value_array_t * encoder_list = hb_dict_get(preset, "AudioList");
+ int count = hb_value_array_len(encoder_list);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_value_t *audio_dict = hb_value_array_get(encoder_list, ii);
+ hb_value_t *value;
+ int codec, mix, sr;
+ value = hb_dict_get(audio_dict, "AudioEncoder");
+ if (hb_value_type(value) == HB_VALUE_TYPE_STRING)
+ {
+ codec = hb_audio_encoder_get_from_name(hb_value_get_string(value));
+ }
+ else
+ {
+ codec = hb_value_get_int(value);
+ }
+ if (hb_audio_encoder_get_from_codec(codec) == NULL)
+ {
+ char *str = hb_value_get_string_xform(value);
+ hb_error("Invalid audio encoder (%s)", str);
+ free(str);
+ return -1;
+ }
+
+ value = hb_dict_get(audio_dict, "AudioMixdown");
+ if (hb_value_type(value) == HB_VALUE_TYPE_STRING)
+ {
+ mix = hb_audio_encoder_get_from_name(hb_value_get_string(value));
+ }
+ else
+ {
+ mix = hb_value_get_int(value);
+ }
+ if (hb_mixdown_get_from_mixdown(mix) == NULL)
+ {
+ char *str = hb_value_get_string_xform(value);
+ hb_error("Invalid audio mixdown (%s)", str);
+ free(str);
+ return -1;
+ }
+
+ value = hb_dict_get(audio_dict, "AudioSamplerate");
+ if (hb_value_type(value) == HB_VALUE_TYPE_STRING)
+ {
+ const char *str = hb_value_get_string(value);
+ if (!strcasecmp(str, "source") ||
+ !strcasecmp(str, "auto") ||
+ !strcasecmp(str, "same as source"))
+ {
+ sr = 0;
+ }
+ else
+ {
+ sr = hb_audio_samplerate_get_from_name(str);
+ }
+ }
+ else
+ {
+ sr = hb_value_get_int(value);
+ }
+ if (sr != 0 && hb_audio_samplerate_get_name(sr) == NULL)
+ {
+ char *str = hb_value_get_string_xform(value);
+ hb_error("Invalid audio samplerate (%s)", str);
+ free(str);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int sanitize_audio_codec(int in_codec, int out_codec,
+ int copy_mask, int fallback, int mux)
+{
+ int codec = out_codec;
+ if (out_codec == HB_ACODEC_AUTO_PASS)
+ {
+ codec = hb_autopassthru_get_encoder(in_codec, copy_mask, fallback, mux);
+ }
+ else if ((out_codec & HB_ACODEC_PASS_FLAG) &&
+ !(in_codec & out_codec & HB_ACODEC_PASS_MASK))
+ {
+ codec = hb_audio_encoder_get_fallback_for_passthru(out_codec);
+ if (codec == 0)
+ codec = fallback;
+ }
+
+ // Check that encoder is valid for mux
+ const hb_encoder_t *encoder = NULL;
+ while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
+ {
+ if (encoder->codec == codec &&
+ !(encoder->muxers & mux))
+ {
+ codec = hb_audio_encoder_get_default(mux);
+ break;
+ }
+ }
+ if (codec == 0)
+ codec = hb_audio_encoder_get_default(mux);
+ return codec;
+}
+
+static void add_audio_for_lang(hb_value_array_t *list, hb_dict_t *preset,
+ hb_title_t *title, int mux, int copy_mask,
+ int fallback, const char *lang,
+ int behavior, int mode, hb_dict_t *track_dict)
+{
+ hb_value_array_t * encoder_list = hb_dict_get(preset, "AudioList");
+ int count = hb_value_array_len(encoder_list);
+ int track = find_audio_track(title, lang, 0);
+ int current_mode = 0;
+ while (track >= 0)
+ {
+ char key[8];
+ snprintf(key, sizeof(key), "%d", track);
+
+ count = current_mode ? 1 : count;
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ // Check if this source track has already been added using these
+ // same encoder settings. If so, continue to next track.
+ hb_dict_t *used = source_audio_track_used(track_dict, ii);
+ if (hb_value_get_bool(hb_dict_get(used, key)))
+ continue;
+ hb_dict_set(used, key, hb_value_bool(1));
+
+ // Create new audio output track settings
+ hb_dict_t *audio_dict = hb_dict_init();
+ hb_value_t *acodec_value;
+ hb_dict_t *encoder_dict = hb_value_array_get(encoder_list, ii);
+ int out_codec;
+
+ acodec_value = hb_dict_get(encoder_dict, "AudioEncoder");
+ if (hb_value_type(acodec_value) == HB_VALUE_TYPE_STRING)
+ {
+ out_codec = hb_audio_encoder_get_from_name(
+ hb_value_get_string(acodec_value));
+ }
+ else
+ {
+ out_codec = hb_value_get_int(acodec_value);
+ }
+ // Save the encoder value before sanitizing. This value is
+ // useful to the frontends.
+ hb_dict_set(audio_dict, "PresetEncoder", hb_value_int(out_codec));
+
+ hb_audio_config_t *aconfig;
+ aconfig = hb_list_audio_config_item(title->list_audio, track);
+ out_codec = sanitize_audio_codec(aconfig->in.codec, out_codec,
+ copy_mask, fallback, mux);
+ hb_dict_set(audio_dict, "Track", hb_value_int(track));
+ hb_dict_set(audio_dict, "Encoder", hb_value_int(out_codec));
+ if (hb_dict_get(encoder_dict, "AudioTrackName") != NULL)
+ {
+ hb_dict_set(audio_dict, "Name", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioTrackName")));
+ }
+ if (!(out_codec & HB_ACODEC_PASS_FLAG))
+ {
+ if (hb_dict_get(encoder_dict, "AudioTrackGainSlider") != NULL)
+ {
+ hb_dict_set(audio_dict, "Gain", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioTrackGainSlider")));
+ }
+ if (hb_dict_get(encoder_dict, "AudioTrackDRCSlider") != NULL)
+ {
+ hb_dict_set(audio_dict, "DRC", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioTrackDRCSlider")));
+ }
+ if (hb_dict_get(encoder_dict, "AudioMixdown") != NULL)
+ {
+ hb_dict_set(audio_dict, "Mixdown", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioMixdown")));
+ }
+ if (hb_dict_get(encoder_dict, "AudioNormalizeMixLevel") != NULL)
+ {
+ hb_dict_set(audio_dict, "NormalizeMixLevel", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioNormalizeMixLevel")));
+ }
+ if (hb_dict_get(encoder_dict, "AudioDitherMethod") != NULL)
+ {
+ hb_dict_set(audio_dict, "DitherMethod", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioDitherMethod")));
+ }
+ if (hb_dict_get(encoder_dict, "AudioSamplerate") != NULL)
+ {
+ hb_dict_set(audio_dict, "Samplerate", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioSamplerate")));
+ }
+ if (hb_dict_get(encoder_dict, "AudioCompressionLevel") != NULL)
+ {
+ hb_dict_set(audio_dict, "CompressionLevel", hb_value_dup(
+ hb_dict_get(encoder_dict, "AudioCompressionLevel")));
+ }
+ if (hb_value_get_bool(hb_dict_get(encoder_dict,
+ "AudioTrackQualityEnable")))
+ {
+ hb_dict_set(audio_dict, "Quality", hb_value_xform(
+ hb_dict_get(encoder_dict, "AudioTrackQuality"),
+ HB_VALUE_TYPE_DOUBLE));
+ }
+ else
+ {
+ hb_dict_set(audio_dict, "Bitrate", hb_value_xform(
+ hb_dict_get(encoder_dict, "AudioBitrate"),
+ HB_VALUE_TYPE_INT));
+ }
+ }
+ hb_value_array_append(list, audio_dict);
+ }
+ if (behavior == 2)
+ track = find_audio_track(title, lang, track + 1);
+ else
+ break;
+ }
+}
+
+// This function assumes that Mux has already been initialized in
+// the job_dict
+int hb_preset_job_add_audio(hb_handle_t *h, int title_index,
+ hb_dict_t *preset, hb_dict_t *job_dict)
+{
+ hb_title_t *title = hb_find_title_by_index(h, title_index);
+ if (title == NULL)
+ {
+ // Can't create audio track list without knowing source audio tracks
+ hb_error("Invalid title index (%d)", title_index);
+ return -1;
+ }
+ if (hb_list_count(title->list_audio) <= 0)
+ {
+ // Source has no audio
+ return 0;
+ }
+
+ int mux = get_job_mux(job_dict);
+ if (mux == HB_MUX_INVALID)
+ {
+ return -1;
+ }
+
+ hb_dict_t *audio_dict = hb_dict_get(job_dict, "Audio");
+ int copy_mask = get_audio_copy_mask(preset);
+ if (copy_mask == HB_ACODEC_INVALID)
+ {
+ return -1;
+ }
+ int fallback = 0;
+ hb_dict_set(audio_dict, "CopyMask", hb_value_int(copy_mask));
+ hb_value_t *fallback_value = hb_dict_get(preset, "AudioEncoderFallback");
+ if (fallback_value != NULL)
+ {
+ hb_dict_set(audio_dict, "FallbackEncoder",
+ hb_value_dup(fallback_value));
+ if (hb_value_type(fallback_value) == HB_VALUE_TYPE_STRING)
+ {
+ const char * s = hb_value_get_string(fallback_value);
+ fallback = hb_audio_encoder_get_from_name(s);
+ if (fallback == 0)
+ {
+ hb_error("Invalid fallback audio codec (%s)", s);
+ return -1;
+ }
+ }
+ else
+ {
+ fallback = hb_value_get_int(fallback_value);
+ }
+ }
+ if (validate_audio_encoders(preset) < 0)
+ return -1;
+
+ hb_value_array_t *list = hb_dict_get(audio_dict, "AudioList");
+ if (list == NULL)
+ {
+ list = hb_value_array_init();
+ hb_dict_set(audio_dict, "AudioList", list);
+ }
+
+ int behavior = 1; // default first
+ const char *s;
+ s = hb_value_get_string(hb_dict_get(preset, "AudioTrackSelectionBehavior"));
+ if (s != NULL)
+ {
+ if (!strcasecmp(s, "none"))
+ return 0;
+ else if (!strcasecmp(s, "all"))
+ behavior = 2;
+ }
+
+ // Create hash that is used to track which tracks have been already added
+ // We do not want to add the same track with the same settings twice
+ hb_dict_t *track_dict = hb_dict_init();
+
+ // Add tracks for all languages in the language list
+ int mode;
+ hb_value_array_t *lang_list = hb_dict_get(preset, "AudioLanguageList");
+ mode = hb_value_get_bool(hb_dict_get(preset, "AudioSecondaryEncoderMode"));
+ int count = hb_value_array_len(lang_list);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ const char *lang;
+ lang = hb_value_get_string(hb_value_array_get(lang_list, ii));
+ add_audio_for_lang(list, preset, title, mux, copy_mask, fallback,
+ lang, behavior, mode, track_dict);
+ }
+ // If no audios found, try "und" language option
+ if (hb_value_array_len(list) <= 0)
+ {
+ add_audio_for_lang(list, preset, title, mux, copy_mask, fallback,
+ "und", behavior, mode, track_dict);
+ }
+ hb_dict_free(&track_dict);
+ return 0;
+}
+
+// Find a source audio track matching given language
+static int find_subtitle_track(const hb_title_t *title,
+ const char *lang, int start)
+{
+ hb_subtitle_t * subtitle;
+ int ii, count;
+
+ count = hb_list_count(title->list_subtitle);
+ for (ii = start; ii < count; ii++)
+ {
+ subtitle = hb_list_item(title->list_subtitle, ii);
+ if (!strcmp(lang, subtitle->iso639_2) || !strcmp(lang, "und"))
+ {
+ return ii;
+ }
+ }
+ return -1;
+}
+
+static void add_subtitle(hb_value_array_t *list, int track,
+ int make_default, int force, int burn)
+{
+ hb_dict_t *subtitle_dict = hb_dict_init();
+ hb_dict_set(subtitle_dict, "Track", hb_value_int(track));
+ hb_dict_set(subtitle_dict, "Default", hb_value_bool(make_default));
+ hb_dict_set(subtitle_dict, "Forced", hb_value_bool(force));
+ hb_dict_set(subtitle_dict, "Burn", hb_value_bool(burn));
+ hb_value_array_append(list, subtitle_dict);
+}
+
+typedef struct subtitle_behavior_s
+{
+ int one;
+ int burn_foreign;
+ int make_default;
+ int burn_first;
+ int burn_dvd;
+ int burn_bd;
+ int one_burned;
+ uint8_t *used;
+} subtitle_behavior_t;
+
+static void add_subtitle_for_lang(hb_value_array_t *list, hb_title_t *title,
+ int mux, const char *lang,
+ subtitle_behavior_t *behavior)
+{
+ int t;
+ t = find_subtitle_track(title, lang, 0);
+ for (t = find_subtitle_track(title, lang, 0);
+ t >= 0;
+ t = behavior->one ? -1 : find_subtitle_track(title, lang, t + 1))
+ {
+ if (behavior->used[t])
+ {
+ if (behavior->one)
+ break;
+ continue;
+ }
+ int burn, make_default;
+ hb_subtitle_t *subtitle;
+ subtitle = hb_list_item(title->list_subtitle, t);
+ burn = !behavior->one_burned &&
+ ((subtitle->source == VOBSUB && behavior->burn_dvd) ||
+ (subtitle->source == PGSSUB && behavior->burn_bd) ||
+ !hb_subtitle_can_pass(subtitle->source, mux) ||
+ behavior->burn_first || behavior->burn_foreign);
+ make_default = !burn && behavior->make_default;
+ behavior->burn_first &= !burn;
+ behavior->one_burned |= burn;
+ behavior->used[t] = 1;
+ add_subtitle(list, t, make_default, 0 /*!force*/, burn);
+ }
+}
+
+// This function assumes that the AudioList and Mux have already been
+// initialized in the job_dict
+int hb_preset_job_add_subtitles(hb_handle_t *h, int title_index,
+ hb_dict_t *preset, hb_dict_t *job_dict)
+{
+ hb_title_t *title = hb_find_title_by_index(h, title_index);
+ if (title == NULL)
+ {
+ // Can't create subtitle track list without knowing source
+ hb_error("Invalid title index (%d)", title_index);
+ return -1;
+ }
+
+ int mux = get_job_mux(job_dict);
+ if (mux == HB_MUX_INVALID)
+ {
+ return -1;
+ }
+
+ // Get the language of the first audio output track
+ // Needed for subtitle track selection
+ hb_dict_t *audio_dict = hb_dict_get(job_dict, "Audio");
+ hb_value_array_t *audio_list = hb_dict_get(audio_dict, "AudioList");
+ const char *first_audio_lang = NULL;
+ if (hb_value_array_len(audio_list) > 0)
+ {
+ int track;
+ hb_value_t *audio = hb_value_array_get(audio_list, 0);
+ track = hb_value_get_int(hb_dict_get(audio, "Track"));
+ if (hb_list_count(title->list_audio) > track)
+ {
+ hb_audio_config_t *aconfig;
+ aconfig = hb_list_audio_config_item(title->list_audio, track);
+ if (aconfig != NULL)
+ first_audio_lang = aconfig->lang.iso639_2;
+ }
+ }
+
+ int source_subtitle_count = hb_list_count(title->list_subtitle);
+ if (source_subtitle_count == 0)
+ return 0;
+
+ hb_dict_t *subtitle_dict = hb_dict_get(job_dict, "Subtitle");
+ hb_value_array_t *list = hb_dict_get(subtitle_dict, "SubtitleList");
+ if (list == NULL)
+ {
+ list = hb_value_array_init();
+ hb_dict_set(subtitle_dict, "SubtitleList", list);
+ }
+
+ int track_behavior = 0; // default no subtitles
+ int burn_behavior = 0;
+ int burn_foreign;
+
+ struct subtitle_behavior_s behavior;
+ behavior.one = 0;
+ behavior.burn_foreign = 0;
+ behavior.make_default = 0;
+ behavior.burn_first = 0;
+ behavior.burn_dvd = 0;
+ behavior.burn_bd = 0;
+ behavior.one_burned = 0;
+ // Create array that is used to track which tracks have been already added
+ // We do not want to add the same track with the same settings twice
+ behavior.used = calloc(source_subtitle_count, sizeof(*behavior.used));
+
+ const char *s;
+ s = hb_value_get_string(hb_dict_get(preset,
+ "SubtitleTrackSelectionBehavior"));
+ if (s != NULL)
+ {
+ if (!strcasecmp(s, "first"))
+ track_behavior = 1;
+ else if (!strcasecmp(s, "all"))
+ track_behavior = 2;
+ }
+
+ s = hb_value_get_string(hb_dict_get(preset, "SubtitleBurnBehavior"));
+ if (s != NULL)
+ {
+ if (!strcasecmp(s, "foreign"))
+ burn_behavior = 1;
+ else if (!strcasecmp(s, "first"))
+ burn_behavior = 2;
+ else if (!strcasecmp(s, "foreign_first"))
+ burn_behavior = 3;
+ }
+
+ behavior.burn_dvd = hb_value_get_int(hb_dict_get(preset,
+ "SubtitleBurnDVDSub"));
+ behavior.burn_bd = hb_value_get_int(hb_dict_get(preset,
+ "SubtitleBurnBDSub"));
+
+ burn_foreign = burn_behavior == 1 || burn_behavior == 3;
+ behavior.burn_first = burn_behavior == 2 || burn_behavior == 3;
+
+ int foreign_audio_search, foreign_first_audio;
+ foreign_audio_search = hb_value_get_bool(hb_dict_get(preset,
+ "SubtitleAddForeignAudioSearch"));
+ foreign_first_audio = hb_value_get_bool(hb_dict_get(preset,
+ "SubtitleAddForeignAudioSubtitle"));
+
+
+ // Add tracks for all languages in the language list
+ hb_value_array_t *lang_list = hb_dict_get(preset, "SubtitleLanguageList");
+ int count = hb_value_array_len(lang_list);
+ const char *pref_lang = "und";
+ if (count > 0)
+ {
+ pref_lang = hb_value_get_string(hb_value_array_get(lang_list, 0));
+ }
+ if (!strcmp(pref_lang, "und"))
+ {
+ foreign_audio_search = foreign_first_audio = 0;
+ }
+
+ int track;
+ if (first_audio_lang != NULL &&
+ foreign_first_audio && strncmp(first_audio_lang, pref_lang, 4))
+ {
+ // First audio lang does not match the preferred subittle lang.
+ // Preset says to add pref lang subtitle.
+ // Foreign audio search is not necessary since entire audio track
+ // is foreign.
+ foreign_audio_search = 0;
+ behavior.one = 1;
+ behavior.burn_foreign = burn_foreign;
+ behavior.make_default = 1;
+ add_subtitle_for_lang(list, title, mux, pref_lang, &behavior);
+ }
+
+ hb_dict_t *search_dict = hb_dict_get(subtitle_dict, "Search");
+ if (search_dict == NULL)
+ {
+ search_dict = hb_dict_init();
+ hb_dict_set(subtitle_dict, "Search", search_dict);
+ }
+ if (first_audio_lang != NULL &&
+ foreign_audio_search && !strncmp(first_audio_lang, pref_lang, 4))
+ {
+ // First audio lang matches the preferred subittle lang.
+ // Preset says to add search for foreign audio subtitles.
+ int burn = burn_foreign || behavior.burn_first;
+ // If not burning, make this the default track.
+ hb_dict_set(search_dict, "Enable", hb_value_bool(1));
+ hb_dict_set(search_dict, "Default", hb_value_bool(!burn));
+ hb_dict_set(search_dict, "Forced", hb_value_bool(1));
+ hb_dict_set(search_dict, "Burn", hb_value_bool(burn));
+ }
+ else
+ {
+ hb_dict_set(search_dict, "Enable", hb_value_bool(0));
+ }
+
+ if (track_behavior > 0)
+ {
+ int ii;
+ behavior.one = track_behavior == 1;
+ behavior.burn_foreign = 0;
+ behavior.make_default = 0;
+ for (ii = 0; ii < count; ii++)
+ {
+ const char *lang;
+ lang = hb_value_get_string(hb_value_array_get(lang_list, ii));
+ add_subtitle_for_lang(list, title, mux, lang, &behavior);
+ }
+ if (count <= 0)
+ {
+ add_subtitle_for_lang(list, title, mux, "und", &behavior);
+ }
+ }
+
+ if (hb_value_get_bool(hb_dict_get(preset, "SubtitleAddCC")))
+ {
+ // Add Closed Caption track
+ for (track = 0; track < source_subtitle_count; track++)
+ {
+ if (behavior.used[track])
+ {
+ continue;
+ }
+ hb_subtitle_t *subtitle = hb_list_item(title->list_subtitle, track);
+ if (subtitle->source == CC608SUB || subtitle->source == CC708SUB)
+ {
+ int burn;
+ burn = !behavior.one_burned &&
+ (!hb_subtitle_can_pass(subtitle->source, mux) ||
+ behavior.burn_first);
+ behavior.used[track] = 1;
+ behavior.one_burned |= burn;
+ add_subtitle(list, track, 0 /*default*/, 0 /*!force*/, burn);
+ break;
+ }
+ }
+ }
+ free(behavior.used);
+
+ return 0;
+}
+
+static int get_video_framerate(hb_value_t *rate_value)
+{
+ int rate = 0;
+ if (hb_value_type(rate_value) != HB_VALUE_TYPE_STRING)
+ {
+ double d;
+ d = hb_value_get_double(rate_value);
+ if (d != 0 && d <= 600)
+ {
+ // Assume the value is an actual framerate and compute
+ // 27Mhz based denominator
+ rate = (int)(27000000 / d);
+ }
+ else
+ {
+ // Assume the value is a 27Mhz based denominator
+ rate = (int)d;
+ }
+ }
+ else
+ {
+ const char *rate_name = hb_value_get_string(rate_value);
+ if (strcasecmp(rate_name, "source") &&
+ strcasecmp(rate_name, "auto") &&
+ strcasecmp(rate_name, "same as source"))
+ {
+ rate = hb_video_framerate_get_from_name(rate_name);
+ if (rate < 0)
+ {
+ // No matching rate found. Error out.
+ rate = -1;
+ }
+ }
+ }
+ return rate;
+}
+
+/**
+ * Initialize an hb_job_t and return a hb_dict_t representation of the job.
+ * This dict will have key/value pairs compatible with json jobs.
+ * @param h - Pointer to hb_handle_t instance that contains the
+ * specified title_index
+ * @param title_index - Index of hb_title_t to use for job initialization.
+ * Index comes from title->index or "Index" key
+ * in json representation of a title.
+ * @param preset - Preset to initialize job with
+ */
+hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index, hb_dict_t *preset)
+{
+ hb_title_t *title = hb_find_title_by_index(h, title_index);
+ if (title == NULL)
+ {
+ hb_error("Invalid title index (%d)", title_index);
+ return NULL;
+ }
+
+ hb_job_t *job = hb_job_init(title);
+ hb_dict_t *job_dict = hb_job_to_dict(job);
+ hb_job_close(&job);
+
+ // Now apply preset settings to the job dict
+
+ hb_value_t *mux_value = hb_dict_get(preset, "FileFormat");
+ int mux;
+ if (hb_value_type(mux_value) == HB_VALUE_TYPE_STRING)
+ {
+ mux = hb_container_get_from_name(hb_value_get_string(mux_value));
+ if (mux == 0)
+ mux = hb_container_get_from_extension(
+ hb_value_get_string(mux_value));
+ }
+ else
+ {
+ mux = hb_value_get_int(mux_value);
+ }
+ hb_container_t *container = hb_container_get_from_format(mux);
+ if (container == NULL)
+ {
+ char *str = hb_value_get_string_xform(mux_value);
+ hb_error("Invalid container (%s)", str);
+ free(str);
+ goto fail;
+ }
+
+ hb_value_t *vcodec_value = hb_dict_get(preset, "VideoEncoder");
+ int vcodec;
+ if (hb_value_type(vcodec_value) == HB_VALUE_TYPE_STRING)
+ {
+ vcodec = hb_video_encoder_get_from_name(
+ hb_value_get_string(vcodec_value));
+ }
+ else
+ {
+ vcodec = hb_value_get_int(vcodec_value);
+ }
+ hb_encoder_t *encoder = hb_video_encoder_get_from_codec(vcodec);
+ if (encoder == NULL)
+ {
+ char *str = hb_value_get_string_xform(vcodec_value);
+ hb_error("Invalid video encoder (%s)", str);
+ free(str);
+ goto fail;
+ }
+ if (!(encoder->muxers & mux))
+ {
+ hb_error("Incompatible video encoder (%s) for muxer (%s)",
+ hb_video_encoder_get_name(vcodec),
+ hb_container_get_name(mux));
+ goto fail;
+ }
+
+ int chapters;
+ chapters = hb_value_get_bool(hb_dict_get(preset, "ChapterMarkers"));
+ if (hb_list_count(title->list_chapter) <= 1)
+ chapters = 0;
+
+ // Set "Destination" settings in job
+ hb_dict_t *dest_dict = hb_dict_get(job_dict, "Destination");
+ hb_dict_set(dest_dict, "ChapterMarkers", hb_value_bool(chapters));
+ hb_dict_set(dest_dict, "Mux", hb_value_dup(mux_value));
+ if (mux == HB_MUX_MASK_MP4)
+ {
+ hb_dict_t *mp4_dict = hb_dict_init();
+ hb_dict_set(mp4_dict, "Mp4Optimize",
+ hb_value_xform(hb_dict_get(preset, "Mp4HttpOptimize"),
+ HB_VALUE_TYPE_BOOL));
+ if (vcodec == HB_VCODEC_X264)
+ {
+ hb_dict_set(mp4_dict, "IpodAtom",
+ hb_value_xform(hb_dict_get(preset, "Mp4iPodCompatible"),
+ HB_VALUE_TYPE_BOOL));
+ }
+ hb_dict_set(dest_dict, "Mp4Options", mp4_dict);
+ }
+ dest_dict = NULL;
+
+ // Calculate default job geometry settings
+ hb_geometry_t srcGeo, resultGeo;
+ hb_geometry_settings_t geo;
+ int keep_aspect;
+
+ srcGeo = title->geometry;
+ if (!hb_value_get_bool(hb_dict_get(preset, "PictureAutoCrop")))
+ {
+ geo.crop[0] = hb_value_get_int(hb_dict_get(preset, "PictureTopCrop"));
+ geo.crop[1] = hb_value_get_int(hb_dict_get(preset, "PictureBottomCrop"));
+ geo.crop[2] = hb_value_get_int(hb_dict_get(preset, "PictureLeftCrop"));
+ geo.crop[3] = hb_value_get_int(hb_dict_get(preset, "PictureRightCrop"));
+ }
+ else
+ {
+ memcpy(geo.crop, title->crop, sizeof(geo.crop));
+ }
+ geo.modulus = hb_value_get_int(hb_dict_get(preset, "PictureModulus"));
+ if (geo.modulus < 2)
+ geo.modulus = 2;
+ if (hb_value_get_bool(hb_dict_get(preset, "PictureLooseCrop")))
+ {
+ // Crop a few extra pixels to avoid scaling to fit Modulus
+ int extra1, extra2, crop_width, crop_height, width, height;
+
+ crop_width = srcGeo.width - geo.crop[2] - geo.crop[3];
+ crop_height = srcGeo.height - geo.crop[0] - geo.crop[1];
+ width = MULTIPLE_MOD_DOWN(crop_width, geo.modulus);
+ height = MULTIPLE_MOD_DOWN(crop_height, geo.modulus);
+
+ extra1 = EVEN((crop_height - height) / 2);
+ extra2 = crop_height - height - extra1;
+ geo.crop[0] += extra1;
+ geo.crop[1] += extra2;
+ extra1 = EVEN((crop_width - width) / 2);
+ extra2 = crop_width - width - extra1;
+ geo.crop[2] += extra1;
+ geo.crop[3] += extra2;
+ }
+ hb_value_t *ana_mode_value = hb_dict_get(preset, "PicturePAR");
+ if (hb_value_type(ana_mode_value) == HB_VALUE_TYPE_STRING)
+ {
+ const char *s = hb_value_get_string(ana_mode_value);
+ if (!strcasecmp(s, "none"))
+ geo.mode = 0;
+ else if (!strcasecmp(s, "strict"))
+ geo.mode = 1;
+ else if (!strcasecmp(s, "custom"))
+ geo.mode = 3;
+ else // default loose
+ geo.mode = 2;
+ }
+ else
+ {
+ geo.mode = hb_value_get_int(hb_dict_get(preset, "PicturePAR"));
+ }
+ keep_aspect = hb_value_get_bool(hb_dict_get(preset, "PictureKeepRatio"));
+ if (geo.mode == HB_ANAMORPHIC_STRICT || geo.mode == HB_ANAMORPHIC_LOOSE)
+ keep_aspect = 1;
+ geo.keep = keep_aspect * HB_KEEP_DISPLAY_ASPECT;
+ geo.itu_par = hb_value_get_bool(hb_dict_get(preset, "PictureItuPAR"));
+ geo.maxWidth = hb_value_get_int(hb_dict_get(preset, "PictureWidth"));
+ geo.maxHeight = hb_value_get_int(hb_dict_get(preset, "PictureHeight"));
+ geo.geometry = title->geometry;
+ int width = hb_value_get_int(hb_dict_get(preset, "PictureForceWidth"));
+ int height = hb_value_get_int(hb_dict_get(preset, "PictureForceHeight"));
+ if (width > 0)
+ geo.geometry.width = width;
+ else
+ geo.geometry.width -= geo.crop[2] + geo.crop[3];
+ if (height > 0)
+ geo.geometry.height = height;
+ else
+ geo.geometry.height -= geo.crop[0] + geo.crop[1];
+ if (geo.mode == HB_ANAMORPHIC_CUSTOM && !keep_aspect)
+ {
+ int dar_width;
+ dar_width = hb_value_get_int(hb_dict_get(preset, "PictureDARWidth"));
+ if (dar_width > 0)
+ {
+ geo.geometry.par.num = dar_width;
+ geo.geometry.par.num = geo.geometry.width;
+ }
+ else
+ {
+ geo.geometry.par.num =
+ hb_value_get_int(hb_dict_get(preset, "PicturePARWidth"));
+ geo.geometry.par.num =
+ hb_value_get_int(hb_dict_get(preset, "PicturePARHeight"));
+ }
+ }
+ hb_set_anamorphic_size2(&srcGeo, &geo, &resultGeo);
+ hb_dict_t *par_dict = hb_dict_get(job_dict, "PAR");
+ hb_dict_set(par_dict, "Num", hb_value_int(resultGeo.par.num));
+ hb_dict_set(par_dict, "Den", hb_value_int(resultGeo.par.den));
+ par_dict = NULL;
+
+ // Filters
+ hb_dict_t *filters_dict = hb_dict_get(job_dict, "Filters");
+ if (filters_dict == NULL)
+ {
+ filters_dict = hb_dict_init();
+ hb_dict_set(job_dict, "Filters", filters_dict);
+ }
+ hb_dict_set(filters_dict, "Grayscale", hb_value_xform(
+ hb_dict_get(preset, "VideoGrayScale"), HB_VALUE_TYPE_BOOL));
+ hb_value_array_t *filter_list = hb_dict_get(filters_dict, "FilterList");
+ if (filter_list == NULL)
+ {
+ filter_list = hb_value_array_init();
+ hb_dict_set(filters_dict, "FilterList", filter_list);
+ }
+
+ 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]);
+
+ 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);
+
+ // Detelecine filter
+ hb_value_t *detel_val = hb_dict_get(preset, "PictureDetelecine");
+ if (detel_val != NULL)
+ {
+ 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)
+ {
+ char *s = hb_value_get_string_xform(detel_val);
+ hb_error("Invalid detelecine filter settings (%s)", s);
+ free(s);
+ goto fail;
+ }
+ else if (filter_str != hb_filter_off)
+ {
+ 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);
+ }
+ }
+
+ // Decomb or deinterlace filters
+ int decomb_or_deint;
+ decomb_or_deint = hb_value_get_bool(hb_dict_get(preset,
+ "PictureDecombDeinterlace"));
+ hb_value_t *decomb_val = hb_dict_get(preset, "PictureDecomb");
+ if (decomb_or_deint && decomb_val != NULL)
+ {
+ const char *custom;
+ custom = hb_value_get_string(hb_dict_get(preset,
+ "PictureDecombCustom"));
+ if (hb_value_type(decomb_val) == HB_VALUE_TYPE_STRING)
+ {
+ filter_str = hb_generate_filter_settings(
+ HB_FILTER_DECOMB, hb_value_get_string(decomb_val), custom);
+ }
+ else
+ {
+ filter_str = hb_generate_filter_settings_by_index(
+ HB_FILTER_DECOMB, hb_value_get_int(decomb_val), custom);
+ }
+ if (filter_str == NULL)
+ {
+ char *s = hb_value_get_string_xform(decomb_val);
+ hb_error("Invalid decomb filter settings (%s)", s);
+ free(s);
+ goto fail;
+ }
+ else if (filter_str != hb_filter_off)
+ {
+ filter_dict = hb_dict_init();
+ hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DECOMB));
+ hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str));
+ hb_value_array_append(filter_list, filter_dict);
+ free(filter_str);
+ }
+ }
+
+ hb_value_t *deint_val = hb_dict_get(preset, "PictureDeinterlace");
+ if (!decomb_or_deint && deint_val != NULL)
+ {
+ const char *custom;
+ custom = hb_value_get_string(hb_dict_get(preset,
+ "PictureDeinterlaceCustom"));
+ if (hb_value_type(deint_val) == HB_VALUE_TYPE_STRING)
+ {
+ filter_str = hb_generate_filter_settings(
+ HB_FILTER_DEINTERLACE, hb_value_get_string(deint_val), custom);
+ }
+ else
+ {
+ filter_str = hb_generate_filter_settings_by_index(
+ HB_FILTER_DEINTERLACE, hb_value_get_int(deint_val), custom);
+ }
+ if (filter_str == NULL)
+ {
+ char *s = hb_value_get_string_xform(deint_val);
+ hb_error("Invalid deinterlace filter settings (%s)", s);
+ free(s);
+ goto fail;
+ }
+ else if (filter_str != hb_filter_off)
+ {
+ filter_dict = hb_dict_init();
+ hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DECOMB));
+ hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str));
+ hb_value_array_append(filter_list, filter_dict);
+ free(filter_str);
+ }
+ }
+
+ // Denoise filter
+ int denoise;
+ hb_value_t *denoise_value = hb_dict_get(preset, "PictureDenoiseFilter");
+ denoise = hb_value_type(denoise_value) == HB_VALUE_TYPE_STRING ? (
+ !strcasecmp(hb_value_get_string(denoise_value), "off") ? 0 :
+ !strcasecmp(hb_value_get_string(denoise_value), "nlmeans") ? 1 : 2) :
+ hb_value_get_int(denoise_value);
+
+ if (denoise != 0)
+ {
+ int filter_id = denoise == 1 ? HB_FILTER_NLMEANS : HB_FILTER_HQDN3D;
+ const char *denoise_preset, *denoise_tune;
+ 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, "PictureDeinterlaceCustom"));
+
+ filter_str = hb_generate_filter_settings(
+ filter_id, denoise_preset, denoise_tune);
+ if (filter_str == NULL)
+ {
+ hb_error("Invalid denoise filter settings (%s%s%s)",
+ denoise_preset,
+ denoise_tune ? "," : "",
+ denoise_tune ? denoise_tune : "");
+ goto fail;
+ }
+ else if (filter_str != hb_filter_off)
+ {
+ 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);
+ }
+ }
+ }
+
+ // Deblock filter
+ char *deblock = hb_value_get_string_xform(
+ hb_dict_get(preset, "PictureDeblock"));
+ if (deblock != NULL)
+ {
+ filter_str = hb_generate_filter_settings(HB_FILTER_DEBLOCK,
+ deblock, NULL);
+ if (filter_str == NULL)
+ {
+ hb_error("Invalid deblock filter settings (%s)", deblock);
+ goto fail;
+ }
+ else if (filter_str != hb_filter_off)
+ {
+ 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);
+ }
+ }
+ free(deblock);
+
+ // Rotate filter
+ char *rotate = hb_value_get_string_xform(
+ hb_dict_get(preset, "PictureRotate"));
+ if (rotate != NULL)
+ {
+ filter_str = hb_generate_filter_settings(HB_FILTER_ROTATE,
+ rotate, NULL);
+ if (filter_str == NULL)
+ {
+ hb_error("Invalid rotate filter settings (%s)", rotate);
+ goto fail;
+ }
+ else if (filter_str != hb_filter_off)
+ {
+ 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);
+ }
+ }
+ free(rotate);
+
+ 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);
+ goto fail;
+ }
+
+ 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 ? (
+ !strcasecmp(hb_value_get_string(fr_mode_value), "cfr") ? 1 :
+ !strcasecmp(hb_value_get_string(fr_mode_value), "pfr") ? 2 : 0) :
+ hb_value_get_int(fr_mode_value);
+
+ if (hb_value_get_bool(hb_dict_get(preset, "x264ZeroLatency")))
+ fr_mode = 1;
+
+ if (vrate_den == 0)
+ filter_str = hb_strdup_printf("%d", fr_mode);
+ else
+ filter_str = hb_strdup_printf("%d:%d:%d", fr_mode, 27000000, vrate_den);
+
+ 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);
+
+ // Video encoder settings
+ hb_dict_t *video_dict = hb_dict_get(job_dict, "Video");
+ hb_value_t *color_value;
+ if ((color_value = hb_dict_get(preset, "VideoColorMatrixCode")) != NULL)
+ hb_dict_set(video_dict, "ColorMatrixCode", hb_value_dup(color_value));
+ hb_dict_set(video_dict, "Encoder", hb_value_dup(vcodec_value));
+ switch (vcodec)
+ {
+ case HB_VCODEC_X264:
+ {
+ if (hb_value_get_bool(
+ hb_dict_get(preset, "x264UseAdvancedOptions")))
+ {
+ hb_dict_set(video_dict, "Options",
+ hb_value_dup(hb_dict_get(preset, "x264Option")));
+ break;
+ }
+ }
+ // Falling through to next case...
+
+ case HB_VCODEC_X265:
+ {
+ hb_value_t *value, *array;
+ if ((value = hb_dict_get(preset, "VideoPreset")) != NULL)
+ hb_dict_set(video_dict, "Preset", hb_value_dup(value));
+ if ((value = hb_dict_get(preset, "VideoProfile")) != NULL)
+ hb_dict_set(video_dict, "Profile", hb_value_dup(value));
+ if ((value = hb_dict_get(preset, "VideoLevel")) != NULL)
+ hb_dict_set(video_dict, "Level", hb_value_dup(value));
+ if ((value = hb_dict_get(preset, "VideoOptionExtra")) != NULL)
+ hb_dict_set(video_dict, "Options", hb_value_dup(value));
+ array = hb_value_array_init();
+ if ((value = hb_dict_get(preset, "VideoTune")) != NULL)
+ hb_value_array_append(array, hb_value_dup(value));
+ if (vcodec == HB_VCODEC_X264)
+ {
+ if (hb_value_get_bool(hb_dict_get(preset, "x264FastDecode")))
+ hb_value_array_append(array, hb_value_string("fastdecode"));
+ if (hb_value_get_bool(hb_dict_get(preset, "x264ZeroLatency")))
+ hb_value_array_append(array, hb_value_string("zerolatency"));
+ }
+ if (hb_value_array_len(array) > 0)
+ hb_dict_set(video_dict, "Tune",
+ hb_value_xform(array, HB_VALUE_TYPE_STRING));
+ hb_value_decref(array);
+ } break;
+
+ case HB_VCODEC_FFMPEG_MPEG2:
+ case HB_VCODEC_FFMPEG_MPEG4:
+ case HB_VCODEC_FFMPEG_VP8:
+ {
+ hb_value_t *value;
+ if ((value = hb_dict_get(preset, "VideoOptionExtra")) != NULL)
+ hb_dict_set(video_dict, "Options", hb_value_dup(value));
+ } break;
+
+ case HB_VCODEC_THEORA:
+ default:
+ {
+ } break;
+ }
+ int vqtype = hb_value_get_int(hb_dict_get(preset, "VideoQualityType"));
+ if (vqtype == 2) // Constant quality
+ {
+ hb_dict_set(video_dict, "Quality",
+ hb_value_xform(hb_dict_get(preset, "VideoQualitySlider"),
+ HB_VALUE_TYPE_DOUBLE));
+ }
+ else if (vqtype == 1) // ABR
+ {
+ hb_dict_set(video_dict, "Bitrate",
+ hb_value_xform(hb_dict_get(preset, "VideoAvgBitrate"),
+ HB_VALUE_TYPE_INT));
+ hb_dict_set(video_dict, "TwoPass",
+ hb_value_xform(hb_dict_get(preset, "VideoTwoPass"),
+ HB_VALUE_TYPE_BOOL));
+ hb_dict_set(video_dict, "Turbo",
+ hb_value_xform(hb_dict_get(preset, "VideoTurboTwoPass"),
+ HB_VALUE_TYPE_BOOL));
+ }
+ else
+ {
+ hb_value_t *value = hb_dict_get(preset, "VideoQualitySlider");
+ if (value != NULL && hb_value_get_double(value) >= 0)
+ hb_dict_set(video_dict, "Quality",
+ hb_value_xform(value, HB_VALUE_TYPE_DOUBLE));
+ else
+ {
+ hb_dict_set(video_dict, "Bitrate",
+ hb_value_xform(hb_dict_get(preset, "VideoAvgBitrate"),
+ HB_VALUE_TYPE_INT));
+ hb_dict_set(video_dict, "TwoPass",
+ hb_value_xform(hb_dict_get(preset, "VideoTwoPass"),
+ HB_VALUE_TYPE_BOOL));
+ hb_dict_set(video_dict, "Turbo",
+ hb_value_xform(hb_dict_get(preset, "VideoTurboTwoPass"),
+ HB_VALUE_TYPE_BOOL));
+ }
+ }
+ hb_dict_t *qsv = hb_dict_get(video_dict, "QSV");
+ if (qsv == NULL)
+ {
+ qsv = hb_dict_init();
+ hb_dict_set(video_dict, "QSV", qsv);
+ }
+ hb_value_t *value;
+ if ((value = hb_dict_get(preset, "VideoQSVDecode")) != NULL)
+ {
+ hb_dict_set(qsv, "Decode",
+ hb_value_xform(value, HB_VALUE_TYPE_BOOL));
+ }
+ if ((value = hb_dict_get(preset, "VideoQSVAsyncDepth")) != NULL)
+ {
+ hb_dict_set(qsv, "AsyncDepth",
+ hb_value_xform(value, HB_VALUE_TYPE_INT));
+ }
+
+ if ((value = hb_dict_get(preset, "VideoScaler")) != NULL)
+ {
+ const char *s = hb_value_get_string(value);
+ if (strcasecmp(s, "opencl"))
+ {
+ hb_dict_set(video_dict, "OpenCL", hb_value_bool(1));
+ }
+ }
+ if ((value = hb_dict_get(preset, "VideoHWDecode")) != NULL)
+ {
+ hb_dict_set(video_dict, "HWDecode",
+ hb_value_xform(value, HB_VALUE_TYPE_BOOL));
+ }
+ video_dict = NULL;
+
+ // Audio settings
+ if (hb_preset_job_add_audio(h, title_index, preset, job_dict) != 0)
+ {
+ goto fail;
+ }
+
+ // Subtitle settings
+ if (hb_preset_job_add_subtitles(h, title_index, preset, job_dict) != 0)
+ {
+ goto fail;
+ }
+
+ return job_dict;
+
+fail:
+ hb_dict_free(&job_dict);
+ return NULL;
+}
+
+// Clean a dictionary of unwanted keys
+// Used to make sure only valid keys are in output presets
+static void
+dict_clean(hb_value_t *dict, hb_value_t *template)
+{
+ hb_value_t *tmp = hb_value_dup(dict);
+ hb_dict_iter_t iter;
+ const char *key;
+ hb_value_t *val;
+ hb_value_t *template_val;
+ hb_value_type_t template_type, val_type;
+ const char *preset_name = NULL;
+
+ val = hb_dict_get(dict, "PresetName");
+ if (val != NULL)
+ preset_name = hb_value_get_string(val);
+
+ for (iter = hb_dict_iter_init(tmp);
+ iter != HB_DICT_ITER_DONE;
+ iter = hb_dict_iter_next(tmp, iter))
+ {
+ key = hb_dict_iter_key(iter);
+ val = hb_dict_iter_value(iter);
+ val_type = hb_value_type(val);
+
+ template_val = hb_dict_get(template, key);
+ template_type = hb_value_type(template_val);
+ if (template_val == NULL)
+ {
+ // Unknown key. These can be keys used privately by the
+ // frontend. So don't make noise about them.
+ hb_dict_remove(dict, key);
+ }
+ else if (val_type != template_type)
+ {
+ if (val_type == HB_VALUE_TYPE_DICT ||
+ val_type == HB_VALUE_TYPE_ARRAY ||
+ template_type == HB_VALUE_TYPE_DICT ||
+ template_type == HB_VALUE_TYPE_ARRAY)
+ {
+ hb_error("Preset %s: Incompatible value types for key %s. "
+ "Dropping.", preset_name, key);
+ hb_dict_remove(dict, key);
+ }
+ else if (hb_value_is_number(val) &&
+ hb_value_is_number(template_val))
+ {
+ // Silently convert compatible numbers
+ hb_value_t *v;
+ v = hb_value_xform(val, template_type);
+ hb_dict_set(dict, key, v);
+ }
+ else
+ {
+ hb_value_t *v;
+ hb_error("Preset %s: Incorrect value type for key %s. "
+ "Converting.", preset_name, key);
+ v = hb_value_xform(val, template_type);
+ hb_dict_set(dict, key, v);
+ }
+ }
+ else if (val_type == HB_VALUE_TYPE_DICT &&
+ template_type == HB_VALUE_TYPE_DICT)
+ {
+ val = hb_dict_get(dict, key);
+ dict_clean(val, template_val);
+ }
+ else if (val_type == HB_VALUE_TYPE_ARRAY &&
+ template_type == HB_VALUE_TYPE_ARRAY &&
+ hb_value_array_len(template_val) > 0)
+ {
+ template_val = hb_value_array_get(template_val, 0);
+ if (hb_value_type(template_val) == HB_VALUE_TYPE_DICT)
+ {
+ val = hb_dict_get(dict, key);
+ int count = hb_value_array_len(val);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_value_t *array_val;
+ array_val = hb_value_array_get(val, ii);
+ if (hb_value_type(array_val) == HB_VALUE_TYPE_DICT)
+ {
+ dict_clean(array_val, template_val);
+ }
+ }
+ }
+ }
+ }
+ hb_value_free(&tmp);
+}
+
+static void preset_clean(hb_value_t *preset, hb_value_t *template)
+{
+ dict_clean(preset, template);
+
+ // Check for proper "short name" values.
+ // Convert as necessary.
+ hb_value_t *val;
+ const char *preset_name = NULL;
+ int muxer;
+
+ val = hb_dict_get(preset, "PresetName");
+ if (val != NULL)
+ preset_name = hb_value_get_string(val);
+
+ val = hb_dict_get(preset, "FileFormat");
+ if (val != NULL)
+ {
+ const char *s, *mux;
+ s = hb_value_get_string(val);
+ muxer = hb_container_get_from_name(s);
+ if (muxer == HB_MUX_INVALID)
+ {
+ const hb_container_t *c = hb_container_get_next(NULL);
+ muxer = c->format;
+ hb_error("Preset %s: Invalid container (%s)", preset_name, s);
+ }
+ mux = hb_container_get_short_name(muxer);
+ val = hb_value_string(mux);
+ hb_dict_set(preset, "FileFormat", val);
+ }
+ val = hb_dict_get(preset, "VideoEncoder");
+ if (val != NULL)
+ {
+ const char *s, *enc;
+ int vcodec;
+ s = hb_value_get_string(val);
+ vcodec = hb_video_encoder_get_from_name(s);
+ if (vcodec == HB_VCODEC_INVALID)
+ {
+ vcodec = hb_video_encoder_get_default(muxer);
+ hb_error("Preset %s: Invalid video encoder (%s)", preset_name, s);
+ }
+ enc = hb_video_encoder_get_short_name(vcodec);
+ val = hb_value_string(enc);
+ hb_dict_set(preset, "VideoEncoder", val);
+ }
+ val = hb_dict_get(preset, "VideoFramerate");
+ if (val != NULL)
+ {
+ const char *s;
+ s = hb_value_get_string(val);
+ if (strcasecmp(s, "auto"))
+ {
+ int fr = hb_video_framerate_get_from_name(s);
+ if (fr < 0)
+ {
+ val = hb_value_string("auto");
+ hb_dict_set(preset, "VideoFramerate", val);
+ hb_error("Preset %s: Invalid video framerate (%s)",
+ preset_name, s);
+ }
+ }
+ }
+ val = hb_dict_get(preset, "AudioEncoderFallback");
+ if (val != NULL)
+ {
+ const char *s, *enc;
+ int acodec;
+ s = hb_value_get_string(val);
+ acodec = hb_audio_encoder_get_from_name(s);
+ if (acodec == HB_ACODEC_INVALID)
+ {
+ acodec = hb_audio_encoder_get_default(muxer);
+ hb_error("Preset %s: Invalid audio fallback encoder (%s)",
+ preset_name, s);
+ }
+ enc = hb_audio_encoder_get_short_name(acodec);
+ val = hb_value_string(enc);
+ hb_dict_set(preset, "AudioEncoderFallback", val);
+ }
+ hb_value_t *alist = hb_dict_get(preset, "AudioList");
+ int count = hb_value_array_len(alist);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_value_t *adict = hb_value_array_get(alist, ii);
+ val = hb_dict_get(adict, "AudioEncoder");
+ if (val != NULL)
+ {
+ const char *s, *enc;
+ int acodec;
+ s = hb_value_get_string(val);
+ acodec = hb_audio_encoder_get_from_name(s);
+ if (acodec == HB_ACODEC_INVALID)
+ {
+ acodec = hb_audio_encoder_get_default(muxer);
+ hb_error("Preset %s: Invalid audio encoder (%s)",
+ preset_name, s);
+ }
+ enc = hb_audio_encoder_get_short_name(acodec);
+ val = hb_value_string(enc);
+ hb_dict_set(preset, "AudioEncoder", val);
+ }
+ val = hb_dict_get(adict, "AudioSamplerate");
+ if (val != NULL)
+ {
+ const char *s;
+ s = hb_value_get_string(val);
+ if (strcasecmp(s, "auto"))
+ {
+ int sr = hb_video_framerate_get_from_name(s);
+ if (sr < 0)
+ {
+ val = hb_value_string("auto");
+ hb_dict_set(preset, "AudioSamplerate", val);
+ hb_error("Preset %s: Invalid audio samplerate (%s)",
+ preset_name, s);
+ }
+ }
+ }
+ val = hb_dict_get(adict, "AudioMixdown");
+ if (val != NULL)
+ {
+ const char *s, *mix;
+ s = hb_value_get_string(val);
+ int mixdown = hb_mixdown_get_from_name(s);
+ if (mixdown == HB_INVALID_AMIXDOWN)
+ {
+ // work.c do_job() sanitizes NONE to default mixdown
+ mixdown = HB_AMIXDOWN_NONE;
+ hb_error("Preset %s: Invalid audio mixdown (%s)",
+ preset_name, s);
+ }
+ mix = hb_mixdown_get_short_name(mixdown);
+ val = hb_value_string(mix);
+ hb_dict_set(adict, "AudioMixdown", val);
+ }
+ }
+}
+
+static void presets_clean(hb_value_t *presets, hb_value_t *template)
+{
+ if (hb_value_type(presets) == HB_VALUE_TYPE_ARRAY)
+ {
+ // An array of presets, clean each one
+ int ii, count;
+ count = hb_value_array_len(presets);
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_value_t *preset = hb_value_array_get(presets, ii);
+ preset_clean(preset, template);
+ }
+ }
+ else if (hb_value_type(presets) == HB_VALUE_TYPE_DICT &&
+ hb_dict_get(presets, "VersionMajor") != NULL)
+ {
+ // A packaged preset list
+ hb_value_t *list = hb_dict_get(presets, "PresetList");
+ presets_clean(list, template);
+ }
+ else if (hb_value_type(presets) == HB_VALUE_TYPE_DICT &&
+ hb_dict_get(presets, "PresetName") != NULL)
+ {
+ // An individual preset
+ preset_clean(presets, template);
+ }
+ else
+ {
+ hb_error("Error: invalid preset format in presets_clean()");
+ }
+}
+
+// Note that unpackage does not make any copies.
+// In one increases the reference count.
+static hb_value_t * preset_unpackage(hb_value_t *packaged_presets)
+{
+ // TODO: Verify compatible version number.
+ // Do any desired legacy translations.
+ if (hb_value_type(packaged_presets) == HB_VALUE_TYPE_ARRAY)
+ {
+ // Not packaged
+ hb_value_incref(packaged_presets);
+ return packaged_presets;
+ }
+ hb_value_t *presets = hb_dict_get(packaged_presets, "PresetList");
+ hb_value_incref(presets);
+ return presets;
+}
+
+static hb_value_t * preset_package(hb_value_t *presets)
+{
+ hb_dict_t *packaged_presets;
+ if (hb_dict_get(presets, "VersionMajor") == NULL)
+ {
+ // Preset is not packaged
+ packaged_presets = hb_dict_init();
+ hb_dict_set(packaged_presets, "VersionMajor",
+ hb_value_int(hb_preset_version_major));
+ hb_dict_set(packaged_presets, "VersionMinor",
+ hb_value_int(hb_preset_version_minor));
+ hb_dict_set(packaged_presets, "VersionMicro",
+ hb_value_int(hb_preset_version_micro));
+
+ // TODO: What else to we want in the preset containers header?
+ if (hb_value_type(presets) == HB_VALUE_TYPE_DICT)
+ {
+ hb_value_array_t *tmp = hb_value_array_init();
+ hb_value_array_append(tmp, presets);
+ presets = tmp;
+ }
+ hb_dict_t *tmp = hb_value_dup(presets);
+ presets_clean(tmp, hb_preset_template);
+ hb_dict_set(packaged_presets, "PresetList", tmp);
+ }
+ else
+ {
+ // Preset is already packaged
+ hb_dict_t *tmp = hb_value_dup(presets);
+ presets_clean(tmp, hb_preset_template);
+ packaged_presets = tmp;
+ }
+ return packaged_presets;
+}
+
+void hb_presets_builtin_init(void)
+{
+ hb_value_t * dict = hb_value_json(hb_builtin_presets_json);
+ hb_value_t * template = hb_dict_get(dict, "PresetTemplate");
+ hb_preset_version_major = hb_value_get_int(
+ hb_dict_get(template, "VersionMajor"));
+ hb_preset_version_minor = hb_value_get_int(
+ hb_dict_get(template, "VersionMinor"));
+ hb_preset_version_micro = hb_value_get_int(
+ hb_dict_get(template, "VersionMicro"));
+ hb_preset_template = hb_value_dup(hb_dict_get(template, "Preset"));
+
+ hb_presets_builtin = hb_value_dup(hb_dict_get(dict, "PresetBuiltin"));
+ hb_value_free(&dict);
+
+ // Make a dup, never change contents of hb_presets_builtin
+ hb_presets = hb_value_dup(hb_presets_builtin);
+ hb_presets_custom = hb_value_array_init();
+
+}
+
+int hb_presets_gui_init(void)
+{
+ char path[1024];
+ hb_value_t * dict = NULL;
+
+#if defined(HB_PRESET_JSON_FILE)
+ hb_get_user_config_filename(path, "%s", HB_PRESET_JSON_FILE);
+ dict = hb_value_read_json(path);
+ if (dict != NULL)
+ {
+ hb_value_t *preset = preset_unpackage(dict);
+ // Unpackaging does some validity checks and can fail
+ if (preset == NULL)
+ return -1;
+ int result = hb_presets_add(preset);
+ hb_value_free(&preset);
+ hb_value_free(&dict);
+ return result;
+ }
+#endif
+#if defined(HB_PRESET_PLIST_FILE)
+ if (dict == NULL)
+ {
+ hb_get_user_config_filename(path, "%s", HB_PRESET_PLIST_FILE);
+ dict = hb_plist_parse_file(path);
+ if (dict != NULL)
+ {
+ int result = hb_presets_add(dict);
+ hb_value_free(&dict);
+ return result;
+ }
+ }
+#endif
+ if (dict == NULL)
+ {
+ hb_error("Failed to load GUI presets file");
+#if defined(HB_PRESET_JSON_FILE)
+ hb_error("Attempted: %s", HB_PRESET_JSON_FILE);
+#endif
+#if defined(HB_PRESET_PLIST_FILE)
+ hb_error("Attempted: %s", HB_PRESET_PLIST_FILE);
+#endif
+ return -1;
+ }
+ return -1;
+}
+
+hb_value_t * hb_presets_builtin_get(void)
+{
+ return hb_value_dup(hb_presets_builtin);
+}
+
+char * hb_presets_builtin_get_json(void)
+{
+ char *json = hb_value_get_json(hb_presets_builtin);
+ return json;
+}
+
+static hb_value_t * preset_lookup(hb_value_t *list, const char *name,
+ int def, int folder, int recurse)
+{
+ int count = hb_value_array_len(list);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ int d;
+ const char *n;
+ hb_dict_t *preset_dict = hb_value_array_get(list, ii);
+ n = hb_value_get_string(hb_dict_get(preset_dict, "PresetName"));
+ d = hb_value_get_bool(hb_dict_get(preset_dict, "Default"));
+ if (hb_value_get_bool(hb_dict_get(preset_dict, "Folder")))
+ {
+ if (folder && !def && n != NULL && !strncmp(name, n, 80))
+ return preset_dict;
+
+ if (recurse)
+ {
+ hb_value_array_t *children;
+ children = hb_dict_get(preset_dict, "ChildrenArray");
+ if (children == NULL)
+ continue;
+ preset_dict = preset_lookup(children, name, def,
+ folder, recurse);
+ if (preset_dict != NULL)
+ return preset_dict;
+ }
+ }
+ else if (!folder)
+ {
+ if (!def && n != NULL && !strncmp(n, name, 80))
+ {
+ // preset is not a folder and we found a matching preset name
+ return preset_dict;
+ }
+ else if (def && d)
+ {
+ return preset_dict;
+ }
+ }
+ }
+ return NULL;
+}
+
+// Lookup a preset in the preset list. The "name" may contain '/'
+// separators to explicitely specify a preset within the preset lists
+// folder structure.
+//
+// If 'recurse' is specified, a recursive search for the first component
+// in the name will be performed.
+//
+// I assume that the actual preset name does not include any '/'
+hb_value_t * hb_preset_get(const char *name, int recurse)
+{
+ if (name == NULL || name[0] == 0)
+ {
+ // bad input.
+ return NULL;
+ }
+
+ char *tmp = strdup(name);
+ char *part, *next;
+ hb_value_t *list;
+
+ list = hb_presets;
+ part = tmp;
+ next = strchr(name, '/');
+ if (next == NULL)
+ {
+ // Only preset name was specified, so do a recursive search
+ hb_value_t *preset = preset_lookup(list, part, 0, 0, recurse);
+ free(tmp);
+ if (preset == NULL)
+ {
+ return NULL;
+ }
+ return hb_value_dup(preset);
+ }
+ // Found folder separator in name, do explicit path search
+ while (part)
+ {
+ *next = 0;
+ next++;
+ if (next[0] == 0)
+ {
+ // name ends in a folder separator '/'. Invalid input
+ free(tmp);
+ return NULL;
+ }
+
+ // We have a folder part. Lookup the folder.
+ // First try non-recursive so that we match top level folders first
+ hb_dict_t *folder = preset_lookup(list, part, 0, 1, 0);
+ if (folder == NULL && recurse)
+ {
+ // Try a recursive search for the folder
+ folder = preset_lookup(list, part, 0, 1, recurse);
+ }
+ if (folder == NULL)
+ {
+ // Not found
+ free(tmp);
+ return NULL;
+ }
+ list = hb_dict_get(folder, "ChildrenArray");
+ if (list == NULL)
+ {
+ // Folder found, but it has no children
+ free(tmp);
+ return NULL;
+ }
+ // Folder found, continue the search
+ part = next;
+ next = strchr(name, '/');
+ if (next == NULL)
+ {
+ // We have reached the final component of the path
+ // which is the preset name. Do a non-recursive search.
+ // If the preset is not in the specified folder, will
+ // return NULL
+ hb_value_t *preset = preset_lookup(list, part, 0, 0, 0);
+ free(tmp);
+ if (preset == NULL)
+ {
+ return NULL;
+ }
+ return hb_value_dup(preset);
+ }
+ }
+ // This should never be reached, but some compilers might complain
+ // without a final return.
+ free(tmp);
+ return NULL;
+}
+
+char * hb_preset_get_json(const char *name, int recurse)
+{
+ hb_value_t * preset;
+ char *json;
+ preset = hb_preset_get(name, recurse);
+ if (preset == NULL)
+ return NULL;
+ json = hb_value_get_json(preset);
+ hb_value_free(&preset);
+ return json;
+}
+
+static hb_dict_t * find_first_preset(hb_value_array_t *list)
+{
+ int count, ii;
+ count = hb_value_array_len(list);
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_dict_t *preset_dict = hb_value_array_get(list, ii);
+ if (hb_value_get_bool(hb_dict_get(preset_dict, "Folder")))
+ {
+ hb_value_array_t *children;
+ children = hb_dict_get(preset_dict, "ChildrenArray");
+ if (children == NULL)
+ continue;
+ preset_dict = find_first_preset(children);
+ if (preset_dict != NULL)
+ return preset_dict;
+ }
+ else
+ {
+ return preset_dict;
+ }
+ }
+ return NULL;
+}
+
+hb_dict_t * hb_presets_get_default(void)
+{
+ // Look for preset with 'Default' flag set
+ hb_value_t *preset = preset_lookup(hb_presets, NULL, 1, 0, 1);
+ if (preset == NULL)
+ {
+ // Look for preset named 'Normal' flag set
+ preset = preset_lookup(hb_presets, "Normal", 0, 0, 1);
+ if (preset == NULL)
+ {
+ // Just grab the first preset available
+ preset = find_first_preset(hb_presets);
+ if (preset == NULL)
+ return NULL;
+ }
+ }
+ return hb_value_dup(preset);
+}
+
+char * hb_presets_get_default_json(void)
+{
+ hb_value_t *preset = preset_lookup(hb_presets, NULL, 1, 0, 1);
+ if (preset == NULL)
+ return NULL;
+ return hb_value_get_json(preset);
+}
+
+// Return:
+// 0 upon success
+// 1 if preset name could not be found
+int hb_presets_set_default(const char *name, int recurse)
+{
+ hb_value_t *preset = preset_lookup(hb_presets, NULL, 1, 0, 1);
+ if (preset != NULL)
+ {
+ // Mark old defalt as not
+ hb_dict_set(preset, "Default", hb_value_bool(0));
+ }
+ preset = preset_lookup(hb_presets, name, 0, 0, recurse);
+ if (preset == NULL)
+ return -1;
+ hb_dict_set(preset, "Default", hb_value_bool(1));
+ return 0;
+}
+
+int hb_presets_add(hb_value_t *preset)
+{
+ if (preset == NULL)
+ return -1;
+ // TODO: validity checking of input preset
+ if (hb_value_type(preset) == HB_VALUE_TYPE_DICT)
+ {
+ // A standalone preset or folder of presets. Add to preset array.
+ // Only allow custom presets to be added
+ if (hb_value_get_int(hb_dict_get(preset, "Type")) == 1)
+ hb_value_array_append(hb_presets_custom, hb_value_dup(preset));
+ }
+ else if (hb_value_type(preset) == HB_VALUE_TYPE_ARRAY)
+ {
+ // An array of presets. Add each element.
+ int count = hb_value_array_len(preset);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_value_t *value = hb_value_array_get(preset, ii);
+ hb_value_array_append(hb_presets_custom, hb_value_dup(value));
+ }
+ }
+
+ // Reconstruct global list
+ hb_value_decref(hb_presets);
+ hb_presets = hb_value_dup(hb_presets_builtin);
+ // Append custom presets
+ int count = hb_value_array_len(hb_presets_custom);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ hb_value_t *value = hb_value_array_get(hb_presets_custom, ii);
+ // Only allow custom presets to be added
+ if (hb_value_get_int(hb_dict_get(value, "Type")) == 1)
+ hb_value_array_append(hb_presets, hb_value_dup(value));
+ }
+ return 0;
+}
+
+int hb_presets_add_json(const char *json)
+{
+ hb_value_t *packaged_preset = hb_value_json(json);
+ hb_value_t *preset = preset_unpackage(packaged_preset);
+ if (preset == NULL)
+ return -1;
+ int result = hb_presets_add(preset);
+ hb_value_free(&preset);
+ hb_value_free(&packaged_preset);
+ return result;
+}
+
+int hb_presets_add_file(const char *filename)
+{
+ hb_value_t *packaged_preset = hb_value_read_json(filename);
+ hb_value_t *preset = preset_unpackage(packaged_preset);
+ // Unpackaging does some validity checks and can fail
+ if (preset == NULL)
+ return -1;
+ int result = hb_presets_add(preset);
+ hb_value_free(&preset);
+ hb_value_free(&packaged_preset);
+ return result;
+}
+
+static int compare_str(const void *a, const void *b)
+{
+ return strncmp(*(const char**)a, *(const char**)b, PATH_MAX);
+}
+
+int hb_presets_add_path(char * path)
+{
+ hb_stat_t sb;
+ HB_DIR * dir;
+ struct dirent * entry;
+ char * filename;
+ int count, ii;
+ char ** files;
+ int result = -1;
+
+ if (hb_stat(path, &sb))
+ return -1;
+
+ if (S_ISREG(sb.st_mode))
+ {
+ return hb_presets_add_file(path);
+ }
+
+ if (!S_ISDIR(sb.st_mode))
+ return -1;
+
+ dir = hb_opendir(path);
+ if ( dir == NULL )
+ return -1;
+
+ // Count the total number of entries
+ count = 0;
+ while ((entry = hb_readdir(dir)))
+ {
+ count++;
+ }
+ files = malloc(count * sizeof(char*));
+
+ // Find all regular files
+ ii = 0;
+ hb_rewinddir(dir);
+ while ((entry = hb_readdir(dir)))
+ {
+ filename = hb_strdup_printf("%s" DIR_SEP_STR "%s", path, entry->d_name);
+ if (hb_stat(filename, &sb))
+ {
+ free(filename);
+ continue;
+ }
+
+ // Only load regular files
+ if (!S_ISREG(sb.st_mode))
+ {
+ free(filename);
+ continue;
+ }
+ // Only load files with .json extension
+ if (strcmp(".json", filename + strlen(filename) - 5))
+ {
+ free(filename);
+ continue;
+ }
+
+ files[ii++] = filename;
+ }
+ count = ii;
+
+ // Sort the files so presets get added in a consistent order
+ qsort(files, count, sizeof(char*), compare_str);
+
+ // Add preset files to preset list
+ for (ii = 0; ii < count; ii++)
+ {
+ int res = hb_presets_add_file(files[ii]);
+ // return success if any one of the files is successfully loaded
+ if (res == 0)
+ result = res;
+ }
+ hb_closedir( dir );
+ free(files);
+
+ return result;
+}
+
+hb_value_t * hb_presets_get(void)
+{
+ return hb_value_dup(hb_presets);
+}
+
+char * hb_presets_get_json(void)
+{
+ return hb_value_get_json(hb_presets);
+}
+
+int hb_preset_write_json(hb_value_t *preset, const char *path)
+{
+ hb_value_t *packaged_preset = preset_package(preset);
+ // Packaging does some validity checks and can fail
+ if (packaged_preset == NULL)
+ return -1;
+ int result = hb_value_write_json(packaged_preset, path);
+ hb_value_free(&packaged_preset);
+ return result;
+}
+
+char * hb_preset_package_json(hb_value_t *preset)
+{
+ hb_value_t *packaged_preset = preset_package(preset);
+ // Packaging does some validity checks and can fail
+ if (packaged_preset == NULL)
+ return NULL;
+ char *json = hb_value_get_json(packaged_preset);
+ hb_value_free(&packaged_preset);
+ return json;
+}
+
+void hb_presets_free(void)
+{
+ hb_value_free(&hb_preset_template);
+ hb_value_free(&hb_presets);
+ hb_value_free(&hb_presets_custom);
+ hb_value_free(&hb_presets_builtin);
+}
diff --git a/libhb/preset.h b/libhb/preset.h
new file mode 100644
index 000000000..5e7c460b6
--- /dev/null
+++ b/libhb/preset.h
@@ -0,0 +1,84 @@
+/* hb_preset.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
+ */
+#if !defined(HB_PRESET_H)
+#define HB_PRESET_H
+
+#include "common.h"
+#include "hb_dict.h"
+
+// Initialize the hb_value_array_t that holds HandBrake builtin presets
+void hb_presets_builtin_init(void);
+
+// Load presets from GUI presets file if possible
+int hb_presets_gui_init(void);
+
+// Free all libhb presets
+void hb_presets_free(void);
+
+// Get list of HandBrake builtin presets as hb_value_array_t
+hb_value_t * hb_presets_builtin_get(void);
+
+// Get list of HandBrake builtin presets as json string
+char * hb_presets_builtin_get_json(void);
+
+// Register new presets with libhb from
+// hb_dict_t (single preset) or hb_value_array_t (list of presets)
+int hb_presets_add(hb_value_t *preset);
+
+// Register new presets with libhb from json string
+int hb_presets_add_json(const char *json);
+
+// Register new presets with libhb from json file
+int hb_presets_add_file(const char *filename);
+
+// Register new presets with libhb from json file(s)
+// path can be a directory, in which case all *.json files in the
+// directory will be added
+int hb_presets_add_path(char * path);
+
+// Get list of all presets registered with libhb as hb_value_array_t
+hb_value_t * hb_presets_get(void);
+
+// Get list of all presets registered with libhb as json string
+char * hb_presets_get_json(void);
+
+// Initialize a job from the given title and preset
+hb_dict_t * hb_preset_job_init(hb_handle_t *h, int title_index,
+ hb_dict_t *preset);
+int hb_preset_job_add_subtitles(hb_handle_t *h, int title_index,
+ hb_dict_t *preset, hb_dict_t *job_dict);
+int hb_preset_job_add_audio(hb_handle_t *h, int title_index,
+ hb_dict_t *preset, hb_dict_t *job_dict);
+
+// Lookup a preset in the preset list. The "name" may contain '/'
+// separators to explicitely specify a preset within the preset lists
+// folder structure.
+//
+// If 'recurse' is specified, a recursive search for the first component
+// in the name will be performed.
+//
+// I assume that the actual preset name does not include any '/'
+hb_value_t * hb_preset_get(const char *name, int recurse);
+char * hb_preset_get_json(const char *name, int recurse);
+
+// Recursively lookup the preset that is marked as 'Default'
+hb_dict_t * hb_presets_get_default(void);
+char * hb_presets_get_default_json(void);
+
+// Set the preset that is marked as 'Default'
+int hb_presets_set_default(const char *name, int recurse);
+
+// Package the provided preset (wrap in dict and add version etc)
+// and write to json file
+int hb_preset_write_json(hb_value_t *preset, const char *path);
+// Package the provided preset (wrap in dict and add version etc)
+// and return as json string
+char * hb_preset_package_json(hb_value_t *preset);
+
+#endif // HB_PRESET_H
diff --git a/libhb/preset_builtin.json b/libhb/preset_builtin.json
new file mode 100644
index 000000000..5bf5d4d8a
--- /dev/null
+++ b/libhb/preset_builtin.json
@@ -0,0 +1,855 @@
+ [
+ {
+ "ChildrenArray": [
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ },
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "copy:ac3",
+ "AudioMixdown": "none",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 576,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 720,
+ "PresetDescription": "HandBrake's settings for compatibility with all Apple devices (including the iPod 6G and later). Includes Dolby Digital audio for surround sound.",
+ "PresetName": "Universal",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.0",
+ "VideoOptionExtra": "",
+ "VideoPreset": "fast",
+ "VideoProfile": "baseline",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 1,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 240,
+ "PictureKeepRatio": 1,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "off",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 320,
+ "PresetDescription": "HandBrake's settings for playback on the iPod with Video (all generations).",
+ "PresetName": "iPod",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "1.3",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "baseline",
+ "VideoQualitySlider": 22.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 640,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 960,
+ "PresetDescription": "HandBrake's settings for handheld iOS devices (iPhone 4, iPod touch 3G and later).",
+ "PresetName": "iPhone & iPod touch",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.1",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "high",
+ "VideoQualitySlider": 22.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 720,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 1280,
+ "PresetDescription": "HandBrake's settings for playback on the iPad (all generations).",
+ "PresetName": "iPad",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.1",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "high",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ },
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "copy:ac3",
+ "AudioMixdown": "none",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 720,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 960,
+ "PresetDescription": "HandBrake's settings for the original AppleTV. Includes Dolby Digital audio for surround sound. Also compatible with iOS devices released since 2009.",
+ "PresetName": "AppleTV",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.1",
+ "VideoOptionExtra": "qpmin=4:cabac=0:ref=2:b-pyramid=none:weightb=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500",
+ "VideoPreset": "medium",
+ "VideoProfile": "high",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ },
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "copy:ac3",
+ "AudioMixdown": "none",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 720,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 1280,
+ "PresetDescription": "HandBrake's settings for the second-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV.",
+ "PresetName": "AppleTV 2",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.1",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "high",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ },
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "copy:ac3",
+ "AudioMixdown": "none",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 3,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 1080,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 1920,
+ "PresetDescription": "HandBrake's settings for the third-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV. May stutter on the second-generation AppleTV.",
+ "PresetName": "AppleTV 3",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "4.0",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "high",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "128",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 0,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 576,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 720,
+ "PresetDescription": "HandBrake's settings for midrange devices running Android 2.3 or later.",
+ "PresetName": "Android",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.0",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "main",
+ "VideoQualitySlider": 22.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "128",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 0,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 720,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 1280,
+ "PresetDescription": "HandBrake's preset for tablets running Android 2.3 or later.",
+ "PresetName": "Android Tablet",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.1",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "main",
+ "VideoQualitySlider": 22.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "128",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 0,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 720,
+ "PictureKeepRatio": 1,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "off",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 1280,
+ "PresetDescription": "HandBrake's preset for Windows Phone 8 devices",
+ "PresetName": "Windows Phone 8",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "30",
+ "VideoFramerateMode": "pfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "3.1",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "main",
+ "VideoQualitySlider": 22.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ }
+ ],
+ "Default": 0,
+ "Folder": true,
+ "PresetName": "Devices",
+ "Type": 0
+ },
+ {
+ "ChildrenArray": [
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 1,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 0,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 0,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 0,
+ "PresetDescription": "HandBrake's normal, default settings.",
+ "PresetName": "Normal",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "auto",
+ "VideoFramerateMode": "vfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "4.0",
+ "VideoOptionExtra": "",
+ "VideoPreset": "veryfast",
+ "VideoProfile": "main",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ },
+ {
+ "AudioAllowAACPass": 1,
+ "AudioAllowAC3Pass": 1,
+ "AudioAllowDTSHDPass": 1,
+ "AudioAllowDTSPass": 1,
+ "AudioAllowMP3Pass": 1,
+ "AudioEncoderFallback": "ac3",
+ "AudioList": [
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "aac",
+ "AudioMixdown": "dpl2",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ },
+ {
+ "AudioBitrate": "160",
+ "AudioEncoder": "copy:ac3",
+ "AudioMixdown": "none",
+ "AudioSamplerate": "auto",
+ "AudioTrack": 1,
+ "AudioTrackDRCSlider": 0.0,
+ "AudioTrackGainSlider": 0.0
+ }
+ ],
+ "ChapterMarkers": 1,
+ "Default": 0,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": 0,
+ "Mp4iPodCompatible": 0,
+ "PictureAutoCrop": 1,
+ "PictureBottomCrop": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": 2,
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": 1,
+ "PictureDeinterlace": 0,
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDetelecine": 0,
+ "PictureDetelecineCustom": "",
+ "PictureHeight": 0,
+ "PictureKeepRatio": 0,
+ "PictureLeftCrop": 0,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureWidth": 0,
+ "PresetDescription": "HandBrake's general-purpose preset for High Profile H.264 video.",
+ "PresetName": "High Profile",
+ "Type": 0,
+ "UsesPictureFilters": 1,
+ "UsesPictureSettings": 1,
+ "VideoAvgBitrate": "2500",
+ "VideoEncoder": "x264",
+ "VideoFramerate": "auto",
+ "VideoFramerateMode": "vfr",
+ "VideoGrayScale": 0,
+ "VideoLevel": "4.1",
+ "VideoOptionExtra": "",
+ "VideoPreset": "medium",
+ "VideoProfile": "high",
+ "VideoQualitySlider": 20.0,
+ "VideoQualityType": 2,
+ "VideoTune": "",
+ "VideoTurboTwoPass": 0,
+ "VideoTwoPass": 0,
+ "x264Option": "",
+ "x264UseAdvancedOptions": 0
+ }
+ ],
+ "Default": 0,
+ "Folder": true,
+ "PresetName": "Regular",
+ "Type": 0
+ }
+ ]
diff --git a/libhb/preset_template.json b/libhb/preset_template.json
new file mode 100644
index 000000000..30449e437
--- /dev/null
+++ b/libhb/preset_template.json
@@ -0,0 +1,104 @@
+ {
+ "AudioAllowMP3Pass": false,
+ "AudioAllowAACPass": false,
+ "AudioAllowAC3Pass": true,
+ "AudioAllowDTSPass": false,
+ "AudioAllowDTSHDPass": false,
+ "AudioAllowEAC3Pass": false,
+ "AudioAllowFLACPass": false,
+ "AudioAllowTRUEHDPass": false,
+ "AudioCopyMask": [
+ ],
+ "AudioEncoderFallback": "ac3",
+ "AudioLanguageList": [
+ "und"
+ ],
+ "AudioList": [
+ {
+ "AudioBitrate": "192",
+ "AudioCompressionLevel": -1.0,
+ "AudioDitherMethod": "auto",
+ "AudioEncoder": "copy:ac3",
+ "AudioMixdown": "dpl2",
+ "AudioNormalizeMixLevel": false,
+ "AudioSamplerate": "auto",
+ "AudioTrackQualityEnable": false,
+ "AudioTrackQuality": -1.0,
+ "AudioTrackGainSlider": 0.0,
+ "AudioTrackDRCSlider": 0.0
+ }
+ ],
+ "AudioSecondaryEncoderMode": true,
+ "AudioTrackSelectionBehavior": "first",
+ "ChapterMarkers": true,
+ "Default": false,
+ "FileFormat": "mp4",
+ "Folder": false,
+ "Mp4HttpOptimize": false,
+ "Mp4iPodCompatible": false,
+ "PictureAutoCrop": true,
+ "PictureBottomCrop": 0,
+ "PictureLeftCrop": 0,
+ "PictureRightCrop": 0,
+ "PictureTopCrop": 0,
+ "PictureDARWidth": 0,
+ "PictureDeblock": 0,
+ "PictureDecomb": "off",
+ "PictureDecombCustom": "",
+ "PictureDecombDeinterlace": true,
+ "PictureDeinterlace": "off",
+ "PictureDeinterlaceCustom": "",
+ "PictureDenoiseCustom": "",
+ "PictureDenoiseFilter": "off",
+ "PictureDenoisePreset": "medium",
+ "PictureDenoiseTune": "none",
+ "PictureDetelecine": "off",
+ "PictureDetelecineCustom": "",
+ "PictureItuPAR": false,
+ "PictureKeepRatio": true,
+ "PictureLooseCrop": false,
+ "PictureModulus": 2,
+ "PicturePAR": "loose",
+ "PicturePARWidth": 853,
+ "PicturePARHeight": 720,
+ "PictureRotate": 0,
+ "PictureWidth": 0,
+ "PictureHeight": 0,
+ "PictureForceHeight": 0,
+ "PictureForceWidth": 0,
+ "PresetDescription": "",
+ "PresetName": "Name Missing",
+ "Type": 1,
+ "UsesPictureFilters": true,
+ "UsesPictureSettings": 2,
+ "SubtitleAddCC": false,
+ "SubtitleAddForeignAudioSearch": false,
+ "SubtitleAddForeignAudioSubtitle": false,
+ "SubtitleBurnBehavior": "none",
+ "SubtitleBurnBDSub": false,
+ "SubtitleBurnDVDSub": false,
+ "SubtitleLanguageList": [
+ ],
+ "SubtitleTrackSelectionBehavior": "none",
+ "VideoAvgBitrate": 1800,
+ "VideoColorMatrixCode": 0,
+ "VideoEncoder": "x264",
+ "VideoFramerate": "auto",
+ "VideoFramerateMode": "vfr",
+ "VideoGrayScale": false,
+ "VideoHWDecode": false,
+ "VideoScaler": "swscale",
+ "VideoPreset": "medium",
+ "VideoTune": "none",
+ "VideoProfile": "auto",
+ "VideoLevel": "auto",
+ "VideoOptionExtra": "",
+ "VideoQualityType": 2,
+ "VideoQualitySlider": 20.0,
+ "VideoQSVDecode": false,
+ "VideoQSVAsyncDepth": 4,
+ "VideoTwoPass": false,
+ "VideoTurboTwoPass": false,
+ "x264Option": "",
+ "x264UseAdvancedOptions": false
+ }
diff --git a/scripts/create_resources.py b/scripts/create_resources.py
new file mode 100644
index 000000000..95921d317
--- /dev/null
+++ b/scripts/create_resources.py
@@ -0,0 +1,161 @@
+#! /bin/python
+#
+
+import types
+import os
+import sys
+import time
+import datetime
+import json
+import plistlib
+import getopt
+from xml.parsers import expat
+
+resources = dict()
+stack = list()
+stack.append(resources)
+
+def top(ss):
+ return ss[len(ss)-1]
+
+def end_element_handler(tag):
+ global stack
+
+ if tag == "section":
+ stack.pop()
+
+def start_element_handler(tag, attr):
+ global resources, stack
+
+ current = top(stack)
+ key = val = None
+ if tag == "section":
+ key = attr["name"]
+ val = dict()
+ stack.append(val)
+ elif tag == "integer":
+ key = attr["name"]
+ val = int(attr["value"])
+ elif tag == "json":
+ fbase = attr["file"]
+ fname = find_file(fbase)
+ key = attr["name"]
+ if fname != None and key != None:
+ try:
+ fp = open(fname)
+ except Exception, err:
+ print >> sys.stderr, ( "Error: %s" % str(err) )
+ val = json.load(fp)
+ elif fname == None:
+ print >> sys.stderr, ( "Error: No such json file %s" % fbase )
+ sys.exit(1)
+ elif tag == "plist":
+ fbase = attr["file"]
+ fname = find_file(fbase)
+ key = attr["name"]
+ if fname != None and key != None:
+ val = plistlib.readPlist(fname)
+ elif fname == None:
+ print >> sys.stderr, ( "Error: No such plist file %s" % fbase )
+ sys.exit(1)
+ elif tag == "string":
+ fbase = attr["file"]
+ fname = find_file(fbase)
+ key = attr["name"]
+ if fname != None and key != None:
+ try:
+ fp = open(fname)
+ val = fp.read()
+ except Exception, err:
+ print >> sys.stderr, ( "Error: %s" % str(err) )
+ sys.exit(1)
+ elif fname == None:
+ print >> sys.stderr, ( "Error: No such string file %s" % fbase )
+ sys.exit(1)
+
+ if val != None:
+ if type(current) == types.DictType:
+ current[key] = val
+ elif type(current) == types.TupleType:
+ current.append(val)
+
+
+def cdata_handler(str):
+ return
+
+def resource_parse_file(infile):
+ parser = expat.ParserCreate()
+ parser.StartElementHandler = start_element_handler
+ parser.EndElementHandler = end_element_handler
+ parser.CharacterDataHandler = cdata_handler
+ parser.ParseFile(infile)
+
+def usage():
+ print >> sys.stderr, (
+ "Usage: %s [-I <inc path>] <resource list> [resource json]\n"
+ "Summary:\n"
+ " Creates a resource json from a resource list\n\n"
+ "Options:\n"
+ " I - Include path to search for files\n"
+ " <resource list> Input resources file\n"
+ " <resource json> Output resources json file\n"
+ % sys.argv[0]
+ )
+
+inc_list = list()
+
+def find_file(name):
+ global inc_list
+
+ for inc_dir in inc_list:
+ inc = "%s/%s" % (inc_dir, name)
+ if os.path.isfile(inc):
+ return inc
+
+ if os.path.isfile(name):
+ return name
+
+ return None
+
+def main():
+ global inc_list
+
+ OPTS = "I:"
+ try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], OPTS)
+ except getopt.GetoptError, err:
+ print >> sys.stderr, str(err)
+ usage()
+ sys.exit(2)
+
+ for o, a in opts:
+ if o == "-I":
+ # add to include list
+ inc_list.append(a)
+ else:
+ assert False, "unhandled option"
+
+ if len(args) > 2 or len(args) < 1:
+ usage()
+ sys.exit(2)
+
+ try:
+ infile = open(args[0])
+ except Exception, err:
+ print >> sys.stderr, ( "Error: %s" % str(err) )
+ sys.exit(1)
+
+ if len(args) > 1:
+ try:
+ outfile = open(args[1], "w")
+ except Exception, err:
+ print >> sys.stderr, ( "Error: %s" % str(err))
+ sys.exit(1)
+ else:
+ outfile = sys.stdout
+
+ resource_parse_file(infile)
+ json.dump(resources, outfile, indent=4, sort_keys=True)
+
+main()
+
diff --git a/scripts/quotestring.py b/scripts/quotestring.py
new file mode 100644
index 000000000..1038719e7
--- /dev/null
+++ b/scripts/quotestring.py
@@ -0,0 +1,62 @@
+#! /usr/bin/python
+
+import re
+import getopt
+import sys
+
+def usage():
+ print >> sys.stderr, (
+ "Usage: %s <input> [output]\n"
+ "Summary:\n"
+ " Creates a quoted string suitable for inclusion in a C char*\n\n"
+ "Options:\n"
+ " <input> Input file to quote\n"
+ " <output> Output quoted string [stdout]\n"
+ % sys.argv[0]
+ )
+
+def main():
+ global inc_list
+
+ OPTS = ""
+ try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], OPTS)
+ except getopt.GetoptError, err:
+ print >> sys.stderr, str(err)
+ usage()
+ sys.exit(2)
+
+ for o, a in opts:
+ usage()
+ assert False, "unhandled option"
+
+ if len(args) > 2 or len(args) < 1:
+ usage()
+ sys.exit(2)
+
+ try:
+ infile = open(args[0])
+ except Exception, err:
+ print >> sys.stderr, ( "Error: %s" % str(err) )
+ sys.exit(1)
+
+ if len(args) > 1:
+ try:
+ outfile = open(args[1], "w")
+ except Exception, err:
+ print >> sys.stderr, ( "Error: %s" % str(err))
+ sys.exit(1)
+ else:
+ outfile = sys.stdout
+
+ ss = infile.read()
+ ss = re.sub(r'\\', r'\\\\', ss)
+ ss = re.sub(r'"', r'\\"', ss)
+ pattern = re.compile("$", re.M)
+ ss = re.sub(pattern, r'\\n"', ss)
+ pattern = re.compile("^", re.M)
+ ss = re.sub(pattern, "\"", ss)
+ outfile.write(ss)
+
+main()
+
diff --git a/test/test.c b/test/test.c
index a3b18a227..d489ffd08 100644
--- a/test/test.c
+++ b/test/test.c
@@ -42,112 +42,117 @@
#endif
/* Options */
-static int debug = HB_DEBUG_ALL;
-static int update = 0;
-static int dvdnav = 1;
-static char * input = NULL;
-static char * output = NULL;
-static char * format = NULL;
-static int titleindex = 1;
-static int titlescan = 0;
-static int main_feature = 0;
-static char * native_language = NULL;
-static int native_dub = 0;
-static int twoPass = 0;
-static int deinterlace = 0;
-static char * deinterlace_opt = 0;
-static int deblock = 0;
-static char * deblock_opt = 0;
-static int denoise = 0;
-static char * denoise_opt = 0;
-static int nlmeans = 0;
-static char * nlmeans_opt = NULL;
-static char * nlmeans_tune_opt = NULL;
-static int detelecine = 0;
-static char * detelecine_opt = 0;
-static int decomb = 0;
-static char * decomb_opt = 0;
-static int rotate = 0;
-static char * rotate_opt = 0;
-static int rotate_val = 0;
-static int grayscale = 0;
-static int vcodec = HB_VCODEC_FFMPEG_MPEG4;
-static hb_list_t * audios = NULL;
-static hb_audio_config_t * audio = NULL;
-static int num_audio_tracks = 0;
-static int allowed_audio_copy = -1;
-static char * mixdowns = NULL;
-static char * dynamic_range_compression = NULL;
-static char * audio_gain = NULL;
-static char ** audio_dither = NULL;
-static char ** normalize_mix_level = NULL;
-static char * atracks = NULL;
-static char * arates = NULL;
-static char ** abitrates = NULL;
-static char ** aqualities = NULL;
-static char ** acompressions = NULL;
-static char * acodec_fallback = NULL;
-static char * acodecs = NULL;
-static char ** anames = NULL;
-static int audio_explicit = 0;
-static char ** subtracks = NULL;
-static char ** subforce = NULL;
-static char * subburn = NULL;
-static char * subdefault = NULL;
-static char ** srtfile = NULL;
-static char ** srtcodeset = NULL;
-static char ** srtoffset = NULL;
-static char ** srtlang = NULL;
-static int srtdefault = -1;
-static int srtburn = -1;
-static int subtitle_scan = 0;
-static int width = 0;
-static int height = 0;
-static int crop[4] = { -1,-1,-1,-1 };
-static int loose_crop = -1;
-static int vrate = 0;
-static float vquality = -1.0;
-static int vbitrate = 0;
-static int mux = 0;
-static int anamorphic_mode = 0;
-static int modulus = 0;
-static int par_height = 0;
-static int par_width = 0;
-static int display_width = 0;
-static int keep_display_aspect = 0;
-static int itu_par = 0;
-static int angle = 0;
-static int chapter_start = 0;
-static int chapter_end = 0;
-static int chapter_markers = 0;
-static char * marker_file = NULL;
-static char * x264_preset = NULL;
-static char * x264_tune = NULL;
-static char * advanced_opts = NULL;
-static char * h264_profile = NULL;
-static char * h264_level = NULL;
-static int maxHeight = 0;
-static int maxWidth = 0;
-static int fastfirstpass = 0;
-static int preset = 0;
-static char * preset_name = 0;
-static int cfr = 0;
-static int mp4_optimize = 0;
-static int ipod_atom = 0;
-static int color_matrix_code = 0;
-static int preview_count = 10;
-static int store_previews = 0;
-static int start_at_preview = 0;
-static int64_t start_at_pts = 0;
-static int start_at_frame = 0;
-static int64_t stop_at_pts = 0;
-static int stop_at_frame = 0;
+static int debug = HB_DEBUG_ALL;
+static int update = 0;
+static int dvdnav = 1;
+static char * input = NULL;
+static char * output = NULL;
+static char * format = NULL;
+static int titleindex = 1;
+static int titlescan = 0;
+static int main_feature = 0;
+static char * native_language = NULL;
+static int native_dub = 0;
+static int twoPass = 0;
+static int deinterlace_disable = 0;
+static int deinterlace_custom = 0;
+static char * deinterlace = NULL;
+static int deblock_disable = 0;
+static char * deblock = NULL;
+static int hqdn3d_disable = 0;
+static int hqdn3d_custom = 0;
+static char * hqdn3d = NULL;
+static int nlmeans_disable = 0;
+static int nlmeans_custom = 0;
+static char * nlmeans = NULL;
+static char * nlmeans_tune = NULL;
+static int detelecine_disable = 0;
+static int detelecine_custom = 0;
+static char * detelecine = NULL;
+static int decomb_disable = 0;
+static int decomb_custom = 0;
+static char * decomb = NULL;
+static char * rotate = NULL;
+static int grayscale = -1;
+static char * vcodec = NULL;
+static int audio_all = -1;
+static char ** audio_copy_list = NULL;
+static char ** audio_lang_list = NULL;
+static char ** atracks = NULL;
+static char ** acodecs = NULL;
+static char ** abitrates = NULL;
+static char ** aqualities = NULL;
+static char ** arates = NULL;
+static char ** mixdowns = NULL;
+static char ** normalize_mix_level = NULL;
+static char ** audio_dither = NULL;
+static char ** dynamic_range_compression = NULL;
+static char ** audio_gain = NULL;
+static char ** acompressions = NULL;
+static char * acodec_fallback = NULL;
+static char ** anames = NULL;
+static char ** subtitle_lang_list = NULL;
+static char ** subtracks = NULL;
+static char ** subforce = NULL;
+static int subtitle_all = -1;
+static int subburn = 0;
+static int subburn_native = 0;
+static int subdefault = 0;
+static char ** srtfile = NULL;
+static char ** srtcodeset = NULL;
+static char ** srtoffset = NULL;
+static char ** srtlang = NULL;
+static int srtdefault = -1;
+static int srtburn = -1;
+static int width = 0;
+static int height = 0;
+static int crop[4] = { -1,-1,-1,-1 };
+static int loose_crop = -1;
+static char * vrate = NULL;
+static float vquality = -1.0;
+static int vbitrate = 0;
+static int mux = 0;
+static int anamorphic_mode = -1;
+static int modulus = 0;
+static int par_height = -1;
+static int par_width = -1;
+static int display_width = -1;
+static int keep_display_aspect = 0;
+static int itu_par = -1;
+static int angle = 0;
+static int chapter_start = 0;
+static int chapter_end = 0;
+static int chapter_markers = -1;
+static char * marker_file = NULL;
+static char * encoder_preset = NULL;
+static char * encoder_tune = NULL;
+static char * encoder_profile = NULL;
+static char * encoder_level = NULL;
+static char * advanced_opts = NULL;
+static int maxHeight = 0;
+static int maxWidth = 0;
+static int fastfirstpass = 0;
+static char * preset_export_name = NULL;
+static char * preset_export_desc = NULL;
+static char * preset_export_file = NULL;
+static char * preset_name = NULL;
+static int cfr = -1;
+static int mp4_optimize = -1;
+static int ipod_atom = -1;
+static int color_matrix_code = -1;
+static int preview_count = 10;
+static int store_previews = 0;
+static int start_at_preview = 0;
+static int64_t start_at_pts = 0;
+static int start_at_frame = 0;
+static int64_t stop_at_pts = 0;
+static int stop_at_frame = 0;
static uint64_t min_title_duration = 10;
-static int use_opencl = 0;
-static int use_hwd = 0;
+static int use_opencl = -1;
+static int use_hwd = -1;
#ifdef USE_QSV
-static int qsv_async_depth = -1;
-static int qsv_decode = 1;
+static int qsv_async_depth = -1;
+static int qsv_decode = -1;
#endif
/* Exit cleanly on Ctrl-C */
@@ -157,7 +162,6 @@ static void SigHandler( int );
/* Utils */
static void ShowHelp();
-static void ShowPresets();
static void ShowCommands()
{
fprintf(stdout, "\nCommands:\n");
@@ -167,10 +171,14 @@ static void ShowCommands()
fprintf(stdout, " [r]esume Resume encoding\n");
}
-static int ParseOptions( int argc, char ** argv );
-static int CheckOptions( int argc, char ** argv );
-static int HandleEvents( hb_handle_t * h );
+static int ParseOptions( int argc, char ** argv );
+static int CheckOptions( int argc, char ** argv );
+static int HandleEvents( hb_handle_t * h, hb_dict_t *preset_dict );
+static hb_dict_t * PreparePreset( const char *preset_name );
+static hb_dict_t * PrepareJob( hb_handle_t *h, hb_title_t *title,
+ hb_dict_t *preset_dict );
+static int str_vlen(char **strv);
static void str_vfree( char **strv );
static char** str_split( char *str, char delem );
@@ -216,7 +224,7 @@ static int get_argv_utf8(int *argc_ptr, char ***argv_ptr)
size += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1, NULL, 0, NULL, NULL );
argv = malloc(size);
- if (argv)
+ if (argv != NULL)
{
for (i = 0; i < argc; i++)
{
@@ -248,7 +256,6 @@ int main( int argc, char ** argv )
hb_global_init();
- audios = hb_list_init();
// Get utf8 command line if windows
get_argv_utf8(&argc, &argv);
@@ -297,6 +304,45 @@ int main( int argc, char ** argv )
/* Exit ASAP on Ctrl-C */
signal( SIGINT, SigHandler );
+ // Apply all command line overrides to the preset that are possible.
+ // Some command line options are applied later to the job
+ // (e.g. chapter names, explicit audio & subtitle tracks).
+ hb_dict_t *preset_dict = PreparePreset(preset_name);
+ if (preset_dict == NULL)
+ {
+ // An appropriate error message should have already
+ // been spilled by PreparePreset.
+ return 1;
+ }
+
+ if (preset_export_name != NULL)
+ {
+ hb_dict_set(preset_dict, "PresetName",
+ hb_value_string(preset_export_name));
+ if (preset_export_desc != NULL)
+ {
+ hb_dict_set(preset_dict, "PresetDescription",
+ hb_value_string(preset_export_desc));
+ }
+ if (preset_export_file != NULL)
+ {
+ hb_preset_write_json(preset_dict, preset_export_file);
+ }
+ else
+ {
+ char *json;
+ json = hb_preset_package_json(preset_dict);
+ fprintf(stdout, "%s\n", json);
+ }
+ // If the user requested to export a preset, but not to
+ // transcode or scan a file, exit here.
+ if (input == NULL || (!titlescan && titleindex != 0 && output == NULL))
+ {
+ hb_value_free(&preset_dict);
+ return 0;
+ }
+ }
+
/* Feed libhb with a DVD to scan */
fprintf( stderr, "Opening %s...\n", input );
@@ -307,15 +353,16 @@ int main( int argc, char ** argv )
titleindex = 0;
}
-
hb_system_sleep_prevent(h);
// FIXME: When hardware decode is enabled, the scan must be performed
// with hardware decode enabled because the decoder context used during
// encoding phase comes from the context used during scan. This is
// broken by design and I would very much like to fix this someday.
- hb_hwd_set_enable(h, use_hwd);
- hb_scan( h, input, titleindex, preview_count, store_previews, min_title_duration * 90000LL );
+ hb_hwd_set_enable(h, hb_value_get_bool(
+ hb_dict_get(preset_dict, "VideoHWDecode")));
+ hb_scan(h, input, titleindex, preview_count, store_previews,
+ min_title_duration * 90000LL);
/* Wait... */
while( !die )
@@ -403,47 +450,49 @@ int main( int argc, char ** argv )
hb_snooze( 200 );
#endif
- HandleEvents( h );
+ HandleEvents( h, preset_dict );
}
/* Clean up */
+ hb_value_free(&preset_dict);
hb_close(&h);
hb_global_close();
- if (audios != NULL)
- {
- while ((audio = hb_list_item(audios, 0)) != NULL)
- {
- hb_list_rem(audios, audio);
- if (audio->out.name != NULL)
- {
- free(audio->out.name);
- }
- free(audio);
- }
- hb_list_close(&audios);
- }
+ str_vfree(audio_copy_list);
str_vfree(abitrates);
str_vfree(acompressions);
str_vfree(aqualities);
str_vfree(audio_dither);
- free(acodecs);
- free(arates);
- free(atracks);
- free(audio_gain);
- free(dynamic_range_compression);
- free(mixdowns);
+ str_vfree(acodecs);
+ str_vfree(arates);
+ str_vfree(atracks);
+ str_vfree(audio_lang_list);
+ str_vfree(audio_gain);
+ str_vfree(dynamic_range_compression);
+ str_vfree(mixdowns);
+ str_vfree(subtitle_lang_list);
+ str_vfree(subtracks);
+ free(acodec_fallback);
free(native_language);
free(format);
free(input);
free(output);
free(preset_name);
- free(x264_preset);
- free(x264_tune);
+ free(encoder_preset);
+ free(encoder_tune);
free(advanced_opts);
- free(h264_profile);
- free(h264_level);
- free(nlmeans_opt);
- free(nlmeans_tune_opt);
+ free(encoder_profile);
+ free(encoder_level);
+ free(rotate);
+ free(deblock);
+ free(detelecine);
+ free(deinterlace);
+ free(decomb);
+ free(hqdn3d);
+ free(nlmeans);
+ free(nlmeans_tune);
+ free(preset_export_name);
+ free(preset_export_desc);
+ free(preset_export_file);
// write a carriage return to stdout
// avoids overlap / line wrapping when stderr is redirected
@@ -455,8 +504,6 @@ int main( int argc, char ** argv )
static void PrintTitleInfo( hb_title_t * title, int feature )
{
- hb_chapter_t * chapter;
- hb_subtitle_t * subtitle;
int i;
fprintf( stderr, "+ title %d:\n", title->index );
@@ -500,6 +547,7 @@ static void PrintTitleInfo( hb_title_t * title, int feature )
fprintf( stderr, " + chapters:\n" );
for( i = 0; i < hb_list_count( title->list_chapter ); i++ )
{
+ hb_chapter_t * chapter;
chapter = hb_list_item( title->list_chapter, i );
fprintf( stderr, " + %d: cells %d->%d, %"PRIu64" blocks, duration "
"%02d:%02d:%02d\n", chapter->index,
@@ -510,20 +558,21 @@ static void PrintTitleInfo( hb_title_t * title, int feature )
fprintf( stderr, " + audio tracks:\n" );
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
+ hb_audio_config_t *audio;
audio = hb_list_audio_config_item( title->list_audio, i );
if( ( audio->in.codec == HB_ACODEC_AC3 ) || ( audio->in.codec == HB_ACODEC_DCA) )
{
- fprintf( stderr, " + %d, %s (iso639-2: %s), %dHz, %dbps\n",
+ fprintf( stderr, " + %d, %s (iso639-2: %s), %dHz, %dbps\n",
i + 1,
- audio->lang.description,
+ audio->lang.description,
audio->lang.iso639_2,
- audio->in.samplerate,
+ audio->in.samplerate,
audio->in.bitrate );
}
else
{
- fprintf( stderr, " + %d, %s (iso639-2: %s)\n",
- i + 1,
+ fprintf( stderr, " + %d, %s (iso639-2: %s)\n",
+ i + 1,
audio->lang.description,
audio->lang.iso639_2 );
}
@@ -531,8 +580,9 @@ static void PrintTitleInfo( hb_title_t * title, int feature )
fprintf( stderr, " + subtitle tracks:\n" );
for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
{
+ hb_subtitle_t *subtitle;
subtitle = hb_list_item( title->list_subtitle, i );
- fprintf( stderr, " + %d, %s (iso639-2: %s) (%s)(%s)\n",
+ fprintf( stderr, " + %d, %s (iso639-2: %s) (%s)(%s)\n",
i + 1, subtitle->lang,
subtitle->iso639_2,
(subtitle->format == TEXTSUB) ? "Text" : "Bitmap",
@@ -578,80 +628,69 @@ static int test_sub_list( char ** list, int pos )
return 0;
}
-static int cmp_lang( char * lang, const char * code )
+void write_chapter_names(hb_dict_t *job_dict, const char *marker_file)
{
- iso639_lang_t * iso639;
+ if (marker_file == NULL)
+ return;
- iso639 = lang_for_code2( code );
+ hb_csv_file_t * file = hb_open_csv_file(marker_file);
+ hb_csv_cell_t * cell;
+ int row = 0;
- if ( iso639 == NULL )
- return 0;
- if ( iso639->eng_name && !strcasecmp( lang, iso639->eng_name ) )
- return 1;
- if ( iso639->native_name && !strcasecmp( lang, iso639->native_name ) )
- return 1;
- if ( iso639->iso639_1 && !strcasecmp( lang, iso639->iso639_1 ) )
- return 1;
- if ( iso639->iso639_2 && !strcasecmp( lang, iso639->iso639_2 ) )
- return 1;
- if ( iso639->iso639_2b && !strcasecmp( lang, iso639->iso639_2b ) )
- return 1;
- return 0;
-}
+ if (file == NULL)
+ {
+ fprintf(stderr, "Cannot open chapter marker file, using defaults\n");
+ return;
+ }
+ fprintf(stderr, "Reading chapter markers from file %s\n", marker_file);
-static void apply_loose_crop(int total, int * v1, int * v2, int mod, int max)
-{
- /* number of extra pixels which must be cropped to reach next modulus */
- int add = (total - *v1 - *v2) % mod;
+ hb_value_array_t *chapter_array;
+ chapter_array = hb_dict_get(hb_dict_get(job_dict, "Destination"),
+ "ChapterList");
- if (add)
- {
- /* number of pixels which must be uncropped to reach previous modulus */
- int sub = mod - add;
+ if (chapter_array == NULL)
+ return;
- /* less than maximum (or can't reduce), increase the crop size */
- if (add <= max || sub > (*v1 + *v2))
+ /* Parse the cells */
+ while (NULL != (cell = hb_read_next_cell(file)))
+ {
+ /* We have a chapter number */
+ if (cell->cell_col == 0)
{
- int add1 = add / 2;
- if ((*v1 + add1) & 1) // avoid odd crop if possible
- ++add1;
- int add2 = (add - add1);
-
- *v1 += add1;
- *v2 += add2;
+ row = cell->cell_row;
}
- /* more than maximum, reduce the crop size instead */
- else
+ /* We have a chapter name */
+ if (cell->cell_col == 1 && row == cell->cell_row)
{
- int sub1 = sub / 2;
- if (sub1 > *v1)
- sub1 = *v1;
- else if ((*v1 - sub1) & 1) // avoid odd crop if possible
- ++sub1;
-
- int sub2 = sub - sub1;
- if (sub2 > *v2)
+ /* If we have a valid chapter, add chapter entry */
+ hb_dict_t *chapter_dict = hb_value_array_get(chapter_array, row);
+ if (chapter_dict != NULL)
{
- sub1 += (sub2 - *v2);
- if ((*v1 - sub1) & 1) // avoid odd crop if possible
- ++sub1;
- sub2 = sub - sub1;
+ hb_dict_set(chapter_dict, "Name",
+ hb_value_string(cell->cell_text));
}
-
- *v1 -= sub1;
- *v2 -= sub2;
}
+ hb_dispose_cell( cell );
+ }
+ hb_close_csv_file( file );
+}
+
+static void lang_list_remove(hb_value_array_t *list, const char *lang)
+{
+ int count = hb_value_array_len(list);
+ int ii;
+ for (ii = count - 1; ii >= 0; ii--)
+ {
+ const char *tmp = hb_value_get_string(hb_value_array_get(list, ii));
+ if (!strncmp(lang, tmp, 4))
+ hb_value_array_remove(list, ii);
}
}
-static int HandleEvents( hb_handle_t * h )
+static int HandleEvents(hb_handle_t * h, hb_dict_t *preset_dict)
{
hb_state_t s;
- const hb_encoder_t *encoder;
- int tmp_num_audio_tracks;
- int filter_cfr;
- hb_rational_t filter_vrate;
hb_get_state( h, &s );
switch( s.state )
@@ -681,23 +720,8 @@ static int HandleEvents( hb_handle_t * h )
{
hb_title_set_t * title_set;
hb_title_t * title;
- hb_job_t * job;
- int i;
- int sub_burned = 0;
-
- /* Audio argument string parsing variables */
- int acodec = 0;
- int abitrate = 0;
- float aquality = 0;
- float acompression = 0;
- int arate = 0;
- int mixdown = HB_AMIXDOWN_DOLBYPLII;
- double d_r_c = 0;
- double gain = 0;
- /* Audio argument string parsing variables */
title_set = hb_get_title_set( h );
-
if( !title_set || !hb_list_count( title_set->list_title ) )
{
/* No valid title, stop right there */
@@ -706,7 +730,7 @@ static int HandleEvents( hb_handle_t * h )
die = 1;
break;
}
- if( main_feature )
+ if (main_feature)
{
int i;
int main_feature_idx=0;
@@ -744,15 +768,15 @@ static int HandleEvents( hb_handle_t * h )
break;
}
titleindex = main_feature_idx;
- fprintf( stderr, "Found main feature title, setting title to %d\n",
- main_feature_idx);
+ fprintf(stderr, "Found main feature title %d\n",
+ main_feature_idx);
- title = hb_list_item( title_set->list_title, main_feature_pos);
+ title = hb_list_item(title_set->list_title, main_feature_pos);
} else {
- title = hb_list_item( title_set->list_title, 0 );
+ title = hb_list_item(title_set->list_title, 0);
}
- if( !titleindex || titlescan )
+ if (!titleindex || titlescan)
{
/* Scan-only mode, print infos and exit */
PrintTitleSetInfo( title_set );
@@ -760,2063 +784,31 @@ static int HandleEvents( hb_handle_t * h )
break;
}
- PrintTitleInfo( title, title_set->feature );
-
- /* Set job settings */
- job = hb_job_init(title);
- filter_cfr = job->cfr;
- filter_vrate = job->vrate;
+ fprintf( stderr, "+ Using preset: %s\n",
+ hb_value_get_string(hb_dict_get(preset_dict, "PresetName")));
+ PrintTitleInfo(title, title_set->feature);
- if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame )
- {
- job->chapter_start = MAX( job->chapter_start,
- chapter_start );
- job->chapter_end = MIN( job->chapter_end,
- chapter_end );
- job->chapter_end = MAX( job->chapter_start,
- job->chapter_end );
- }
-
- if ( angle )
+ // All overrides to the preset are complete
+ // Initialize the job from preset + overrides
+ // and apply job specific command line overrides
+ hb_dict_t *job_dict = PrepareJob(h, title, preset_dict);
+ if (job_dict == NULL)
{
- job->angle = angle;
- }
-
- if (preset)
- {
- fprintf( stderr, "+ Using preset: %s\n", preset_name);
-
- if (!strcasecmp(preset_name, "Universal"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1,1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac,copy:ac3");
- }
- if( !abitrates )
- {
- abitrates = str_split("160,160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2,none");
- }
- if( !arates )
- {
- arates = strdup("Auto,Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0,0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 720;
- maxHeight = 576;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("fast");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("baseline");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.0");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "iPod"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- job->ipod_atom = 1;
- vcodec = HB_VCODEC_X264;
- job->vquality = 22.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 320;
- maxHeight = 240;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("baseline");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("1.3");
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "iPhone & iPod touch"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 22.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 960;
- maxHeight = 640;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("high");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.1");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "iPad"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 1280;
- maxHeight = 720;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("high");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.1");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "AppleTV"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1,1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac,copy:ac3");
- }
- if( !abitrates )
- {
- abitrates = str_split("160,160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2,none");
- }
- if( !arates )
- {
- arates = strdup("Auto,Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0,0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 960;
- maxHeight = 720;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("high");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.1");
- }
- if (advanced_opts == NULL)
- {
- advanced_opts = strdup("qpmin=4:cabac=0:ref=2:b-pyramid=none:weightb=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "AppleTV 2"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1,1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac,copy:ac3");
- }
- if( !abitrates )
- {
- abitrates = str_split("160,160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2,none");
- }
- if( !arates )
- {
- arates = strdup("Auto,Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0,0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 1280;
- maxHeight = 720;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("high");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.1");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "AppleTV 3"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1,1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac,copy:ac3");
- }
- if( !abitrates )
- {
- abitrates = str_split("160,160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2,none");
- }
- if( !arates )
- {
- arates = strdup("Auto,Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0,0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 1920;
- maxHeight = 1080;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("high");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("4.0");
- }
- decomb = 1;
- decomb_opt = "7:2:6:9:1:80";
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "Android"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 22.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("128", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 720;
- maxHeight = 576;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("main");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.0");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- }
- if (!strcasecmp(preset_name, "Android Tablet"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 22.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("128", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 1280;
- maxHeight = 720;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("main");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.1");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- }
- if (!strcasecmp(preset_name, "Windows Phone 8"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 22.0;
- filter_vrate.den = 900000;
- filter_cfr = 2;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("128", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- maxWidth = 1280;
- maxHeight = 720;
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("main");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("3.1");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 0;
- }
- modulus = 2;
- }
- if (!strcasecmp(preset_name, "Normal"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- if( !atracks )
- {
- atracks = strdup("1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac");
- }
- if( !abitrates )
- {
- abitrates = str_split("160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2");
- }
- if( !arates )
- {
- arates = strdup("Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- if (x264_preset == NULL)
- {
- x264_preset = strdup("veryfast");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("main");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("4.0");
- }
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- if (!strcasecmp(preset_name, "High Profile"))
- {
- if( !mux )
- {
- mux = HB_MUX_MP4;
- }
- vcodec = HB_VCODEC_X264;
- job->vquality = 20.0;
- if( !atracks )
- {
- atracks = strdup("1,1");
- }
- if( !acodecs )
- {
- acodecs = strdup("ffaac,copy:ac3");
- }
- if( !abitrates )
- {
- abitrates = str_split("160,160", ',');
- }
- if( !mixdowns )
- {
- mixdowns = strdup("dpl2,none");
- }
- if( !arates )
- {
- arates = strdup("Auto,Auto");
- }
- if( !dynamic_range_compression )
- {
- dynamic_range_compression = strdup("0.0,0.0");
- }
- if( allowed_audio_copy == -1 )
- {
- allowed_audio_copy = 0;
- allowed_audio_copy |= HB_ACODEC_AAC_PASS;
- allowed_audio_copy |= HB_ACODEC_AC3_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS;
- allowed_audio_copy |= HB_ACODEC_DCA_PASS;
- allowed_audio_copy |= HB_ACODEC_MP3_PASS;
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- }
- if( acodec_fallback == NULL )
- {
- acodec_fallback = "ffac3";
- }
- if (x264_preset == NULL)
- {
- x264_preset = strdup("medium");
- }
- if (h264_profile == NULL)
- {
- h264_profile = strdup("high");
- }
- if (h264_level == NULL)
- {
- h264_level = strdup("4.1");
- }
- decomb = 1;
- if( !anamorphic_mode )
- {
- anamorphic_mode = 2;
- }
- modulus = 2;
- job->chapter_markers = 1;
- }
- }
-
- if ( chapter_markers )
- {
- job->chapter_markers = chapter_markers;
-
- if( marker_file != NULL )
- {
- hb_csv_file_t * file = hb_open_csv_file( marker_file );
- hb_csv_cell_t * cell;
- int row = 0;
- int chapter = 0;
-
- fprintf( stderr, "Reading chapter markers from file %s\n", marker_file );
-
- if( file == NULL )
- {
- fprintf( stderr, "Cannot open chapter marker file, using defaults\n" );
- }
- else
- {
- /* Parse the cells */
- while( NULL != ( cell = hb_read_next_cell( file ) ) )
- {
- /* We have a chapter number */
- if( cell->cell_col == 0 )
- {
- row = cell->cell_row;
- chapter = atoi( cell->cell_text );
- }
-
- /* We have a chapter name */
- if( cell->cell_col == 1 && row == cell->cell_row )
- {
- /* If we have a valid chapter, copy the string an terminate it */
- if( chapter >= job->chapter_start && chapter <= job->chapter_end )
- {
- hb_chapter_t * chapter_s;
-
- chapter_s = hb_list_item( job->list_chapter, chapter - 1);
- hb_chapter_set_title(chapter_s, cell->cell_text);
- }
- }
-
-
- hb_dispose_cell( cell );
- }
- hb_close_csv_file( file );
- }
- }
- }
-
- if (crop[0] < 0 || crop[1] < 0 || crop[2] < 0 || crop[3] < 0)
- {
- memcpy(crop, title->crop, sizeof(int[4]));
- }
-
- if (loose_crop >= 0)
- {
- int mod = modulus > 0 ? modulus : 2;
- apply_loose_crop(title->geometry.height,
- &crop[0], &crop[1], mod, loose_crop);
- apply_loose_crop(title->geometry.width,
- &crop[2], &crop[3], mod, loose_crop);
- }
-
- job->grayscale = grayscale;
-
- hb_filter_object_t * filter;
-
- /* Add selected filters */
- if( detelecine )
- {
- filter = hb_filter_init( HB_FILTER_DETELECINE );
- hb_add_filter( job, filter, detelecine_opt );
- }
- if( decomb )
- {
- filter = hb_filter_init( HB_FILTER_DECOMB );
- hb_add_filter( job, filter, decomb_opt );
- }
- if( deinterlace )
- {
- filter = hb_filter_init( HB_FILTER_DEINTERLACE );
- hb_add_filter( job, filter, deinterlace_opt );
- }
- if( deblock )
- {
- filter = hb_filter_init( HB_FILTER_DEBLOCK );
- hb_add_filter( job, filter, deblock_opt );
- }
- if( denoise )
- {
- filter = hb_filter_init( HB_FILTER_DENOISE );
- hb_add_filter( job, filter, denoise_opt );
- }
- if( nlmeans )
- {
- filter = hb_filter_init( HB_FILTER_NLMEANS );
- hb_add_filter( job, filter, nlmeans_opt );
- }
- if( rotate )
- {
- filter = hb_filter_init( HB_FILTER_ROTATE );
- hb_add_filter( job, filter, rotate_opt);
- }
-
- if (use_hwd)
- {
- job->use_hwd = use_hwd;
- }
-
- hb_geometry_t srcGeo, resultGeo;
- hb_geometry_settings_t uiGeo;
-
- srcGeo = title->geometry;
-
- keep_display_aspect |= anamorphic_mode != HB_ANAMORPHIC_CUSTOM;
- uiGeo.mode = anamorphic_mode;
- if (width != 0 && height != 0)
- {
- if (anamorphic_mode == HB_ANAMORPHIC_NONE)
- {
- keep_display_aspect = 0;
- }
- else
- {
- uiGeo.mode = HB_ANAMORPHIC_CUSTOM;
- }
- }
- uiGeo.keep = !!keep_display_aspect * HB_KEEP_DISPLAY_ASPECT;
- uiGeo.itu_par = itu_par;
- uiGeo.modulus = modulus;
- memcpy(uiGeo.crop, crop, sizeof(int[4]));
- if (width == 0)
- {
- uiGeo.geometry.width = title->geometry.width - crop[2] - crop[3];
- }
- else
- {
- uiGeo.keep |= HB_KEEP_WIDTH;
- uiGeo.geometry.width = width;
- }
- if (height == 0)
- {
- uiGeo.geometry.height = title->geometry.height - crop[0] - crop[1];
- }
- else
- {
- uiGeo.keep |= HB_KEEP_HEIGHT;
- uiGeo.geometry.height = height;
- }
- uiGeo.maxWidth = maxWidth;
- uiGeo.maxHeight = maxHeight;
- if( par_width && par_height )
- {
- uiGeo.geometry.par.num = par_width;
- uiGeo.geometry.par.den = par_height;
- }
- else if (display_width != 0 && width != 0)
- {
- if (height != 0)
- {
- fprintf(stderr, "display_width (%d), width (%d), and height (%d) can not all be specified, ignoring height", display_width, width, height);
- }
- uiGeo.geometry.par.num = display_width;
- uiGeo.geometry.par.den = width;
- }
- else if (display_width != 0)
- {
- uiGeo.geometry.par.num = display_width;
- uiGeo.geometry.par.den = uiGeo.geometry.width;
- }
- else
- {
- uiGeo.geometry.par = srcGeo.par;
- }
-
- hb_set_anamorphic_size2(&srcGeo, &uiGeo, &resultGeo);
- job->par = resultGeo.par;
-
- // Add filter that does cropping and scaling
- char * filter_str;
- filter_str = hb_strdup_printf("%d:%d:%d:%d:%d:%d",
- resultGeo.width, resultGeo.height,
- crop[0], crop[1], crop[2], crop[3] );
-
- filter = hb_filter_init( HB_FILTER_CROP_SCALE );
- hb_add_filter( job, filter, filter_str );
- free( filter_str );
-
- // Add framerate shaping filter
- if (vrate)
- {
- filter_cfr = cfr;
- filter_vrate.num = 27000000;
- filter_vrate.den = vrate;
- }
- else if (cfr)
- {
- // cfr or pfr flag with no rate specified implies
- // use the title rate.
- filter_cfr = cfr;
- filter_vrate = title->vrate;
- }
- filter = hb_filter_init(HB_FILTER_VFR);
- filter_str = hb_strdup_printf("%d:%d:%d", filter_cfr,
- filter_vrate.num, filter_vrate.den);
- hb_add_filter(job, filter, filter_str);
- free(filter_str);
-
- // hb_job_init() will set a default muxer for us
- // only override it if a specific muxer has been set
- // note: the muxer must be set after presets, but before encoders
- if (mux)
- {
- job->mux = mux;
- }
- // then, muxer options
- if (mp4_optimize)
- {
- job->mp4_optimize = 1;
- }
- if (ipod_atom)
- {
- job->ipod_atom = 1;
- }
-
- if( vquality >= 0.0 )
- {
- job->vquality = vquality;
- job->vbitrate = 0;
- }
- else if( vbitrate )
- {
- job->vquality = -1.0;
- job->vbitrate = vbitrate;
- }
-
- /* Set video encoder and check muxer compatibility */
- if (vcodec)
- {
- job->vcodec = vcodec;
- }
- encoder = NULL;
- while ((encoder = hb_video_encoder_get_next(encoder)) != NULL)
- {
- if ((encoder->codec == job->vcodec) &&
- (encoder->muxers & job->mux) == 0)
- {
- hb_error("incompatible video encoder '%s' for muxer '%s'",
- hb_video_encoder_get_short_name(job->vcodec),
- hb_container_get_short_name (job->mux));
- done_error = HB_ERROR_INIT;
- die = 1;
- return -1;
- }
- }
-
-#ifdef USE_QSV
- if (qsv_async_depth >= 0)
- {
- job->qsv.async_depth = qsv_async_depth;
- }
- job->qsv.decode = qsv_decode;
-#endif
-
- /* Grab audio tracks */
- if( atracks )
- {
- char * token = strtok( atracks, "," );
- if( token == NULL )
- token = optarg;
- int track_start, track_end;
- for( ; token != NULL; token = strtok( NULL, "," ) )
- {
- if( strlen( token ) >= 3 )
- {
- if( sscanf( token, "%d-%d", &track_start, &track_end ) == 2 )
- {
- int i;
- for( i = track_start - 1; i < track_end; i++ )
- {
- if( hb_list_item( title->list_audio, i ) == NULL )
- {
- fprintf( stderr, "Warning: Could not find audio track %d, skipped\n", i + 1 );
- continue;
- }
- audio = calloc( 1, sizeof( *audio ) );
- hb_audio_config_init( audio );
- audio->in.track = i;
- audio->out.track = num_audio_tracks++;
- hb_list_add( audios, audio );
- }
- }
- else if( !strcasecmp(token, "none" ) )
- {
- audio = calloc( 1, sizeof( *audio ) );
- hb_audio_config_init( audio );
- audio->in.track = audio->out.track = -1;
- audio->out.codec = 0;
- hb_list_add( audios, audio );
- break;
- }
- else
- {
- fprintf( stderr, "ERROR: unable to parse audio input \"%s\", skipping\n",
- token);
- }
- }
- else
- {
- int i = atoi( token ) - 1;
- if( hb_list_item( title->list_audio, i ) == NULL )
- {
- fprintf(stderr,
- "Warning: Could not find audio track '%s', skipped\n",
- token);
- continue;
- }
- audio = calloc( 1, sizeof( *audio ) );
- hb_audio_config_init( audio );
- audio->in.track = i;
- audio->out.track = num_audio_tracks++;
- hb_list_add( audios, audio );
- }
- }
- }
-
- /* Parse audio tracks */
- if( native_language && native_dub )
- {
- if( hb_list_count( audios ) == 0 || !audio_explicit )
- {
- for( i = 0; i < hb_list_count( title->list_audio ); i++ )
- {
- int track = i;
-
- audio = hb_list_audio_config_item( title->list_audio, i );
-
- if( cmp_lang( native_language, audio->lang.iso639_2 ) &&
- audio->lang.type != 3 && // Directors 1
- audio->lang.type != 4) // Directors 2
- {
- /*
- * Matched an audio to our native language - use it.
- * Replace any existing audio tracks that a preset may
- * have put here.
- */
- if( hb_list_count( audios ) == 0 )
- {
- audio = calloc( 1, sizeof( *audio ) );
- hb_audio_config_init( audio );
- audio->in.track = track;
- audio->out.track = num_audio_tracks++;
- /* Add it to our audios */
- hb_list_add( audios, audio );
- }
- else
- {
- /*
- * Update the track numbers on what is already in
- * there.
- */
- for( i = 0; i < hb_list_count( audios ); i++ )
- {
- audio = hb_list_item( audios, i );
- audio->in.track = track;
- }
- }
- break;
- }
- }
- }
- else
- {
- fprintf( stderr, "Warning: Native language (dubbing) selection ignored since an audio track has already been selected\n" );
- }
- }
-
- if( hb_list_count(audios) == 0 &&
- hb_list_count(title->list_audio) > 0 )
- {
- /* Create a new audio track with default settings */
- audio = calloc( 1, sizeof( *audio ) );
- hb_audio_config_init( audio );
- /* Add it to our audios */
- hb_list_add( audios, audio );
- }
- tmp_num_audio_tracks = num_audio_tracks = hb_list_count( audios );
- for( i = 0; i < tmp_num_audio_tracks; i++ )
- {
- audio = hb_list_item( audios, 0 );
- if( audio == NULL ||
- audio->in.track == -1 ||
- audio->out.track == -1 ||
- audio->out.codec == 0 ||
- hb_audio_add( job, audio ) == 0 )
- {
- num_audio_tracks--;
- }
- if( audio != NULL )
- {
- hb_list_rem( audios, audio );
- if( audio->out.name )
- {
- free( audio->out.name );
- }
- free( audio );
- }
- }
-
- /* Audio Codecs */
- i = 0;
- if( acodecs )
- {
- char * token = strtok(acodecs, ",");
- if( token == NULL )
- token = acodecs;
- while ( token != NULL )
- {
- if ((acodec = hb_audio_encoder_get_from_name(token)) <= 0)
- {
- fprintf(stderr, "Invalid codec %s, using default for container.\n", token);
- acodec = hb_audio_encoder_get_default(job->mux);
- }
- if( i < num_audio_tracks )
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.codec = acodec;
- }
- else
- {
- hb_audio_config_t * last_audio = hb_list_audio_config_item( job->list_audio, i - 1 );
- hb_audio_config_t audio;
-
- if( last_audio )
- {
- fprintf(stderr, "More audio codecs than audio tracks, copying track %i and using encoder %s\n",
- i, token);
- hb_audio_config_init(&audio);
- audio.in.track = last_audio->in.track;
- audio.out.track = num_audio_tracks++;
- audio.out.codec = acodec;
- hb_audio_add(job, &audio);
- }
- else
- {
- fprintf(stderr, "Audio codecs and no valid audio tracks, skipping codec %s\n", token);
- }
- }
- token = strtok(NULL, ",");
- i++;
- }
- }
- if( i < num_audio_tracks )
- {
- /* We have fewer inputs than audio tracks, use the default codec for
- * this container for the remaining tracks. Unless we only have one input
- * then use that codec instead.
- */
- if (i != 1)
- acodec = hb_audio_encoder_get_default(job->mux);
- for ( ; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.codec = acodec;
- }
- }
- // sanity check muxer compatibility
- for (i = 0; i < num_audio_tracks; i++)
- {
- encoder = NULL;
- audio = hb_list_audio_config_item(job->list_audio, i);
- if (audio != NULL)
- {
- while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
- {
- if ((encoder->codec == audio->out.codec) &&
- (encoder->muxers & job->mux) == 0)
- {
- hb_error("audio track %d: incompatible encoder '%s' for muxer '%s'", i + 1,
- hb_audio_encoder_get_short_name(audio->out.codec),
- hb_container_get_short_name (job->mux));
- done_error = HB_ERROR_INIT;
- die = 1;
- return -1;
- }
- }
- }
- }
- /* Audio Codecs */
-
- /* Sample Rate */
- int auto_sample_rate = 0;
- i = 0;
- if( arates )
- {
- char * token = strtok(arates, ",");
- if (token == NULL)
- token = arates;
- while ( token != NULL )
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
-
- if( audio != NULL )
- {
- if ( !strcasecmp( token, "auto" ) )
- {
- arate = audio->in.samplerate;
- auto_sample_rate = 1;
- }
- else
- {
- arate = hb_audio_samplerate_get_from_name(token);
- }
- if (arate <= 0)
- {
- fprintf(stderr,
- "Invalid sample rate %s, using input rate %d\n",
- token, audio->in.samplerate);
- arate = audio->in.samplerate;
- }
-
- audio->out.samplerate = arate;
- if( (++i) >= num_audio_tracks )
- break; /* We have more inputs than audio tracks, oops */
- }
- else
- {
- fprintf(stderr, "Ignoring sample rate %d, no audio tracks\n", arate);
- }
- token = strtok(NULL, ",");
- }
- }
- if (i < num_audio_tracks)
- {
- /* We have fewer inputs than audio tracks, use default sample rate.
- * Unless we only have one input, then use that for all tracks.
- */
- int use_default = 0;
- if( i != 1 || auto_sample_rate )
- use_default = 1;
-
- for ( ; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( use_default )
- arate = audio->in.samplerate;
- audio->out.samplerate = arate;
- }
- }
- /* Sample Rate */
-
- /* Audio Mixdown */
- i = 0;
- if ( mixdowns )
- {
- char * token = strtok(mixdowns, ",");
- if (token == NULL)
- token = mixdowns;
- while ( token != NULL )
- {
- mixdown = hb_mixdown_get_from_name(token);
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio != NULL )
- {
- audio->out.mixdown = mixdown;
- if( (++i) >= num_audio_tracks )
- break; /* We have more inputs than audio tracks, oops */
- }
- else
- {
- fprintf(stderr, "Ignoring mixdown, no audio tracks\n");
- }
- token = strtok(NULL, ",");
- }
- }
- if (i < num_audio_tracks && i == 1)
- {
- /* We have fewer inputs than audio tracks
- * and we only have one input, then use that.
- */
- for (; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.mixdown = mixdown;
- }
- }
- /* Audio Mixdown */
-
- /* Audio Bitrate */
- i = 0;
- if( abitrates )
- {
- for ( i = 0; abitrates[i] != NULL && i < num_audio_tracks; i++ )
- {
- char * token = abitrates[i];
- abitrate = atoi(token);
- audio = hb_list_audio_config_item(job->list_audio, i);
-
- if( audio != NULL )
- {
- audio->out.bitrate = abitrate;
- }
- else
- {
- fprintf(stderr, "Ignoring bitrate %d, no audio tracks\n", abitrate);
- }
- }
- }
- if (i < num_audio_tracks && i == 1)
- {
- /* We have fewer inputs than audio tracks,
- * and we only have one input, use
- * that for all tracks.
- */
- for (; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.bitrate = abitrate;
- }
- }
- /* Audio Bitrate */
-
- /* Audio Quality */
- i = 0;
- if( aqualities )
- {
- for ( i = 0; aqualities[i] != NULL && i < num_audio_tracks; i++ )
- {
- char * token = aqualities[i];
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio == NULL )
- {
- fprintf(stderr, "Ignoring quality %.3f, no audio tracks\n", aquality);
- }
- else if( *token != 0 )
- {
- aquality = atof(token);
-
- audio->out.quality = aquality;
- audio->out.bitrate = -1;
- }
- }
- }
- if (i < num_audio_tracks && i == 1)
- {
- /* We have fewer inputs than audio tracks,
- * and we only have one input, use
- * that for all tracks.
- */
- for (; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio->out.bitrate <= 0 )
- audio->out.quality = aquality;
- }
- }
- /* Audio Quality */
-
- /* Audio Compression Level */
- i = 0;
- if( acompressions )
- {
- for ( i = 0; acompressions[i] != NULL && i < num_audio_tracks; i++ )
- {
- char * token = acompressions[i];
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio == NULL )
- {
- fprintf(stderr, "Ignoring compression level %.2f, no audio tracks\n", acompression);
- }
- else if( *token != 0 )
- {
- acompression = atof(token);
-
- audio->out.compression_level = acompression;
- }
- }
- }
- // Compression levels are codec specific values. So don't
- // try to apply to other tracks.
- /* Audio Compression Level */
-
- /* Audio DRC */
- i = 0;
- if ( dynamic_range_compression )
- {
- char * token = strtok(dynamic_range_compression, ",");
- if (token == NULL)
- token = dynamic_range_compression;
- while ( token != NULL )
- {
- d_r_c = atof(token);
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio != NULL )
- {
- audio->out.dynamic_range_compression = d_r_c;
- if( (++i) >= num_audio_tracks )
- break; /* We have more inputs than audio tracks, oops */
- }
- else
- {
- fprintf(stderr, "Ignoring drc, no audio tracks\n");
- }
- token = strtok(NULL, ",");
- }
- }
- if (i < num_audio_tracks)
- {
- /* We have fewer inputs than audio tracks, use no DRC for the remaining
- * tracks. Unless we only have one input, then use the same DRC for all
- * tracks.
- */
- if (i != 1)
- d_r_c = 0;
- for (; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.dynamic_range_compression = d_r_c;
- }
- }
- /* Audio DRC */
-
- /* Audio Gain */
- i = 0;
- if ( audio_gain )
- {
- char * token = strtok(audio_gain, ",");
- if (token == NULL)
- token = audio_gain;
- while ( token != NULL )
- {
- gain = atof(token);
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio != NULL )
- {
- audio->out.gain = gain;
- if( (++i) >= num_audio_tracks )
- break; /* We have more inputs than audio tracks, oops */
- }
- else
- {
- fprintf(stderr, "Ignoring gain, no audio tracks\n");
- }
- token = strtok(NULL, ",");
- }
- }
- if (i < num_audio_tracks)
- {
- /* We have fewer inputs than audio tracks, use no gain for the remaining
- * tracks. Unless we only have one input, then use the same gain for all
- * tracks.
- */
- if (i != 1)
- gain = 0;
- for (; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.gain = gain;
- }
- }
- /* Audio Gain */
-
- /* Audio Dither */
- if (audio_dither != NULL)
- {
- int dither_method = hb_audio_dither_get_default();
- for (i = 0; audio_dither[i] != NULL; i++)
- {
- dither_method = hb_audio_dither_get_from_name(audio_dither[i]);
- audio = hb_list_audio_config_item(job->list_audio, i);
- if (audio != NULL)
- {
- if (hb_audio_dither_is_supported(audio->out.codec))
- {
- audio->out.dither_method = dither_method;
- }
- else if (dither_method != hb_audio_dither_get_default())
- {
- fprintf(stderr,
- "Ignoring dither %s, not supported by codec\n",
- audio_dither[i]);
- }
- }
- else
- {
- fprintf(stderr, "Ignoring dither %s, no audio tracks\n",
- audio_dither[i]);
- }
- }
- if (i < num_audio_tracks && i == 1)
- {
- /*
- * We have fewer inputs than audio tracks, and we only have
- * one input: use that for all tracks.
- */
- while (i < num_audio_tracks)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- if (hb_audio_dither_is_supported(audio->out.codec))
- {
- audio->out.dither_method = dither_method;
- }
- else if (dither_method != hb_audio_dither_get_default())
- {
- fprintf(stderr,
- "Ignoring dither %s, not supported by codec\n",
- audio_dither[0]);
- }
- i++;
- }
- }
- }
- /* Audio Dither */
-
- /* Audio Mix Normalization */
- i = 0;
- int norm = 0;
- if( normalize_mix_level )
- {
- for ( i = 0; normalize_mix_level[i] != NULL && i < num_audio_tracks; i++ )
- {
- char * token = normalize_mix_level[i];
- norm = atoi(token);
- audio = hb_list_audio_config_item(job->list_audio, i);
-
- if( audio != NULL )
- {
- audio->out.normalize_mix_level = norm;
- }
- else
- {
- fprintf(stderr, "Ignoring normalization %d, no audio tracks\n", norm);
- }
- }
- }
- if (i < num_audio_tracks && i == 1)
- {
- /* We have fewer inputs than audio tracks,
- * and we only have one input, use
- * that for all tracks.
- */
- for (; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.normalize_mix_level = norm;
- }
- }
- /* Audio Mix Normalization */
-
- /* Audio Track Names */
- if ( anames )
- {
- char * token;
- for ( i = 0; anames[i] != NULL && i < num_audio_tracks; i++ )
- {
- token = anames[i];
- if ( *token )
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- if( audio != NULL )
- {
- audio->out.name = strdup(token);
- }
- else
- {
- fprintf(stderr, "Ignoring aname '%s', no audio track\n",
- token);
- }
- }
- }
- }
- if( i < num_audio_tracks && i == 1 )
- {
- /* We have exactly one name and more than one audio track. Use the same
- * name for all tracks. */
- for ( ; i < num_audio_tracks; i++)
- {
- audio = hb_list_audio_config_item(job->list_audio, i);
- audio->out.name = strdup(anames[0]);
- }
- }
- /* Audio Track Names */
-
- /* Sanitize passthru (drop/fallback if necessary) */
- for( i = 0; i < hb_list_count( job->list_audio ); )
- {
- audio = hb_list_audio_config_item( job->list_audio, i );
- if( audio->out.codec == HB_ACODEC_AUTO_PASS )
- {
- // Auto Passthru
- job->acodec_copy_mask = allowed_audio_copy == -1 ? HB_ACODEC_PASS_MASK : allowed_audio_copy;
- job->acodec_fallback = hb_audio_encoder_get_from_name(acodec_fallback);
- }
- else if( ( audio->out.codec & HB_ACODEC_PASS_FLAG ) &&
- !( audio->out.codec & audio->in.codec & HB_ACODEC_PASS_MASK ) )
- {
- // passthru fallbacks
- int requested_passthru = audio->out.codec;
- audio->out.codec =
- hb_audio_encoder_get_fallback_for_passthru(requested_passthru);
- if (!(audio->out.codec & HB_ACODEC_MASK))
- {
- // Passthru not possible, drop audio.
- fprintf(stderr,
- "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n",
- audio->out.track);
- hb_audio_t *item = hb_list_item(job->list_audio, i);
- hb_list_rem(job->list_audio, item);
- hb_audio_close(&item);
- continue;
- }
- fprintf(stderr,
- "%s requested and input codec is not compatible for track %d, using %s encoder\n",
- hb_audio_encoder_get_name(requested_passthru), audio->out.track,
- hb_audio_encoder_get_name(audio->out.codec));
- }
- // we didn't drop the track
- i++;
- }
-
- if( subtracks )
- {
- char * token;
- int i;
- int burnpos = 0, defaultpos = 0;
-
- if ( subburn )
- burnpos = strtol( subburn, NULL, 0 );
- if ( subdefault )
- defaultpos = strtol( subdefault, NULL, 0 );
- for ( i = 0; subtracks[i] != NULL; i++ )
- {
- token = subtracks[i];
- if( strcasecmp(token, "scan" ) == 0 )
- {
- int burn = 0, force = 0, def = 0;
-
- if ( subburn != NULL )
- {
- burn = ( i == 0 && subburn[0] == 0 ) ||
- ( burnpos == i+1 );
- }
- if ( subdefault != NULL )
- {
- def = ( i == 0 && subdefault[0] == 0 ) ||
- ( defaultpos == i+1 );
- }
- force = test_sub_list( subforce, i+1 );
-
- if ( !burn )
- {
- job->select_subtitle_config.dest = PASSTHRUSUB;
- }
- else
- {
- if ( sub_burned )
- {
- continue;
- }
- sub_burned = 1;
- }
- job->select_subtitle_config.force = force;
- job->select_subtitle_config.default_track = def;
- subtitle_scan = 1;
- }
- else
- {
- hb_subtitle_t * subtitle;
- hb_subtitle_config_t sub_config;
- int track;
- int burn = 0, force = 0, def = 0;
-
- track = atoi(token) - 1;
- subtitle = hb_list_item(title->list_subtitle, track);
- if( subtitle == NULL )
- {
- fprintf(stderr,
- "Warning: Could not find subtitle track '%s', skipped\n",
- token);
- continue;
- }
- sub_config = subtitle->config;
-
- if ( subburn != NULL )
- {
- burn = ( i == 0 && subburn[0] == 0 ) ||
- ( burnpos == i+1 );
- }
- if ( subdefault != NULL )
- {
- def = ( i == 0 && subdefault[0] == 0 ) ||
- ( defaultpos == i+1 );
- }
-
- force = test_sub_list(subforce, i+1);
-
- int supports_burn = hb_subtitle_can_burn( subtitle->source );
-
- if ( ( burn && supports_burn ) ||
- !hb_subtitle_can_pass( subtitle->source, mux ) )
- {
- // Only allow one subtitle to be burned into video
- if ( sub_burned )
- {
- fprintf( stderr, "Warning: Skipping subtitle track %d, can't have more than one track burnt in\n", track+1 );
- continue;
- }
- sub_burned = 1;
-
- // Mark as burn-in
- sub_config.dest = RENDERSUB;
- }
- else
- {
- sub_config.dest = PASSTHRUSUB;
- }
- sub_config.force = force;
- sub_config.default_track = def;
- hb_subtitle_add( job, &sub_config, track );
- }
- }
- }
-
- if( srtfile )
- {
- int i;
- hb_subtitle_config_t sub_config;
-
- for( i=0; srtfile[i] != NULL; i++ )
- {
- char *codeset = "L1";
- int64_t offset = 0;
- char *lang = "und";
-
- if (srtburn == i + 1 && hb_subtitle_can_burn(SRTSUB))
- {
- // Only allow one subtitle to be burned into video
- if ( sub_burned )
- {
- fprintf( stderr, "Warning: Skipping SRT track %d, can't have more than one track burnt in\n", i+1 );
- continue;
- }
- sub_burned = 1;
-
- // Mark as burn-in
- sub_config.dest = RENDERSUB;
- }
- else
- {
- sub_config.dest = PASSTHRUSUB;
- }
- if( srtcodeset && srtcodeset[i] )
- {
- codeset = srtcodeset[i];
- }
- if( srtoffset && srtoffset[i] )
- {
- offset = strtoll( srtoffset[i], &srtoffset[i], 0 );
- }
- if ( srtlang && srtlang[i] )
- {
- lang = srtlang[i];
- }
- sub_config.default_track = srtdefault == i + 1;
- sub_config.force = 0;
- strncpy( sub_config.src_filename, srtfile[i], 255);
- sub_config.src_filename[255] = 0;
- strncpy( sub_config.src_codeset, codeset, 39);
- sub_config.src_codeset[39] = 0;
- sub_config.offset = offset;
-
- hb_srt_add( job, &sub_config, lang);
- }
- }
-
- if ( sub_burned )
- {
- char * filter_str;
- filter_str = hb_strdup_printf("%d:%d:%d:%d",
- crop[0], crop[1], crop[2], crop[3] );
- filter = hb_filter_init( HB_FILTER_RENDER_SUB );
- hb_add_filter( job, filter, filter_str);
- free( filter_str );
- }
-
- if( native_language )
- {
- audio = hb_list_audio_config_item(job->list_audio, 0);
-
- if( audio )
- {
- if( !cmp_lang( native_language, audio->lang.iso639_2 ) )
- {
- /*
- * Audio language is not the same as our native language.
- * If we have any subtitles in our native language they
- * should be selected here if they haven't already been.
- */
- hb_subtitle_t *subtitle, *subtitle2 = NULL;
- int matched_track = 0;
-
- for( i = 0; i < hb_list_count( title->list_subtitle ); i++ )
- {
- subtitle = hb_list_item( title->list_subtitle, i );
- matched_track = i;
- if (cmp_lang(native_language, subtitle->iso639_2))
- {
- /*
- * Found the first matching subtitle in our
- * native language. Is it already selected?
- */
- for( i = 0; i < hb_list_count( job->list_subtitle ); i++ )
- {
- subtitle2 = hb_list_item( job->list_subtitle, i );
-
- if( subtitle2->track == subtitle->track) {
- /*
- * Already selected
- */
- break;
- }
- subtitle2 = NULL;
- }
-
- if( subtitle2 == NULL )
- {
- /*
- * Not already selected, so select it.
- */
- hb_subtitle_config_t sub_config;
-
- if( native_dub )
- {
- fprintf( stderr, "Warning: no matching audio for native language - using subtitles instead.\n");
- }
- sub_config = subtitle->config;
-
- if ((mux & HB_MUX_MASK_MKV) || subtitle->format == TEXTSUB)
- {
- sub_config.dest = PASSTHRUSUB;
- }
-
- sub_config.force = 0;
- sub_config.default_track = 1;
- hb_subtitle_add( job, &sub_config, matched_track);
- }
- /*
- * Stop searching.
- */
- break;
- }
- }
- }
- }
+ die = 1;
+ return -1;
}
- hb_job_set_file( job, output );
-
- if( color_matrix_code )
+ hb_job_t * job = NULL;
+ job = hb_dict_to_job(h, job_dict);
+ hb_value_free(&job_dict);
+ if (job == NULL)
{
- job->color_matrix_code = color_matrix_code;
- }
-
- hb_job_set_encoder_preset (job, x264_preset);
- hb_job_set_encoder_tune (job, x264_tune);
- hb_job_set_encoder_profile(job, h264_profile);
- hb_job_set_encoder_level (job, h264_level);
-
- if( start_at_preview )
- {
- job->start_at_preview = start_at_preview - 1;
- job->seek_points = preview_count;
- }
-
- if( stop_at_pts )
- {
- job->pts_to_stop = stop_at_pts;
- subtitle_scan = 0;
- }
-
- if( stop_at_frame )
- {
- job->frame_to_stop = stop_at_frame;
- subtitle_scan = 0;
- }
-
- if( start_at_pts )
- {
- job->pts_to_start = start_at_pts;
- subtitle_scan = 0;
- }
-
- if( start_at_frame )
- {
- job->frame_to_start = start_at_frame;
- subtitle_scan = 0;
+ fprintf(stderr, "Error in setting up job! Aborting.\n");
+ die = 1;
+ return -1;
}
- /* OpenCL */
- job->use_opencl = use_opencl;
-
- job->indepth_scan = subtitle_scan;
- job->twopass = twoPass;
- job->fastfirstpass = fastfirstpass;
- hb_job_set_encoder_options(job, advanced_opts);
-
hb_add( h, job );
hb_job_close( &job );
hb_start( h );
@@ -2829,7 +821,7 @@ static int HandleEvents( hb_handle_t * h )
p.pass, p.pass_count, 100.0 * p.progress );
if( p.seconds > -1 )
{
- fprintf( stdout, " (ETA %02dh%02dm%02ds)",
+ fprintf( stdout, " (ETA %02dh%02dm%02ds)",
p.hours, p.minutes, p.seconds );
}
fflush(stdout);
@@ -2911,7 +903,6 @@ void SigHandler( int i_signal )
static void ShowHelp()
{
int i;
- const char *name;
const hb_rate_t *rate;
const hb_dither_t *dither;
const hb_mixdown_t *mixdown;
@@ -2920,45 +911,57 @@ static void ShowHelp()
FILE* const out = stdout;
fprintf( out,
- "Syntax: HandBrakeCLI [options] -i <device> -o <file>\n"
- "\n"
- "### General Handbrake Options------------------------------------------------\n\n"
- " -h, --help Print help\n"
- " -u, --update Check for updates and exit\n"
- " -v, --verbose <#> Be verbose (optional argument: logging level)\n"
- " -Z. --preset <string> Use a built-in preset. Capitalization matters, and\n"
- " if the preset name has spaces, surround it with\n"
- " double quotation marks\n"
- " -z, --preset-list See a list of available built-in presets\n"
- " --no-dvdnav Do not use dvdnav for reading DVDs\n"
- " --no-opencl Disable use of OpenCL\n"
- "\n"
-
- "### Source Options-----------------------------------------------------------\n\n"
- " -i, --input <string> Set input device\n"
- " -t, --title <number> Select a title to encode (0 to scan all titles only,\n"
- " default: 1)\n"
- " --min-duration Set the minimum title duration (in seconds). Shorter\n"
- " titles will not be scanned (default: 10).\n"
- " --scan Scan selected title only.\n"
- " --main-feature Detect and select the main feature title.\n"
- " -c, --chapters <string> Select chapters (e.g. \"1-3\" for chapters\n"
- " 1 to 3, or \"3\" for chapter 3 only,\n"
- " default: all chapters)\n"
- " --angle <number> Select the video angle (DVD or Blu-ray only)\n"
- " --previews <#:B> Select how many preview images are generated,\n"
- " and whether or not they're stored to disk (0 or 1).\n"
- " (default: 10:0)\n"
- " --start-at-preview <#> Start encoding at a given preview.\n"
- " --start-at <unit:#> Start encoding at a given frame, duration (in seconds),\n"
- " or pts (on a 90kHz clock)\n"
- " --stop-at <unit:#> Stop encoding at a given frame, duration (in seconds),\n"
- " or pts (on a 90kHz clock)"
- "\n"
-
- "### Destination Options------------------------------------------------------\n\n"
- " -o, --output <string> Set output file name\n"
- " -f, --format <string> Set output container format (");
+"Syntax: HandBrakeCLI [options] -i <device> -o <file>\n"
+"\n"
+"### General Handbrake Options---------------------------------------------\n\n"
+" -h, --help Print help\n"
+" -u, --update Check for updates and exit\n"
+" -v, --verbose <#> Be verbose (optional argument: logging level)\n"
+" -Z. --preset <string> Use a built-in preset. Capitalization matters,\n"
+" and if the preset name has spaces, surround it\n"
+" with double quotation marks\n"
+" -z, --preset-list See a list of available built-in presets\n"
+" --preset-import-file Import presets from a json preset file.\n"
+" <filespec> 'filespec' may be a list of files separated\n"
+" by spaces, or it may use shell wildcards.\n"
+" --preset-import-gui Import presets from GUI config preset file.\n"
+" --preset-export Create a new preset from command line options and\n"
+" <name> write a json representation of the preset to the\n"
+" console or a file if '--preset-export-file' is\n"
+" specified. The required 'name' argument will be\n"
+" the new preset's name.\n"
+" --preset-export-file Write new preset generated by '--preset-export'\n"
+" <filename> to file 'filename'.\n"
+" --preset-export-description\n"
+" <description> Add a description to the new preset created with\n"
+" '--preset-export'\n"
+" --no-dvdnav Do not use dvdnav for reading DVDs\n"
+" --no-opencl Disable use of OpenCL\n"
+"\n"
+"### Source Options--------------------------------------------------------\n\n"
+" -i, --input <string> Set input device\n"
+" -t, --title <number> Select a title to encode (0 to scan all titles\n"
+" only, default: 1)\n"
+" --min-duration Set the minimum title duration (in seconds).\n"
+" Shorter titles will be ignored (default: 10).\n"
+" --scan Scan selected title only.\n"
+" --main-feature Detect and select the main feature title.\n"
+" -c, --chapters <string> Select chapters (e.g. \"1-3\" for chapters\n"
+" 1 to 3, or \"3\" for chapter 3 only,\n"
+" default: all chapters)\n"
+" --angle <number> Select the video angle (DVD or Blu-ray only)\n"
+" --previews <#:B> Select how many preview images are generated,\n"
+" and whether to store to disk (0 or 1).\n"
+" (default: 10:0)\n"
+" --start-at-preview <#> Start encoding at a given preview.\n"
+" --start-at <unit:#> Start encoding at a given frame, duration\n"
+" (in seconds), or pts (on a 90kHz clock)\n"
+" --stop-at <unit:#> Stop encoding at a given frame, duration\n"
+" (in seconds), or pts (on a 90kHz clock)"
+"\n"
+"### Destination Options---------------------------------------------------\n\n"
+" -o, --output <string> Set output file name\n"
+" -f, --format <string> Set output container format (");
container = NULL;
while ((container = hb_container_get_next(container)) != NULL)
{
@@ -2973,19 +976,23 @@ static void ShowHelp()
}
}
fprintf(out,
- " (default: autodetected from file name)\n"
- " -m, --markers Add chapter markers\n"
- " -O, --optimize Optimize mp4 files for HTTP streaming (\"fast start\")\n"
- " -I, --ipod-atom Mark mp4 files so 5.5G iPods will accept them\n"
- " -P, --use-opencl Use OpenCL where applicable\n"
- " -U, --use-hwd Use DXVA2 hardware decoding\n"
- "\n"
-
-
- "### Video Options------------------------------------------------------------\n\n"
- " -e, --encoder <string> Set video library encoder\n"
- " Options: " );
- name = NULL;
+" (default: autodetected from file name)\n"
+" -m, --markers Add chapter markers\n"
+" --no-markers Disable preset chapter markers\n"
+" -O, --optimize Optimize mp4 files for HTTP streaming\n"
+" (\"fast start\")\n"
+" --no-optimize Disable preset 'optimize'\n"
+" -I, --ipod-atom Mark mp4 files so 5.5G iPods will accept them\n"
+" --no-ipod-atom Disable 5.5G iPod tag\n"
+" -P, --use-opencl Use OpenCL where applicable\n"
+" -U, --use-hwd Use DXVA2 hardware decoding\n"
+" --no-hwd Disable DXVA2 hardware decoding\n"
+"\n"
+
+
+"### Video Options------------------------------------------------------------\n\n"
+" -e, --encoder <string> Set video library encoder\n"
+" Options: " );
encoder = NULL;
while ((encoder = hb_video_encoder_get_next(encoder)) != NULL)
{
@@ -2998,38 +1005,35 @@ static void ShowHelp()
{
fprintf(out, "\n");
}
- if (encoder->codec == vcodec)
- {
- name = encoder->short_name;
- }
}
- fprintf(out, " (default: %s)\n", name);
fprintf(out,
- " --encoder-preset Adjust video encoding settings for a particular\n"
- " <string> speed/efficiency tradeoff (encoder-specific)\n"
- " --encoder-preset-list List supported --encoder-preset values for the\n"
- " <string> specified video encoder\n"
- " --encoder-tune Adjust video encoding settings for a particular\n"
- " <string> type of souce or situation (encoder-specific)\n"
- " --encoder-tune-list List supported --encoder-tune values for the\n"
- " <string> specified video encoder\n"
- " -x, --encopts <string> Specify advanced encoding options in the same\n"
- " style as mencoder (all encoders except theora):\n"
- " option1=value1:option2=value2\n"
- " --encoder-profile Ensures compliance with the requested codec\n"
- " <string> profile (encoder-specific)\n"
- " --encoder-profile-list List supported --encoder-profile values for the\n"
- " <string> specified video encoder\n"
- " --encoder-level Ensures compliance with the requested codec\n"
- " <string> level (encoder-specific)\n"
- " --encoder-level-list List supported --encoder-level values for the\n"
- " <string> specified video encoder\n"
- " -q, --quality <number> Set video quality\n"
- " -b, --vb <kb/s> Set video bitrate (default: 1000)\n"
- " -2, --two-pass Use two-pass mode\n"
- " -T, --turbo When using 2-pass use \"turbo\" options on the\n"
- " 1st pass to improve speed (only works with x264)\n"
- " -r, --rate Set video framerate (" );
+" --encoder-preset Adjust video encoding settings for a particular\n"
+" <string> speed/efficiency tradeoff (encoder-specific)\n"
+" --encoder-preset-list List supported --encoder-preset values for the\n"
+" <string> specified video encoder\n"
+" --encoder-tune Adjust video encoding settings for a particular\n"
+" <string> type of souce or situation (encoder-specific)\n"
+" --encoder-tune-list List supported --encoder-tune values for the\n"
+" <string> specified video encoder\n"
+" -x, --encopts <string> Specify advanced encoding options in the same\n"
+" style as mencoder (all encoders except theora):\n"
+" option1=value1:option2=value2\n"
+" --encoder-profile Ensures compliance with the requested codec\n"
+" <string> profile (encoder-specific)\n"
+" --encoder-profile-list List supported --encoder-profile values for the\n"
+" <string> specified video encoder\n"
+" --encoder-level Ensures compliance with the requested codec\n"
+" <string> level (encoder-specific)\n"
+" --encoder-level-list List supported --encoder-level values for the\n"
+" <string> specified video encoder\n"
+" -q, --quality <number> Set video quality\n"
+" -b, --vb <kb/s> Set video bitrate (default: 1000)\n"
+" -2, --two-pass Use two-pass mode\n"
+" -T, --turbo When using 2-pass use \"turbo\" options on the\n"
+" 1st pass to improve speed\n"
+" (works with x264 and x265)\n"
+" -r, --rate Set video framerate\n"
+" (" );
rate = NULL;
while ((rate = hb_video_framerate_get_next(rate)) != NULL)
{
@@ -3040,27 +1044,39 @@ static void ShowHelp()
}
}
fprintf( out, ")\n"
- " Be aware that not specifying a framerate lets\n"
- " HandBrake preserve a source's time stamps,\n"
- " potentially creating variable framerate video\n"
- " --vfr, --cfr, --pfr Select variable, constant or peak-limited\n"
- " frame rate control. VFR preserves the source\n"
- " timing. CFR makes the output constant rate at\n"
- " the rate given by the -r flag (or the source's\n"
- " average rate if no -r is given). PFR doesn't\n"
- " allow the rate to go over the rate specified\n"
- " with the -r flag but won't change the source\n"
- " timing if it's below that rate.\n"
- " If none of these flags are given, the default\n"
- " is --cfr when -r is given and --vfr otherwise\n"
-
- "\n"
- "### Audio Options-----------------------------------------------------------\n\n"
- " -a, --audio <string> Select audio track(s), separated by commas\n"
- " (\"none\" for no audio, \"1,2,3\" for multiple\n"
- " tracks, default: first one).\n"
- " Multiple output tracks can be used for one input.\n"
- " -E, --aencoder <string> Audio encoder(s):\n" );
+" Be aware that not specifying a framerate lets\n"
+" HandBrake preserve a source's time stamps,\n"
+" potentially creating variable framerate video\n"
+" --vfr, --cfr, --pfr Select variable, constant or peak-limited\n"
+" frame rate control. VFR preserves the source\n"
+" timing. CFR makes the output constant rate at\n"
+" the rate given by the -r flag (or the source's\n"
+" average rate if no -r is given). PFR doesn't\n"
+" allow the rate to go over the rate specified\n"
+" with the -r flag but won't change the source\n"
+" timing if it's below that rate.\n"
+" If none of these flags are given, the default\n"
+" is --cfr when -r is given and --vfr otherwise\n"
+"\n"
+"### Audio Options---------------------------------------------------------\n\n"
+" --audio-lang-list Specifiy a comma separated list of audio\n"
+" <string> languages you would like to select from the\n"
+" source title. By default, the first audio\n"
+" matching each language will be added to your\n"
+" output. Provide the language's iso639-2 code\n"
+" (fre, eng, spa, dut, et cetera)\n"
+" Use code 'und' (Unknown) to match all languages.\n"
+" --all-audio Select all audio tracks matching languages in\n"
+" the specified language list (--audio-lang-list).\n"
+" Any language if list is not specified.\n"
+" --first-audio Select first audio track matching languages in\n"
+" the specified language list (--audio-lang-list).\n"
+" Any language if list is not specified.\n"
+" -a, --audio <string> Select audio track(s), separated by commas\n"
+" (\"none\" for no audio, \"1,2,3\" for multiple\n"
+" tracks, default: first one).\n"
+" Multiple output tracks can be used for one input.\n"
+" -E, --aencoder <string> Audio encoder(s):\n" );
encoder = NULL;
while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
{
@@ -3068,11 +1084,11 @@ static void ShowHelp()
encoder->short_name);
}
fprintf(out,
- " copy:* will passthrough the corresponding\n"
- " audio unmodified to the muxer if it is a\n"
- " supported passthrough audio type.\n"
- " Separated by commas for more than one audio track.\n"
- " Defaults:\n");
+" copy:* will passthrough the corresponding\n"
+" audio unmodified to the muxer if it is a\n"
+" supported passthrough audio type.\n"
+" Separate tracks by commas.\n"
+" Defaults:\n");
container = NULL;
while ((container = hb_container_get_next(container)) != NULL)
{
@@ -3082,9 +1098,9 @@ static void ShowHelp()
hb_audio_encoder_get_short_name(audio_encoder));
}
fprintf(out,
- " --audio-copy-mask Set audio codecs that are permitted when the\n"
- " <string> \"copy\" audio encoder option is specified\n"
- " (" );
+" --audio-copy-mask Set audio codecs that are permitted when the\n"
+" <string> \"copy\" audio encoder option is specified\n"
+" (" );
i = 0;
encoder = NULL;
while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
@@ -3101,20 +1117,19 @@ static void ShowHelp()
fprintf(out, "%s", encoder->short_name + 5);
}
}
- fprintf(out, ", default: all).\n"
- " Separated by commas for multiple allowed options.\n"
- " --audio-fallback Set audio codec to use when it is not possible\n"
- " <string> to copy an audio track without re-encoding.\n"
- " -B, --ab <kb/s> Set audio bitrate(s) (default: depends on the\n"
- " selected codec, mixdown and samplerate)\n"
- " Separated by commas for more than one audio track.\n"
- " -Q, --aq <quality> Set audio quality metric (default: depends on the\n"
- " selected codec)\n"
- " Separated by commas for more than one audio track.\n"
- " -C, --ac <compression> Set audio compression metric (default: depends on the\n"
- " selected codec)\n"
- " Separated by commas for more than one audio track.\n"
- " -6, --mixdown <string> Format(s) for audio downmixing/upmixing:\n");
+ fprintf(out, ")\n"
+" Separated by commas for multiple allowed options.\n"
+" --audio-fallback Set audio codec to use when it is not possible\n"
+" <string> to copy an audio track without re-encoding.\n"
+" -B, --ab <kb/s> Set audio bitrate(s) (default: depends on the\n"
+" selected codec, mixdown and samplerate)\n"
+" Separate tracks by commas.\n"
+" -Q, --aq <quality> Set audio quality metric.\n"
+" Separate tracks by commas.\n"
+" -C, --ac <compression> Set audio compression metric.\n"
+" selected codec)\n"
+" Separate tracks by commas.\n"
+" -6, --mixdown <string> Format(s) for audio downmixing/upmixing:\n");
// skip HB_AMIXDOWN_NONE
mixdown = hb_mixdown_get_next(NULL);
while((mixdown = hb_mixdown_get_next(mixdown)) != NULL)
@@ -3123,8 +1138,8 @@ static void ShowHelp()
mixdown->short_name);
}
fprintf(out,
- " Separated by commas for more than one audio track.\n"
- " Defaults:\n");
+" Separate tracks by commas.\n"
+" Defaults:\n");
encoder = NULL;
while((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
{
@@ -3138,11 +1153,12 @@ static void ShowHelp()
}
}
fprintf(out,
- " --normalize-mix Normalize audio mix levels to prevent clipping.\n"
- " <string> Separated by commas for more than one audio track.\n"
- " 0 = Disable Normalization (default)\n"
- " 1 = Enable Normalization\n"
- " -R, --arate Set audio samplerate(s) (" );
+" --normalize-mix Normalize audio mix levels to prevent clipping.\n"
+" <string> Separate tracks by commas.\n"
+" 0 = Disable Normalization (default)\n"
+" 1 = Enable Normalization\n"
+" -R, --arate Set audio samplerate(s)\n"
+" (" );
rate = NULL;
while ((rate = hb_audio_samplerate_get_next(rate)) != NULL)
{
@@ -3153,18 +1169,21 @@ static void ShowHelp()
}
}
fprintf( out, " kHz)\n"
- " Separated by commas for more than one audio track.\n"
- " -D, --drc <float> Apply extra dynamic range compression to the audio,\n"
- " making soft sounds louder. Range is 1.0 to 4.0\n"
- " (too loud), with 1.5 - 2.5 being a useful range.\n"
- " Separated by commas for more than one audio track.\n"
- " --gain <float> Amplify or attenuate audio before encoding. Does\n"
- " NOT work with audio passthru (copy). Values are in\n"
- " dB. Negative values attenuate, positive values\n"
- " amplify. A 1 dB difference is barely audible.\n"
- " --adither <string> Apply dithering to the audio before encoding.\n"
- " Separated by commas for more than one audio track.\n"
- " Only supported by some encoders (");
+" Separate tracks by commas.\n"
+" -D, --drc <float> Apply extra dynamic range compression to the\n"
+" audio, making soft sounds louder. Range is 1.0\n"
+" to 4.0 (too loud), with 1.5 - 2.5 being a useful\n"
+" range.\n"
+" Separate tracks by commas.\n"
+" --gain <float> Amplify or attenuate audio before encoding. Does\n"
+" NOT work with audio passthru (copy). Values are\n"
+" in dB. Negative values attenuate, positive\n"
+" values amplify. A 1 dB difference is barely\n"
+" audible.\n"
+" --adither <string> Apply dithering to the audio before encoding.\n"
+" Separate tracks by commas.\n"
+" Only supported by some encoders\n"
+" (");
i = 0;
encoder = NULL;
while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
@@ -3197,45 +1216,46 @@ static void ShowHelp()
}
}
fprintf(out,
- " -A, --aname <string> Audio track name(s),\n"
- " Separated by commas for more than one audio track.\n"
- "\n"
-
- "### Picture Settings---------------------------------------------------------\n\n"
- " -w, --width <number> Set picture width\n"
- " -l, --height <number> Set picture height\n"
- " --crop <T:B:L:R> Set cropping values (default: autocrop)\n"
- " --loose-crop <#> Always crop to a multiple of the modulus\n"
- " Specifies the maximum number of extra pixels\n"
- " which may be cropped (default: 15)\n"
- " -Y, --maxHeight <#> Set maximum height\n"
- " -X, --maxWidth <#> Set maximum width\n"
- " --strict-anamorphic Store pixel aspect ratio in video stream\n"
- " --loose-anamorphic Store pixel aspect ratio with specified width\n"
- " --custom-anamorphic Store pixel aspect ratio in video stream and\n"
- " directly control all parameters.\n"
- " --display-width Set the width to scale the actual pixels to\n"
- " <number> at playback, for custom anamorphic.\n"
- " --keep-display-aspect Preserve the source's display aspect ratio\n"
- " when using custom anamorphic\n"
- " --pixel-aspect Set a custom pixel aspect for custom anamorphic\n"
- " <PARX:PARY>\n"
- " (--display-width and --pixel-aspect are mutually\n"
- " exclusive and the former will override the latter)\n"
- " --itu-par Use wider, ITU pixel aspect values for loose and\n"
- " custom anamorphic, useful with underscanned sources\n"
- " --modulus Set the number you want the scaled pixel dimensions\n"
- " <number> to divide cleanly by. Does not affect strict\n"
- " anamorphic mode, which is always mod 2 (default: 16)\n"
- " -M, --color-matrix Set the color space signaled by the output\n"
- " Values: 709, pal, ntsc, 601 (same as ntsc)\n"
- " (default: detected from source)\n"
- "\n"
-
- "### Filters---------------------------------------------------------\n\n"
-
- " -d, --deinterlace Unconditionally deinterlaces all frames\n"
- " <fast/slow/slower/bob");
+" -A, --aname <string> Audio track name(s),\n"
+" Separate tracks by commas.\n"
+"\n"
+"### Picture Settings------------------------------------------------------\n\n"
+" -w, --width <number> Set picture width\n"
+" -l, --height <number> Set picture height\n"
+" --crop <T:B:L:R> Set cropping values (default: autocrop)\n"
+" --loose-crop Always crop to a multiple of the modulus\n"
+" --no-loose-crop Disable preset 'loose-crop'\n"
+" -Y, --maxHeight <#> Set maximum height\n"
+" -X, --maxWidth <#> Set maximum width\n"
+" --non-anamorphic Set pixel aspect ratio to 1:1\n"
+" --strict-anamorphic Store pixel aspect ratio in video stream\n"
+" --loose-anamorphic Store pixel aspect ratio with specified width\n"
+" --custom-anamorphic Store pixel aspect ratio in video stream and\n"
+" directly control all parameters.\n"
+" --display-width Set the width to scale the actual pixels to\n"
+" <number> at playback, for custom anamorphic.\n"
+" --keep-display-aspect Preserve the source's display aspect ratio\n"
+" when using custom anamorphic\n"
+" --no-keep-display-aspect Disable preset 'keep-display-aspect'\n"
+" --pixel-aspect Set a custom pixel aspect for custom anamorphic\n"
+" <PARX:PARY> (--display-width and --pixel-aspect are mutually\n"
+" exclusive.\n"
+" --itu-par Use wider, ITU pixel aspect values for loose and\n"
+" custom anamorphic, useful with underscanned\n"
+" sources\n"
+" --no-itu-par Disable preset 'itu-par'\n"
+" --modulus Set the number you want the scaled pixel\n"
+" dimensions\n"
+" <number> to divide cleanly by. Does not affect strict\n"
+" anamorphic mode, which is always mod 2\n"
+" (default: 16)\n"
+" -M, --color-matrix Set the color space signaled by the output\n"
+" Values: 709, pal, ntsc, 601 (same as ntsc)\n"
+" (default: detected from source)\n"
+"\n"
+"### Filters---------------------------------------------------------------\n\n"
+" -d, --deinterlace Unconditionally deinterlaces all frames\n"
+" <fast/slow/slower/bob");
#ifdef USE_QSV
if (hb_qsv_available())
{
@@ -3244,116 +1264,149 @@ if (hb_qsv_available())
#endif
fprintf( out, "> or omitted (default settings)\n"
" or\n"
- " <YM:FD> (default 0:-1)\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"
- " -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 (--rate 29.97)\n"
- " <L:R:T:B:SB:MP:FD> (default 1:1:4:4:0:0:-1)\n"
- " -8, --denoise 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"
- " --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"
- " --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"
- " --rotate <mode> Rotate image or flip its axes.\n"
- " Modes: (can be combined)\n"
- " 1 vertical flip\n"
- " 2 horizontal flip\n"
- " 4 rotate clockwise 90 degrees\n"
- " Default: 3 (vertical and horizontal flip)\n"
- " -g, --grayscale Grayscale encoding\n"
- "\n"
-
- "### Subtitle Options------------------------------------------------------------\n\n"
- " -s, --subtitle <string> Select subtitle track(s), separated by commas\n"
- " More than one output track can be used for one\n"
- " input.\n"
- " Example: \"1,2,3\" for multiple tracks.\n"
- " A special track name \"scan\" adds an extra 1st pass.\n"
- " This extra pass scans subtitles matching the\n"
- " language of the first audio or the language \n"
- " selected by --native-language.\n"
- " The one that's only used 10 percent of the time\n"
- " or less is selected. This should locate subtitles\n"
- " for short foreign language segments. Best used in\n"
- " conjunction with --subtitle-forced.\n"
- " -F, --subtitle-forced Only display subtitles from the selected stream if\n"
- " <string> the subtitle has the forced flag set. The values in\n"
- " \"string\" are indexes into the subtitle list\n"
- " specified with '--subtitle'.\n"
- " Separated by commas for more than one subtitle track.\n"
- " Example: \"1,2,3\" for multiple tracks.\n"
- " If \"string\" is omitted, the first track is forced.\n"
- " --subtitle-burned \"Burn\" the selected subtitle into the video track\n"
- " <number> If \"number\" is omitted, the first track is burned.\n"
- " \"number\" is an index into the subtitle list\n"
- " specified with '--subtitle'.\n"
- " --subtitle-default Flag the selected subtitle as the default subtitle\n"
- " <number> to be displayed upon playback. Setting no default\n"
- " means no subtitle will be automatically displayed\n"
- " If \"number\" is omitted, the first track is default.\n"
- " \"number\" is an index into the subtitle list\n"
- " specified with '--subtitle'.\n"
- " -N, --native-language Specifiy your language preference. When the first\n"
- " <string> audio track does not match your native language then\n"
- " select the first subtitle that does. When used in\n"
- " conjunction with --native-dub the audio track is\n"
- " changed in preference to subtitles. Provide the\n"
- " language's iso639-2 code (fre, eng, spa, dut, et cetera)\n"
- " --native-dub Used in conjunction with --native-language\n"
- " requests that if no audio tracks are selected the\n"
- " default selected audio track will be the first one\n"
- " that matches the --native-language. If there are no\n"
- " matching audio tracks then the first matching\n"
- " subtitle track is used instead.\n"
- " --srt-file <string> SubRip SRT filename(s), separated by commas.\n"
- " --srt-codeset Character codeset(s) that the SRT file(s) are\n"
- " <string> encoded in, separated by commas.\n"
- " Use 'iconv -l' for a list of valid\n"
- " codesets. If not specified, 'latin1' is assumed\n"
- " --srt-offset Offset (in milliseconds) to apply to the SRT file(s),\n"
- " <string> separated by commas. If not specified, zero is assumed.\n"
- " Offsets may be negative.\n"
- " --srt-lang <string> Language as an iso639-2 code fra, eng, spa et cetera)\n"
- " for the SRT file(s), separated by commas. If not specified,\n"
- " then 'und' is used.\n"
- " --srt-default Flag the selected srt as the default subtitle\n"
- " <number> to be displayed upon playback. Setting no default\n"
- " means no subtitle will be automatically displayed\n"
- " If \"number\" is omitted, the first srt is default.\n"
- " \"number\" is an 1 based index into the srt-file list\n"
- " --srt-burn \"Burn\" the selected srt subtitle into the video track\n"
- " <number> If \"number\" is omitted, the first srt is burned.\n"
- " \"number\" is an 1 based index into the srt-file list\n"
- "\n"
+" <YM:FD> (default 0:-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"
+" -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 (--rate 29.97)\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"
+" --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 <mode> Rotate image or flip its axes.\n"
+" Modes: (can be combined)\n"
+" 0 disable rotate\n"
+" 1 vertical flip\n"
+" 2 horizontal flip\n"
+" 4 rotate clockwise 90 degrees\n"
+" More Examples:\n"
+" 3 horiz + vert (aka rotate 180')\n"
+" 7 horiz + vert + 90' (aka rotate 270')\n"
+" Default: 3 (vertical and horizontal flip)\n"
+" -g, --grayscale Grayscale encoding\n"
+" --no-grayscale Disable preset 'grayscale'\n"
+"\n"
+"### Subtitle Options------------------------------------------------------\n\n"
+" --subtitle-lang-list Specifiy a comma separated list of subtitle\n"
+" <string> languages you would like to select from the\n"
+" source title. By default, the first subtitle\n"
+" matching each language will be added to your\n"
+" output. Provide the language's iso639-2 code\n"
+" (fre, eng, spa, dut, et cetera)\n"
+" --all-subtitles Select all subtitle tracks matching languages in\n"
+" the specified language list\n"
+" (--subtitle-lang-list).\n"
+" Any language if list is not specified.\n"
+" --first-subtitle Select first subtitle track matching languages in\n"
+" the specified language list\n"
+" (--subtitle-lang-list).\n"
+" Any language if list is not specified.\n"
+" -s, --subtitle <string> Select subtitle track(s), separated by commas\n"
+" More than one output track can be used for one\n"
+" input. \"none\" for no subtitles.\n"
+" Example: \"1,2,3\" for multiple tracks.\n"
+" A special track name \"scan\" adds an extra 1st\n"
+" pass. This extra pass scans subtitles matching\n"
+" the language of the first audio or the language \n"
+" selected by --native-language.\n"
+" The one that's only used 10 percent of the time\n"
+" or less is selected. This should locate subtitles\n"
+" for short foreign language segments. Best used in\n"
+" conjunction with --subtitle-forced.\n"
+" -F, --subtitle-forced Only display subtitles from the selected stream\n"
+" <string> if the subtitle has the forced flag set. The\n"
+" values in \"string\" are indexes into the\n"
+" subtitle list specified with '--subtitle'.\n"
+" Separate tracks by commas.\n"
+" Example: \"1,2,3\" for multiple tracks.\n"
+" If \"string\" is omitted, the first track is\n"
+" forced.\n"
+" --subtitle-burned \"Burn\" the selected subtitle into the video\n"
+" <subtitle> track. If \"subtitle\" is omitted, the first\n"
+" track is burned. \"subtitle\" is an index into\n"
+" the subtitle list specified with '--subtitle'\n"
+" or \"native\" to burn the subtitle track that may\n"
+" be added by the 'native-language' option.\n"
+" --subtitle-default Flag the selected subtitle as the default\n"
+" <number> subtitle to be displayed upon playback. Setting\n"
+" no default means no subtitle will be displayed\n"
+" automatically. \"number\" is an index into the\n"
+" subtitle list specified with '--subtitle'.\n"
+" -N, --native-language Specifiy your language preference. When the first\n"
+" <string> audio track does not match your native language\n"
+" then select the first subtitle that does. When\n"
+" used in conjunction with --native-dub the audio\n"
+" track is changed in preference to subtitles.\n"
+" Provide the language's iso639-2 code:\n"
+" (fre, eng, spa, dut, et cetera)\n"
+" --native-dub Used in conjunction with --native-language\n"
+" requests that if no audio tracks are selected the\n"
+" default selected audio track will be the first\n"
+" one that matches the --native-language. If there\n"
+" are no matching audio tracks then the first\n"
+" matching subtitle track is used instead.\n"
+" --srt-file <string> SubRip SRT filename(s), separated by commas.\n"
+" --srt-codeset Character codeset(s) that the SRT file(s) are\n"
+" <string> encoded in, separated by commas.\n"
+" Use 'iconv -l' for a list of valid\n"
+" codesets. If not specified, 'latin1' is assumed\n"
+" --srt-offset Offset (in milliseconds) to apply to the SRT\n"
+" <string> file(s), separated by commas. If not specified,\n"
+" zero is assumed. Offsets may be negative.\n"
+" --srt-lang <string> SRT track language as an iso639-2 code:\n"
+" (fre, eng, spa, dut, et cetera)\n"
+" Separated by commas. If not specified, then 'und'\n"
+" is used.\n"
+" --srt-default Flag the selected srt as the default subtitle\n"
+" <number> to be displayed upon playback. Setting no default\n"
+" means no subtitle will be automatically displayed\n"
+" If \"number\" is omitted, the first SRT is the\n"
+" default. \"number\" is an 1 based index into the\n"
+" 'srt-file' list\n"
+" --srt-burn \"Burn\" the selected SRT subtitle into the\n"
+" <number> video track. If \"number\" is omitted, the first\n"
+" SRT is burned. \"number\" is an 1 based index\n"
+" into the 'srt-file' list\n"
+"\n"
);
#ifdef USE_QSV
if (hb_qsv_available())
{
fprintf( out,
- "### Intel Quick Sync Video------------------------------------------------------\n\n"
- " --disable-qsv-decoding Force software decoding of the video track.\n"
- " --qsv-async-depth Specifies how many asynchronous operations should be\n"
- " performed before the result is explicitly synchronized.\n"
- " Default: 4. If zero, the value is not specified.\n"
- "\n"
+"### Intel Quick Sync Video------------------------------------------------\n\n"
+" --disable-qsv-decoding Force software decoding of the video track.\n"
+" --enable-qsv-decoding Allow QSV hardware decoding of the video track.\n"
+" --qsv-async-depth Specifies how many asynchronous operations\n"
+" should be performed before the result is\n"
+" explicitly synchronized.\n"
+" Default: 4. If zero, the value is not specified.\n"
+"\n"
);
}
#endif
@@ -3362,26 +1415,141 @@ if (hb_qsv_available())
/****************************************************************************
* ShowPresets:
****************************************************************************/
-static void ShowPresets()
+static const char *
+reverse_search_char(const char *front, const char *back, char delim)
{
- fprintf( stderr, "%s - %s - %s\n", HB_PROJECT_TITLE, HB_PROJECT_BUILD_TITLE, HB_PROJECT_URL_WEBSITE );
-
- printf("\n< Devices\n");
- printf("\n + Universal: -e x264 -q 20.0 -r 30 --pfr -a 1,1 -E ffaac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 720 -Y 576 --loose-anamorphic --modulus 2 -m --x264-preset fast --h264-profile baseline --h264-level 3.0\n");
- printf("\n + iPod: -e x264 -q 22.0 -r 30 --pfr -a 1 -E ffaac -B 160 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -I -X 320 -Y 240 --modulus 2 -m --x264-preset medium --h264-profile baseline --h264-level 1.3\n");
- printf("\n + iPhone & iPod touch: -e x264 -q 22.0 -r 30 --pfr -a 1 -E ffaac -B 160 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 960 -Y 640 --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 3.1\n");
- printf("\n + iPad: -e x264 -q 20.0 -r 30 --pfr -a 1 -E ffaac -B 160 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1280 -Y 720 --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 3.1\n");
- printf("\n + AppleTV: -e x264 -q 20.0 -r 30 --pfr -a 1,1 -E ffaac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 960 -Y 720 --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 3.1 -x qpmin=4:cabac=0:ref=2:b-pyramid=none:weightb=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500\n");
- printf("\n + AppleTV 2: -e x264 -q 20.0 -r 30 --pfr -a 1,1 -E ffaac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1280 -Y 720 --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 3.1\n");
- printf("\n + AppleTV 3: -e x264 -q 20.0 -r 30 --pfr -a 1,1 -E ffaac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1920 -Y 1080 --decomb=fast --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 4.0\n");
- printf("\n + Android: -e x264 -q 22.0 -r 30 --pfr -a 1 -E ffaac -B 128 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 720 -Y 576 --loose-anamorphic --modulus 2 --x264-preset medium --h264-profile main --h264-level 3.0\n");
- printf("\n + Android Tablet: -e x264 -q 22.0 -r 30 --pfr -a 1 -E ffaac -B 128 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1280 -Y 720 --loose-anamorphic --modulus 2 --x264-preset medium --h264-profile main --h264-level 3.1\n");
- printf("\n + Windows Phone 8: -e x264 -q 22.0 -r 30 --pfr -a 1 -E ffaac -B 128 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1280 -Y 720 --modulus 2 --x264-preset medium --h264-profile main --h264-level 3.1\n");
- printf("\n>\n");
- printf("\n< Regular\n");
- printf("\n + Normal: -e x264 -q 20.0 -a 1 -E ffaac -B 160 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 --loose-anamorphic --modulus 2 -m --x264-preset veryfast --h264-profile main --h264-level 4.0\n");
- printf("\n + High Profile: -e x264 -q 20.0 -a 1,1 -E ffaac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 --decomb --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 4.1\n");
- printf("\n>\n");
+ while (back != front && *back != delim)
+ back--;
+ return back;
+}
+
+#if defined( __MINGW32__ )
+static char * my_strndup(const char *src, int len)
+{
+ int src_len = strlen(src);
+ int alloc = src_len < len ? src_len + 1 : len + 1;
+ char *result = malloc(alloc);
+ strncpy(result, src, alloc - 1);
+ result[alloc - 1] = 0;
+ return result;
+}
+#else
+#define my_strndup strndup
+#endif
+
+static char** str_width_split( const char *str, int width )
+{
+ const char * pos;
+ const char * end;
+ char ** ret;
+ int count, ii;
+ int len;
+ char delem = ' ';
+
+ if ( str == NULL || str[0] == 0 )
+ {
+ ret = malloc( sizeof(char*) );
+ *ret = NULL;
+ return ret;
+ }
+
+ len = strlen(str);
+
+ // Find number of elements in the string
+ count = 1;
+ pos = str;
+ end = pos + width;
+ while (end < str + len)
+ {
+ end = reverse_search_char(pos, end, delem);
+ if (end == pos)
+ {
+ // Shouldn't happen for reasonable input
+ break;
+ }
+ count++;
+ pos = end + 1;
+ end = pos + width;
+ }
+ count++;
+ ret = calloc( ( count + 1 ), sizeof(char*) );
+
+ pos = str;
+ end = pos + width;
+ for (ii = 0; ii < count - 1 && end < str + len; ii++)
+ {
+ end = reverse_search_char(pos, end, delem);
+ if (end == pos)
+ {
+ break;
+ }
+ ret[ii] = my_strndup(pos, end - pos);
+ pos = end + 1;
+ end = pos + width;
+ }
+ if (*pos != 0 && ii < count - 1)
+ {
+ ret[ii] = my_strndup(pos, width);
+ }
+
+ return ret;
+}
+
+static void Indent(FILE *f, char *whitespace, int indent)
+{
+ int ii;
+ for (ii = 0; ii < indent; ii++)
+ {
+ fprintf(f, "%s", whitespace);
+ }
+}
+
+static void ShowPresets(hb_value_array_t *presets, int indent, int descriptions)
+{
+ if (presets == NULL)
+ presets = hb_presets_get();
+
+ int count = hb_value_array_len(presets);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ const char *name;
+ hb_dict_t *preset_dict = hb_value_array_get(presets, ii);
+ name = hb_value_get_string(hb_dict_get(preset_dict, "PresetName"));
+ Indent(stderr, " ", indent);
+ if (hb_value_get_bool(hb_dict_get(preset_dict, "Folder")))
+ {
+ indent++;
+ fprintf(stderr, "%s/\n", name);
+ hb_value_array_t *children;
+ children = hb_dict_get(preset_dict, "ChildrenArray");
+ if (children == NULL)
+ continue;
+ ShowPresets(children, indent, descriptions);
+ indent--;
+ }
+ else
+ {
+ fprintf(stderr, "%s\n", name);
+ if (descriptions)
+ {
+ const char *desc;
+ desc = hb_value_get_string(hb_dict_get(preset_dict,
+ "PresetDescription"));
+ if (desc != NULL && desc[0] != 0)
+ {
+ int ii;
+ char **split = str_width_split(desc, 60);
+ for (ii = 0; split[ii] != NULL; ii++)
+ {
+ Indent(stderr, " ", indent+1);
+ fprintf(stderr, "%s\n", split[ii]);
+ }
+ str_vfree(split);
+ }
+ }
+ }
+ }
}
static char* strchr_quote(char *pos, char c, char q)
@@ -3434,6 +1602,15 @@ static char *strndup_quote(char *str, char q, int len)
return res;
}
+static int str_vlen(char **strv)
+{
+ int i;
+ if (strv == NULL)
+ return 0;
+ for (i = 0; strv[i]; i++);
+ return i;
+}
+
static char** str_split( char *str, char delem )
{
char * pos;
@@ -3510,7 +1687,7 @@ static double parse_hhmmss_strtok()
****************************************************************************/
static int ParseOptions( int argc, char ** argv )
{
-
+
#define PREVIEWS 257
#define START_AT_PREVIEW 258
#define START_AT 259
@@ -3546,7 +1723,6 @@ static int ParseOptions( int argc, char ** argv )
#define ENCODER_PROFILE_LIST 289
#define ENCODER_LEVEL 290
#define ENCODER_LEVEL_LIST 291
- #define NO_OPENCL 292
#define NORMALIZE_MIX 293
#define AUDIO_DITHER 294
#define QSV_BASELINE 295
@@ -3554,6 +1730,13 @@ static int ParseOptions( int argc, char ** argv )
#define QSV_IMPLEMENTATION 297
#define FILTER_NLMEANS 298
#define FILTER_NLMEANS_TUNE 299
+ #define AUDIO_LANG_LIST 300
+ #define SUBTITLE_LANG_LIST 301
+ #define PRESET_EXPORT 302
+ #define PRESET_EXPORT_DESC 303
+ #define PRESET_EXPORT_FILE 304
+ #define PRESET_IMPORT 305
+ #define PRESET_IMPORT_GUI 306
for( ;; )
{
@@ -3563,22 +1746,26 @@ static int ParseOptions( int argc, char ** argv )
{ "update", no_argument, NULL, 'u' },
{ "verbose", optional_argument, NULL, 'v' },
{ "no-dvdnav", no_argument, NULL, DVDNAV },
- { "no-opencl", no_argument, NULL, NO_OPENCL },
+ { "no-opencl", no_argument, &use_opencl, 0 },
#ifdef USE_QSV
{ "qsv-baseline", no_argument, NULL, QSV_BASELINE, },
{ "qsv-async-depth", required_argument, NULL, QSV_ASYNC_DEPTH, },
{ "qsv-implementation", required_argument, NULL, QSV_IMPLEMENTATION, },
{ "disable-qsv-decoding", no_argument, &qsv_decode, 0, },
+ { "enable-qsv-decoding", no_argument, &qsv_decode, 1, },
#endif
{ "format", required_argument, NULL, 'f' },
{ "input", required_argument, NULL, 'i' },
{ "output", required_argument, NULL, 'o' },
- { "optimize", no_argument, NULL, 'O' },
- { "ipod-atom", no_argument, NULL, 'I' },
- { "use-opencl", no_argument, NULL, 'P' },
- { "use-hwd", no_argument, NULL, 'U' },
+ { "optimize", no_argument, &mp4_optimize, 1 },
+ { "no-optimize", no_argument, &mp4_optimize, 0 },
+ { "ipod-atom", no_argument, &ipod_atom, 1 },
+ { "no-ipod-atom",no_argument, &ipod_atom, 0 },
+ { "use-opencl", no_argument, &use_opencl, 1 },
+ { "use-hwd", no_argument, &use_hwd, 1 },
+ { "no-hwd", no_argument, &use_hwd, 0 },
{ "title", required_argument, NULL, 't' },
{ "min-duration",required_argument, NULL, MIN_DURATION },
@@ -3587,12 +1774,19 @@ static int ParseOptions( int argc, char ** argv )
{ "chapters", required_argument, NULL, 'c' },
{ "angle", required_argument, NULL, ANGLE },
{ "markers", optional_argument, NULL, 'm' },
+ { "no-markers", no_argument, &chapter_markers, 0 },
+ { "audio-lang-list", required_argument, NULL, AUDIO_LANG_LIST },
+ { "all-audio", no_argument, &audio_all, 1 },
+ { "first-audio", no_argument, &audio_all, 0 },
{ "audio", required_argument, NULL, 'a' },
{ "mixdown", required_argument, NULL, '6' },
{ "normalize-mix", required_argument, NULL, NORMALIZE_MIX },
{ "drc", required_argument, NULL, 'D' },
{ "gain", required_argument, NULL, AUDIO_GAIN },
{ "adither", required_argument, NULL, AUDIO_DITHER },
+ { "subtitle-lang-list", required_argument, NULL, SUBTITLE_LANG_LIST },
+ { "all-subtitles", no_argument, &subtitle_all, 1 },
+ { "first-subtitle", no_argument, &subtitle_all, 0 },
{ "subtitle", required_argument, NULL, 's' },
{ "subtitle-forced", optional_argument, NULL, 'F' },
{ "subtitle-burned", optional_argument, NULL, SUB_BURNED },
@@ -3609,26 +1803,38 @@ static int ParseOptions( int argc, char ** argv )
{ "aencoder", required_argument, NULL, 'E' },
{ "two-pass", no_argument, NULL, '2' },
{ "deinterlace", optional_argument, NULL, 'd' },
+ { "no-deinterlace", no_argument, &deinterlace_disable, 1 },
{ "deblock", optional_argument, NULL, '7' },
+ { "no-deblock", no_argument, &deblock_disable, 1 },
{ "denoise", optional_argument, NULL, '8' },
+ { "hqdn3d", optional_argument, NULL, '8' },
+ { "no-hqdn3d", no_argument, &hqdn3d_disable, 1 },
{ "nlmeans", optional_argument, NULL, FILTER_NLMEANS },
+ { "no-nlmeans", no_argument, &nlmeans_disable, 1 },
{ "nlmeans-tune",required_argument, NULL, FILTER_NLMEANS_TUNE },
{ "detelecine", optional_argument, NULL, '9' },
+ { "no-detelecine", no_argument, &detelecine_disable, 1 },
{ "decomb", optional_argument, NULL, '5' },
- { "grayscale", no_argument, NULL, 'g' },
+ { "no-decomb", no_argument, &decomb_disable, 1 },
+ { "grayscale", no_argument, &grayscale, 1 },
+ { "no-grayscale",no_argument, &grayscale, 0 },
{ "rotate", optional_argument, NULL, ROTATE_FILTER },
+ { "non-anamorphic", no_argument, &anamorphic_mode, 0 },
{ "strict-anamorphic", no_argument, &anamorphic_mode, 1 },
{ "loose-anamorphic", no_argument, &anamorphic_mode, 2 },
{ "custom-anamorphic", no_argument, &anamorphic_mode, 3 },
{ "display-width", required_argument, NULL, DISPLAY_WIDTH },
- { "keep-display-aspect", no_argument, &keep_display_aspect, 1 },
+ { "keep-display-aspect", optional_argument, NULL, KEEP_DISPLAY_ASPECT },
+ { "no-keep-display-aspect", no_argument, &keep_display_aspect, 0 },
{ "pixel-aspect", required_argument, NULL, PIXEL_ASPECT },
{ "modulus", required_argument, NULL, MODULUS },
{ "itu-par", no_argument, &itu_par, 1 },
+ { "no-itu-par", no_argument, &itu_par, 0 },
{ "width", required_argument, NULL, 'w' },
{ "height", required_argument, NULL, 'l' },
{ "crop", required_argument, NULL, 'n' },
{ "loose-crop", optional_argument, NULL, LOOSE_CROP },
+ { "no-loose-crop", no_argument, &loose_crop, 0 },
// mapping of legacy option names for backwards compatibility
{ "qsv-preset", required_argument, NULL, ENCODER_PRESET, },
@@ -3664,6 +1870,11 @@ static int ParseOptions( int argc, char ** argv )
{ "maxWidth", required_argument, NULL, 'X' },
{ "preset", required_argument, NULL, 'Z' },
{ "preset-list", no_argument, NULL, 'z' },
+ { "preset-import-file", no_argument, NULL, PRESET_IMPORT },
+ { "preset-import-gui", no_argument, NULL, PRESET_IMPORT_GUI },
+ { "preset-export", required_argument, NULL, PRESET_EXPORT },
+ { "preset-export-file", required_argument, NULL, PRESET_EXPORT_FILE },
+ { "preset-export-description", required_argument, NULL, PRESET_EXPORT_DESC },
{ "aname", required_argument, NULL, 'A' },
{ "color-matrix",required_argument, NULL, 'M' },
@@ -3715,12 +1926,37 @@ static int ParseOptions( int argc, char ** argv )
}
break;
case 'Z':
- preset = 1;
preset_name = strdup(optarg);
break;
case 'z':
- ShowPresets();
+ ShowPresets(NULL, 0, 1);
exit ( 0 );
+ case PRESET_EXPORT:
+ preset_export_name = strdup(optarg);
+ break;
+ case PRESET_EXPORT_DESC:
+ preset_export_desc = strdup(optarg);
+ break;
+ case PRESET_EXPORT_FILE:
+ preset_export_file = strdup(optarg);
+ break;
+ case PRESET_IMPORT:
+ {
+ // Import list of preset files
+ while (optind < argc && argv[optind][0] != '-')
+ {
+ int result = hb_presets_add_path(argv[optind]);
+ if (result != 0)
+ {
+ fprintf(stderr, "Preset import failed, file (%s)\n",
+ argv[optind]);
+ }
+ optind++;
+ }
+ } break;
+ case PRESET_IMPORT_GUI:
+ hb_presets_gui_init();
+ break;
case DVDNAV:
dvdnav = 0;
break;
@@ -3732,7 +1968,7 @@ static int ParseOptions( int argc, char ** argv )
input = strdup( optarg );
#ifdef __APPLE_CC__
char *devName = bsd_name_for_path( input ); // alloc
- if( devName )
+ if( devName != NULL )
{
if( device_is_dvd( devName ))
{
@@ -3747,19 +1983,6 @@ static int ParseOptions( int argc, char ** argv )
case 'o':
output = strdup( optarg );
break;
- case 'O':
- mp4_optimize = 1;
- break;
- case 'I':
- ipod_atom = 1;
- break;
- case 'P':
- use_opencl = 1;
- break;
- case 'U':
- use_hwd = 1;
- break;
-
case 't':
titleindex = atoi( optarg );
break;
@@ -3784,15 +2007,12 @@ static int ParseOptions( int argc, char ** argv )
}
else
{
- fprintf( stderr, "chapters: invalid syntax (%s)\n",
+ fprintf( stderr, "chapters: Invalid syntax (%s)\n",
optarg );
return -1;
}
break;
}
- case NO_OPENCL:
- use_opencl = 0;
- break;
case ANGLE:
angle = atoi( optarg );
break;
@@ -3803,33 +2023,38 @@ static int ParseOptions( int argc, char ** argv )
}
chapter_markers = 1;
break;
+ case AUDIO_LANG_LIST:
+ audio_lang_list = str_split(optarg, ',');
+ break;
+ case SUBTITLE_LANG_LIST:
+ subtitle_lang_list = str_split(optarg, ',');
+ break;
case 'a':
if( optarg != NULL )
{
- atracks = strdup( optarg );
- audio_explicit = 1;
+ atracks = str_split(optarg, ',');
}
else
{
- atracks = "1" ;
+ atracks = str_split("1", ',');
}
break;
case '6':
if( optarg != NULL )
{
- mixdowns = strdup( optarg );
+ mixdowns = str_split(optarg, ',');
}
break;
case 'D':
if( optarg != NULL )
{
- dynamic_range_compression = strdup( optarg );
+ dynamic_range_compression = str_split(optarg, ',');
}
break;
case AUDIO_GAIN:
if( optarg != NULL )
{
- audio_gain = strdup( optarg );
+ audio_gain = str_split(optarg, ',');
}
break;
case AUDIO_DITHER:
@@ -3839,10 +2064,7 @@ static int ParseOptions( int argc, char ** argv )
}
break;
case NORMALIZE_MIX:
- if( optarg != NULL )
- {
- normalize_mix_level = str_split( optarg, ',' );
- }
+ normalize_mix_level = str_split(optarg, ',');
break;
case 's':
subtracks = str_split( optarg, ',' );
@@ -3851,28 +2073,52 @@ static int ParseOptions( int argc, char ** argv )
subforce = str_split( optarg, ',' );
break;
case SUB_BURNED:
- if( optarg != NULL )
+ if (optarg != NULL)
{
- subburn = strdup( optarg );
+ if (!strcasecmp(optarg, "native") ||
+ !strcasecmp(optarg, "scan"))
+ subburn_native = 1;
+ else
+ {
+ subburn = strtol(optarg, NULL, 0);
+ }
}
else
{
- subburn = "" ;
+ subburn = 1;
+ }
+ if (subburn > 0)
+ {
+ if (subtracks != NULL && str_vlen(subtracks) >= subburn &&
+ !strcasecmp("scan", subtracks[subburn-1]))
+ {
+ subburn_native = 1;
+ }
}
break;
case SUB_DEFAULT:
- if( optarg != NULL )
+ if (optarg != NULL)
{
- subdefault = strdup( optarg );
+ subdefault = strtol(optarg, NULL, 0);
}
else
{
- subdefault = "" ;
+ subdefault = 1;
}
break;
case 'N':
- native_language = strdup( optarg );
- break;
+ {
+ const iso639_lang_t *lang = lang_lookup(optarg);
+ if (lang != NULL)
+ {
+ native_language = strdup(lang->iso639_2);
+ }
+ else
+ {
+ fprintf(stderr, "Invalid native language (%s)\n", optarg);
+ return -1;
+ }
+ } break;
case NATIVE_DUB:
native_dub = 1;
break;
@@ -3912,129 +2158,123 @@ static int ParseOptions( int argc, char ** argv )
twoPass = 1;
break;
case 'd':
- if( optarg != NULL )
+ free(deinterlace);
+ if (optarg != NULL)
{
- if (!( strcmp( optarg, "fast" ) ))
- {
- deinterlace_opt = "0";
- }
- else if (!( strcmp( optarg, "slow" ) ))
- {
- deinterlace_opt = "1";
- }
- else if (!( strcmp( optarg, "slower" ) ))
- {
- deinterlace_opt = "3";
- }
- else if (!( strcmp( optarg, "bob" ) ))
- {
- deinterlace_opt = "15";
- }
- else
- {
- deinterlace_opt = strdup( optarg );
- }
+ deinterlace = strdup(optarg);
+ }
+ else
+ {
+ deinterlace = strdup("default");
}
- deinterlace = 1;
break;
case '7':
+ free(deblock);
if( optarg != NULL )
{
- deblock_opt = strdup( optarg );
+ deblock = strdup(optarg);
+ }
+ else
+ {
+ deblock = strdup("5");
}
- deblock = 1;
break;
case '8':
- if( optarg != NULL )
+ free(hqdn3d);
+ if (optarg != NULL)
+ {
+ hqdn3d = strdup(optarg);
+ }
+ else
{
- free(denoise_opt);
- denoise_opt = strdup( optarg );
+ hqdn3d = strdup("default");
}
- denoise = 1;
break;
case FILTER_NLMEANS:
+ free(nlmeans);
if (optarg != NULL)
{
- free(nlmeans_opt);
- nlmeans_opt = strdup(optarg);
+ nlmeans = strdup(optarg);
+ }
+ else
+ {
+ nlmeans = strdup("light");
}
- nlmeans = 1;
break;
case FILTER_NLMEANS_TUNE:
+ free(nlmeans_tune);
+ nlmeans_tune = strdup(optarg);
+ break;
+ case '9':
+ free(detelecine);
if (optarg != NULL)
{
- free(nlmeans_tune_opt);
- nlmeans_tune_opt = strdup(optarg);
+ detelecine = strdup(optarg);
}
- break;
- case '9':
- if( optarg != NULL )
+ else
{
- detelecine_opt = strdup( optarg );
+ detelecine = strdup("default");
}
- detelecine = 1;
break;
case '5':
- if( optarg != NULL )
+ free(decomb);
+ if (optarg != NULL)
{
- if (!( strcmp( optarg, "fast" ) ))
- {
- decomb_opt = "7:2:6:9:1:80";
- }
- else if (!( strcmp( optarg, "bob" ) ))
- {
- decomb_opt = "455";
- }
- else
- {
- decomb_opt = strdup( optarg );
- }
+ decomb = strdup(optarg);
+ }
+ else
+ {
+ decomb = strdup("default");
}
- decomb = 1;
- break;
- case 'g':
- grayscale = 1;
break;
case ROTATE_FILTER:
+ free(rotate);
+ if (optarg != NULL)
+ {
+ rotate = strdup(optarg);
+ }
+ else
+ {
+ rotate = strdup("3");
+ }
+ break;
+ case KEEP_DISPLAY_ASPECT:
if( optarg != NULL )
{
- rotate_opt = strdup( optarg );
- rotate_val = atoi( optarg );
+ keep_display_aspect = atoi(optarg);
+ }
+ else
+ {
+ keep_display_aspect = 1;
}
- rotate = 1;
break;
case DISPLAY_WIDTH:
if( optarg != NULL )
{
- sscanf( optarg, "%i", &display_width );
+ display_width = atoi(optarg);
}
break;
case PIXEL_ASPECT:
if( optarg != NULL )
{
- sscanf( optarg, "%i:%i", &par_width, &par_height );
+ sscanf(optarg, "%i:%i", &par_width, &par_height);
}
break;
case MODULUS:
if( optarg != NULL )
{
- sscanf( optarg, "%i", &modulus );
+ modulus = atoi(optarg);
}
break;
case 'e':
{
- vcodec = hb_video_encoder_get_from_name(optarg);
- if (vcodec <= 0)
- {
- fprintf(stderr, "invalid codec (%s)\n", optarg);
- return -1;
- }
+ vcodec = strdup(optarg);
break;
}
case 'E':
if( optarg != NULL )
{
- acodecs = strdup( optarg );
+ acodecs = str_split(optarg, ',');
}
break;
case 'w':
@@ -4057,27 +2297,22 @@ static int ParseOptions( int argc, char ** argv )
break;
}
case LOOSE_CROP:
- loose_crop = optarg ? atoi(optarg) : 15;
+ if (optarg != NULL)
+ loose_crop = atoi(optarg);
+ else
+ loose_crop = 1;
break;
case 'r':
{
- vrate = hb_video_framerate_get_from_name(optarg);
- if (vrate <= 0)
- {
- vrate = 0;
- fprintf(stderr, "invalid framerate %s\n", optarg);
- }
- else if (!cfr)
+ vrate = strdup(optarg);
+ if (!cfr)
{
cfr = 1;
}
break;
}
case 'R':
- if( optarg != NULL )
- {
- arates = strdup( optarg );
- }
+ arates = str_split( optarg, ',' );
break;
case 'b':
vbitrate = atoi( optarg );
@@ -4095,19 +2330,19 @@ static int ParseOptions( int argc, char ** argv )
acompressions = str_split( optarg, ',' );
break;
case ENCODER_PRESET:
- x264_preset = strdup( optarg );
+ encoder_preset = strdup( optarg );
break;
case ENCODER_TUNE:
- x264_tune = strdup( optarg );
+ encoder_tune = strdup( optarg );
break;
case 'x':
advanced_opts = strdup( optarg );
break;
case ENCODER_PROFILE:
- h264_profile = strdup( optarg );
+ encoder_profile = strdup( optarg );
break;
case ENCODER_LEVEL:
- h264_level = strdup( optarg );
+ encoder_level = strdup( optarg );
break;
case ENCODER_PRESET_LIST:
fprintf(stderr, "Available --encoder-preset values for '%s' encoder:\n",
@@ -4208,31 +2443,7 @@ static int ParseOptions( int argc, char ** argv )
}
case ALLOWED_AUDIO_COPY:
{
- allowed_audio_copy = 0;
- const hb_encoder_t *audio_encoder = NULL;
- char **allowed = str_split(optarg, ',');
-
- while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
- {
- if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) &&
- (audio_encoder->codec != HB_ACODEC_AUTO_PASS))
- {
- int i = -1;
- while(allowed[++i] != NULL)
- {
- // skip "copy:"
- if (!strcasecmp(allowed[i],
- audio_encoder->short_name + 5))
- {
- allowed_audio_copy |= audio_encoder->codec;
- break;
- }
- }
- }
- }
-
- allowed_audio_copy &= HB_ACODEC_PASS_MASK;
- str_vfree(allowed);
+ audio_copy_list = str_split(optarg, ',');
break;
}
case AUDIO_FALLBACK:
@@ -4270,37 +2481,144 @@ static int ParseOptions( int argc, char ** argv )
}
- if (nlmeans)
+ if (deblock != NULL)
{
- char *opt = hb_generate_filter_settings(HB_FILTER_NLMEANS,
- nlmeans_opt, nlmeans_tune_opt);
- if (opt != NULL)
+ if (deblock_disable)
{
- free(nlmeans_opt);
- nlmeans_opt = opt;
+ fprintf(stderr,
+ "Incompatible options --deblock and --no-deblock\n");
+ return -1;
}
- else if (nlmeans_opt != NULL)
+ if (hb_validate_filter_settings(HB_FILTER_DEBLOCK, deblock))
+ {
+ fprintf(stderr, "Invalid deblock option %s\n", deblock);
+ return -1;
+ }
+ }
+
+ if (detelecine != NULL)
+ {
+ if (detelecine_disable)
{
- fprintf(stderr, "Invalid parameters for nlmeans (%s).", nlmeans_opt);
+ fprintf(stderr,
+ "Incompatible options --detelecine and --no-detelecine\n");
return -1;
}
- else if (nlmeans_tune_opt != NULL)
+ if (!hb_validate_filter_preset(HB_FILTER_DETELECINE,
+ detelecine, NULL))
{
- fprintf(stdout, "Default nlmeans parameters specified; ignoring nlmeans tune (%s).\n", nlmeans_tune_opt);
+ // 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))
+ {
+ detelecine_custom = 1;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid detelecine option %s\n", detelecine);
+ return -1;
}
}
- if (denoise)
+
+ if (deinterlace != NULL)
{
- char *opt = hb_generate_filter_settings(HB_FILTER_DENOISE,
- denoise_opt, NULL);
- if (opt != NULL)
+ if (deinterlace_disable)
+ {
+ fprintf(stderr,
+ "Incompatible options --deinterlace and --no-deinterlace\n");
+ return -1;
+ }
+ if (!hb_validate_filter_preset(HB_FILTER_DEINTERLACE,
+ deinterlace, NULL))
{
- free(denoise_opt);
- denoise_opt = opt;
+ // Nothing to do, but must validate preset before
+ // attempting to validate custom settings to prevent potential
+ // false positive
}
- else if (denoise_opt != NULL)
+ else if (!hb_validate_filter_settings(HB_FILTER_HQDN3D, deinterlace))
{
- fprintf(stderr, "Invalid parameters for hqdn3d (%s).", denoise_opt);
+ deinterlace_custom = 1;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid deinterlace option %s\n", deinterlace);
+ return -1;
+ }
+ }
+
+ if (decomb != NULL)
+ {
+ if (decomb_disable)
+ {
+ fprintf(stderr,
+ "Incompatible options --decomb and --no-decomb\n");
+ return -1;
+ }
+ if (!hb_validate_filter_preset(HB_FILTER_DECOMB, decomb, 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))
+ {
+ decomb_custom = 1;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid decomb option %s\n", decomb);
+ return -1;
+ }
+ }
+
+ if (hqdn3d != NULL)
+ {
+ if (hqdn3d_disable)
+ {
+ fprintf(stderr,
+ "Incompatible options --hqdn3d and --no-hqdn3d\n");
+ return -1;
+ }
+ if (!hb_validate_filter_preset(HB_FILTER_HQDN3D, hqdn3d, 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))
+ {
+ hqdn3d_custom = 1;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid hqdn3d option %s\n", hqdn3d);
+ return -1;
+ }
+ }
+
+ if (nlmeans != NULL)
+ {
+ if (nlmeans_disable)
+ {
+ fprintf(stderr,
+ "Incompatible options --nlmeans and --no-nlmeans\n");
+ return -1;
+ }
+ if (!hb_validate_filter_preset(HB_FILTER_HQDN3D, nlmeans, nlmeans_tune))
+ {
+ // 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, nlmeans))
+ {
+ nlmeans_custom = 1;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid hqdn3d option %s\n", nlmeans);
return -1;
}
}
@@ -4308,6 +2626,42 @@ static int ParseOptions( int argc, char ** argv )
return 0;
}
+static int foreign_audio_scan(char **subtracks)
+{
+ if (subtracks != NULL)
+ {
+ int count = str_vlen(subtracks);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ if (!strcasecmp(subtracks[0], "scan"))
+ {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int count_subtitles(char **subtracks)
+{
+ int subtitle_track_count = 0;
+ if (subtracks != NULL)
+ {
+ int count = str_vlen(subtracks);
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ if (strcasecmp(subtracks[0], "scan") &&
+ strcasecmp(subtracks[0], "none"))
+ {
+ subtitle_track_count++;
+ }
+ }
+ }
+ return subtitle_track_count;
+}
+
static int CheckOptions( int argc, char ** argv )
{
if( update )
@@ -4315,7 +2669,7 @@ static int CheckOptions( int argc, char ** argv )
return 0;
}
- if( input == NULL || *input == '\0' )
+ if (preset_export_name == NULL && (input == NULL || *input == '\0'))
{
fprintf( stderr, "Missing input device. Run %s --help for "
"syntax.\n", argv[0] );
@@ -4323,16 +2677,16 @@ static int CheckOptions( int argc, char ** argv )
}
/* Parse format */
- if( titleindex > 0 && !titlescan )
+ if (titleindex > 0 && !titlescan)
{
- if( output == NULL || *output == '\0' )
+ if (preset_export_name == NULL && (output == NULL || *output == '\0'))
{
fprintf( stderr, "Missing output file name. Run %s --help "
"for syntax.\n", argv[0] );
return 1;
}
- if (format == NULL)
+ if (format == NULL && output != NULL)
{
/* autodetect */
const char *extension = strrchr(output, '.');
@@ -4341,44 +2695,1399 @@ static int CheckOptions( int argc, char ** argv )
// skip '.'
mux = hb_container_get_from_extension(extension + 1);
}
- if (mux <= 0)
+ hb_container_t * c = hb_container_get_from_format(mux);
+ if (c != NULL)
+ format = strdup(c->short_name);
+ }
+ }
+
+ int subtitle_track_count = count_subtitles(subtracks);
+ if (subtitle_track_count > 0 && subtitle_lang_list != NULL)
+ {
+ fprintf(stderr,
+ "Incompatible options: --subtitle-lang-list and --subtitle\n");
+ return 1;
+ }
+
+ if (subtitle_track_count > 0 && subtitle_all != -1)
+ {
+ fprintf(stderr,
+ "Incompatible options: --all-subtitles/--first-subtitle and --subtitle\n");
+ return 1;
+ }
+
+ if (atracks != NULL && audio_lang_list != NULL)
+ {
+ fprintf(stderr,
+ "Incompatible options: --audio-lang-list and --audio\n");
+ return 1;
+ }
+
+ if (atracks != NULL && audio_all != -1)
+ {
+ fprintf(stderr,
+ "Incompatible options: --all-audio/--first-audio and --audio\n");
+ return 1;
+ }
+
+ if ((par_width > 0 && par_height > 0) && display_width > 0)
+ {
+ fprintf(stderr,
+ "Incompatible options: --display-width and --pixel-aspect\n");
+ return 1;
+ }
+
+ if (preset_export_file != NULL && preset_export_name == NULL)
+ {
+ fprintf(stderr,
+ "Error: --preset-export-file requires option --preset-export\n");
+ return 1;
+ }
+
+ if (preset_export_desc != NULL && preset_export_name == NULL)
+ {
+ fprintf(stderr,
+ "Error: --preset-export-desc requires option --preset-export\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static hb_dict_t * PreparePreset(const char *preset_name)
+{
+ int ii;
+ hb_dict_t *preset;
+
+ if (preset_name != NULL)
+ {
+ preset = hb_preset_get(preset_name, 1 /*recurse*/);
+ if (preset == NULL)
+ {
+ fprintf(stderr, "Invalid preset %s\n"
+ "Valid presets are:\n", preset_name);
+ ShowPresets(NULL, 1, 1);
+ return NULL;
+ }
+ }
+ else
+ {
+ preset = hb_presets_get_default();
+ }
+ if (preset == NULL)
+ {
+ fprintf(stderr, "Error loading presets! Aborting.\n");
+ return NULL;
+ }
+
+ int subtitle_track_count = count_subtitles(subtracks);
+ // Apply any overrides that can be made directly to the preset
+ if (format != NULL)
+ {
+ hb_dict_set(preset, "FileFormat", hb_value_string(format));
+ }
+ if (mp4_optimize != -1)
+ {
+ hb_dict_set(preset, "Mp4HttpOptimize", hb_value_bool(mp4_optimize));
+ }
+ if (ipod_atom != -1)
+ {
+ hb_dict_set(preset, "Mp4iPodCompatible", hb_value_bool(ipod_atom));
+ }
+ if (chapter_markers != -1)
+ {
+ hb_dict_set(preset, "ChapterMarkers", hb_value_bool(chapter_markers));
+ }
+ hb_value_array_t *subtitle_lang_array;
+ subtitle_lang_array = hb_dict_get(preset, "SubtitleLanguageList");
+ if (subtitle_lang_array == NULL)
+ {
+ subtitle_lang_array = hb_value_array_init();
+ hb_dict_set(preset, "SubtitleLanguageList", subtitle_lang_array);
+ }
+ if (subtitle_lang_list != NULL)
+ {
+ hb_value_array_clear(subtitle_lang_array);
+ int count = str_vlen(subtitle_lang_list);
+ for (ii = 0; ii < count; ii++)
+ {
+ const iso639_lang_t *lang = lang_lookup(subtitle_lang_list[ii]);
+ if (lang != NULL)
{
- fprintf(stderr,
- "Output format can't be guessed from file name (%s), "
- "using default.\n", output);
- // reset the muxer (use default)
- mux = 0;
- return 0;
+ hb_value_array_append(subtitle_lang_array,
+ hb_value_string(lang->iso639_2));
+ }
+ else
+ {
+ fprintf(stderr, "Warning: Invalid subtitle language (%s)\n",
+ subtitle_lang_list[ii]);
+ return NULL;
}
}
- else
+ hb_dict_set(preset, "SubtitleTrackSelectionBehavior",
+ hb_value_string("first"));
+ }
+ if (native_language != NULL)
+ {
+ // Add native language subtitles if audio is not native
+ lang_list_remove(subtitle_lang_array, native_language);
+ hb_value_array_insert(subtitle_lang_array, 0,
+ hb_value_string(native_language));
+ hb_dict_set(preset, "SubtitleAddForeignAudioSubtitle",
+ hb_value_bool(1));
+ }
+ if (foreign_audio_scan(subtracks))
+ {
+ // Add foreign audio search
+ hb_dict_set(preset, "SubtitleAddForeignAudioSearch", hb_value_bool(1));
+ }
+ // Subtitle burn behavior
+ const char *burn = "none";
+ if (subtitle_track_count == 0)
+ {
+ if (subburn_native && subburn == 1)
+ {
+ burn = "foreign_first";
+ }
+ else if (subburn_native)
{
- mux = hb_container_get_from_name(format);
- if (mux <= 0)
+ burn = "foreign";
+ }
+ else if (subburn == 1)
+ {
+ burn = "first";
+ }
+ }
+ else
+ {
+ if (subburn_native)
+ {
+ burn = "foreign";
+ }
+ }
+ hb_dict_set(preset, "SubtitleBurnBehavior", hb_value_string(burn));
+ const char *selection = NULL;
+ if (subtitle_track_count == 0 && subtitle_all != -1)
+ {
+ selection = subtitle_all == 1 ? "all" : "first";
+ }
+ else
+ {
+ selection = "none";
+ }
+ if (selection != NULL)
+ {
+ hb_dict_set(preset, "SubtitleTrackSelectionBehavior",
+ hb_value_string(selection));
+ }
+
+ if (audio_copy_list != NULL)
+ {
+ // Create autopassthru copy mask
+ hb_value_array_t *array = hb_value_array_init();
+ for (ii = 0; audio_copy_list[ii] != NULL; ii++)
+ {
+ hb_value_array_append(array, hb_value_string(audio_copy_list[ii]));
+ }
+ hb_dict_set(preset, "AudioCopyMask", array);
+ }
+ if (acodec_fallback != NULL)
+ {
+ hb_dict_set(preset, "AudioEncoderFallback",
+ hb_value_string(acodec_fallback));
+ }
+
+ hb_value_array_t *audio_lang_array;
+ audio_lang_array = hb_dict_get(preset, "AudioLanguageList");
+ if (audio_lang_array == NULL)
+ {
+ audio_lang_array = hb_value_array_init();
+ hb_dict_set(preset, "AudioLanguageList", audio_lang_array);
+ }
+ if (audio_lang_list != NULL)
+ {
+ hb_value_array_clear(audio_lang_array);
+ int count = str_vlen(audio_lang_list);
+ for (ii = 0; ii < count; ii++)
+ {
+ const iso639_lang_t *lang = lang_lookup(audio_lang_list[ii]);
+ if (lang != NULL)
+ {
+ hb_value_array_append(audio_lang_array,
+ hb_value_string(lang->iso639_2));
+ }
+ else
{
- fprintf(stderr, "Invalid output format (%s).", format);
- fprintf(stderr, "Possible choices are: ");
- const hb_container_t *container = NULL;
- while ((container = hb_container_get_next(container)) != NULL)
+ fprintf(stderr, "Warning: Invalid audio language (%s)\n",
+ audio_lang_list[ii]);
+ return NULL;
+ }
+ }
+ hb_dict_set(preset, "AudioTrackSelectionBehavior",
+ hb_value_string("first"));
+ }
+ if (native_dub && native_language)
+ {
+ // Add native language audio
+ lang_list_remove(audio_lang_array, native_language);
+ hb_value_array_insert(audio_lang_array, 0,
+ hb_value_string(native_language));
+ }
+ if (audio_all != -1)
+ {
+ hb_dict_set(preset, "AudioTrackSelectionBehavior",
+ hb_value_string(audio_all == 1 ? "all" : "first"));
+ }
+
+ // Audio overrides
+ if (atracks == NULL && (
+ acodecs != NULL ||
+ abitrates != NULL ||
+ arates != NULL ||
+ mixdowns != NULL ||
+ normalize_mix_level != NULL ||
+ audio_dither != NULL ||
+ dynamic_range_compression != NULL ||
+ audio_gain != NULL ||
+ aqualities != NULL ||
+ acompressions != NULL ||
+ anames != NULL))
+ {
+ // No explicit audio tracks, but track settings modified.
+ // Modify the presets audio settings.
+ hb_value_array_t *list;
+ list = hb_dict_get(preset, "AudioList");
+ if (list == NULL)
+ {
+ list = hb_value_array_init();
+ hb_dict_set(preset, "AudioList", list);
+ }
+ int count = MAX(str_vlen(mixdowns),
+ MAX(str_vlen(dynamic_range_compression),
+ MAX(str_vlen(audio_gain),
+ MAX(str_vlen(audio_dither),
+ MAX(str_vlen(normalize_mix_level),
+ MAX(str_vlen(arates),
+ MAX(str_vlen(abitrates),
+ MAX(str_vlen(aqualities),
+ MAX(str_vlen(acompressions),
+ MAX(str_vlen(acodecs),
+ str_vlen(anames)))))))))));
+
+ hb_dict_t *audio_dict;
+ // Add audio dict entries to list if needed
+ for (ii = 0; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ if (audio_dict == NULL)
+ {
+ audio_dict = hb_dict_init();
+ hb_value_array_append(list, audio_dict);
+ }
+ }
+
+ // Update codecs
+ if (str_vlen(acodecs) > 0)
+ {
+ for (ii = 0; acodecs[ii] != NULL; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioEncoder",
+ hb_value_string(acodecs[ii]));
+ }
+ // Apply last codec in list to all other entries
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioEncoder",
+ hb_value_string(acodecs[ii-1]));
+ }
+ }
+
+ // Update qualities
+ if (str_vlen(aqualities) > 0)
+ {
+ for (ii = 0; aqualities[ii] != NULL &&
+ aqualities[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioTrackQualityEnable",
+ hb_value_bool(1));
+ hb_dict_set(audio_dict, "AudioTrackQuality",
+ hb_value_double(strtod(aqualities[ii], NULL)));
+ }
+ }
+
+ // Update bitrates
+ if (str_vlen(abitrates) > 0)
+ {
+ for (ii = 0; abitrates[ii] != NULL &&
+ abitrates[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ if (hb_value_get_bool(hb_dict_get(audio_dict,
+ "AudioTrackQualityEnable")))
{
- fprintf(stderr, "%s", container->short_name);
- if (hb_container_get_next(container) != NULL)
+ continue;
+ }
+ hb_dict_set(audio_dict, "AudioBitrate",
+ hb_value_int(atoi(abitrates[ii])));
+ }
+ // Apply last bitrate in list to all other entries
+ if (abitrates[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ if (hb_value_get_bool(hb_dict_get(audio_dict,
+ "AudioTrackQualityEnable")))
{
- fprintf(stderr, ", ");
+ continue;
}
- else
+ hb_dict_set(audio_dict, "AudioBitrate",
+ hb_value_int(atoi(abitrates[ii-1])));
+ }
+ }
+
+ // Update samplerates
+ if (str_vlen(arates) > 0)
+ {
+ for (ii = 0; arates[ii] != NULL &&
+ arates[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioSamplerate",
+ hb_value_string(arates[ii]));
+ }
+ // Apply last samplerate in list to all other entries
+ if (arates[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioSamplerate",
+ hb_value_string(arates[ii-1]));
+ }
+ }
+
+ // Update mixdowns
+ if (str_vlen(mixdowns) > 0)
+ {
+ for (ii = 0; mixdowns[ii] != NULL &&
+ mixdowns[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioMixdown",
+ hb_value_string(mixdowns[ii]));
+ }
+ // Apply last codec in list to all other entries
+ if (mixdowns[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioMixdown",
+ hb_value_string(mixdowns[ii-1]));
+ }
+ }
+
+ // Update mixdowns normalization
+ if (str_vlen(normalize_mix_level) > 0)
+ {
+ for (ii = 0; normalize_mix_level[ii] != NULL &&
+ normalize_mix_level[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioNormalizeMixLevel",
+ hb_value_bool(atoi(normalize_mix_level[ii])));
+ }
+ // Apply last mix norm in list to all other entries
+ if (normalize_mix_level[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict,
+ "AudioNormalizeMixLevel",
+ hb_value_bool(
+ atoi(normalize_mix_level[ii-1])));
+ }
+ }
+
+ // Update DRC
+ if (str_vlen(dynamic_range_compression) > 0)
+ {
+ for (ii = 0;dynamic_range_compression[ii] != NULL &&
+ dynamic_range_compression[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioTrackDRCSlider",
+ hb_value_double(
+ strtod(dynamic_range_compression[ii], NULL)));
+ }
+ // Apply last DRC in list to all other entries
+ if (dynamic_range_compression[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioTrackDRCSlider",
+ hb_value_double(
+ strtod(dynamic_range_compression[ii-1],
+ NULL)));
+ }
+ }
+
+ // Update Gain
+ if (str_vlen(audio_gain) > 0)
+ {
+ for (ii = 0; audio_gain[ii] != NULL &&
+ audio_gain[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioTrackGainSlider",
+ hb_value_double(
+ strtod(audio_gain[ii], NULL)));
+ }
+ // Apply last gain in list to all other entries
+ if (audio_gain[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioTrackGainSlider",
+ hb_value_double(
+ strtod(audio_gain[ii-1], NULL)));
+ }
+ }
+
+ // Update dither method
+ if (str_vlen(audio_dither) > 0)
+ {
+ for (ii = 0; audio_dither[ii] != NULL &&
+ audio_dither[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioDitherMethod",
+ hb_value_string(audio_dither[ii]));
+ }
+ // Apply last dither in list to all other entries
+ if (audio_dither[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioDitherMethod",
+ hb_value_string(audio_dither[ii-1]));
+ }
+ }
+
+ // Update compression
+ if (str_vlen(acompressions) > 0)
+ {
+ for (ii = 0; acompressions[ii] != NULL &&
+ acompressions[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioCompressionLevel",
+ hb_value_double(
+ strtod(acompressions[ii], NULL)));
+ }
+ // Apply last compression in list to all other entries
+ if (acompressions[ii-1][0] != 0)
+ for (; ii < count; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioCompressionLevel",
+ hb_value_double(
+ strtod(acompressions[ii-1], NULL)));
+ }
+ }
+
+ // Update track names
+ if (str_vlen(anames) > 0)
+ {
+ for (ii = 0; anames[ii] != NULL &&
+ anames[ii][0] != 0; ii++)
+ {
+ audio_dict = hb_value_array_get(list, ii);
+ hb_dict_set(audio_dict, "AudioTrackName",
+ hb_value_string(acodecs[ii]));
+ }
+ }
+ }
+
+ if (atracks != NULL)
+ {
+ // User has specified explicit audio tracks
+ // Disable preset's audio track selection
+ hb_dict_set(preset, "AudioTrackSelectionBehavior",
+ hb_value_string("none"));
+ }
+
+ if (vcodec != NULL)
+ {
+ hb_dict_set(preset, "VideoEncoder", hb_value_string(vcodec));
+ }
+ if (encoder_preset != NULL)
+ {
+ hb_dict_set(preset, "VideoPreset", hb_value_string(encoder_preset));
+ }
+ if (encoder_tune != NULL)
+ {
+ hb_dict_set(preset, "VideoTune", hb_value_string(encoder_tune));
+ }
+ if (encoder_profile != NULL)
+ {
+ hb_dict_set(preset, "VideoProfile", hb_value_string(encoder_profile));
+ }
+ if (encoder_level != NULL)
+ {
+ hb_dict_set(preset, "VideoLevel", hb_value_string(encoder_level));
+ }
+ if (advanced_opts != NULL)
+ {
+ hb_dict_set(preset, "VideoOptionExtra", hb_value_string(advanced_opts));
+ }
+ if (vquality >= 0)
+ {
+ hb_dict_set(preset, "VideoQualityType", hb_value_int(2));
+ hb_dict_set(preset, "VideoQualitySlider", hb_value_double(vquality));
+ }
+ else if (vbitrate != 0)
+ {
+ hb_dict_set(preset, "VideoQualityType", hb_value_int(1));
+ hb_dict_set(preset, "VideoAvgBitrate", hb_value_int(vbitrate));
+ if (twoPass)
+ {
+ hb_dict_set(preset, "VideoTwoPass", hb_value_bool(1));
+ }
+ if (fastfirstpass)
+ {
+ hb_dict_set(preset, "VideoTurboTwoPass", hb_value_bool(1));
+ }
+ }
+ if (vrate != NULL)
+ {
+ hb_dict_set(preset, "VideoFramerate", hb_value_string(vrate));
+ }
+ else
+ {
+ hb_dict_set(preset, "VideoFramerate", hb_value_string("auto"));
+ }
+ if (cfr != -1)
+ {
+ hb_dict_set(preset, "VideoFramerateMode",
+ hb_value_string(cfr == 0 ? "vfr" :
+ cfr == 1 ? "cfr" : "pfr"));
+ }
+ if (color_matrix_code > 0)
+ {
+ hb_dict_set(preset, "VideoColorMatrixCode",
+ hb_value_int(color_matrix_code));
+ }
+#ifdef USE_QSV
+ if (qsv_async_depth >= 0)
+ {
+ hb_dict_set(preset, "VideoQSVAsyncDepth",
+ hb_value_int(qsv_async_depth));
+ }
+ if (qsv_decode != -1)
+ {
+ hb_dict_set(preset, "VideoQSVDecode", hb_value_int(qsv_decode));
+ }
+#endif
+ if (use_hwd != -1)
+ {
+ hb_dict_set(preset, "VideoHWDecode", hb_value_bool(use_hwd));
+ }
+ if (use_opencl != -1)
+ {
+ hb_dict_set(preset, "VideoScaler",
+ hb_value_string(use_opencl ? "opencl" : "swscale"));
+ }
+ if (maxWidth > 0)
+ {
+ hb_dict_set(preset, "PictureWidth", hb_value_int(maxWidth));
+ }
+ if (maxHeight > 0)
+ {
+ hb_dict_set(preset, "PictureHeight", hb_value_int(maxHeight));
+ }
+ if (width > 0)
+ {
+ hb_dict_set(preset, "PictureForceWidth", hb_value_int(width));
+ }
+ if (height > 0)
+ {
+ hb_dict_set(preset, "PictureForceHeight", hb_value_int(height));
+ }
+ if (crop[0] >= 0)
+ {
+ hb_dict_set(preset, "PictureTopCrop", hb_value_int(crop[0]));
+ }
+ if (crop[1] >= 0)
+ {
+ hb_dict_set(preset, "PictureBottomCrop", hb_value_int(crop[1]));
+ }
+ if (crop[2] >= 0)
+ {
+ hb_dict_set(preset, "PictureLeftCrop", hb_value_int(crop[2]));
+ }
+ if (crop[3] >= 0)
+ {
+ hb_dict_set(preset, "PictureRightCrop", hb_value_int(crop[3]));
+ }
+ if (loose_crop != -1)
+ {
+ hb_dict_set(preset, "PictureLooseCrop", hb_value_bool(loose_crop));
+ }
+ if (display_width > 0)
+ {
+ keep_display_aspect = 0;
+ anamorphic_mode = 3;
+ hb_dict_set(preset, "PictureDARWidth", hb_value_int(display_width));
+ }
+ else if (par_width > 0 && par_height > 0)
+ {
+ keep_display_aspect = 0;
+ anamorphic_mode = 3;
+ hb_dict_set(preset, "PicturePARWidth", hb_value_int(par_width));
+ hb_dict_set(preset, "PicturePARHeight", hb_value_int(par_height));
+ }
+ if (anamorphic_mode != -1)
+ {
+ hb_dict_set(preset, "PicturePAR", hb_value_int(anamorphic_mode));
+ }
+ if (keep_display_aspect != -1)
+ {
+ hb_dict_set(preset, "PictureKeepRatio",
+ hb_value_bool(keep_display_aspect));
+ }
+ if (itu_par != -1)
+ {
+ hb_dict_set(preset, "PictureItuPAR", hb_value_bool(itu_par));
+ }
+ if (modulus > 0)
+ {
+ hb_dict_set(preset, "PictureModulus", hb_value_int(modulus));
+ }
+ if (grayscale != -1)
+ {
+ hb_dict_set(preset, "VideoGrayScale", hb_value_bool(grayscale));
+ }
+ if (deinterlace_disable)
+ {
+ hb_dict_set(preset, "PictureDeinterlace", hb_value_string("off"));
+ }
+ if (deinterlace != NULL)
+ {
+ hb_dict_set(preset, "PictureDecombDeinterlace", hb_value_int(0));
+ if (!deinterlace_custom)
+ {
+ hb_dict_set(preset, "PictureDeinterlace",
+ hb_value_string(deinterlace));
+ }
+ else
+ {
+ hb_dict_set(preset, "PictureDeinterlace",
+ hb_value_string("custom"));
+ hb_dict_set(preset, "PictureDeinterlaceCustom",
+ hb_value_string(deinterlace));
+ }
+ }
+ if (decomb_disable)
+ {
+ hb_dict_set(preset, "PictureDecomb", hb_value_string("off"));
+ }
+ if (decomb != NULL)
+ {
+ hb_dict_set(preset, "PictureDecombDeinterlace", hb_value_int(1));
+ if (!decomb_custom)
+ {
+ hb_dict_set(preset, "PictureDecomb", hb_value_string(decomb));
+ }
+ else
+ {
+ hb_dict_set(preset, "PictureDecomb", hb_value_string("custom"));
+ hb_dict_set(preset, "PictureDecombCustom", hb_value_string(decomb));
+ }
+ }
+ if (detelecine_disable)
+ {
+ hb_dict_set(preset, "PictureDetelecine", hb_value_string("off"));
+ }
+ if (detelecine != NULL)
+ {
+ if (!detelecine_custom)
+ {
+ hb_dict_set(preset, "PictureDetelecine",
+ hb_value_string(detelecine));
+ }
+ else
+ {
+ hb_dict_set(preset, "PictureDetelecine", hb_value_string("custom"));
+ hb_dict_set(preset, "PictureDetelecineCustom",
+ hb_value_string(detelecine));
+ }
+ }
+ const char *s;
+ s = hb_value_get_string(hb_dict_get(preset, "PictureDenoiseFilter"));
+ if (hqdn3d_disable && !strcasecmp(s, "hqdn3d"))
+ {
+ hb_dict_set(preset, "PictureDenoiseFilter", hb_value_string("off"));
+ }
+ if (hqdn3d != NULL)
+ {
+ hb_dict_set(preset, "PictureDenoiseFilter", hb_value_string("hqdn3d"));
+ if (!hqdn3d_custom)
+ {
+ hb_dict_set(preset, "PictureDenoisePreset",
+ hb_value_string(hqdn3d));
+ }
+ else
+ {
+ hb_dict_set(preset, "PictureDenoisePreset",
+ hb_value_string("custom"));
+ hb_dict_set(preset, "PictureDenoiseCustom",
+ hb_value_string(hqdn3d));
+ }
+ }
+ if (nlmeans_disable && !strcasecmp(s, "nlmeans"))
+ {
+ hb_dict_set(preset, "PictureDenoiseFilter", hb_value_string("off"));
+ }
+ if (nlmeans != NULL)
+ {
+ hb_dict_set(preset, "PictureDenoiseFilter", hb_value_string("nlmeans"));
+ if (!nlmeans_custom)
+ {
+ hb_dict_set(preset, "PictureDenoisePreset",
+ hb_value_string(nlmeans));
+ if (nlmeans_tune != NULL)
+ {
+ hb_dict_set(preset, "PictureDenoisePreset",
+ hb_value_string(nlmeans_tune));
+ }
+ }
+ else
+ {
+ hb_dict_set(preset, "PictureDenoisePreset",
+ hb_value_string("custom"));
+ hb_dict_set(preset, "PictureDenoiseCustom",
+ hb_value_string(nlmeans));
+ }
+ }
+ if (deblock_disable)
+ {
+ hb_dict_set(preset, "PictureDeblock", hb_value_string("0"));
+ }
+ if (deblock != NULL)
+ {
+ hb_dict_set(preset, "PictureDeblock", hb_value_string(deblock));
+ }
+ if (rotate != NULL)
+ {
+ hb_dict_set(preset, "PictureRotate", hb_value_string(rotate));
+ }
+
+ return preset;
+}
+
+
+static int add_sub(hb_value_array_t *list, hb_title_t *title, int track, int *one_burned)
+{
+ hb_subtitle_t *subtitle;
+ // Check that the track exists
+ subtitle = hb_list_item(title->list_subtitle, track);
+ if (subtitle == NULL)
+ {
+ fprintf(stderr, "Warning: Could not find subtitle track %d, skipped\n",
+ track + 1);
+ return -1;
+ }
+
+ int burn = !*one_burned && subburn == track + 1 &&
+ hb_subtitle_can_burn(subtitle->source);
+ *one_burned |= burn;
+ int def = subdefault == track + 1;
+ int force = test_sub_list(subforce, track + 1);
+
+ if (!burn &&
+ !hb_subtitle_can_pass(subtitle->source, mux))
+ {
+ // Only allow one subtitle to be burned into video
+ if (*one_burned)
+ {
+ fprintf(stderr, "Warning: Skipping subtitle track %d, can't have more than one track burnt in\n", track + 1);
+ return -1;
+ }
+ *one_burned = 1;
+ }
+ hb_dict_t *subtitle_dict = hb_dict_init();
+ hb_dict_set(subtitle_dict, "Track", hb_value_int(track));
+ hb_dict_set(subtitle_dict, "Default", hb_value_bool(def));
+ hb_dict_set(subtitle_dict, "Forced", hb_value_bool(force));
+ hb_dict_set(subtitle_dict, "Burn", hb_value_bool(burn));
+ hb_value_array_append(list, subtitle_dict);
+ return 0;
+}
+
+static int add_srt(hb_value_array_t *list, int track, int *one_burned)
+{
+ char *codeset = "ISO-8859-1";
+ int64_t offset = 0;
+ char *iso639_2 = "und";
+ int burn = !*one_burned && srtburn == track + 1 &&
+ hb_subtitle_can_burn(SRTSUB);
+ *one_burned |= burn;
+ int def = srtdefault == track + 1;
+
+ if (srtcodeset && track < str_vlen(srtcodeset) && srtcodeset[track])
+ codeset = srtcodeset[track];
+ if (srtoffset && track < str_vlen(srtoffset) && srtoffset[track])
+ offset = strtoll(srtoffset[track], NULL, 0);
+ if (srtlang && track < str_vlen(srtlang) && srtlang[track])
+ {
+ const iso639_lang_t *lang = lang_lookup(srtlang[track]);
+ if (lang != NULL)
+ {
+ iso639_2 = lang->iso639_2;
+ }
+ else
+ {
+ fprintf(stderr, "Warning: Invalid SRT language (%s)\n",
+ srtlang[track]);
+ }
+ }
+
+ hb_dict_t *subtitle_dict = hb_dict_init();
+ hb_dict_t *srt_dict = hb_dict_init();
+ hb_dict_set(subtitle_dict, "SRT", srt_dict);
+ hb_dict_set(subtitle_dict, "Default", hb_value_bool(def));
+ hb_dict_set(subtitle_dict, "Burn", hb_value_bool(burn));
+ hb_dict_set(subtitle_dict, "Offset", hb_value_int(offset));
+ hb_dict_set(srt_dict, "Filename", hb_value_string(srtfile[track]));
+ hb_dict_set(srt_dict, "Language", hb_value_string(iso639_2));
+ hb_dict_set(srt_dict, "Codeset", hb_value_string(codeset));
+ hb_value_array_append(list, subtitle_dict);
+ return 0;
+}
+
+static int add_audio(hb_value_array_t *list, hb_title_t *title, int track)
+{
+ // Check that the track exists
+ if (hb_list_item(title->list_audio, track) == NULL)
+ {
+ fprintf(stderr, "Warning: Could not find audio track %d, skipped\n",
+ track + 1);
+ return -1;
+ }
+ hb_dict_t *audio_dict = hb_dict_init();
+ hb_dict_set(audio_dict, "Track", hb_value_int(track));
+ hb_value_array_append(list, audio_dict);
+
+ return 0;
+}
+
+static hb_dict_t*
+PrepareJob(hb_handle_t *h, hb_title_t *title, hb_dict_t *preset_dict)
+{
+ hb_dict_t *job_dict;
+ job_dict = hb_preset_job_init(h, title->index, preset_dict);
+ if (job_dict == NULL)
+ {
+ fprintf(stderr, "Failed to initialize job\n");
+ return NULL;
+ }
+
+ if (hb_value_get_bool(hb_dict_get(job_dict, "ChapterMarkers")))
+ {
+ write_chapter_names(job_dict, marker_file);
+ }
+
+ hb_dict_t *dest_dict = hb_dict_get(job_dict, "Destination");
+ hb_dict_set(dest_dict, "File", hb_value_string(output));
+
+ // Now that the job is initialized, we need to find out
+ // what muxer is being used.
+ mux = hb_container_get_from_name(
+ hb_value_get_string(hb_dict_get(dest_dict, "Mux")));
+
+ // Now set non-preset settings in the job dict
+ int range_start = 0, range_end = 0, range_seek_points = 0;
+ const char *range_type = "chapter";
+ if (chapter_start && chapter_end &&
+ !start_at_pts && !stop_at_pts &&
+ !start_at_frame && !stop_at_frame &&
+ !start_at_preview )
+ {
+ range_type = "chapter";
+ int chapter_count = hb_list_count(title->list_chapter);
+ range_start = MAX(1, chapter_start);
+ range_end = MIN(chapter_count, chapter_end);
+ range_end = MAX(chapter_start, chapter_end);
+ }
+ else if (start_at_preview)
+ {
+ range_type = "preview";
+ range_start = start_at_preview -1;
+ range_end = stop_at_pts;
+ range_seek_points = preview_count;
+ }
+ else if (start_at_pts || stop_at_pts)
+ {
+ range_type = "time";
+ range_start = start_at_pts;
+ range_end = stop_at_pts;
+ }
+ else if (start_at_frame || stop_at_frame)
+ {
+ range_type = "frame";
+ range_start = start_at_frame;
+ range_end = stop_at_frame;
+ }
+ if (range_start || range_end)
+ {
+ hb_dict_t *range_dict = hb_dict_get(
+ hb_dict_get(job_dict, "Source"), "Range");
+ hb_dict_set(range_dict, "Type", hb_value_string(range_type));
+ if (range_start)
+ hb_dict_set(range_dict, "Start", hb_value_int(range_start));
+ if (range_end)
+ hb_dict_set(range_dict, "End", hb_value_int(range_end));
+ if (range_seek_points)
+ hb_dict_set(range_dict, "SeekPoints",
+ hb_value_int(range_seek_points));
+ }
+
+ if (angle)
+ {
+ hb_dict_t *source_dict = hb_dict_get(job_dict, "Source");
+ hb_dict_set(source_dict, "Angle", hb_value_int(angle));
+ }
+
+ hb_dict_t *subtitles_dict = hb_dict_get(job_dict, "Subtitle");
+ hb_value_array_t * subtitle_array;
+ subtitle_array = hb_dict_get(subtitles_dict, "SubtitleList");
+
+ hb_dict_t *audios_dict = hb_dict_get(job_dict, "Audio");
+ hb_value_array_t * audio_array = hb_dict_get(audios_dict, "AudioList");
+ hb_dict_t *audio_dict;
+ int track_count = hb_value_array_len(audio_array);
+
+ /* Grab audio tracks */
+ if (atracks != NULL)
+ {
+ int ii;
+ if (atracks[0] != NULL && strcasecmp("none", atracks[0]))
+ {
+ // First "track" is not "none", add tracks
+ for (ii = 0; atracks[ii] != NULL; ii++)
+ {
+ int first, last, track;
+ if (sscanf(atracks[ii], "%d-%d", &first, &last ) == 2)
+ {
+ for (track = first - 1; track < last; track++)
{
- fprintf(stderr, "\n");
+ add_audio(audio_array, title, track);
}
}
- return 1;
+ else if (sscanf(atracks[ii], "%d", &track) == 1)
+ {
+ add_audio(audio_array, title, track);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: unable to parse audio input \"%s\", skipping\n", atracks[ii]);
+ }
+ }
+ }
+ track_count = hb_value_array_len(audio_array);
+
+ // Now we need to take care of initializing subtitle selection
+ // for foreign audio since this could not be done by the preset
+ // due to disabling of preset audio selection.
+
+ // Determine the language of the first audio track
+ if (track_count > 0)
+ {
+ audio_dict = hb_value_array_get(audio_array, 0);
+ int track = hb_value_get_int(hb_dict_get(audio_dict, "Track"));
+
+ hb_audio_config_t *audio;
+ audio = hb_list_audio_config_item(title->list_audio, track);
+ if (audio != NULL)
+ {
+ hb_preset_job_add_subtitles(h, title->index,
+ preset_dict, job_dict);
+ }
+ }
+
+ /* Audio Codecs */
+ int acodec;
+ ii = 0;
+ if (acodecs != NULL)
+ {
+ for (; acodecs[ii] != NULL && ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ acodec = hb_audio_encoder_get_from_name(acodecs[ii]);
+ if (acodec <= 0)
+ {
+ fprintf(stderr,
+ "Invalid codec %s, using default for container.\n",
+ acodecs[ii]);
+ acodec = hb_audio_encoder_get_default(mux);
+ }
+ hb_dict_set(audio_dict, "Encoder", hb_value_int(acodec));
+ }
+ if (acodecs[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio encoders\n");
}
}
+ acodec = hb_audio_encoder_get_default(mux);
+ for (; ii < track_count; ii++)
+ {
+ // We have fewer inputs than audio tracks, use the
+ // default codec for this container for the remaining
+ // tracks. Unless we only have one input then use that
+ // codec instead.
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Encoder", hb_value_int(acodec));
+ }
+
+ /* Sample Rate */
+ int arate;
+ ii = 0;
+ if (arates != NULL)
+ {
+ for (; arates[ii] != NULL && ii < track_count; ii++)
+ {
+ if (!strcasecmp(arates[ii], "auto"))
+ {
+ arate = 0;
+ }
+ else
+ {
+ arate = hb_audio_samplerate_get_from_name(arates[ii]);
+ }
+ if (arate <= 0)
+ {
+ fprintf(stderr, "Invalid sample rate %s, using input rate\n",
+ arates[ii]);
+ arate = 0;
+ }
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Samplerate", hb_value_int(arate));
+ }
+ if (arates[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio sample rates\n");
+ }
+ }
+ // If exactly one samplerate was specified, apply it to the reset
+ // of the tracks.
+ //
+ // For any tracks that we do not set the rate for, libhb will
+ // assign the source audio track's rate
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Samplerate", hb_value_int(arate));
+ }
+
+ /* Audio Mixdown */
+ int mix;
+ ii = 0;
+ if (mixdowns != NULL)
+ {
+ for (; mixdowns[ii] != NULL && ii < track_count; ii++)
+ {
+ mix = hb_mixdown_get_from_name(mixdowns[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Mixdown", hb_value_int(mix));
+ }
+ if (mixdowns[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio mixdowns\n");
+ }
+ }
+ // If exactly one mix was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Mixdown", hb_value_int(mix));
+ }
+
+ /* Audio Bitrate */
+ int abitrate;
+ ii = 0;
+ if (abitrates != NULL)
+ {
+ for (; abitrates[ii] != NULL && ii < track_count; ii++)
+ {
+ if (*abitrates[ii])
+ {
+ abitrate = atoi(abitrates[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Bitrate", hb_value_int(abitrate));
+ }
+ }
+ if (abitrates[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio bitrates\n");
+ }
+ }
+ // If exactly one bitrate was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Bitrate", hb_value_int(abitrate));
+ }
+
+ /* Audio Quality */
+ double aquality;
+ ii = 0;
+ if (aqualities != NULL)
+ {
+ for (; aqualities[ii] != NULL && ii < track_count; ii++)
+ {
+ if (*aqualities[ii])
+ {
+ aquality = atof(aqualities[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Quality",
+ hb_value_double(aquality));
+ hb_dict_set(audio_dict, "Bitrate", hb_value_int(-1));
+ }
+ }
+ if (aqualities[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio qualities\n");
+ }
+ }
+ // If exactly one quality was specified, apply it to the reset
+ // of the tracks that do not already have the bitrate set.
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ abitrate = hb_value_get_int(hb_dict_get(audio_dict, "Bitrate"));
+ if (abitrate <= 0)
+ {
+ hb_dict_set(audio_dict, "Quality", hb_value_double(aquality));
+ hb_dict_set(audio_dict, "Bitrate", hb_value_int(-1));
+ }
+ }
+
+ /* Audio Compression Level */
+ double acompression;
+ ii = 0;
+ if (acompressions != NULL)
+ {
+ for (; acompressions[ii] != NULL && ii < track_count; ii++)
+ {
+ if (*acompressions[ii])
+ {
+ acompression = atof(acompressions[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "CompressionLevel",
+ hb_value_double(acompression));
+ }
+ }
+ if (acompressions[ii] != NULL)
+ {
+ fprintf(stderr,
+ "Dropping excess audio compression levels\n");
+ }
+ }
+ // Compression levels are codec specific values. So don't
+ // try to apply to other tracks.
+
+ /* Audio DRC */
+ ii = 0;
+ double drc;
+ if (dynamic_range_compression)
+ {
+ char **drcs = dynamic_range_compression;
+ for (; drcs[ii] != NULL && ii < track_count; ii++)
+ {
+ drc = atof(drcs[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "DRC", hb_value_double(drc));
+ }
+ if (drcs[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio dynamic range controls\n");
+ }
+ }
+ // If exactly one DRC was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "DRC", hb_value_double(drc));
+ }
+
+ /* Audio Gain */
+ ii = 0;
+ double gain;
+ if (audio_gain)
+ {
+ for (; audio_gain[ii] != NULL && ii < track_count; ii++)
+ {
+ gain = atof(audio_gain[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Gain", hb_value_double(gain));
+ }
+ if (audio_gain[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio gains\n");
+ }
+ }
+ // If exactly one gain was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Gain", hb_value_double(gain));
+ }
+
+ /* Audio Dither */
+ int dither;
+ ii = 0;
+ if (audio_dither != NULL)
+ {
+ for (; audio_dither[ii] != NULL && ii < track_count; ii++)
+ {
+ if (*audio_dither[ii])
+ {
+ dither = hb_audio_dither_get_from_name(audio_dither[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "DitherMethod",
+ hb_value_int(dither));
+ }
+ }
+ if (audio_dither[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio dither methods\n");
+ }
+ }
+ // If exactly one dither was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ int codec;
+ audio_dict = hb_value_array_get(audio_array, ii);
+ codec = hb_value_get_int(hb_dict_get(audio_dict, "Encoder"));
+ if (hb_audio_dither_is_supported(codec))
+ {
+ hb_dict_set(audio_dict, "DitherMethod",
+ hb_value_double(dither));
+ }
+ }
+
+ /* Audio Mix Normalization */
+ int norm = 0;
+ ii = 0;
+ if (normalize_mix_level)
+ {
+ char **nmls = normalize_mix_level;
+ for (; nmls[ii] != NULL && ii < track_count; ii++)
+ {
+ norm = atoi(nmls[ii]);
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "NormalizeMixLevel",
+ hb_value_int(norm));
+ }
+ if (nmls[ii] != NULL)
+ {
+ fprintf(stderr,
+ "Dropping excess audio mixdown normalizations\n");
+ }
+ }
+ // If exactly one norm was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "NormalizeMixLevel", hb_value_int(norm));
+ }
+
+ /* Audio Track Names */
+ ii = 0;
+ if (anames != NULL)
+ {
+ for (; anames[ii] != NULL && ii < track_count; ii++)
+ {
+ if (*anames[ii])
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Name",
+ hb_value_string(anames[ii]));
+ }
+ }
+ if (anames[ii] != NULL)
+ {
+ fprintf(stderr, "Dropping excess audio track names\n");
+ }
+ }
+ // If exactly one name was specified, apply it to the reset
+ // of the tracks
+ if (ii == 1 && *anames[0]) for (; ii < track_count; ii++)
+ {
+ audio_dict = hb_value_array_get(audio_array, ii);
+ hb_dict_set(audio_dict, "Name", hb_value_string(anames[0]));
+ }
}
- return 0;
+ int one_burned = 0;
+ if (subtracks != NULL)
+ {
+ int ii;
+ for (ii = 0; subtracks[ii] != NULL; ii++)
+ {
+ if (strcasecmp(subtracks[ii], "none" ) == 0)
+ {
+ // Taken care of already when initializing the job
+ // from a preset
+ continue;
+ }
+ if (strcasecmp(subtracks[ii], "scan" ) == 0)
+ {
+ // Taken care of already when initializing the job
+ // from a preset
+ continue;
+ }
+
+ int first, last, track;
+ if (sscanf(subtracks[ii], "%d-%d", &first, &last ) == 2)
+ {
+ for (track = first - 1; track < last; track++)
+ {
+ add_sub(subtitle_array, title, track, &one_burned);
+ }
+ }
+ else if (sscanf(subtracks[ii], "%d", &track) == 1)
+ {
+ add_sub(subtitle_array, title, track, &one_burned);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: unable to parse subtitle input \"%s\", skipping\n", subtracks[ii]);
+ }
+ }
+ }
+
+ if (srtfile != NULL)
+ {
+ int ii;
+ for (ii = 0; srtfile[ii] != NULL; ii++)
+ {
+ add_srt(subtitle_array, ii, &one_burned);
+ }
+ }
+
+ return job_dict;
}
+
static void print_string_list(FILE *out, const char* const *list, const char *prefix)
{
if (out != NULL && prefix != NULL)