3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
10 #include "builtin_presets.h"
15 #if defined(SYS_LINUX)
16 #define HB_PRESET_PLIST_FILE "ghb/presets"
17 #define HB_PRESET_JSON_FILE "ghb/presets.json"
18 #elif defined(SYS_MINGW)
19 #define HB_PRESET_PLIST_FILE "HandBrake\\user_presets.xml"
20 #define HB_PRESET_JSON_FILE "HandBrake\\user_presets.json"
21 #elif defined(SYS_DARWIN)
22 #define HB_PRESET_PLIST_FILE "HandBrake/UserPresets.plist"
23 #define HB_PRESET_JSON_FILE "HandBrake/UserPresets.json"
26 int hb_preset_version_major
;
27 int hb_preset_version_minor
;
28 int hb_preset_version_micro
;
30 static hb_value_t
*hb_preset_template
= NULL
;
31 static hb_value_t
*hb_presets
= NULL
;
32 static hb_value_t
*hb_presets_builtin
= NULL
;
34 static void preset_clean(hb_value_t
*preset
, hb_value_t
*template);
35 static void preset_import(hb_value_t
*preset
, int major
, int minor
, int micro
);
50 hb_preset_index_t path
;
51 } preset_do_context_t
;
55 preset_do_context_t do_ctx
;
57 } preset_clean_context_t
;
61 preset_do_context_t do_ctx
;
65 } preset_import_context_t
;
69 preset_do_context_t do_ctx
;
73 } preset_search_context_t
;
75 typedef int (*preset_do_f
)(hb_value_t
*preset
, preset_do_context_t
*ctx
);
77 static int preset_cmp_idx(hb_value_t
*preset
, int idx
, const char *name
)
79 const char *next
, *preset_name
;
86 // Find the part of the "name" path we want to match.
87 for (ii
= 0; ii
< idx
; ii
++)
89 next
= strchr(name
, '/');
91 return PRESET_DO_SKIP
;
96 // Find the end of the part we want to match
97 next
= strchr(name
, '/');
103 return PRESET_DO_SKIP
;
105 preset_name
= hb_value_get_string(hb_dict_get(preset
, "PresetName"));
106 if (strlen(preset_name
) > len
)
107 len
= strlen(preset_name
);
109 // If match found and it's the last component of the "name", success!
110 if (!strncmp(name
, preset_name
, len
))
113 return PRESET_DO_SUCCESS
;
115 return PRESET_DO_PARTIAL
;
117 return PRESET_DO_NEXT
;
120 static int do_preset_search(hb_value_t
*preset
, preset_do_context_t
*do_ctx
)
122 preset_search_context_t
*ctx
= (preset_search_context_t
*)do_ctx
;
125 idx
= ctx
->do_ctx
.path
.depth
- 1;
126 if (ctx
->last_match_idx
>= 0 && idx
> ctx
->last_match_idx
)
128 // If there was a previous partial match, try to continue the match
129 idx
-= ctx
->last_match_idx
;
132 result
= preset_cmp_idx(preset
, idx
, ctx
->name
);
133 if (ctx
->recurse
&& result
== PRESET_DO_SKIP
)
135 result
= preset_cmp_idx(preset
, 0, ctx
->name
);
136 ctx
->last_match_idx
= idx
;
138 if (result
== PRESET_DO_PARTIAL
)
140 return PRESET_DO_NEXT
;
144 ctx
->last_match_idx
= -1;
150 static int do_preset_import(hb_value_t
*preset
, preset_do_context_t
*do_ctx
)
152 preset_import_context_t
*ctx
= (preset_import_context_t
*)do_ctx
;
153 preset_import(preset
, ctx
->major
, ctx
->minor
, ctx
->micro
);
154 return PRESET_DO_NEXT
;
157 static int do_preset_clean(hb_value_t
*preset
, preset_do_context_t
*do_ctx
)
159 preset_clean_context_t
*ctx
= (preset_clean_context_t
*)do_ctx
;
160 preset_clean(preset
, ctx
->template);
161 return PRESET_DO_NEXT
;
164 static int do_delete_builtin(hb_value_t
*preset
, preset_do_context_t
*ctx
)
166 if (hb_value_get_int(hb_dict_get(preset
, "Type")) == 0)
167 return PRESET_DO_DELETE
;
168 return PRESET_DO_NEXT
;
171 static int do_clear_default(hb_value_t
*preset
, preset_do_context_t
*ctx
)
173 hb_dict_set(preset
, "Default", hb_value_bool(0));
174 return PRESET_DO_NEXT
;
177 static int do_find_default(hb_value_t
*preset
, preset_do_context_t
*ctx
)
179 if (!hb_value_get_bool(hb_dict_get(preset
, "Folder")) &&
180 hb_value_get_bool(hb_dict_get(preset
, "Default")))
182 return PRESET_DO_SUCCESS
;
184 return PRESET_DO_NEXT
;
187 static int presets_do(preset_do_f do_func
, hb_value_t
*preset
,
188 preset_do_context_t
*ctx
)
193 if (hb_value_type(preset
) == HB_VALUE_TYPE_ARRAY
)
195 // An array of presets, clean each one
198 for (ii
= 0; ii
< hb_value_array_len(preset
); )
200 ctx
->path
.index
[ctx
->path
.depth
-1] = ii
;
201 next
= hb_value_array_get(preset
, ii
);
202 result
= presets_do(do_func
, next
, ctx
);
203 if (result
== PRESET_DO_DELETE
)
205 hb_value_array_remove(preset
, ii
);
209 if (result
== PRESET_DO_SKIP
)
210 return PRESET_DO_NEXT
;
211 if (result
!= PRESET_DO_NEXT
)
214 return PRESET_DO_NEXT
;
216 else if (hb_value_type(preset
) == HB_VALUE_TYPE_DICT
&&
217 hb_dict_get(preset
, "VersionMajor") != NULL
)
219 // A packaged preset list
220 next
= hb_dict_get(preset
, "PresetList");
221 return presets_do(do_func
, next
, ctx
);
223 else if (hb_value_type(preset
) == HB_VALUE_TYPE_DICT
&&
224 hb_value_get_bool(hb_dict_get(preset
, "Folder")))
226 // Perform do_func on the folder...
227 result
= do_func(preset
, ctx
);
228 if (result
!= PRESET_DO_NEXT
)
231 // Then perform preset action on the children of the folder
233 next
= hb_dict_get(preset
, "ChildrenArray");
234 result
= presets_do(do_func
, next
, ctx
);
235 if (result
== PRESET_DO_SUCCESS
)
240 else if (hb_value_type(preset
) == HB_VALUE_TYPE_DICT
&&
241 hb_dict_get(preset
, "PresetName") != NULL
)
243 // An individual, non-folder, preset
244 return do_func(preset
, ctx
);
248 hb_error("Error: invalid preset format in presets_do()");
249 return PRESET_DO_NEXT
;
251 return PRESET_DO_DONE
;
254 hb_preset_index_t
* hb_preset_index_init(const int *index
, int depth
)
256 hb_preset_index_t
*path
;
257 path
= malloc(sizeof(hb_preset_index_t
));
260 memcpy(path
->index
, index
, depth
* sizeof(int));
264 hb_preset_index_t
* hb_preset_index_dup(const hb_preset_index_t
*path
)
268 return hb_preset_index_init(path
->index
, path
->depth
);
271 void hb_preset_index_append(hb_preset_index_t
*dst
,
272 const hb_preset_index_t
*src
)
275 for (ii
= 0; ii
< src
->depth
&&
276 dst
->depth
< HB_MAX_PRESET_FOLDER_DEPTH
; ii
++, dst
->depth
++)
278 dst
->index
[dst
->depth
] = src
->index
[ii
];
282 static int get_job_mux(hb_dict_t
*job_dict
)
286 hb_dict_t
*dest_dict
= hb_dict_get(job_dict
, "Destination");
287 hb_value_t
*mux_value
= hb_dict_get(dest_dict
, "Mux");
288 if (hb_value_type(mux_value
) == HB_VALUE_TYPE_STRING
)
290 mux
= hb_container_get_from_name(hb_value_get_string(mux_value
));
292 mux
= hb_container_get_from_extension(
293 hb_value_get_string(mux_value
));
297 mux
= hb_value_get_int(mux_value
);
299 hb_container_t
*container
= hb_container_get_from_format(mux
);
300 if (container
== NULL
)
302 char *str
= hb_value_get_string_xform(mux_value
);
303 hb_error("Invalid container (%s)", str
);
305 return HB_MUX_INVALID
;
310 static hb_value_t
* get_audio_copy_mask(const hb_dict_t
* preset
, int *mask
)
313 hb_value_array_t
*out_copy_mask
, *in_copy_mask
;
317 in_copy_mask
= hb_dict_get(preset
, "AudioCopyMask");
318 out_copy_mask
= hb_value_array_init();
319 if (in_copy_mask
!= NULL
)
322 count
= hb_value_array_len(in_copy_mask
);
323 for (ii
= 0; ii
< count
; ii
++)
327 value
= hb_value_array_get(in_copy_mask
, ii
);
328 if (hb_value_type(value
) == HB_VALUE_TYPE_STRING
)
331 const char * s
= hb_value_get_string(value
);
332 // Only codecs that start with 'copy:' can be copied
333 if (strncmp(s
, "copy:", 5))
335 s
= tmp
= hb_strdup_printf("copy:%s", s
);
337 codec
= hb_audio_encoder_get_from_name(s
);
340 hb_error("Invalid audio codec in autopassthru copy mask (%s)", s
);
341 hb_error("Codec name is invalid or can not be copied");
343 hb_value_free(&out_copy_mask
);
350 codec
= hb_value_get_int(value
);
352 hb_value_array_append(out_copy_mask
, hb_value_string(
353 hb_audio_encoder_get_short_name(codec
)));
359 return out_copy_mask
;
362 static hb_dict_t
* source_audio_track_used(hb_dict_t
*track_dict
, int track
)
364 // Kind of hacky, but keys must be strings
366 snprintf(key
, sizeof(key
), "%d", track
);
368 hb_dict_t
*used
= hb_dict_get(track_dict
, key
);
371 used
= hb_dict_init();
372 hb_dict_set(track_dict
, key
, used
);
377 // Find a source audio track matching given language
378 static int find_audio_track(const hb_title_t
*title
,
379 const char *lang
, int start
)
381 hb_audio_config_t
* audio
;
384 count
= hb_list_count(title
->list_audio
);
385 for (ii
= start
; ii
< count
; ii
++)
387 audio
= hb_list_audio_config_item(title
->list_audio
, ii
);
388 // Ignore secondary audio types
389 if ((audio
->lang
.type
== HB_AUDIO_TYPE_NONE
||
390 audio
->lang
.type
== HB_AUDIO_TYPE_NORMAL
) &&
391 (!strcmp(lang
, audio
->lang
.iso639_2
) || !strcmp(lang
, "und")))
399 static int validate_audio_encoders(const hb_dict_t
*preset
)
401 hb_value_array_t
* encoder_list
= hb_dict_get(preset
, "AudioList");
402 int count
= hb_value_array_len(encoder_list
);
404 for (ii
= 0; ii
< count
; ii
++)
406 hb_value_t
*audio_dict
= hb_value_array_get(encoder_list
, ii
);
409 value
= hb_dict_get(audio_dict
, "AudioEncoder");
410 if (hb_value_type(value
) == HB_VALUE_TYPE_STRING
)
412 codec
= hb_audio_encoder_get_from_name(hb_value_get_string(value
));
416 codec
= hb_value_get_int(value
);
418 if (hb_audio_encoder_get_from_codec(codec
) == NULL
)
420 char *str
= hb_value_get_string_xform(value
);
421 hb_error("Invalid audio encoder (%s)", str
);
426 value
= hb_dict_get(audio_dict
, "AudioMixdown");
427 if (hb_value_type(value
) == HB_VALUE_TYPE_STRING
)
429 mix
= hb_audio_encoder_get_from_name(hb_value_get_string(value
));
433 mix
= hb_value_get_int(value
);
435 if (hb_mixdown_get_from_mixdown(mix
) == NULL
)
437 char *str
= hb_value_get_string_xform(value
);
438 hb_error("Invalid audio mixdown (%s)", str
);
443 value
= hb_dict_get(audio_dict
, "AudioSamplerate");
444 if (hb_value_type(value
) == HB_VALUE_TYPE_STRING
)
446 const char *str
= hb_value_get_string(value
);
447 if (!strcasecmp(str
, "source") ||
448 !strcasecmp(str
, "auto") ||
449 !strcasecmp(str
, "same as source"))
455 sr
= hb_audio_samplerate_get_from_name(str
);
460 sr
= hb_value_get_int(value
);
462 if (sr
!= 0 && hb_audio_samplerate_get_name(sr
) == NULL
)
464 char *str
= hb_value_get_string_xform(value
);
465 hb_error("Invalid audio samplerate (%s)", str
);
473 static int sanitize_audio_codec(int in_codec
, int out_codec
,
474 int copy_mask
, int fallback
, int mux
)
476 int codec
= out_codec
;
477 if (out_codec
== HB_ACODEC_AUTO_PASS
)
479 codec
= hb_autopassthru_get_encoder(in_codec
, copy_mask
, fallback
, mux
);
481 else if ((out_codec
& HB_ACODEC_PASS_FLAG
) &&
482 !(in_codec
& out_codec
& HB_ACODEC_PASS_MASK
))
484 codec
= hb_audio_encoder_get_fallback_for_passthru(out_codec
);
489 // Check that encoder is valid for mux
490 const hb_encoder_t
*encoder
= NULL
;
491 while ((encoder
= hb_audio_encoder_get_next(encoder
)) != NULL
)
493 if (encoder
->codec
== codec
&&
494 !(encoder
->muxers
& mux
))
496 codec
= hb_audio_encoder_get_default(mux
);
501 codec
= hb_audio_encoder_get_default(mux
);
505 static void add_audio_for_lang(hb_value_array_t
*list
, const hb_dict_t
*preset
,
506 hb_title_t
*title
, int mux
, int copy_mask
,
507 int fallback
, const char *lang
,
508 int behavior
, int mode
, hb_dict_t
*track_dict
)
510 hb_value_array_t
* encoder_list
= hb_dict_get(preset
, "AudioList");
511 int count
= hb_value_array_len(encoder_list
);
512 int track
= find_audio_track(title
, lang
, 0);
513 int current_mode
= 0;
517 snprintf(key
, sizeof(key
), "%d", track
);
519 count
= current_mode
? 1 : count
;
521 for (ii
= 0; ii
< count
; ii
++)
523 // Check if this source track has already been added using these
524 // same encoder settings. If so, continue to next track.
525 hb_dict_t
*used
= source_audio_track_used(track_dict
, ii
);
526 if (hb_value_get_bool(hb_dict_get(used
, key
)))
528 hb_dict_set(used
, key
, hb_value_bool(1));
530 // Create new audio output track settings
531 hb_dict_t
*audio_dict
= hb_dict_init();
532 hb_value_t
*acodec_value
;
533 hb_dict_t
*encoder_dict
= hb_value_array_get(encoder_list
, ii
);
536 acodec_value
= hb_dict_get(encoder_dict
, "AudioEncoder");
537 if (hb_value_type(acodec_value
) == HB_VALUE_TYPE_STRING
)
539 out_codec
= hb_audio_encoder_get_from_name(
540 hb_value_get_string(acodec_value
));
544 out_codec
= hb_value_get_int(acodec_value
);
546 // Save the encoder value before sanitizing. This value is
547 // useful to the frontends.
548 hb_dict_set(audio_dict
, "PresetEncoder",
549 hb_value_string(hb_audio_encoder_get_short_name(out_codec
)));
551 hb_audio_config_t
*aconfig
;
552 aconfig
= hb_list_audio_config_item(title
->list_audio
, track
);
553 out_codec
= sanitize_audio_codec(aconfig
->in
.codec
, out_codec
,
554 copy_mask
, fallback
, mux
);
555 hb_dict_set(audio_dict
, "Track", hb_value_int(track
));
556 hb_dict_set(audio_dict
, "Encoder", hb_value_string(
557 hb_audio_encoder_get_short_name(out_codec
)));
558 if (hb_dict_get(encoder_dict
, "AudioTrackName") != NULL
)
560 hb_dict_set(audio_dict
, "Name", hb_value_dup(
561 hb_dict_get(encoder_dict
, "AudioTrackName")));
563 if (!(out_codec
& HB_ACODEC_PASS_FLAG
))
565 if (hb_dict_get(encoder_dict
, "AudioTrackGainSlider") != NULL
)
567 hb_dict_set(audio_dict
, "Gain", hb_value_dup(
568 hb_dict_get(encoder_dict
, "AudioTrackGainSlider")));
570 if (hb_dict_get(encoder_dict
, "AudioTrackDRCSlider") != NULL
)
572 hb_dict_set(audio_dict
, "DRC", hb_value_dup(
573 hb_dict_get(encoder_dict
, "AudioTrackDRCSlider")));
575 if (hb_dict_get(encoder_dict
, "AudioMixdown") != NULL
)
577 hb_dict_set(audio_dict
, "Mixdown", hb_value_dup(
578 hb_dict_get(encoder_dict
, "AudioMixdown")));
580 if (hb_dict_get(encoder_dict
, "AudioNormalizeMixLevel") != NULL
)
582 hb_dict_set(audio_dict
, "NormalizeMixLevel", hb_value_dup(
583 hb_dict_get(encoder_dict
, "AudioNormalizeMixLevel")));
585 if (hb_dict_get(encoder_dict
, "AudioDitherMethod") != NULL
)
587 hb_dict_set(audio_dict
, "DitherMethod", hb_value_dup(
588 hb_dict_get(encoder_dict
, "AudioDitherMethod")));
590 if (hb_dict_get(encoder_dict
, "AudioSamplerate") != NULL
)
592 hb_dict_set(audio_dict
, "Samplerate", hb_value_dup(
593 hb_dict_get(encoder_dict
, "AudioSamplerate")));
595 if (hb_dict_get(encoder_dict
, "AudioCompressionLevel") != NULL
)
597 hb_dict_set(audio_dict
, "CompressionLevel", hb_value_dup(
598 hb_dict_get(encoder_dict
, "AudioCompressionLevel")));
600 if (hb_value_get_bool(hb_dict_get(encoder_dict
,
601 "AudioTrackQualityEnable")))
603 hb_dict_set(audio_dict
, "Quality", hb_value_xform(
604 hb_dict_get(encoder_dict
, "AudioTrackQuality"),
605 HB_VALUE_TYPE_DOUBLE
));
609 hb_dict_set(audio_dict
, "Bitrate", hb_value_xform(
610 hb_dict_get(encoder_dict
, "AudioBitrate"),
614 hb_value_array_append(list
, audio_dict
);
617 track
= find_audio_track(title
, lang
, track
+ 1);
623 // This function assumes that Mux has already been initialized in
625 int hb_preset_job_add_audio(hb_handle_t
*h
, int title_index
,
626 const hb_dict_t
*preset
, hb_dict_t
*job_dict
)
628 hb_title_t
*title
= hb_find_title_by_index(h
, title_index
);
631 // Can't create audio track list without knowing source audio tracks
632 hb_error("Invalid title index (%d)", title_index
);
635 if (hb_list_count(title
->list_audio
) <= 0)
637 // Source has no audio
641 int mux
= get_job_mux(job_dict
);
642 if (mux
== HB_MUX_INVALID
)
647 hb_dict_t
*audio_dict
= hb_dict_get(job_dict
, "Audio");
648 if (audio_dict
== NULL
)
650 audio_dict
= hb_dict_init();
651 hb_dict_set(job_dict
, "Audio", audio_dict
);
654 hb_value_t
*copy_mask_array
= get_audio_copy_mask(preset
, ©_mask
);
655 if (copy_mask_array
== NULL
)
660 hb_dict_set(audio_dict
, "CopyMask", copy_mask_array
);
661 hb_value_t
*fallback_value
= hb_dict_get(preset
, "AudioEncoderFallback");
662 if (fallback_value
!= NULL
)
664 hb_dict_set(audio_dict
, "FallbackEncoder",
665 hb_value_dup(fallback_value
));
666 if (hb_value_type(fallback_value
) == HB_VALUE_TYPE_STRING
)
668 const char * s
= hb_value_get_string(fallback_value
);
669 fallback
= hb_audio_encoder_get_from_name(s
);
672 hb_error("Invalid fallback audio codec (%s)", s
);
678 fallback
= hb_value_get_int(fallback_value
);
681 if (validate_audio_encoders(preset
) < 0)
684 hb_value_array_t
*list
= hb_dict_get(audio_dict
, "AudioList");
687 list
= hb_value_array_init();
688 hb_dict_set(audio_dict
, "AudioList", list
);
691 int behavior
= 1; // default first
693 s
= hb_value_get_string(hb_dict_get(preset
, "AudioTrackSelectionBehavior"));
696 if (!strcasecmp(s
, "none"))
698 else if (!strcasecmp(s
, "all"))
702 // Create hash that is used to track which tracks have been already added
703 // We do not want to add the same track with the same settings twice
704 hb_dict_t
*track_dict
= hb_dict_init();
706 // Add tracks for all languages in the language list
708 hb_value_array_t
*lang_list
= hb_dict_get(preset
, "AudioLanguageList");
709 mode
= hb_value_get_bool(hb_dict_get(preset
, "AudioSecondaryEncoderMode"));
710 int count
= hb_value_array_len(lang_list
);
712 for (ii
= 0; ii
< count
; ii
++)
715 lang
= hb_value_get_string(hb_value_array_get(lang_list
, ii
));
716 add_audio_for_lang(list
, preset
, title
, mux
, copy_mask
, fallback
,
717 lang
, behavior
, mode
, track_dict
);
719 // If no audios found, try "und" language option
720 if (hb_value_array_len(list
) <= 0)
722 add_audio_for_lang(list
, preset
, title
, mux
, copy_mask
, fallback
,
723 "und", behavior
, mode
, track_dict
);
725 hb_dict_free(&track_dict
);
729 // Find a source audio track matching given language
730 static int find_subtitle_track(const hb_title_t
*title
,
731 const char *lang
, int start
)
733 hb_subtitle_t
* subtitle
;
736 count
= hb_list_count(title
->list_subtitle
);
737 for (ii
= start
; ii
< count
; ii
++)
739 subtitle
= hb_list_item(title
->list_subtitle
, ii
);
740 if (!strcmp(lang
, subtitle
->iso639_2
) || !strcmp(lang
, "und"))
748 static void add_subtitle(hb_value_array_t
*list
, int track
,
749 int make_default
, int force
, int burn
)
751 hb_dict_t
*subtitle_dict
= hb_dict_init();
752 hb_dict_set(subtitle_dict
, "Track", hb_value_int(track
));
753 hb_dict_set(subtitle_dict
, "Default", hb_value_bool(make_default
));
754 hb_dict_set(subtitle_dict
, "Forced", hb_value_bool(force
));
755 hb_dict_set(subtitle_dict
, "Burn", hb_value_bool(burn
));
756 hb_value_array_append(list
, subtitle_dict
);
759 typedef struct subtitle_behavior_s
769 } subtitle_behavior_t
;
771 static void add_subtitle_for_lang(hb_value_array_t
*list
, hb_title_t
*title
,
772 int mux
, const char *lang
,
773 subtitle_behavior_t
*behavior
)
776 t
= find_subtitle_track(title
, lang
, 0);
777 for (t
= find_subtitle_track(title
, lang
, 0);
779 t
= behavior
->one
? -1 : find_subtitle_track(title
, lang
, t
+ 1))
781 if (behavior
->used
[t
])
787 int burn
, make_default
;
788 hb_subtitle_t
*subtitle
;
789 subtitle
= hb_list_item(title
->list_subtitle
, t
);
790 burn
= !behavior
->one_burned
&&
791 ((subtitle
->source
== VOBSUB
&& behavior
->burn_dvd
) ||
792 (subtitle
->source
== PGSSUB
&& behavior
->burn_bd
) ||
793 !hb_subtitle_can_pass(subtitle
->source
, mux
) ||
794 behavior
->burn_first
|| behavior
->burn_foreign
);
795 make_default
= !burn
&& behavior
->make_default
;
796 behavior
->burn_first
&= !burn
;
797 behavior
->one_burned
|= burn
;
798 behavior
->used
[t
] = 1;
799 add_subtitle(list
, t
, make_default
, 0 /*!force*/, burn
);
803 // This function assumes that the AudioList and Mux have already been
804 // initialized in the job_dict
805 int hb_preset_job_add_subtitles(hb_handle_t
*h
, int title_index
,
806 const hb_dict_t
*preset
, hb_dict_t
*job_dict
)
808 hb_title_t
*title
= hb_find_title_by_index(h
, title_index
);
811 // Can't create subtitle track list without knowing source
812 hb_error("Invalid title index (%d)", title_index
);
816 int mux
= get_job_mux(job_dict
);
817 if (mux
== HB_MUX_INVALID
)
822 // Get the language of the first audio output track
823 // Needed for subtitle track selection
824 hb_dict_t
*audio_dict
= hb_dict_get(job_dict
, "Audio");
825 hb_value_array_t
*audio_list
= hb_dict_get(audio_dict
, "AudioList");
826 const char *first_audio_lang
= NULL
;
827 if (hb_value_array_len(audio_list
) > 0)
830 hb_value_t
*audio
= hb_value_array_get(audio_list
, 0);
831 track
= hb_value_get_int(hb_dict_get(audio
, "Track"));
832 if (hb_list_count(title
->list_audio
) > track
)
834 hb_audio_config_t
*aconfig
;
835 aconfig
= hb_list_audio_config_item(title
->list_audio
, track
);
837 first_audio_lang
= aconfig
->lang
.iso639_2
;
841 int source_subtitle_count
= hb_list_count(title
->list_subtitle
);
842 if (source_subtitle_count
== 0)
845 hb_dict_t
*subtitle_dict
= hb_dict_get(job_dict
, "Subtitle");
846 if (subtitle_dict
== NULL
)
848 subtitle_dict
= hb_dict_init();
849 hb_dict_set(job_dict
, "Subtitle", subtitle_dict
);
851 hb_value_array_t
*list
= hb_dict_get(subtitle_dict
, "SubtitleList");
854 list
= hb_value_array_init();
855 hb_dict_set(subtitle_dict
, "SubtitleList", list
);
858 int track_behavior
= 0; // default no subtitles
859 int burn_behavior
= 0;
862 struct subtitle_behavior_s behavior
;
864 behavior
.burn_foreign
= 0;
865 behavior
.make_default
= 0;
866 behavior
.burn_first
= 0;
867 behavior
.burn_dvd
= 0;
868 behavior
.burn_bd
= 0;
869 behavior
.one_burned
= 0;
870 // Create array that is used to track which tracks have been already added
871 // We do not want to add the same track with the same settings twice
872 behavior
.used
= calloc(source_subtitle_count
, sizeof(*behavior
.used
));
874 // Since this function can be called multiple times, we need to
875 // initialize the "used" array from the existing subtitles in the list.
877 count
= hb_value_array_len(list
);
878 for (ii
= 0; ii
< count
; ii
++)
880 hb_value_t
*sub
= hb_value_array_get(list
, ii
);
881 int track
= hb_value_get_int(hb_dict_get(sub
, "Track"));
882 behavior
.used
[track
] = 1;
886 s
= hb_value_get_string(hb_dict_get(preset
,
887 "SubtitleTrackSelectionBehavior"));
890 if (!strcasecmp(s
, "first"))
892 else if (!strcasecmp(s
, "all"))
896 s
= hb_value_get_string(hb_dict_get(preset
, "SubtitleBurnBehavior"));
899 if (!strcasecmp(s
, "foreign"))
901 else if (!strcasecmp(s
, "first"))
903 else if (!strcasecmp(s
, "foreign_first"))
907 behavior
.burn_dvd
= hb_value_get_int(hb_dict_get(preset
,
908 "SubtitleBurnDVDSub"));
909 behavior
.burn_bd
= hb_value_get_int(hb_dict_get(preset
,
910 "SubtitleBurnBDSub"));
912 burn_foreign
= burn_behavior
== 1 || burn_behavior
== 3;
913 behavior
.burn_first
= burn_behavior
== 2 || burn_behavior
== 3;
915 int foreign_audio_search
, foreign_first_audio
;
916 foreign_audio_search
= hb_value_get_bool(hb_dict_get(preset
,
917 "SubtitleAddForeignAudioSearch"));
918 foreign_first_audio
= hb_value_get_bool(hb_dict_get(preset
,
919 "SubtitleAddForeignAudioSubtitle"));
922 // Add tracks for all languages in the language list
923 hb_value_array_t
*lang_list
= hb_dict_get(preset
, "SubtitleLanguageList");
924 count
= hb_value_array_len(lang_list
);
925 const char *pref_lang
= "und";
928 pref_lang
= hb_value_get_string(hb_value_array_get(lang_list
, 0));
930 if (!strcmp(pref_lang
, "und"))
932 foreign_audio_search
= foreign_first_audio
= 0;
936 if (first_audio_lang
!= NULL
&&
937 foreign_first_audio
&& strncmp(first_audio_lang
, pref_lang
, 4))
939 // First audio lang does not match the preferred subittle lang.
940 // Preset says to add pref lang subtitle.
941 // Foreign audio search is not necessary since entire audio track
943 foreign_audio_search
= 0;
945 behavior
.burn_foreign
= burn_foreign
;
946 behavior
.make_default
= 1;
947 add_subtitle_for_lang(list
, title
, mux
, pref_lang
, &behavior
);
950 hb_dict_t
*search_dict
= hb_dict_get(subtitle_dict
, "Search");
951 if (search_dict
== NULL
)
953 search_dict
= hb_dict_init();
954 hb_dict_set(subtitle_dict
, "Search", search_dict
);
956 if (first_audio_lang
!= NULL
&&
957 foreign_audio_search
&& !strncmp(first_audio_lang
, pref_lang
, 4))
959 // First audio lang matches the preferred subittle lang.
960 // Preset says to add search for foreign audio subtitles.
961 int burn
= burn_foreign
|| behavior
.burn_first
;
962 // If not burning, make this the default track.
963 hb_dict_set(search_dict
, "Enable", hb_value_bool(1));
964 hb_dict_set(search_dict
, "Default", hb_value_bool(!burn
));
965 hb_dict_set(search_dict
, "Forced", hb_value_bool(1));
966 hb_dict_set(search_dict
, "Burn", hb_value_bool(burn
));
970 hb_dict_set(search_dict
, "Enable", hb_value_bool(0));
973 if (track_behavior
> 0)
976 behavior
.one
= track_behavior
== 1;
977 behavior
.burn_foreign
= 0;
978 behavior
.make_default
= 0;
979 for (ii
= 0; ii
< count
; ii
++)
982 lang
= hb_value_get_string(hb_value_array_get(lang_list
, ii
));
983 add_subtitle_for_lang(list
, title
, mux
, lang
, &behavior
);
987 add_subtitle_for_lang(list
, title
, mux
, "und", &behavior
);
991 if (hb_value_get_bool(hb_dict_get(preset
, "SubtitleAddCC")))
993 // Add Closed Caption track
994 for (track
= 0; track
< source_subtitle_count
; track
++)
996 if (behavior
.used
[track
])
1000 hb_subtitle_t
*subtitle
= hb_list_item(title
->list_subtitle
, track
);
1001 if (subtitle
->source
== CC608SUB
|| subtitle
->source
== CC708SUB
)
1004 burn
= !behavior
.one_burned
&&
1005 (!hb_subtitle_can_pass(subtitle
->source
, mux
) ||
1006 behavior
.burn_first
);
1007 behavior
.used
[track
] = 1;
1008 behavior
.one_burned
|= burn
;
1009 add_subtitle(list
, track
, 0 /*default*/, 0 /*!force*/, burn
);
1014 free(behavior
.used
);
1019 static int get_video_framerate(hb_value_t
*rate_value
)
1022 if (hb_value_type(rate_value
) != HB_VALUE_TYPE_STRING
)
1025 d
= hb_value_get_double(rate_value
);
1026 if (d
!= 0 && d
<= 600)
1028 // Assume the value is an actual framerate and compute
1029 // 27Mhz based denominator
1030 rate
= (int)(27000000 / d
);
1034 // Assume the value is a 27Mhz based denominator
1040 const char *rate_name
= hb_value_get_string(rate_value
);
1041 if (strcasecmp(rate_name
, "source") &&
1042 strcasecmp(rate_name
, "auto") &&
1043 strcasecmp(rate_name
, "same as source"))
1045 rate
= hb_video_framerate_get_from_name(rate_name
);
1048 // No matching rate found. Error out.
1056 int hb_preset_apply_filters(const hb_dict_t
*preset
, hb_dict_t
*job_dict
)
1058 hb_value_t
*filters_dict
, *filter_list
, *filter_dict
;
1061 // Create new filters
1062 filters_dict
= hb_dict_init();
1063 hb_dict_set(job_dict
, "Filters", filters_dict
);
1064 filter_list
= hb_value_array_init();
1065 hb_dict_set(filters_dict
, "FilterList", filter_list
);
1067 hb_dict_set(filters_dict
, "Grayscale", hb_value_xform(
1068 hb_dict_get(preset
, "VideoGrayScale"), HB_VALUE_TYPE_BOOL
));
1070 // Detelecine filter
1071 hb_value_t
*detel_val
= hb_dict_get(preset
, "PictureDetelecine");
1072 if (detel_val
!= NULL
)
1075 custom
= hb_value_get_string(hb_dict_get(preset
,
1076 "PictureDetelecineCustom"));
1077 if (hb_value_type(detel_val
) == HB_VALUE_TYPE_STRING
)
1079 filter_str
= hb_generate_filter_settings(
1080 HB_FILTER_DETELECINE
, hb_value_get_string(detel_val
), custom
);
1084 filter_str
= hb_generate_filter_settings_by_index(
1085 HB_FILTER_DETELECINE
, hb_value_get_int(detel_val
), custom
);
1087 if (filter_str
== NULL
)
1089 char *s
= hb_value_get_string_xform(detel_val
);
1090 hb_error("Invalid detelecine filter settings (%s)", s
);
1094 else if (filter_str
!= hb_filter_off
)
1096 filter_dict
= hb_dict_init();
1097 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_DETELECINE
));
1098 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1099 hb_value_array_append(filter_list
, filter_dict
);
1104 // Decomb or deinterlace filters
1105 int decomb_or_deint
;
1106 decomb_or_deint
= hb_value_get_bool(hb_dict_get(preset
,
1107 "PictureDecombDeinterlace"));
1108 hb_value_t
*decomb_val
= hb_dict_get(preset
, "PictureDecomb");
1109 if (decomb_or_deint
&& decomb_val
!= NULL
)
1112 custom
= hb_value_get_string(hb_dict_get(preset
,
1113 "PictureDecombCustom"));
1114 if (hb_value_type(decomb_val
) == HB_VALUE_TYPE_STRING
)
1116 filter_str
= hb_generate_filter_settings(
1117 HB_FILTER_DECOMB
, hb_value_get_string(decomb_val
), custom
);
1121 filter_str
= hb_generate_filter_settings_by_index(
1122 HB_FILTER_DECOMB
, hb_value_get_int(decomb_val
), custom
);
1124 if (filter_str
== NULL
)
1126 char *s
= hb_value_get_string_xform(decomb_val
);
1127 hb_error("Invalid decomb filter settings (%s)", s
);
1131 else if (filter_str
!= hb_filter_off
)
1133 filter_dict
= hb_dict_init();
1134 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_DECOMB
));
1135 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1136 hb_value_array_append(filter_list
, filter_dict
);
1141 hb_value_t
*deint_val
= hb_dict_get(preset
, "PictureDeinterlace");
1142 if (!decomb_or_deint
&& deint_val
!= NULL
)
1145 custom
= hb_value_get_string(hb_dict_get(preset
,
1146 "PictureDeinterlaceCustom"));
1147 if (hb_value_type(deint_val
) == HB_VALUE_TYPE_STRING
)
1149 filter_str
= hb_generate_filter_settings(
1150 HB_FILTER_DEINTERLACE
, hb_value_get_string(deint_val
), custom
);
1154 filter_str
= hb_generate_filter_settings_by_index(
1155 HB_FILTER_DEINTERLACE
, hb_value_get_int(deint_val
), custom
);
1157 if (filter_str
== NULL
)
1159 char *s
= hb_value_get_string_xform(deint_val
);
1160 hb_error("Invalid deinterlace filter settings (%s)", s
);
1164 else if (filter_str
!= hb_filter_off
)
1166 filter_dict
= hb_dict_init();
1167 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_DEINTERLACE
));
1168 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1169 hb_value_array_append(filter_list
, filter_dict
);
1176 hb_value_t
*denoise_value
= hb_dict_get(preset
, "PictureDenoiseFilter");
1177 denoise
= hb_value_type(denoise_value
) == HB_VALUE_TYPE_STRING
? (
1178 !strcasecmp(hb_value_get_string(denoise_value
), "off") ? 0 :
1179 !strcasecmp(hb_value_get_string(denoise_value
), "nlmeans") ? 1 : 2) :
1180 hb_value_get_int(denoise_value
);
1184 int filter_id
= denoise
== 1 ? HB_FILTER_NLMEANS
: HB_FILTER_HQDN3D
;
1185 const char *denoise_preset
, *denoise_tune
;
1186 denoise_preset
= hb_value_get_string(
1187 hb_dict_get(preset
, "PictureDenoisePreset"));
1188 if (denoise_preset
!= NULL
)
1190 if (strcasecmp(denoise_preset
, "custom"))
1191 denoise_tune
= hb_value_get_string(
1192 hb_dict_get(preset
, "PictureDenoiseTune"));
1194 denoise_tune
= hb_value_get_string(
1195 hb_dict_get(preset
, "PictureDenoiseCustom"));
1197 filter_str
= hb_generate_filter_settings(
1198 filter_id
, denoise_preset
, denoise_tune
);
1199 if (filter_str
== NULL
)
1201 hb_error("Invalid denoise filter settings (%s%s%s)",
1203 denoise_tune
? "," : "",
1204 denoise_tune
? denoise_tune
: "");
1207 else if (filter_str
!= hb_filter_off
)
1209 filter_dict
= hb_dict_init();
1210 hb_dict_set(filter_dict
, "ID", hb_value_int(filter_id
));
1211 hb_dict_set(filter_dict
, "Settings",
1212 hb_value_string(filter_str
));
1213 hb_value_array_append(filter_list
, filter_dict
);
1220 char *deblock
= hb_value_get_string_xform(
1221 hb_dict_get(preset
, "PictureDeblock"));
1222 if (deblock
!= NULL
)
1224 filter_str
= hb_generate_filter_settings(HB_FILTER_DEBLOCK
,
1226 if (filter_str
== NULL
)
1228 hb_error("Invalid deblock filter settings (%s)", deblock
);
1231 else if (filter_str
!= hb_filter_off
)
1233 filter_dict
= hb_dict_init();
1234 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_DEBLOCK
));
1235 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1236 hb_value_array_append(filter_list
, filter_dict
);
1243 char *rotate
= hb_value_get_string_xform(
1244 hb_dict_get(preset
, "PictureRotate"));
1247 filter_str
= hb_generate_filter_settings(HB_FILTER_ROTATE
,
1249 if (filter_str
== NULL
)
1251 hb_error("Invalid rotate filter settings (%s)", rotate
);
1254 else if (filter_str
!= hb_filter_off
)
1256 filter_dict
= hb_dict_init();
1257 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_ROTATE
));
1258 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1259 hb_value_array_append(filter_list
, filter_dict
);
1265 hb_value_t
*fr_value
= hb_dict_get(preset
, "VideoFramerate");
1266 int vrate_den
= get_video_framerate(fr_value
);
1269 char *str
= hb_value_get_string_xform(fr_value
);
1270 hb_error("Invalid video framerate (%s)", str
);
1276 hb_value_t
*fr_mode_value
= hb_dict_get(preset
, "VideoFramerateMode");
1277 fr_mode
= hb_value_type(fr_mode_value
) == HB_VALUE_TYPE_STRING
? (
1278 !strcasecmp(hb_value_get_string(fr_mode_value
), "cfr") ? 1 :
1279 !strcasecmp(hb_value_get_string(fr_mode_value
), "pfr") ? 2 : 0) :
1280 hb_value_get_int(fr_mode_value
);
1283 filter_str
= hb_strdup_printf("%d", fr_mode
);
1285 filter_str
= hb_strdup_printf("%d:%d:%d", fr_mode
, 27000000, vrate_den
);
1287 filter_dict
= hb_dict_init();
1288 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_VFR
));
1289 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1290 hb_value_array_append(filter_list
, filter_dict
);
1296 int hb_preset_apply_video(const hb_dict_t
*preset
, hb_dict_t
*job_dict
)
1298 hb_dict_t
*dest_dict
, *video_dict
, *qsv
;
1299 hb_value_t
*value
, *vcodec_value
, *color_value
;
1300 int mux
, vcodec
, vqtype
;
1301 hb_encoder_t
*encoder
;
1303 dest_dict
= hb_dict_get(job_dict
, "Destination");
1304 mux
= hb_container_get_from_name(hb_value_get_string(
1305 hb_dict_get(dest_dict
, "Mux")));
1306 vcodec_value
= hb_dict_get(preset
, "VideoEncoder");
1307 if (hb_value_type(vcodec_value
) == HB_VALUE_TYPE_STRING
)
1309 vcodec
= hb_video_encoder_get_from_name(
1310 hb_value_get_string(vcodec_value
));
1314 vcodec
= hb_value_get_int(vcodec_value
);
1316 encoder
= hb_video_encoder_get_from_codec(vcodec
);
1317 if (encoder
== NULL
)
1319 char *str
= hb_value_get_string_xform(vcodec_value
);
1320 hb_error("Invalid video encoder (%s)", str
);
1324 if (!(encoder
->muxers
& mux
))
1326 hb_error("Incompatible video encoder (%s) for muxer (%s)",
1327 hb_video_encoder_get_name(vcodec
),
1328 hb_container_get_name(mux
));
1332 video_dict
= hb_dict_get(job_dict
, "Video");
1333 hb_dict_set(video_dict
, "Encoder", hb_value_string(encoder
->short_name
));
1335 if ((color_value
= hb_dict_get(preset
, "VideoColorMatrixCode")) != NULL
)
1336 hb_dict_set(video_dict
, "ColorMatrixCode", hb_value_dup(color_value
));
1337 hb_dict_set(video_dict
, "Encoder", hb_value_dup(vcodec_value
));
1339 if (vcodec
== HB_VCODEC_X264
&&
1340 hb_value_get_bool(hb_dict_get(preset
, "x264UseAdvancedOptions")))
1342 hb_dict_set(video_dict
, "Options",
1343 hb_value_dup(hb_dict_get(preset
, "x264Option")));
1347 if ((value
= hb_dict_get(preset
, "VideoPreset")) != NULL
)
1348 hb_dict_set(video_dict
, "Preset", hb_value_dup(value
));
1349 if ((value
= hb_dict_get(preset
, "VideoProfile")) != NULL
)
1350 hb_dict_set(video_dict
, "Profile", hb_value_dup(value
));
1351 if ((value
= hb_dict_get(preset
, "VideoLevel")) != NULL
)
1352 hb_dict_set(video_dict
, "Level", hb_value_dup(value
));
1353 if ((value
= hb_dict_get(preset
, "VideoTune")) != NULL
)
1354 hb_dict_set(video_dict
, "Tune", hb_value_dup(value
));
1355 if ((value
= hb_dict_get(preset
, "VideoOptionExtra")) != NULL
)
1356 hb_dict_set(video_dict
, "Options", hb_value_dup(value
));
1359 vqtype
= hb_value_get_int(hb_dict_get(preset
, "VideoQualityType"));
1360 if (vqtype
== 2) // Constant quality
1362 hb_dict_set(video_dict
, "Quality",
1363 hb_value_xform(hb_dict_get(preset
, "VideoQualitySlider"),
1364 HB_VALUE_TYPE_DOUBLE
));
1365 hb_dict_set(video_dict
, "Bitrate", hb_value_int(-1));
1367 else if (vqtype
== 1) // ABR
1369 hb_dict_set(video_dict
, "Bitrate",
1370 hb_value_xform(hb_dict_get(preset
, "VideoAvgBitrate"),
1371 HB_VALUE_TYPE_INT
));
1372 hb_dict_set(video_dict
, "TwoPass",
1373 hb_value_xform(hb_dict_get(preset
, "VideoTwoPass"),
1374 HB_VALUE_TYPE_BOOL
));
1375 hb_dict_set(video_dict
, "Turbo",
1376 hb_value_xform(hb_dict_get(preset
, "VideoTurboTwoPass"),
1377 HB_VALUE_TYPE_BOOL
));
1378 hb_dict_set(video_dict
, "Quality", hb_value_double(-1.0));
1382 value
= hb_dict_get(preset
, "VideoQualitySlider");
1383 if (value
!= NULL
&& hb_value_get_double(value
) >= 0)
1385 hb_dict_set(video_dict
, "Quality",
1386 hb_value_xform(value
, HB_VALUE_TYPE_DOUBLE
));
1387 hb_dict_set(video_dict
, "Bitrate", hb_value_int(-1));
1391 hb_dict_set(video_dict
, "Bitrate",
1392 hb_value_xform(hb_dict_get(preset
, "VideoAvgBitrate"),
1393 HB_VALUE_TYPE_INT
));
1394 hb_dict_set(video_dict
, "TwoPass",
1395 hb_value_xform(hb_dict_get(preset
, "VideoTwoPass"),
1396 HB_VALUE_TYPE_BOOL
));
1397 hb_dict_set(video_dict
, "Turbo",
1398 hb_value_xform(hb_dict_get(preset
, "VideoTurboTwoPass"),
1399 HB_VALUE_TYPE_BOOL
));
1400 hb_dict_set(video_dict
, "Quality", hb_value_double(-1.0));
1403 qsv
= hb_dict_get(video_dict
, "QSV");
1406 qsv
= hb_dict_init();
1407 hb_dict_set(video_dict
, "QSV", qsv
);
1409 if ((value
= hb_dict_get(preset
, "VideoQSVDecode")) != NULL
)
1411 hb_dict_set(qsv
, "Decode",
1412 hb_value_xform(value
, HB_VALUE_TYPE_BOOL
));
1414 if ((value
= hb_dict_get(preset
, "VideoQSVAsyncDepth")) != NULL
)
1416 hb_dict_set(qsv
, "AsyncDepth",
1417 hb_value_xform(value
, HB_VALUE_TYPE_INT
));
1420 if ((value
= hb_dict_get(preset
, "VideoScaler")) != NULL
)
1422 const char *s
= hb_value_get_string(value
);
1423 if (!strcasecmp(s
, "opencl"))
1425 hb_dict_set(video_dict
, "OpenCL", hb_value_bool(1));
1428 if ((value
= hb_dict_get(preset
, "VideoHWDecode")) != NULL
)
1430 hb_dict_set(video_dict
, "HWDecode",
1431 hb_value_xform(value
, HB_VALUE_TYPE_BOOL
));
1437 int hb_preset_apply_mux(const hb_dict_t
*preset
, hb_dict_t
*job_dict
)
1439 hb_value_t
*mux_value
= hb_dict_get(preset
, "FileFormat");
1441 if (hb_value_type(mux_value
) == HB_VALUE_TYPE_STRING
)
1443 mux
= hb_container_get_from_name(hb_value_get_string(mux_value
));
1445 mux
= hb_container_get_from_extension(
1446 hb_value_get_string(mux_value
));
1450 mux
= hb_value_get_int(mux_value
);
1452 hb_container_t
*container
= hb_container_get_from_format(mux
);
1453 if (container
== NULL
)
1455 char *str
= hb_value_get_string_xform(mux_value
);
1456 hb_error("Invalid container (%s)", str
);
1461 hb_dict_t
*dest_dict
= hb_dict_get(job_dict
, "Destination");
1462 hb_dict_set(dest_dict
, "Mux", hb_value_string(container
->short_name
));
1464 if (mux
& HB_MUX_MASK_MP4
)
1466 hb_dict_t
*mp4_dict
= hb_dict_init();
1467 hb_dict_set(mp4_dict
, "Mp4Optimize",
1468 hb_value_xform(hb_dict_get(preset
, "Mp4HttpOptimize"),
1469 HB_VALUE_TYPE_BOOL
));
1470 hb_dict_set(mp4_dict
, "IpodAtom",
1471 hb_value_xform(hb_dict_get(preset
, "Mp4iPodCompatible"),
1472 HB_VALUE_TYPE_BOOL
));
1473 hb_dict_set(dest_dict
, "Mp4Options", mp4_dict
);
1479 int hb_preset_apply_title(hb_handle_t
*h
, int title_index
,
1480 const hb_dict_t
*preset
, hb_dict_t
*job_dict
)
1482 // Apply preset settings that requires the title
1483 hb_title_t
*title
= hb_find_title_by_index(h
, title_index
);
1488 chapters
= hb_value_get_bool(hb_dict_get(preset
, "ChapterMarkers"));
1489 if (title
!= NULL
&& hb_list_count(title
->list_chapter
) <= 1)
1492 // Set "Destination" settings in job
1493 hb_dict_t
*dest_dict
= hb_dict_get(job_dict
, "Destination");
1494 hb_dict_set(dest_dict
, "ChapterMarkers", hb_value_bool(chapters
));
1496 hb_dict_t
*filters_dict
= hb_dict_get(job_dict
, "Filters");
1497 hb_value_array_t
*filter_list
= hb_dict_get(filters_dict
, "FilterList");
1499 // Calculate default job geometry settings
1500 hb_geometry_t srcGeo
, resultGeo
;
1501 hb_geometry_settings_t geo
;
1504 srcGeo
= title
->geometry
;
1505 if (!hb_value_get_bool(hb_dict_get(preset
, "PictureAutoCrop")))
1507 geo
.crop
[0] = hb_value_get_int(hb_dict_get(preset
, "PictureTopCrop"));
1508 geo
.crop
[1] = hb_value_get_int(hb_dict_get(preset
, "PictureBottomCrop"));
1509 geo
.crop
[2] = hb_value_get_int(hb_dict_get(preset
, "PictureLeftCrop"));
1510 geo
.crop
[3] = hb_value_get_int(hb_dict_get(preset
, "PictureRightCrop"));
1514 memcpy(geo
.crop
, title
->crop
, sizeof(geo
.crop
));
1516 geo
.modulus
= hb_value_get_int(hb_dict_get(preset
, "PictureModulus"));
1517 if (geo
.modulus
< 2)
1519 if (hb_value_get_bool(hb_dict_get(preset
, "PictureLooseCrop")))
1521 // Crop a few extra pixels to avoid scaling to fit Modulus
1522 int extra1
, extra2
, crop_width
, crop_height
, width
, height
;
1524 crop_width
= srcGeo
.width
- geo
.crop
[2] - geo
.crop
[3];
1525 crop_height
= srcGeo
.height
- geo
.crop
[0] - geo
.crop
[1];
1526 width
= MULTIPLE_MOD_DOWN(crop_width
, geo
.modulus
);
1527 height
= MULTIPLE_MOD_DOWN(crop_height
, geo
.modulus
);
1529 extra1
= EVEN((crop_height
- height
) / 2);
1530 extra2
= crop_height
- height
- extra1
;
1531 geo
.crop
[0] += extra1
;
1532 geo
.crop
[1] += extra2
;
1533 extra1
= EVEN((crop_width
- width
) / 2);
1534 extra2
= crop_width
- width
- extra1
;
1535 geo
.crop
[2] += extra1
;
1536 geo
.crop
[3] += extra2
;
1538 hb_value_t
*ana_mode_value
= hb_dict_get(preset
, "PicturePAR");
1539 if (hb_value_type(ana_mode_value
) == HB_VALUE_TYPE_STRING
)
1541 const char *s
= hb_value_get_string(ana_mode_value
);
1542 if (!strcasecmp(s
, "none"))
1544 else if (!strcasecmp(s
, "strict"))
1546 else if (!strcasecmp(s
, "custom"))
1548 else // default loose
1553 geo
.mode
= hb_value_get_int(hb_dict_get(preset
, "PicturePAR"));
1555 keep_aspect
= hb_value_get_bool(hb_dict_get(preset
, "PictureKeepRatio"));
1556 if (geo
.mode
== HB_ANAMORPHIC_STRICT
|| geo
.mode
== HB_ANAMORPHIC_LOOSE
)
1558 geo
.keep
= keep_aspect
* HB_KEEP_DISPLAY_ASPECT
;
1559 geo
.itu_par
= hb_value_get_bool(hb_dict_get(preset
, "PictureItuPAR"));
1560 geo
.maxWidth
= hb_value_get_int(hb_dict_get(preset
, "PictureWidth"));
1561 geo
.maxHeight
= hb_value_get_int(hb_dict_get(preset
, "PictureHeight"));
1562 geo
.geometry
= title
->geometry
;
1563 int width
= hb_value_get_int(hb_dict_get(preset
, "PictureForceWidth"));
1564 int height
= hb_value_get_int(hb_dict_get(preset
, "PictureForceHeight"));
1567 geo
.geometry
.width
= width
;
1568 geo
.keep
|= HB_KEEP_WIDTH
;
1572 geo
.geometry
.width
-= geo
.crop
[2] + geo
.crop
[3];
1576 geo
.geometry
.height
= height
;
1577 geo
.keep
|= HB_KEEP_HEIGHT
;
1581 geo
.geometry
.height
-= geo
.crop
[0] + geo
.crop
[1];
1583 if (geo
.mode
== HB_ANAMORPHIC_CUSTOM
&& !keep_aspect
)
1586 dar_width
= hb_value_get_int(hb_dict_get(preset
, "PictureDARWidth"));
1589 geo
.geometry
.par
.num
= dar_width
;
1590 geo
.geometry
.par
.den
= geo
.geometry
.width
;
1594 geo
.geometry
.par
.num
=
1595 hb_value_get_int(hb_dict_get(preset
, "PicturePARWidth"));
1596 geo
.geometry
.par
.den
=
1597 hb_value_get_int(hb_dict_get(preset
, "PicturePARHeight"));
1600 hb_set_anamorphic_size2(&srcGeo
, &geo
, &resultGeo
);
1601 hb_dict_t
*par_dict
= hb_dict_get(job_dict
, "PAR");
1602 hb_dict_set(par_dict
, "Num", hb_value_int(resultGeo
.par
.num
));
1603 hb_dict_set(par_dict
, "Den", hb_value_int(resultGeo
.par
.den
));
1606 hb_dict_t
*filter_dict
;
1609 // Setup scale filter
1610 filter_str
= hb_strdup_printf("%d:%d:%d:%d:%d:%d",
1611 resultGeo
.width
, resultGeo
.height
,
1612 geo
.crop
[0], geo
.crop
[1],
1613 geo
.crop
[2], geo
.crop
[3]);
1615 filter_dict
= hb_dict_init();
1616 hb_dict_set(filter_dict
, "ID", hb_value_int(HB_FILTER_CROP_SCALE
));
1617 hb_dict_set(filter_dict
, "Settings", hb_value_string(filter_str
));
1619 hb_value_array_append(filter_list
, filter_dict
);
1622 if (hb_preset_job_add_audio(h
, title_index
, preset
, job_dict
) != 0)
1627 // Subtitle settings
1628 if (hb_preset_job_add_subtitles(h
, title_index
, preset
, job_dict
) != 0)
1639 * Initialize an hb_job_t and return a hb_dict_t representation of the job.
1640 * This dict will have key/value pairs compatible with json jobs.
1641 * @param h - Pointer to hb_handle_t instance that contains the
1642 * specified title_index
1643 * @param title_index - Index of hb_title_t to use for job initialization.
1644 * Index comes from title->index or "Index" key
1645 * in json representation of a title.
1646 * @param preset - Preset to initialize job with
1648 hb_dict_t
* hb_preset_job_init(hb_handle_t
*h
, int title_index
,
1649 const hb_dict_t
*preset
)
1651 hb_title_t
*title
= hb_find_title_by_index(h
, title_index
);
1654 hb_error("Invalid title index (%d)", title_index
);
1658 hb_job_t
*job
= hb_job_init(title
);
1659 hb_dict_t
*job_dict
= hb_job_to_dict(job
);
1662 if (hb_preset_apply_mux(preset
, job_dict
) < 0)
1665 if (hb_preset_apply_video(preset
, job_dict
) < 0)
1668 if (hb_preset_apply_filters(preset
, job_dict
) < 0)
1671 if (hb_preset_apply_title(h
, title_index
, preset
, job_dict
) < 0)
1677 hb_value_free(&job_dict
);
1681 // Clean a dictionary of unwanted keys
1682 // Used to make sure only valid keys are in output presets
1684 dict_clean(hb_value_t
*dict
, hb_value_t
*template)
1686 hb_value_t
*tmp
= hb_value_dup(dict
);
1687 hb_dict_iter_t iter
;
1690 hb_value_t
*template_val
;
1691 hb_value_type_t template_type
, val_type
;
1692 const char *preset_name
= NULL
;
1694 val
= hb_dict_get(dict
, "PresetName");
1696 preset_name
= hb_value_get_string(val
);
1698 // Remove keys that are not in the template and translate compatible
1699 // data types to the types used in the template.
1700 for (iter
= hb_dict_iter_init(tmp
);
1701 iter
!= HB_DICT_ITER_DONE
;
1702 iter
= hb_dict_iter_next(tmp
, iter
))
1704 key
= hb_dict_iter_key(iter
);
1705 val
= hb_dict_iter_value(iter
);
1706 val_type
= hb_value_type(val
);
1708 template_val
= hb_dict_get(template, key
);
1709 template_type
= hb_value_type(template_val
);
1710 if (template_val
== NULL
)
1712 // Unknown key. These can be keys used privately by the
1713 // frontend. So don't make noise about them.
1714 hb_dict_remove(dict
, key
);
1716 else if (val_type
!= template_type
)
1718 if (val_type
== HB_VALUE_TYPE_DICT
||
1719 val_type
== HB_VALUE_TYPE_ARRAY
||
1720 template_type
== HB_VALUE_TYPE_DICT
||
1721 template_type
== HB_VALUE_TYPE_ARRAY
)
1723 hb_error("Preset %s: Incompatible value types for key %s. "
1724 "Dropping.", preset_name
, key
);
1725 hb_dict_remove(dict
, key
);
1727 else if (hb_value_is_number(val
) &&
1728 hb_value_is_number(template_val
))
1730 // Silently convert compatible numbers
1732 v
= hb_value_xform(val
, template_type
);
1733 hb_dict_set(dict
, key
, v
);
1738 hb_error("Preset %s: Incorrect value type for key %s. "
1739 "Converting.", preset_name
, key
);
1740 v
= hb_value_xform(val
, template_type
);
1741 hb_dict_set(dict
, key
, v
);
1744 else if (val_type
== HB_VALUE_TYPE_DICT
&&
1745 template_type
== HB_VALUE_TYPE_DICT
)
1747 val
= hb_dict_get(dict
, key
);
1748 dict_clean(val
, template_val
);
1750 else if (val_type
== HB_VALUE_TYPE_ARRAY
&&
1751 template_type
== HB_VALUE_TYPE_ARRAY
&&
1752 hb_value_array_len(template_val
) > 0)
1754 template_val
= hb_value_array_get(template_val
, 0);
1755 if (hb_value_type(template_val
) == HB_VALUE_TYPE_DICT
)
1757 val
= hb_dict_get(dict
, key
);
1758 int count
= hb_value_array_len(val
);
1760 for (ii
= 0; ii
< count
; ii
++)
1762 hb_value_t
*array_val
;
1763 array_val
= hb_value_array_get(val
, ii
);
1764 if (hb_value_type(array_val
) == HB_VALUE_TYPE_DICT
)
1766 dict_clean(array_val
, template_val
);
1772 hb_value_free(&tmp
);
1774 if (!hb_value_get_bool(hb_dict_get(dict
, "Folder")))
1776 // Add key/value pairs that are in the template but not in the dict.
1777 for (iter
= hb_dict_iter_init(template);
1778 iter
!= HB_DICT_ITER_DONE
;
1779 iter
= hb_dict_iter_next(template, iter
))
1781 key
= hb_dict_iter_key(iter
);
1782 template_val
= hb_dict_iter_value(iter
);
1783 val
= hb_dict_get(dict
, key
);
1786 hb_dict_set(dict
, key
, hb_value_dup(template_val
));
1792 static void preset_clean(hb_value_t
*preset
, hb_value_t
*template)
1794 dict_clean(preset
, template);
1796 // Check for proper "short name" values.
1797 // Convert as necessary.
1799 const char *preset_name
= NULL
;
1802 val
= hb_dict_get(preset
, "PresetName");
1804 preset_name
= hb_value_get_string(val
);
1806 val
= hb_dict_get(preset
, "FileFormat");
1809 const char *s
, *mux
;
1810 s
= hb_value_get_string(val
);
1811 muxer
= hb_container_get_from_name(s
);
1812 if (muxer
== HB_MUX_INVALID
)
1814 const hb_container_t
*c
= hb_container_get_next(NULL
);
1816 hb_error("Preset %s: Invalid container (%s)", preset_name
, s
);
1818 mux
= hb_container_get_short_name(muxer
);
1819 val
= hb_value_string(mux
);
1820 hb_dict_set(preset
, "FileFormat", val
);
1824 const hb_container_t
*c
= hb_container_get_next(NULL
);
1827 val
= hb_dict_get(preset
, "VideoEncoder");
1830 const char *s
, *enc
;
1832 s
= hb_value_get_string(val
);
1833 vcodec
= hb_video_encoder_get_from_name(s
);
1834 if (vcodec
== HB_VCODEC_INVALID
)
1836 vcodec
= hb_video_encoder_get_default(muxer
);
1837 hb_error("Preset %s: Invalid video encoder (%s)", preset_name
, s
);
1839 enc
= hb_video_encoder_get_short_name(vcodec
);
1840 val
= hb_value_string(enc
);
1841 hb_dict_set(preset
, "VideoEncoder", val
);
1843 val
= hb_dict_get(preset
, "VideoFramerate");
1847 s
= hb_value_get_string(val
);
1848 if (strcasecmp(s
, "auto"))
1850 int fr
= hb_video_framerate_get_from_name(s
);
1853 if (strcasecmp(s
, "same as source"))
1855 hb_error("Preset %s: Invalid video framerate (%s)",
1858 val
= hb_value_string("auto");
1859 hb_dict_set(preset
, "VideoFramerate", val
);
1863 val
= hb_dict_get(preset
, "AudioEncoderFallback");
1866 const char *s
, *enc
;
1868 s
= hb_value_get_string(val
);
1869 acodec
= hb_audio_encoder_get_from_name(s
);
1870 if (acodec
== HB_ACODEC_INVALID
)
1872 acodec
= hb_audio_encoder_get_default(muxer
);
1873 hb_error("Preset %s: Invalid audio fallback encoder (%s)",
1876 enc
= hb_audio_encoder_get_short_name(acodec
);
1877 val
= hb_value_string(enc
);
1878 hb_dict_set(preset
, "AudioEncoderFallback", val
);
1880 hb_value_t
*alist
= hb_dict_get(preset
, "AudioList");
1881 int count
= hb_value_array_len(alist
);
1883 for (ii
= 0; ii
< count
; ii
++)
1885 hb_value_t
*adict
= hb_value_array_get(alist
, ii
);
1886 val
= hb_dict_get(adict
, "AudioEncoder");
1889 const char *s
, *enc
;
1891 s
= hb_value_get_string(val
);
1892 acodec
= hb_audio_encoder_get_from_name(s
);
1893 if (acodec
== HB_ACODEC_INVALID
)
1895 acodec
= hb_audio_encoder_get_default(muxer
);
1896 hb_error("Preset %s: Invalid audio encoder (%s)",
1899 enc
= hb_audio_encoder_get_short_name(acodec
);
1900 val
= hb_value_string(enc
);
1901 hb_dict_set(adict
, "AudioEncoder", val
);
1903 val
= hb_dict_get(adict
, "AudioSamplerate");
1907 s
= hb_value_get_string(val
);
1908 if (strcasecmp(s
, "auto"))
1910 int sr
= hb_audio_samplerate_get_from_name(s
);
1913 hb_error("Preset %s: Invalid audio samplerate (%s)",
1915 val
= hb_value_string("auto");
1916 hb_dict_set(adict
, "AudioSamplerate", val
);
1920 val
= hb_dict_get(adict
, "AudioMixdown");
1923 const char *s
, *mix
;
1924 s
= hb_value_get_string(val
);
1925 int mixdown
= hb_mixdown_get_from_name(s
);
1926 if (mixdown
== HB_INVALID_AMIXDOWN
)
1928 // work.c do_job() sanitizes NONE to default mixdown
1929 mixdown
= HB_AMIXDOWN_NONE
;
1930 hb_error("Preset %s: Invalid audio mixdown (%s)",
1933 mix
= hb_mixdown_get_short_name(mixdown
);
1934 val
= hb_value_string(mix
);
1935 hb_dict_set(adict
, "AudioMixdown", val
);
1940 static void presets_clean(hb_value_t
*presets
, hb_value_t
*template)
1942 preset_clean_context_t ctx
;
1943 ctx
.do_ctx
.path
.depth
= 1;
1944 ctx
.template = template;
1945 presets_do(do_preset_clean
, presets
, (preset_do_context_t
*)&ctx
);
1948 void hb_presets_clean(hb_value_t
*preset
)
1950 presets_clean(preset
, hb_preset_template
);
1953 static const char* import_indexed_filter(int filter_id
, int index
)
1955 hb_filter_param_t
*filter_presets
;
1956 filter_presets
= hb_filter_param_get_presets(filter_id
);
1959 for (ii
= 0; filter_presets
[ii
].name
!= NULL
; ii
++)
1961 if (filter_presets
[ii
].index
== index
)
1964 return filter_presets
[ii
].short_name
;
1967 static void import_decomb(hb_value_t
*preset
)
1969 hb_value_t
*val
= hb_dict_get(preset
, "PictureDecomb");
1970 if (hb_value_is_number(val
))
1973 int index
= hb_value_get_int(val
);
1974 s
= import_indexed_filter(HB_FILTER_DECOMB
, index
);
1977 hb_dict_set(preset
, "PictureDecomb", hb_value_string(s
));
1981 hb_error("Invalid decomb index %d", index
);
1982 hb_dict_set(preset
, "PictureDecomb", hb_value_string("off"));
1987 static void import_deint(hb_value_t
*preset
)
1989 hb_value_t
*val
= hb_dict_get(preset
, "PictureDeinterlace");
1990 if (hb_value_is_number(val
))
1993 int index
= hb_value_get_int(val
);
1994 s
= import_indexed_filter(HB_FILTER_DEINTERLACE
, index
);
1997 hb_dict_set(preset
, "PictureDeinterlace", hb_value_string(s
));
2001 hb_error("Invalid deinterlace index %d", index
);
2002 hb_dict_set(preset
, "PictureDeinterlace", hb_value_string("off"));
2007 static void import_detel(hb_value_t
*preset
)
2009 hb_value_t
*val
= hb_dict_get(preset
, "PictureDetelecine");
2010 if (hb_value_is_number(val
))
2013 int index
= hb_value_get_int(val
);
2014 s
= import_indexed_filter(HB_FILTER_DETELECINE
, index
);
2017 hb_dict_set(preset
, "PictureDetelecine", hb_value_string(s
));
2021 hb_error("Invalid detelecine index %d", index
);
2022 hb_dict_set(preset
, "PictureDetelecine", hb_value_string("off"));
2027 static void import_denoise(hb_value_t
*preset
)
2029 hb_value_t
*val
= hb_dict_get(preset
, "PictureDenoise");
2030 if (hb_value_is_number(val
))
2033 int index
= hb_value_get_int(val
);
2034 s
= import_indexed_filter(HB_FILTER_HQDN3D
, index
);
2037 hb_dict_set(preset
, "PictureDenoiseFilter",
2038 hb_value_string("hqdn3d"));
2039 hb_dict_set(preset
, "PictureDenoisePreset", hb_value_string(s
));
2044 hb_error("Invalid denoise index %d", index
);
2045 hb_dict_set(preset
, "PictureDenoiseFilter", hb_value_string("off"));
2050 static void import_pic(hb_value_t
*preset
)
2052 if (hb_value_get_bool(hb_dict_get(preset
, "UsesMaxPictureSettings")))
2054 // UsesMaxPictureSettings was deprecated
2055 hb_dict_set(preset
, "UsesPictureSettings", hb_value_int(2));
2058 hb_value_t
*val
= hb_dict_get(preset
, "PicturePAR");
2059 if (hb_value_is_number(val
))
2062 int pic_par
= hb_value_get_int(val
);
2079 hb_dict_set(preset
, "PicturePAR", hb_value_string(s
));
2083 static void import_audio(hb_value_t
*preset
)
2085 hb_value_t
*copy
= hb_dict_get(preset
, "AudioCopyMask");
2089 copy
= hb_value_array_init();
2090 hb_dict_set(preset
, "AudioCopyMask", copy
);
2091 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowMP3Pass")))
2092 hb_value_array_append(copy
, hb_value_string("copy:mp3"));
2093 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowAACPass")))
2094 hb_value_array_append(copy
, hb_value_string("copy:aac"));
2095 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowAC3Pass")))
2096 hb_value_array_append(copy
, hb_value_string("copy:ac3"));
2097 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowDTSPass")))
2098 hb_value_array_append(copy
, hb_value_string("copy:dts"));
2099 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowDTSHDPass")))
2100 hb_value_array_append(copy
, hb_value_string("copy:dtshd"));
2101 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowEAC3Pass")))
2102 hb_value_array_append(copy
, hb_value_string("copy:eac3"));
2103 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowFLACPass")))
2104 hb_value_array_append(copy
, hb_value_string("copy:flac"));
2105 if (hb_value_get_bool(hb_dict_get(preset
, "AudioAllowTRUEHDPass")))
2106 hb_value_array_append(copy
, hb_value_string("copy:truehd"));
2109 static void import_video(hb_value_t
*preset
)
2113 if ((val
= hb_dict_get(preset
, "x264Preset")) != NULL
)
2114 hb_dict_set(preset
, "VideoPreset", hb_value_dup(val
));
2115 if ((val
= hb_dict_get(preset
, "x264Tune")) != NULL
)
2116 hb_dict_set(preset
, "VideoTune", hb_value_dup(val
));
2117 if ((val
= hb_dict_get(preset
, "h264Profile")) != NULL
)
2118 hb_dict_set(preset
, "VideoProfile", hb_value_dup(val
));
2119 if ((val
= hb_dict_get(preset
, "h264Level")) != NULL
)
2120 hb_dict_set(preset
, "VideoLevel", hb_value_dup(val
));
2121 if ((val
= hb_dict_get(preset
, "x264OptionExtra")) != NULL
)
2122 hb_dict_set(preset
, "VideoOptionExtra", hb_value_dup(val
));
2124 // Remove invalid "none" tune from VideoTune. Frontends should
2125 // be removing this before saving a preset.
2126 if ((val
= hb_dict_get(preset
, "VideoTune")) != NULL
)
2129 tune
= hb_value_get_string(val
);
2130 // "none" is not a valid tune, but is used by HandBrake
2131 // to indicate no tune options.
2132 if (tune
!= NULL
&& !strncasecmp(tune
, "none", 4))
2142 hb_dict_set(preset
, "VideoTune", hb_value_string(tune
));
2146 if (hb_value_get_int(hb_dict_get(preset
, "VideoQualityType")) == 0)
2148 // Target size no longer supported
2149 hb_dict_set(preset
, "VideoQualityType", hb_value_int(1));
2152 if (hb_value_get_bool(hb_dict_get(preset
, "VideoFrameratePFR")))
2154 hb_dict_set(preset
, "VideoFramerateMode", hb_value_string("pfr"));
2156 else if (hb_value_get_bool(hb_dict_get(preset
, "VideoFramerateCFR")))
2158 hb_dict_set(preset
, "VideoFramerateMode", hb_value_string("cfr"));
2160 else if (hb_value_get_bool(hb_dict_get(preset
, "VideoFramerateVFR")))
2162 hb_dict_set(preset
, "VideoFramerateMode", hb_value_string("vfr"));
2167 enc
= hb_value_get_string(hb_dict_get(preset
, "VideoEncoder"));
2168 codec
= hb_video_encoder_get_from_name(enc
);
2169 if (codec
& HB_VCODEC_FFMPEG_MASK
)
2171 if ((val
= hb_dict_get(preset
, "lavcOption")) != NULL
)
2172 hb_dict_set(preset
, "VideoOptionExtra", hb_value_dup(val
));
2176 static void preset_import(hb_value_t
*preset
, int major
, int minor
, int micro
)
2178 if (!hb_value_get_bool(hb_dict_get(preset
, "Folder")))
2180 if (major
== 0 && minor
== 0 && micro
== 0)
2182 // Convert legacy presets (before versioning introduced)
2183 import_video(preset
);
2185 import_audio(preset
);
2186 import_decomb(preset
);
2187 import_deint(preset
);
2188 import_detel(preset
);
2189 import_denoise(preset
);
2191 preset_clean(preset
, hb_preset_template
);
2195 int hb_presets_version(hb_value_t
*preset
, int *major
, int *minor
, int *micro
)
2197 *major
= 0; *minor
= 0; *micro
= 0;
2198 if (hb_value_type(preset
) == HB_VALUE_TYPE_DICT
)
2200 // Is this a single preset or a packaged collection of presets?
2201 hb_value_t
*val
= hb_dict_get(preset
, "PresetName");
2204 val
= hb_dict_get(preset
, "VersionMajor");
2207 *major
= hb_value_get_int(hb_dict_get(preset
, "VersionMajor"));
2208 *minor
= hb_value_get_int(hb_dict_get(preset
, "VersionMinor"));
2209 *micro
= hb_value_get_int(hb_dict_get(preset
, "VersionMicro"));
2217 void hb_presets_import(hb_value_t
*preset
)
2219 preset_import_context_t ctx
;
2221 ctx
.do_ctx
.path
.depth
= 1;
2222 hb_presets_version(preset
, &ctx
.major
, &ctx
.minor
, &ctx
.micro
);
2223 presets_do(do_preset_import
, preset
, (preset_do_context_t
*)&ctx
);
2226 char * hb_presets_import_json(const char *json
)
2228 hb_value_t
* dict
= hb_value_json(json
);
2232 hb_presets_import(dict
);
2233 char * result
= hb_value_get_json(dict
);
2234 hb_value_free(&dict
);
2238 char * hb_presets_clean_json(const char *json
)
2240 hb_value_t
* dict
= hb_value_json(json
);
2244 presets_clean(dict
, hb_preset_template
);
2245 char * result
= hb_value_get_json(dict
);
2246 hb_value_free(&dict
);
2250 // Note that unpackage does not make any copies.
2251 // In one increases the reference count.
2252 static hb_value_t
* presets_unpackage(const hb_value_t
*packaged_presets
)
2254 // Do any legacy translations.
2255 hb_value_t
*tmp
= hb_value_dup(packaged_presets
);
2256 hb_presets_import(tmp
);
2257 if (hb_value_type(tmp
) == HB_VALUE_TYPE_ARRAY
)
2262 if (hb_dict_get(tmp
, "PresetName") != NULL
)
2264 // Bare single preset
2267 hb_value_t
*presets
= hb_dict_get(tmp
, "PresetList");
2268 hb_value_incref(presets
);
2269 hb_value_free(&tmp
);
2273 static hb_value_t
* presets_package(const hb_value_t
*presets
)
2275 hb_dict_t
*packaged_presets
;
2276 if (hb_value_type(presets
) != HB_VALUE_TYPE_DICT
||
2277 hb_dict_get(presets
, "VersionMajor") == NULL
)
2279 // Preset is not packaged
2280 packaged_presets
= hb_dict_init();
2281 hb_dict_set(packaged_presets
, "VersionMajor",
2282 hb_value_int(hb_preset_version_major
));
2283 hb_dict_set(packaged_presets
, "VersionMinor",
2284 hb_value_int(hb_preset_version_minor
));
2285 hb_dict_set(packaged_presets
, "VersionMicro",
2286 hb_value_int(hb_preset_version_micro
));
2288 // TODO: What else do we want in the preset containers header?
2289 hb_dict_t
*tmp
= hb_value_dup(presets
);
2290 if (hb_value_type(presets
) == HB_VALUE_TYPE_DICT
)
2292 hb_value_array_t
*array
= hb_value_array_init();
2293 hb_value_array_append(array
, tmp
);
2296 presets_clean(tmp
, hb_preset_template
);
2297 hb_dict_set(packaged_presets
, "PresetList", tmp
);
2301 // Preset is already packaged
2302 hb_dict_t
*tmp
= hb_value_dup(presets
);
2303 presets_clean(tmp
, hb_preset_template
);
2304 packaged_presets
= tmp
;
2306 return packaged_presets
;
2309 void hb_presets_builtin_init(void)
2311 hb_value_t
* dict
= hb_value_json(hb_builtin_presets_json
);
2312 hb_value_t
* template = hb_dict_get(dict
, "PresetTemplate");
2313 hb_preset_version_major
= hb_value_get_int(
2314 hb_dict_get(template, "VersionMajor"));
2315 hb_preset_version_minor
= hb_value_get_int(
2316 hb_dict_get(template, "VersionMinor"));
2317 hb_preset_version_micro
= hb_value_get_int(
2318 hb_dict_get(template, "VersionMicro"));
2319 hb_preset_template
= hb_value_dup(hb_dict_get(template, "Preset"));
2321 hb_presets_builtin
= hb_value_dup(hb_dict_get(dict
, "PresetBuiltin"));
2322 hb_presets_clean(hb_presets_builtin
);
2324 hb_presets
= hb_value_array_init();
2325 hb_value_free(&dict
);
2328 void hb_presets_current_version(int *major
, int* minor
, int *micro
)
2330 *major
= hb_preset_version_major
;
2331 *minor
= hb_preset_version_minor
;
2332 *micro
= hb_preset_version_micro
;
2335 int hb_presets_gui_init(void)
2338 hb_value_t
* dict
= NULL
;
2340 #if defined(HB_PRESET_JSON_FILE)
2341 hb_get_user_config_filename(path
, "%s", HB_PRESET_JSON_FILE
);
2342 dict
= hb_value_read_json(path
);
2344 #if defined(HB_PRESET_PLIST_FILE)
2347 hb_get_user_config_filename(path
, "%s", HB_PRESET_PLIST_FILE
);
2348 dict
= hb_plist_parse_file(path
);
2353 hb_error("Failed to load GUI presets file");
2354 #if defined(HB_PRESET_JSON_FILE)
2355 hb_error("Attempted: %s", HB_PRESET_JSON_FILE
);
2357 #if defined(HB_PRESET_PLIST_FILE)
2358 hb_error("Attempted: %s", HB_PRESET_PLIST_FILE
);
2364 preset_do_context_t ctx
;
2366 presets_do(do_delete_builtin
, dict
, &ctx
);
2367 int result
= hb_presets_add(dict
);
2368 hb_value_free(&dict
);
2374 hb_value_t
* hb_presets_builtin_get(void)
2376 return hb_value_dup(hb_presets_builtin
);
2379 char * hb_presets_builtin_get_json(void)
2381 char *json
= hb_value_get_json(hb_presets_builtin
);
2385 // Lookup a preset in the preset list. The "name" may contain '/'
2386 // separators to explicitely specify a preset within the preset lists
2387 // folder structure.
2389 // If 'recurse' is specified, a recursive search for the first component
2390 // in the name will be performed.
2392 // I assume that the actual preset name does not include any '/'
2394 // A reference to the preset is returned
2395 static hb_preset_index_t
* preset_lookup_path(const char *name
, int recurse
)
2397 preset_search_context_t ctx
;
2400 ctx
.do_ctx
.path
.depth
= 1;
2402 ctx
.recurse
= recurse
;
2403 ctx
.last_match_idx
= -1;
2404 result
= presets_do(do_preset_search
, hb_presets
,
2405 (preset_do_context_t
*)&ctx
);
2406 if (result
!= PRESET_DO_SUCCESS
)
2407 ctx
.do_ctx
.path
.depth
= 0;
2409 return hb_preset_index_dup(&ctx
.do_ctx
.path
);
2412 // Lookup a preset in the preset list. The "name" may contain '/'
2413 // separators to explicitely specify a preset within the preset lists
2414 // folder structure.
2416 // If 'recurse' is specified, a recursive search for the first component
2417 // in the name will be performed.
2419 // I assume that the actual preset name does not include any '/'
2421 // A copy of the preset is returned
2422 hb_preset_index_t
* hb_preset_search_index(const char *name
, int recurse
)
2424 return preset_lookup_path(name
, recurse
);
2427 hb_value_t
* hb_preset_search(const char *name
, int recurse
)
2429 hb_preset_index_t
*path
= preset_lookup_path(name
, recurse
);
2430 hb_value_t
*preset
= hb_preset_get(path
);
2435 char * hb_preset_search_json(const char *name
, int recurse
)
2437 hb_value_t
* preset
;
2439 preset
= hb_preset_search(name
, recurse
);
2442 json
= hb_value_get_json(preset
);
2446 static hb_preset_index_t
* lookup_default_index(hb_value_t
*list
)
2448 preset_do_context_t ctx
;
2452 result
= presets_do(do_find_default
, list
, &ctx
);
2453 if (result
!= PRESET_DO_SUCCESS
)
2455 return hb_preset_index_dup(&ctx
.path
);
2458 hb_preset_index_t
* hb_presets_get_default_index(void)
2460 hb_preset_index_t
*path
= lookup_default_index(hb_presets
);
2464 hb_dict_t
* hb_presets_get_default(void)
2466 hb_preset_index_t
*path
= hb_presets_get_default_index();
2467 return hb_preset_get(path
);
2470 char * hb_presets_get_default_json(void)
2472 // Look for default preset
2473 hb_value_t
*def
= hb_presets_get_default();
2474 return hb_value_get_json(def
);
2477 void hb_presets_clear_default()
2479 preset_do_context_t ctx
;
2481 presets_do(do_clear_default
, hb_presets
, &ctx
);
2484 void hb_presets_builtin_update(void)
2486 preset_do_context_t ctx
;
2487 hb_preset_index_t
*path
;
2488 hb_value_t
*builtin
;
2492 presets_do(do_delete_builtin
, hb_presets
, &ctx
);
2494 builtin
= hb_value_dup(hb_presets_builtin
);
2495 path
= lookup_default_index(hb_presets
);
2496 if (path
!= NULL
&& path
->depth
!= 0)
2498 // The "Default" preset is an existing custom preset.
2499 // Clear the default preset in builtins
2501 presets_do(do_clear_default
, builtin
, &ctx
);
2505 for (ii
= hb_value_array_len(builtin
) - 1; ii
>= 0; ii
--)
2508 dict
= hb_value_array_get(builtin
, ii
);
2509 hb_value_incref(dict
);
2510 hb_value_array_insert(hb_presets
, 0, dict
);
2512 hb_value_free(&builtin
);
2515 int hb_presets_add(hb_value_t
*preset
)
2517 hb_preset_index_t
*path
;
2523 preset
= presets_unpackage(preset
);
2527 path
= lookup_default_index(preset
);
2528 if (path
!= NULL
&& path
->depth
!= 0)
2530 // There is a "Default" preset in the preset(s) being added.
2531 // Clear any existing default preset.
2532 hb_presets_clear_default();
2536 int index
= hb_value_array_len(hb_presets
);
2537 if (hb_value_type(preset
) == HB_VALUE_TYPE_DICT
)
2539 // A standalone preset or folder of presets. Add to preset array.
2540 hb_value_array_append(hb_presets
, hb_value_dup(preset
));
2543 else if (hb_value_type(preset
) == HB_VALUE_TYPE_ARRAY
)
2545 // An array of presets. Add each element.
2546 int count
= hb_value_array_len(preset
);
2548 for (ii
= 0; ii
< count
; ii
++)
2550 hb_value_t
*value
= hb_value_array_get(preset
, ii
);
2551 hb_value_array_append(hb_presets
, hb_value_dup(value
));
2556 hb_value_free(&preset
);
2565 int hb_presets_add_json(const char *json
)
2567 hb_value_t
*preset
= hb_value_json(json
);
2570 int result
= hb_presets_add(preset
);
2571 hb_value_free(&preset
);
2575 int hb_presets_version_file(const char *filename
,
2576 int *major
, int *minor
, int *micro
)
2580 hb_value_t
*preset
= hb_value_read_json(filename
);
2582 preset
= hb_plist_parse_file(filename
);
2586 result
= hb_presets_version(preset
, major
, minor
, micro
);
2587 hb_value_free(&preset
);
2592 hb_value_t
* hb_presets_read_file(const char *filename
)
2594 hb_value_t
*preset
= hb_value_read_json(filename
);
2596 preset
= hb_plist_parse_file(filename
);
2603 char * hb_presets_read_file_json(const char *filename
)
2606 hb_value_t
*preset
= hb_value_read_json(filename
);
2608 preset
= hb_plist_parse_file(filename
);
2612 result
= hb_value_get_json(preset
);
2616 int hb_presets_add_file(const char *filename
)
2618 hb_value_t
*preset
= hb_value_read_json(filename
);
2620 preset
= hb_plist_parse_file(filename
);
2624 int result
= hb_presets_add(preset
);
2625 hb_value_free(&preset
);
2630 static int compare_str(const void *a
, const void *b
)
2632 return strncmp(*(const char**)a
, *(const char**)b
, PATH_MAX
);
2635 int hb_presets_add_path(char * path
)
2639 struct dirent
* entry
;
2645 if (hb_stat(path
, &sb
))
2648 if (S_ISREG(sb
.st_mode
))
2650 return hb_presets_add_file(path
);
2653 if (!S_ISDIR(sb
.st_mode
))
2656 dir
= hb_opendir(path
);
2660 // Count the total number of entries
2662 while ((entry
= hb_readdir(dir
)))
2666 files
= malloc(count
* sizeof(char*));
2668 // Find all regular files
2671 while ((entry
= hb_readdir(dir
)))
2673 filename
= hb_strdup_printf("%s" DIR_SEP_STR
"%s", path
, entry
->d_name
);
2674 if (hb_stat(filename
, &sb
))
2680 // Only load regular files
2681 if (!S_ISREG(sb
.st_mode
))
2686 // Only load files with .json extension
2687 if (strcmp(".json", filename
+ strlen(filename
) - 5))
2693 files
[ii
++] = filename
;
2697 // Sort the files so presets get added in a consistent order
2698 qsort(files
, count
, sizeof(char*), compare_str
);
2700 // Add preset files to preset list
2701 for (ii
= 0; ii
< count
; ii
++)
2703 int res
= hb_presets_add_file(files
[ii
]);
2704 // return success if any one of the files is successfully loaded
2714 hb_value_t
* hb_presets_get(void)
2719 char * hb_presets_get_json(void)
2722 hb_value_t
*presets
= hb_presets_get();
2723 result
= hb_value_get_json(presets
);
2727 int hb_presets_write_json(const hb_value_t
*preset
, const char *path
)
2729 hb_value_t
*packaged_preset
= presets_package(preset
);
2730 // Packaging does some validity checks and can fail
2731 if (packaged_preset
== NULL
)
2733 int result
= hb_value_write_json(packaged_preset
, path
);
2734 hb_value_free(&packaged_preset
);
2738 char * hb_presets_package_json(const hb_value_t
*preset
)
2740 hb_value_t
*packaged_preset
= presets_package(preset
);
2741 // Packaging does some validity checks and can fail
2742 if (packaged_preset
== NULL
)
2744 char *out_json
= hb_value_get_json(packaged_preset
);
2745 hb_value_free(&packaged_preset
);
2749 char * hb_presets_json_package(const char *in_json
)
2751 hb_value_t
*preset
= hb_value_json(in_json
);
2752 hb_value_t
*packaged_preset
= presets_package(preset
);
2753 // Packaging does some validity checks and can fail
2754 if (packaged_preset
== NULL
)
2756 char *out_json
= hb_value_get_json(packaged_preset
);
2757 hb_value_free(&packaged_preset
);
2758 hb_value_free(&preset
);
2762 void hb_presets_free(void)
2764 hb_value_free(&hb_preset_template
);
2765 hb_value_free(&hb_presets
);
2766 hb_value_free(&hb_presets_builtin
);
2770 hb_presets_get_folder_children(const hb_preset_index_t
*path
)
2772 int ii
, count
, folder
;
2778 hb_value_t
*presets
= hb_presets
;
2779 for (ii
= 0; ii
< path
->depth
; ii
++)
2781 count
= hb_value_array_len(presets
);
2782 if (path
->index
[ii
] >= count
) return NULL
;
2783 dict
= hb_value_array_get(presets
, path
->index
[ii
]);
2784 folder
= hb_value_get_bool(hb_dict_get(dict
, "Folder"));
2787 presets
= hb_dict_get(dict
, "ChildrenArray");
2789 if (ii
< path
->depth
)
2795 hb_preset_get(const hb_preset_index_t
*path
)
2797 hb_value_t
*folder
= NULL
;
2799 if (path
== NULL
|| path
->depth
<= 0)
2802 hb_preset_index_t folder_path
= *path
;
2803 folder_path
.depth
--;
2804 folder
= hb_presets_get_folder_children(&folder_path
);
2807 if (hb_value_array_len(folder
) <= path
->index
[path
->depth
-1])
2809 hb_error("hb_preset_get: not found");
2813 return hb_value_array_get(folder
, path
->index
[path
->depth
-1]);
2818 hb_error("hb_preset_get: not found");
2824 hb_preset_set(const hb_preset_index_t
*path
, const hb_value_t
*dict
)
2826 hb_value_t
*folder
= NULL
;
2828 if (dict
== NULL
|| path
== NULL
|| path
->depth
<= 0)
2831 hb_preset_index_t folder_path
= *path
;
2832 folder_path
.depth
--;
2833 folder
= hb_presets_get_folder_children(&folder_path
);
2836 if (hb_value_array_len(folder
) <= path
->index
[path
->depth
-1])
2838 hb_error("hb_preset_replace: not found");
2843 hb_value_t
*dup
= hb_value_dup(dict
);
2844 presets_clean(dup
, hb_preset_template
);
2845 hb_value_array_set(folder
, path
->index
[path
->depth
-1], dup
);
2850 hb_error("hb_preset_replace: not found");
2856 int hb_preset_insert(const hb_preset_index_t
*path
, const hb_value_t
*dict
)
2858 hb_value_t
*folder
= NULL
;
2860 if (dict
== NULL
|| path
== NULL
|| path
->depth
< 0)
2863 int index
= path
->index
[path
->depth
- 1];
2864 hb_preset_index_t folder_path
= *path
;
2865 folder_path
.depth
--;
2866 folder
= hb_presets_get_folder_children(&folder_path
);
2869 hb_value_t
*dup
= hb_value_dup(dict
);
2870 presets_clean(dup
, hb_preset_template
);
2871 if (hb_value_array_len(folder
) <= index
)
2873 index
= hb_value_array_len(folder
);
2874 hb_value_array_append(folder
, dup
);
2878 hb_value_array_insert(folder
, index
, dup
);
2883 hb_error("hb_preset_insert: not found");
2889 int hb_preset_append(const hb_preset_index_t
*path
, const hb_value_t
*dict
)
2891 hb_value_t
*folder
= NULL
;
2896 folder
= hb_presets_get_folder_children(path
);
2900 hb_value_t
*dup
= hb_value_dup(dict
);
2901 presets_clean(dup
, hb_preset_template
);
2902 index
= hb_value_array_len(folder
);
2903 hb_value_array_append(folder
, dup
);
2908 hb_error("hb_preset_append: not found");
2915 hb_preset_delete(const hb_preset_index_t
*path
)
2917 hb_value_t
*folder
= NULL
;
2922 hb_preset_index_t folder_path
= *path
;
2923 folder_path
.depth
--;
2924 folder
= hb_presets_get_folder_children(&folder_path
);
2927 if (hb_value_array_len(folder
) <= path
->index
[path
->depth
-1])
2929 hb_error("hb_preset_delete: not found");
2934 hb_value_array_remove(folder
, path
->index
[path
->depth
-1]);
2939 hb_error("hb_preset_delete: not found");
2945 int hb_preset_move(const hb_preset_index_t
*src_path
,
2946 const hb_preset_index_t
*dst_path
)
2948 hb_value_t
*src_folder
= NULL
;
2949 hb_value_t
*dst_folder
= NULL
;
2951 hb_preset_index_t src_folder_path
= *src_path
;
2952 hb_preset_index_t dst_folder_path
= *dst_path
;
2953 src_folder_path
.depth
--;
2954 dst_folder_path
.depth
--;
2955 src_folder
= hb_presets_get_folder_children(&src_folder_path
);
2956 dst_folder
= hb_presets_get_folder_children(&dst_folder_path
);
2957 if (src_folder
== NULL
|| dst_folder
== NULL
)
2959 hb_error("hb_preset_move: not found");
2964 int src_index
, dst_index
;
2966 src_index
= src_path
->index
[src_path
->depth
-1];
2967 dst_index
= dst_path
->index
[src_path
->depth
-1];
2968 dict
= hb_value_array_get(src_folder
, src_index
);
2969 hb_value_incref(dict
);
2970 hb_value_array_remove(src_folder
, src_index
);
2972 // Be careful about indexes in the case that they are in the same folder
2973 if (src_folder
== dst_folder
&& src_index
< dst_index
)
2975 if (hb_value_array_len(dst_folder
) <= dst_index
)
2976 hb_value_array_append(dst_folder
, dict
);
2978 hb_value_array_insert(dst_folder
, dst_index
, dict
);