summaryrefslogtreecommitdiffstats
path: root/libhb/preset.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/preset.c')
-rw-r--r--libhb/preset.c680
1 files changed, 361 insertions, 319 deletions
diff --git a/libhb/preset.c b/libhb/preset.c
index 5035cacc9..4066b2bec 100644
--- a/libhb/preset.c
+++ b/libhb/preset.c
@@ -305,21 +305,24 @@ static int get_job_mux(hb_dict_t *job_dict)
return mux;
}
-static int get_audio_copy_mask(const hb_dict_t * preset)
+static hb_value_t* get_audio_copy_mask(const hb_dict_t * preset, int *mask)
{
- int mask = HB_ACODEC_PASS_FLAG;
+ int copy_mask;
+ hb_value_array_t *out_copy_mask, *in_copy_mask;
- hb_value_array_t *copy_mask_array = hb_dict_get(preset, "AudioCopyMask");
- if (copy_mask_array != NULL)
+ if (mask != NULL)
+ *mask = 0;
+ in_copy_mask = hb_dict_get(preset, "AudioCopyMask");
+ out_copy_mask = hb_value_array_init();
+ if (in_copy_mask != NULL)
{
- mask = HB_ACODEC_PASS_FLAG;
- int count = hb_value_array_len(copy_mask_array);
- int ii;
+ int count, ii;
+ count = hb_value_array_len(in_copy_mask);
for (ii = 0; ii < count; ii++)
{
int codec;
hb_value_t *value;
- value = hb_value_array_get(copy_mask_array, ii);
+ value = hb_value_array_get(in_copy_mask, ii);
if (hb_value_type(value) == HB_VALUE_TYPE_STRING)
{
char *tmp = NULL;
@@ -335,7 +338,8 @@ static int get_audio_copy_mask(const hb_dict_t * preset)
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;
+ hb_value_free(&out_copy_mask);
+ return NULL;
}
free(tmp);
}
@@ -343,10 +347,14 @@ static int get_audio_copy_mask(const hb_dict_t * preset)
{
codec = hb_value_get_int(value);
}
- mask |= codec;
+ hb_value_array_append(out_copy_mask, hb_value_string(
+ hb_audio_encoder_get_short_name(codec)));
+ copy_mask |= codec;
}
}
- return mask;
+ if (mask != NULL)
+ *mask = copy_mask;
+ return out_copy_mask;
}
static hb_dict_t * source_audio_track_used(hb_dict_t *track_dict, int track)
@@ -535,7 +543,8 @@ static void add_audio_for_lang(hb_value_array_t *list, const hb_dict_t *preset,
}
// 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_dict_set(audio_dict, "PresetEncoder",
+ hb_value_string(hb_audio_encoder_get_short_name(out_codec)));
hb_audio_config_t *aconfig;
aconfig = hb_list_audio_config_item(title->list_audio, track);
@@ -639,13 +648,14 @@ int hb_preset_job_add_audio(hb_handle_t *h, int title_index,
audio_dict = hb_dict_init();
hb_dict_set(job_dict, "Audio", audio_dict);
}
- int copy_mask = get_audio_copy_mask(preset);
- if (copy_mask == HB_ACODEC_INVALID)
+ int copy_mask;
+ hb_value_t *copy_mask_array = get_audio_copy_mask(preset, &copy_mask);
+ if (copy_mask_array == NULL)
{
return -1;
}
int fallback = 0;
- hb_dict_set(audio_dict, "CopyMask", hb_value_int(copy_mask));
+ hb_dict_set(audio_dict, "CopyMask", copy_mask_array);
hb_value_t *fallback_value = hb_dict_get(preset, "AudioEncoderFallback");
if (fallback_value != NULL)
{
@@ -1041,243 +1051,19 @@ static int get_video_framerate(hb_value_t *rate_value)
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,
- const hb_dict_t *preset)
+int hb_preset_apply_filters(const hb_dict_t *preset, hb_dict_t *job_dict)
{
- 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);
+ hb_value_t *filters_dict, *filter_list, *filter_dict;
+ char *filter_str;
- 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;
- geo.keep |= HB_KEEP_WIDTH;
- }
- else
- {
- geo.geometry.width -= geo.crop[2] + geo.crop[3];
- }
- if (height > 0)
- {
- geo.geometry.height = height;
- geo.keep |= HB_KEEP_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;
+ // Create new filters
+ filters_dict = hb_dict_init();
+ hb_dict_set(job_dict, "Filters", filters_dict);
+ filter_list = hb_value_array_init();
+ hb_dict_set(filters_dict, "FilterList", filter_list);
- // 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");
@@ -1301,7 +1087,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
char *s = hb_value_get_string_xform(detel_val);
hb_error("Invalid detelecine filter settings (%s)", s);
free(s);
- goto fail;
+ return -1;
}
else if (filter_str != hb_filter_off)
{
@@ -1338,7 +1124,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
char *s = hb_value_get_string_xform(decomb_val);
hb_error("Invalid decomb filter settings (%s)", s);
free(s);
- goto fail;
+ return -1;
}
else if (filter_str != hb_filter_off)
{
@@ -1371,7 +1157,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
char *s = hb_value_get_string_xform(deint_val);
hb_error("Invalid deinterlace filter settings (%s)", s);
free(s);
- goto fail;
+ return -1;
}
else if (filter_str != hb_filter_off)
{
@@ -1414,7 +1200,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
denoise_preset,
denoise_tune ? "," : "",
denoise_tune ? denoise_tune : "");
- goto fail;
+ return -1;
}
else if (filter_str != hb_filter_off)
{
@@ -1438,7 +1224,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
if (filter_str == NULL)
{
hb_error("Invalid deblock filter settings (%s)", deblock);
- goto fail;
+ return -1;
}
else if (filter_str != hb_filter_off)
{
@@ -1461,7 +1247,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
if (filter_str == NULL)
{
hb_error("Invalid rotate filter settings (%s)", rotate);
- goto fail;
+ return -1;
}
else if (filter_str != hb_filter_off)
{
@@ -1481,7 +1267,7 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
char *str = hb_value_get_string_xform(fr_value);
hb_error("Invalid video framerate (%s)", str);
free(str);
- goto fail;
+ return -1;
}
int fr_mode;
@@ -1491,9 +1277,6 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
!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
@@ -1505,73 +1288,79 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
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;
+ return 0;
+}
+
+int hb_preset_apply_video(const hb_dict_t *preset, hb_dict_t *job_dict)
+{
+ hb_dict_t *dest_dict, *video_dict, *qsv;
+ hb_value_t *value, *vcodec_value, *color_value;
+ int mux, vcodec, vqtype;
+ hb_encoder_t *encoder;
+
+ dest_dict = hb_dict_get(job_dict, "Destination");
+ mux = hb_container_get_from_name(hb_value_get_string(
+ hb_dict_get(dest_dict, "Mux")));
+ vcodec_value = hb_dict_get(preset, "VideoEncoder");
+ 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);
+ }
+ 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);
+ return -1;
+ }
+ if (!(encoder->muxers & mux))
+ {
+ hb_error("Incompatible video encoder (%s) for muxer (%s)",
+ hb_video_encoder_get_name(vcodec),
+ hb_container_get_name(mux));
+ return -1;
+ }
+
+ video_dict = hb_dict_get(job_dict, "Video");
+ hb_dict_set(video_dict, "Encoder", hb_value_string(encoder->short_name));
+
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;
+ if (vcodec == HB_VCODEC_X264 &&
+ hb_value_get_bool(hb_dict_get(preset, "x264UseAdvancedOptions")))
+ {
+ hb_dict_set(video_dict, "Options",
+ hb_value_dup(hb_dict_get(preset, "x264Option")));
+ }
+ else
+ {
+ 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, "VideoTune")) != NULL)
+ hb_dict_set(video_dict, "Tune", hb_value_dup(value));
+ if ((value = hb_dict_get(preset, "VideoOptionExtra")) != NULL)
+ hb_dict_set(video_dict, "Options", hb_value_dup(value));
}
- int vqtype = hb_value_get_int(hb_dict_get(preset, "VideoQualityType"));
+
+ 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));
+ hb_dict_set(video_dict, "Bitrate", hb_value_int(-1));
}
else if (vqtype == 1) // ABR
{
@@ -1584,13 +1373,17 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
hb_dict_set(video_dict, "Turbo",
hb_value_xform(hb_dict_get(preset, "VideoTurboTwoPass"),
HB_VALUE_TYPE_BOOL));
+ hb_dict_set(video_dict, "Quality", hb_value_double(-1.0));
}
else
{
- hb_value_t *value = hb_dict_get(preset, "VideoQualitySlider");
+ 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));
+ hb_dict_set(video_dict, "Bitrate", hb_value_int(-1));
+ }
else
{
hb_dict_set(video_dict, "Bitrate",
@@ -1602,15 +1395,15 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
hb_dict_set(video_dict, "Turbo",
hb_value_xform(hb_dict_get(preset, "VideoTurboTwoPass"),
HB_VALUE_TYPE_BOOL));
+ hb_dict_set(video_dict, "Quality", hb_value_double(-1.0));
}
}
- hb_dict_t *qsv = hb_dict_get(video_dict, "QSV");
+ 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",
@@ -1635,7 +1428,193 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
hb_dict_set(video_dict, "HWDecode",
hb_value_xform(value, HB_VALUE_TYPE_BOOL));
}
- video_dict = NULL;
+
+ return 0;
+}
+
+int hb_preset_apply_mux(const hb_dict_t *preset, hb_dict_t *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);
+ return -1;
+ }
+
+ hb_dict_t *dest_dict = hb_dict_get(job_dict, "Destination");
+ hb_dict_set(dest_dict, "Mux", hb_value_string(container->short_name));
+
+ 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));
+ 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);
+ }
+
+ return 0;
+}
+
+int hb_preset_apply_title(hb_handle_t *h, int title_index,
+ const hb_dict_t *preset, hb_dict_t *job_dict)
+{
+ // Apply preset settings that requires the title
+ hb_title_t *title = hb_find_title_by_index(h, title_index);
+ if (title == NULL)
+ return -1;
+
+ int chapters;
+ chapters = hb_value_get_bool(hb_dict_get(preset, "ChapterMarkers"));
+ if (title != NULL && 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_t *filters_dict = hb_dict_get(job_dict, "Filters");
+ hb_value_array_t *filter_list = hb_dict_get(filters_dict, "FilterList");
+
+ // 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;
+ geo.keep |= HB_KEEP_WIDTH;
+ }
+ else
+ {
+ geo.geometry.width -= geo.crop[2] + geo.crop[3];
+ }
+ if (height > 0)
+ {
+ geo.geometry.height = height;
+ geo.keep |= HB_KEEP_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;
+
+ 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);
// Audio settings
if (hb_preset_job_add_audio(h, title_index, preset, job_dict) != 0)
@@ -1648,11 +1627,52 @@ hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index,
{
goto fail;
}
+ return 0;
+
+fail:
+ return -1;
+}
+
+/**
+ * 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,
+ const 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);
+
+ if (hb_preset_apply_mux(preset, job_dict) < 0)
+ goto fail;
+
+ if (hb_preset_apply_video(preset, job_dict) < 0)
+ goto fail;
+
+ if (hb_preset_apply_filters(preset, job_dict) < 0)
+ goto fail;
+
+ if (hb_preset_apply_title(h, title_index, preset, job_dict) < 0)
+ goto fail;
return job_dict;
fail:
- hb_dict_free(&job_dict);
+ hb_value_free(&job_dict);
return NULL;
}
@@ -2099,6 +2119,28 @@ static void import_video(hb_value_t *preset)
if ((val = hb_dict_get(preset, "x264OptionExtra")) != NULL)
hb_dict_set(preset, "VideoOptionExtra", hb_value_dup(val));
+ // Remove invalid "none" tune from VideoTune. Frontends should
+ // be removing this before saving a preset.
+ if ((val = hb_dict_get(preset, "VideoTune")) != NULL)
+ {
+ const char *tune;
+ tune = hb_value_get_string(val);
+ // "none" is not a valid tune, but is used by HandBrake
+ // to indicate no tune options.
+ if (tune != NULL && !strncasecmp(tune, "none", 4))
+ {
+ tune += 4;
+ if (tune[0] == ',')
+ {
+ tune++;
+ }
+ }
+ if (tune != NULL)
+ {
+ hb_dict_set(preset, "VideoTune", hb_value_string(tune));
+ }
+ }
+
if (hb_value_get_int(hb_dict_get(preset, "VideoQualityType")) == 0)
{
// Target size no longer supported