diff options
author | jstebbins <[email protected]> | 2015-05-06 16:04:08 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2015-05-06 16:04:08 +0000 |
commit | 9c0e97cc2c369e0c720441d182bbde20210742f4 (patch) | |
tree | 8b8f74ed24d0f617c9980d9043ebd53c33c531f3 /libhb | |
parent | 81bcee10d2ad88f44c0f7791f2dd8da4ee2c1b76 (diff) |
libhb,cli: add preset management to libhb, use it in cli
This results in custom preset support in the CLI and additional
command line options to fully support all preset keys.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@7158 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/builtin_presets.h | 965 | ||||
-rw-r--r-- | libhb/common.c | 21 | ||||
-rw-r--r-- | libhb/hb.c | 5 | ||||
-rw-r--r-- | libhb/hb.h | 3 | ||||
-rw-r--r-- | libhb/hb_dict.c | 5 | ||||
-rw-r--r-- | libhb/hb_dict.h | 1 | ||||
-rw-r--r-- | libhb/lang.c | 8 | ||||
-rw-r--r-- | libhb/lang.h | 2 | ||||
-rw-r--r-- | libhb/libhb_presets.list | 9 | ||||
-rw-r--r-- | libhb/module.defs | 6 | ||||
-rw-r--r-- | libhb/plist.c | 678 | ||||
-rw-r--r-- | libhb/plist.h | 13 | ||||
-rw-r--r-- | libhb/preset.c | 2198 | ||||
-rw-r--r-- | libhb/preset.h | 84 | ||||
-rw-r--r-- | libhb/preset_builtin.json | 855 | ||||
-rw-r--r-- | libhb/preset_template.json | 104 |
16 files changed, 4945 insertions, 12 deletions
diff --git a/libhb/builtin_presets.h b/libhb/builtin_presets.h new file mode 100644 index 000000000..b0b3e5cd8 --- /dev/null +++ b/libhb/builtin_presets.h @@ -0,0 +1,965 @@ +const char hb_builtin_presets_json[] = +"{\n" +" \"PresetBuiltin\": [\n" +" {\n" +" \"ChildrenArray\": [\n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }, \n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"copy:ac3\", \n" +" \"AudioMixdown\": \"none\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 576, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 720, \n" +" \"PresetDescription\": \"HandBrake's settings for compatibility with all Apple devices (including the iPod 6G and later). Includes Dolby Digital audio for surround sound.\", \n" +" \"PresetName\": \"Universal\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.0\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"fast\", \n" +" \"VideoProfile\": \"baseline\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 1, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 240, \n" +" \"PictureKeepRatio\": 1, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"off\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 320, \n" +" \"PresetDescription\": \"HandBrake's settings for playback on the iPod with Video (all generations).\", \n" +" \"PresetName\": \"iPod\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"1.3\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"baseline\", \n" +" \"VideoQualitySlider\": 22.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 640, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 960, \n" +" \"PresetDescription\": \"HandBrake's settings for handheld iOS devices (iPhone 4, iPod touch 3G and later).\", \n" +" \"PresetName\": \"iPhone & iPod touch\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.1\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"high\", \n" +" \"VideoQualitySlider\": 22.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 720, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 1280, \n" +" \"PresetDescription\": \"HandBrake's settings for playback on the iPad (all generations).\", \n" +" \"PresetName\": \"iPad\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.1\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"high\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }, \n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"copy:ac3\", \n" +" \"AudioMixdown\": \"none\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 720, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 960, \n" +" \"PresetDescription\": \"HandBrake's settings for the original AppleTV. Includes Dolby Digital audio for surround sound. Also compatible with iOS devices released since 2009.\", \n" +" \"PresetName\": \"AppleTV\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.1\", \n" +" \"VideoOptionExtra\": \"qpmin=4:cabac=0:ref=2:b-pyramid=none:weightb=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"high\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }, \n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"copy:ac3\", \n" +" \"AudioMixdown\": \"none\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 720, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 1280, \n" +" \"PresetDescription\": \"HandBrake's settings for the second-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV.\", \n" +" \"PresetName\": \"AppleTV 2\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.1\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"high\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }, \n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"copy:ac3\", \n" +" \"AudioMixdown\": \"none\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 3, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 1080, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 1920, \n" +" \"PresetDescription\": \"HandBrake's settings for the third-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV. May stutter on the second-generation AppleTV.\", \n" +" \"PresetName\": \"AppleTV 3\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"4.0\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"high\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"128\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 0, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 576, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 720, \n" +" \"PresetDescription\": \"HandBrake's settings for midrange devices running Android 2.3 or later.\", \n" +" \"PresetName\": \"Android\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.0\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"main\", \n" +" \"VideoQualitySlider\": 22.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"128\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 0, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 720, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 1280, \n" +" \"PresetDescription\": \"HandBrake's preset for tablets running Android 2.3 or later.\", \n" +" \"PresetName\": \"Android Tablet\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.1\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"main\", \n" +" \"VideoQualitySlider\": 22.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"128\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 0, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 720, \n" +" \"PictureKeepRatio\": 1, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"off\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 1280, \n" +" \"PresetDescription\": \"HandBrake's preset for Windows Phone 8 devices\", \n" +" \"PresetName\": \"Windows Phone 8\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"30\", \n" +" \"VideoFramerateMode\": \"pfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"3.1\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"main\", \n" +" \"VideoQualitySlider\": 22.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }\n" +" ], \n" +" \"Default\": 0, \n" +" \"Folder\": true, \n" +" \"PresetName\": \"Devices\", \n" +" \"Type\": 0\n" +" }, \n" +" {\n" +" \"ChildrenArray\": [\n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 1, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 0, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 0, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 0, \n" +" \"PresetDescription\": \"HandBrake's normal, default settings.\", \n" +" \"PresetName\": \"Normal\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"auto\", \n" +" \"VideoFramerateMode\": \"vfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"4.0\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"veryfast\", \n" +" \"VideoProfile\": \"main\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }, \n" +" {\n" +" \"AudioAllowAACPass\": 1, \n" +" \"AudioAllowAC3Pass\": 1, \n" +" \"AudioAllowDTSHDPass\": 1, \n" +" \"AudioAllowDTSPass\": 1, \n" +" \"AudioAllowMP3Pass\": 1, \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"aac\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }, \n" +" {\n" +" \"AudioBitrate\": \"160\", \n" +" \"AudioEncoder\": \"copy:ac3\", \n" +" \"AudioMixdown\": \"none\", \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrack\": 1, \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0\n" +" }\n" +" ], \n" +" \"ChapterMarkers\": 1, \n" +" \"Default\": 0, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": 0, \n" +" \"Mp4iPodCompatible\": 0, \n" +" \"PictureAutoCrop\": 1, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": 2, \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": 1, \n" +" \"PictureDeinterlace\": 0, \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDetelecine\": 0, \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureHeight\": 0, \n" +" \"PictureKeepRatio\": 0, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 0, \n" +" \"PresetDescription\": \"HandBrake's general-purpose preset for High Profile H.264 video.\", \n" +" \"PresetName\": \"High Profile\", \n" +" \"Type\": 0, \n" +" \"UsesPictureFilters\": 1, \n" +" \"UsesPictureSettings\": 1, \n" +" \"VideoAvgBitrate\": \"2500\", \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"auto\", \n" +" \"VideoFramerateMode\": \"vfr\", \n" +" \"VideoGrayScale\": 0, \n" +" \"VideoLevel\": \"4.1\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"high\", \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoTune\": \"\", \n" +" \"VideoTurboTwoPass\": 0, \n" +" \"VideoTwoPass\": 0, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": 0\n" +" }\n" +" ], \n" +" \"Default\": 0, \n" +" \"Folder\": true, \n" +" \"PresetName\": \"Regular\", \n" +" \"Type\": 0\n" +" }\n" +" ], \n" +" \"PresetTemplate\": {\n" +" \"Preset\": {\n" +" \"AudioAllowAACPass\": false, \n" +" \"AudioAllowAC3Pass\": true, \n" +" \"AudioAllowDTSHDPass\": false, \n" +" \"AudioAllowDTSPass\": false, \n" +" \"AudioAllowEAC3Pass\": false, \n" +" \"AudioAllowFLACPass\": false, \n" +" \"AudioAllowMP3Pass\": false, \n" +" \"AudioAllowTRUEHDPass\": false, \n" +" \"AudioCopyMask\": [], \n" +" \"AudioEncoderFallback\": \"ac3\", \n" +" \"AudioLanguageList\": [\n" +" \"und\"\n" +" ], \n" +" \"AudioList\": [\n" +" {\n" +" \"AudioBitrate\": \"192\", \n" +" \"AudioCompressionLevel\": -1.0, \n" +" \"AudioDitherMethod\": \"auto\", \n" +" \"AudioEncoder\": \"copy:ac3\", \n" +" \"AudioMixdown\": \"dpl2\", \n" +" \"AudioNormalizeMixLevel\": false, \n" +" \"AudioSamplerate\": \"auto\", \n" +" \"AudioTrackDRCSlider\": 0.0, \n" +" \"AudioTrackGainSlider\": 0.0, \n" +" \"AudioTrackQuality\": -1.0, \n" +" \"AudioTrackQualityEnable\": false\n" +" }\n" +" ], \n" +" \"AudioSecondaryEncoderMode\": true, \n" +" \"AudioTrackSelectionBehavior\": \"first\", \n" +" \"ChapterMarkers\": true, \n" +" \"Default\": false, \n" +" \"FileFormat\": \"mp4\", \n" +" \"Folder\": false, \n" +" \"Mp4HttpOptimize\": false, \n" +" \"Mp4iPodCompatible\": false, \n" +" \"PictureAutoCrop\": true, \n" +" \"PictureBottomCrop\": 0, \n" +" \"PictureDARWidth\": 0, \n" +" \"PictureDeblock\": 0, \n" +" \"PictureDecomb\": \"off\", \n" +" \"PictureDecombCustom\": \"\", \n" +" \"PictureDecombDeinterlace\": true, \n" +" \"PictureDeinterlace\": \"off\", \n" +" \"PictureDeinterlaceCustom\": \"\", \n" +" \"PictureDenoiseCustom\": \"\", \n" +" \"PictureDenoiseFilter\": \"off\", \n" +" \"PictureDenoisePreset\": \"medium\", \n" +" \"PictureDenoiseTune\": \"none\", \n" +" \"PictureDetelecine\": \"off\", \n" +" \"PictureDetelecineCustom\": \"\", \n" +" \"PictureForceHeight\": 0, \n" +" \"PictureForceWidth\": 0, \n" +" \"PictureHeight\": 0, \n" +" \"PictureItuPAR\": false, \n" +" \"PictureKeepRatio\": true, \n" +" \"PictureLeftCrop\": 0, \n" +" \"PictureLooseCrop\": false, \n" +" \"PictureModulus\": 2, \n" +" \"PicturePAR\": \"loose\", \n" +" \"PicturePARHeight\": 720, \n" +" \"PicturePARWidth\": 853, \n" +" \"PictureRightCrop\": 0, \n" +" \"PictureRotate\": 0, \n" +" \"PictureTopCrop\": 0, \n" +" \"PictureWidth\": 0, \n" +" \"PresetDescription\": \"\", \n" +" \"PresetName\": \"Name Missing\", \n" +" \"SubtitleAddCC\": false, \n" +" \"SubtitleAddForeignAudioSearch\": false, \n" +" \"SubtitleAddForeignAudioSubtitle\": false, \n" +" \"SubtitleBurnBDSub\": false, \n" +" \"SubtitleBurnBehavior\": \"none\", \n" +" \"SubtitleBurnDVDSub\": false, \n" +" \"SubtitleLanguageList\": [], \n" +" \"SubtitleTrackSelectionBehavior\": \"none\", \n" +" \"Type\": 1, \n" +" \"UsesPictureFilters\": true, \n" +" \"UsesPictureSettings\": 2, \n" +" \"VideoAvgBitrate\": 1800, \n" +" \"VideoColorMatrixCode\": 0, \n" +" \"VideoEncoder\": \"x264\", \n" +" \"VideoFramerate\": \"auto\", \n" +" \"VideoFramerateMode\": \"vfr\", \n" +" \"VideoGrayScale\": false, \n" +" \"VideoHWDecode\": false, \n" +" \"VideoLevel\": \"auto\", \n" +" \"VideoOptionExtra\": \"\", \n" +" \"VideoPreset\": \"medium\", \n" +" \"VideoProfile\": \"auto\", \n" +" \"VideoQSVAsyncDepth\": 4, \n" +" \"VideoQSVDecode\": false, \n" +" \"VideoQualitySlider\": 20.0, \n" +" \"VideoQualityType\": 2, \n" +" \"VideoScaler\": \"swscale\", \n" +" \"VideoTune\": \"none\", \n" +" \"VideoTurboTwoPass\": false, \n" +" \"VideoTwoPass\": false, \n" +" \"x264Option\": \"\", \n" +" \"x264UseAdvancedOptions\": false\n" +" }, \n" +" \"VersionMajor\": 10, \n" +" \"VersionMicro\": 0, \n" +" \"VersionMinor\": 0\n" +" }\n" +"}\n"; diff --git a/libhb/common.c b/libhb/common.c index 7bb3f2a56..8a7b72522 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -262,6 +262,9 @@ hb_encoder_internal_t hb_audio_encoders[] = { { "Vorbis (vorbis)", "libvorbis", NULL, HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_VORBIS, }, { { "FLAC (ffmpeg)", "ffflac", NULL, HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, }, { { "FLAC (24-bit)", "ffflac24", NULL, HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, }, + // generic names + { { "AAC", "aac", NULL, 0, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AAC, }, + { { "HE-AAC", "haac", NULL, 0, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AAC_HE, }, // actual encoders { { "AAC (CoreAudio)", "ca_aac", "AAC (Apple AudioToolbox)", HB_ACODEC_CA_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "HE-AAC (CoreAudio)", "ca_haac", "HE-AAC (Apple AudioToolbox)", HB_ACODEC_CA_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_HE, }, @@ -1793,7 +1796,7 @@ int hb_video_encoder_get_default(int muxer) } fail: - return 0; + return HB_VCODEC_INVALID; } hb_encoder_t * hb_video_encoder_get_from_codec(int codec) @@ -1826,7 +1829,7 @@ int hb_video_encoder_get_from_name(const char *name) } fail: - return 0; + return HB_VCODEC_INVALID; } const char* hb_video_encoder_get_name(int encoder) @@ -1937,10 +1940,10 @@ int hb_audio_encoder_get_fallback_for_passthru(int passthru) } // passthru tracks are often the second audio from the same source track - // if we don't have an encoder matching the passthru codec, return 0 + // if we don't have an encoder matching the passthru codec, return INVALID // dropping the track, as well as ensuring that there is at least one // audio track in the output is then up to the UIs - return 0; + return HB_ACODEC_INVALID; } int hb_audio_encoder_get_default(int muxer) @@ -1974,7 +1977,7 @@ int hb_audio_encoder_get_default(int muxer) } fail: - return 0; + return HB_ACODEC_INVALID; } hb_encoder_t* hb_audio_encoder_get_from_codec(int codec) @@ -1988,7 +1991,7 @@ hb_encoder_t* hb_audio_encoder_get_from_codec(int codec) } } - return 0; + return NULL; } int hb_audio_encoder_get_from_name(const char *name) @@ -2007,7 +2010,7 @@ int hb_audio_encoder_get_from_name(const char *name) } fail: - return 0; + return HB_ACODEC_INVALID; } const char* hb_audio_encoder_get_name(int encoder) @@ -2302,7 +2305,7 @@ int hb_container_get_from_name(const char *name) } fail: - return 0; + return HB_MUX_INVALID; } int hb_container_get_from_extension(const char *extension) @@ -2320,7 +2323,7 @@ int hb_container_get_from_extension(const char *extension) } fail: - return 0; + return HB_MUX_INVALID; } const char* hb_container_get_name(int format) diff --git a/libhb/hb.c b/libhb/hb.c index 7a7429153..f4ec2308f 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -1655,6 +1655,9 @@ int hb_global_init() */ hb_buffer_pool_init(); + // Initialize the builtin presets hb_dict_t + hb_presets_builtin_init(); + return result; } @@ -1667,6 +1670,8 @@ void hb_global_close() DIR * dir; struct dirent * entry; + hb_presets_free(); + /* Find and remove temp folder */ memset( dirname, 0, 1024 ); hb_get_temporary_directory( dirname ); diff --git a/libhb/hb.h b/libhb/hb.h index 38418ac3b..215455cda 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -14,11 +14,12 @@ extern "C" { #endif -#include "project.h" #include "common.h" +#include "project.h" #include "compat.h" #include "hb_dict.h" #include "hb_json.h" +#include "preset.h" #include "param.h" /* hb_init() diff --git a/libhb/hb_dict.c b/libhb/hb_dict.c index 7fd12b565..866803f58 100644 --- a/libhb/hb_dict.c +++ b/libhb/hb_dict.c @@ -21,6 +21,11 @@ hb_value_type_t hb_value_type(const hb_value_t *value) return type; } +int hb_value_is_number(const hb_value_t *value) +{ + return json_is_number(value); +} + hb_value_t * hb_value_dup(const hb_value_t *value) { if (value == NULL) return NULL; diff --git a/libhb/hb_dict.h b/libhb/hb_dict.h index 52898e413..2a4f71cfe 100644 --- a/libhb/hb_dict.h +++ b/libhb/hb_dict.h @@ -84,6 +84,7 @@ size_t hb_value_array_len(const hb_value_array_t *array); /* hb_value_t */ int hb_value_type(const hb_value_t *value); +int hb_value_is_number(const hb_value_t *value); hb_value_t * hb_value_dup(const hb_value_t *value); void hb_value_incref(hb_value_t *value); void hb_value_decref(hb_value_t *value); diff --git a/libhb/lang.c b/libhb/lang.c index f40520a23..34466da34 100644 --- a/libhb/lang.c +++ b/libhb/lang.c @@ -202,10 +202,16 @@ static const iso639_lang_t languages[] = static const int lang_count = sizeof(languages) / sizeof(languages[0]); -iso639_lang_t * lang_lookup( const char * str ) +const iso639_lang_t * lang_lookup( const char * str ) { iso639_lang_t * lang; + // We use "Any" as a synonym for undefined + if (!strcasecmp("any", str)) + { + return &languages[0]; + } + for (lang = (iso639_lang_t*) languages; lang->eng_name; lang++) { if ((lang->iso639_1 != NULL && !strcasecmp(lang->iso639_1, str)) || diff --git a/libhb/lang.h b/libhb/lang.h index 21aab70af..7e7b82bd5 100644 --- a/libhb/lang.h +++ b/libhb/lang.h @@ -24,7 +24,7 @@ typedef struct iso639_lang_t extern "C" { #endif /* find language, match any of names in lang struct */ -iso639_lang_t * lang_lookup( const char * str ); +const iso639_lang_t * lang_lookup( const char * str ); /* find language associated with ISO-639-1 language code */ iso639_lang_t * lang_for_code( int code ); diff --git a/libhb/libhb_presets.list b/libhb/libhb_presets.list new file mode 100644 index 000000000..3742b1d40 --- /dev/null +++ b/libhb/libhb_presets.list @@ -0,0 +1,9 @@ +<resources> + <section name="PresetTemplate"> + <integer name="VersionMajor" value="10" /> + <integer name="VersionMinor" value="0" /> + <integer name="VersionMicro" value="0" /> + <json name="Preset" file="preset_template.json" /> + </section> + <json name="PresetBuiltin" file="preset_builtin.json" /> +</resources> diff --git a/libhb/module.defs b/libhb/module.defs index 3d7d55ee3..f98930dd5 100644 --- a/libhb/module.defs +++ b/libhb/module.defs @@ -47,6 +47,12 @@ endif LIBHB.GCC.D += __LIBHB__ USE_PTHREAD LIBHB.GCC.I += $(LIBHB.build/) $(CONTRIB.build/)include +ifneq (,$(filter $(BUILD.system),darwin cygwin mingw)) +LIBHB.GCC.I += $(CONTRIB.build/)include/libxml2 +else +LIBHB.GCC.I += /usr/include/libxml2 +endif + ifeq ($(BUILD.system),cygwin) LIBHB.GCC.D += SYS_CYGWIN else ifeq ($(BUILD.system),darwin) diff --git a/libhb/plist.c b/libhb/plist.c new file mode 100644 index 000000000..f61014537 --- /dev/null +++ b/libhb/plist.c @@ -0,0 +1,678 @@ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <inttypes.h> +#include "libxml/parser.h" + +#include "common.h" +#include "hb_dict.h" +#include "plist.h" + +#define BUF_SZ (128*1024) + +static char *preamble = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n"; +static char *postfix = + "</plist>\n"; + +typedef struct queue_item_s queue_item_t; +struct queue_item_s +{ + void *value; + queue_item_t *next; +}; + +typedef struct +{ + queue_item_t *head; +} queue_t; + +queue_t * queue_new() +{ + return calloc(1, sizeof(queue_t)); +} + +void queue_free(queue_t **_q) +{ + queue_t *q = *_q; + if (q == NULL) + return; + + queue_item_t *n, *i = q->head; + while (i != NULL) + { + n = i->next; + free(i); + i = n; + } + free(q); + *_q = NULL; +} + +void queue_push_head(queue_t *q, void *v) +{ + queue_item_t *i = calloc(1, sizeof(queue_item_t)); + i->value = v; + i->next = q->head; + q->head = i; +} + +void * queue_peek_head(queue_t *q) +{ + if (q->head != NULL) + return q->head->value; + return NULL; +} + +void * queue_pop_head(queue_t *q) +{ + void *result; + queue_item_t *i; + + if (q->head == NULL) + return NULL; + + i = q->head; + result = i->value; + q->head = i->next; + free(i); + + return result; +} + +int queue_is_empty(queue_t *q) +{ + return q->head == NULL; +} + +char * markup_escape_text(const char *str) +{ + int ii, jj; + int len = strlen(str); + int step = 40; + int alloc = len + step; + char *markup = malloc(alloc); + + for (ii = 0, jj = 0; ii < len; ii++) + { + if (jj > alloc - 8) + { + alloc += step; + char *tmp = realloc(markup, alloc); + if (tmp == NULL) + { + markup[jj] = 0; + return markup; + } + markup = tmp; + } + switch (str[ii]) + { + case '<': + markup[jj++] = '&'; + markup[jj++] = 'l'; + markup[jj++] = 't'; + markup[jj++] = ';'; + break; + case '>': + markup[jj++] = '&'; + markup[jj++] = 'g'; + markup[jj++] = 't'; + markup[jj++] = ';'; + break; + case '\'': + markup[jj++] = '&'; + markup[jj++] = 'a'; + markup[jj++] = 'p'; + markup[jj++] = 'o'; + markup[jj++] = 's'; + markup[jj++] = ';'; + break; + case '"': + markup[jj++] = '&'; + markup[jj++] = 'q'; + markup[jj++] = 'u'; + markup[jj++] = 'o'; + markup[jj++] = 't'; + markup[jj++] = ';'; + break; + case '&': + markup[jj++] = '&'; + markup[jj++] = 'a'; + markup[jj++] = 'm'; + markup[jj++] = 'p'; + markup[jj++] = ';'; + break; + default: + markup[jj++] = str[ii]; + break; + } + markup[jj] = 0; + } + return markup; +} + +enum +{ + P_NONE = 0, + P_PLIST, + P_KEY, + P_ARRAY, + P_DICT, + P_INTEGER, + P_REAL, + P_STRING, + P_DATE, + P_TRUE, + P_FALSE, + P_DATA, +}; + +typedef struct +{ + char *tag; + int id; +} tag_map_t; + +static tag_map_t tag_map[] = +{ + {"plist", P_PLIST}, + {"key", P_KEY}, + {"array", P_ARRAY}, + {"dict", P_DICT}, + {"integer", P_INTEGER}, + {"real", P_REAL}, + {"string", P_STRING}, + {"date", P_DATE}, + {"true", P_TRUE}, + {"false", P_FALSE}, + {"data", P_DATA}, +}; +#define TAG_MAP_SZ (sizeof(tag_map)/sizeof(tag_map_t)) + +typedef struct +{ + char *key; + char *value; + hb_value_t *plist; + queue_t *stack; + queue_t *tag_stack; + int closed_top; +} parse_data_t; + +static void +start_element( + void *ud, + const xmlChar *xname, + const xmlChar **attr_names) +{ + char *name = (char*)xname; + parse_data_t *pd = (parse_data_t*)ud; + union + { + int id; + void * pid; + } id; + int ii; + + // Check to see if the first element found has been closed + // If so, ignore any junk following it. + if (pd->closed_top) + return; + + for (ii = 0; ii < TAG_MAP_SZ; ii++) + { + if (strcmp(name, tag_map[ii].tag) == 0) + { + id.id = tag_map[ii].id; + break; + } + } + if (ii == TAG_MAP_SZ) + { + hb_error("Unrecognized start tag (%s)", name); + return; + } + if (pd->value) + { + free(pd->value); + pd->value = NULL; + } + queue_push_head(pd->tag_stack, id.pid); + hb_value_type_t gtype = 0; + hb_value_t *gval = NULL; + hb_value_t *current = queue_peek_head(pd->stack); + switch (id.id) + { + case P_PLIST: + { // Ignore + } break; + case P_KEY: + { + if (pd->key) free(pd->key); + pd->key = NULL; + } break; + case P_DICT: + { + gval = hb_dict_init(); + queue_push_head(pd->stack, gval); + } break; + case P_ARRAY: + { + gval = hb_value_array_init(); + queue_push_head(pd->stack, gval); + } break; + case P_INTEGER: + { + } break; + case P_REAL: + { + } break; + case P_STRING: + { + } break; + case P_DATE: + { + } break; + case P_TRUE: + { + } break; + case P_FALSE: + { + } break; + case P_DATA: + { + } break; + } + // Add the element to the current container + if (gval) + { // There's an element to add + if (current == NULL) + { + pd->plist = gval; + return; + } + gtype = hb_value_type(current); + if (gtype == HB_VALUE_TYPE_ARRAY) + { + hb_value_array_append(current, gval); + } + else if (gtype == HB_VALUE_TYPE_DICT) + { + if (pd->key == NULL) + { + hb_error("No key for dictionary item"); + hb_value_free(&gval); + } + else + { + hb_dict_set(current, pd->key, gval); + } + } + else + { + hb_error("Invalid container type. This shouldn't happen"); + } + } +} + +static void +end_element( + void *ud, + const xmlChar *xname) +{ + char *name = (char*)xname; + parse_data_t *pd = (parse_data_t*)ud; + int id; + union + { + int id; + void * pid; + } start_id; + int ii; + + // Check to see if the first element found has been closed + // If so, ignore any junk following it. + if (pd->closed_top) + return; + + for (ii = 0; ii < TAG_MAP_SZ; ii++) + { + if (strcmp(name, tag_map[ii].tag) == 0) + { + id = tag_map[ii].id; + break; + } + } + if (ii == TAG_MAP_SZ) + { + hb_error("Unrecognized start tag (%s)", name); + return; + } + start_id.pid = queue_pop_head(pd->tag_stack); + if (start_id.id != id) + hb_error("start tag != end tag: (%s %d) %d", name, id, id); + + hb_value_t *gval = NULL; + hb_value_t *current = queue_peek_head(pd->stack); + hb_value_type_t gtype = 0; + const char *value; + if (pd->value != NULL) + value = pd->value; + else + value = ""; + switch (id) + { + case P_PLIST: + { // Ignore + } break; + case P_KEY: + { + if (pd->key) free(pd->key); + pd->key = strdup(value); + return; + } break; + case P_DICT: + { + queue_pop_head(pd->stack); + } break; + case P_ARRAY: + { + queue_pop_head(pd->stack); + } break; + case P_INTEGER: + { + uint64_t val = strtoll(value, NULL, 0); + gval = hb_value_int(val); + } break; + case P_REAL: + { + double val = strtod(value, NULL); + gval = hb_value_double(val); + } break; + case P_STRING: + { + gval = hb_value_string(value); + } break; + case P_TRUE: + { + gval = hb_value_bool(1); + } break; + case P_FALSE: + { + gval = hb_value_bool(0); + } break; + default: + { + hb_error("Unhandled plist type %d", id); + } break; + } + if (gval) + { + // Get the top of the data structure stack and if it's an array + // or dict, add the current element + if (current == NULL) + { + pd->plist = gval; + pd->closed_top = 1; + return; + } + gtype = hb_value_type(current); + if (gtype == HB_VALUE_TYPE_ARRAY) + { + hb_value_array_append(current, gval); + } + else if (gtype == HB_VALUE_TYPE_DICT) + { + if (pd->key == NULL) + { + hb_error("No key for dictionary item"); + hb_value_free(&gval); + } + else + { + hb_dict_set(current, pd->key, gval); + } + } + else + { + hb_error("Invalid container type. This shouldn't happen"); + } + } + if (queue_is_empty(pd->stack)) + pd->closed_top = 1; +} + +static void +text_data( + void *ud, + const xmlChar *xtext, + int len) +{ + char *text = (char*)xtext; + parse_data_t *pd = (parse_data_t*)ud; + if (pd->value) free(pd->value); + pd->value = malloc(len + 1); + strncpy(pd->value, text, len); + pd->value[len] = 0; +} + +static void +parse_warning(void *ud, const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + hb_valog(0, "Plist parse warning: ", msg, args); + va_end(args); +} + +static void +parse_error(void *ud, const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + hb_valog(0, "Plist parse error: ", msg, args); + va_end(args); +} + +hb_value_t* +hb_plist_parse(const char *buf, size_t len) +{ + xmlSAXHandler parser; + parse_data_t pd; + + pd.stack = queue_new(); + pd.tag_stack = queue_new(); + pd.key = NULL; + pd.value = NULL; + pd.plist = NULL; + pd.closed_top = 0; + + memset(&parser, 0, sizeof(parser)); + parser.initialized = XML_SAX2_MAGIC; + parser.startElement = start_element; + parser.endElement = end_element; + parser.characters = text_data; + parser.warning = parse_warning; + parser.error = parse_error; + int result = xmlSAXUserParseMemory(&parser, &pd, buf, len); + if (result != 0) + { + hb_error("Plist parse failed"); + return NULL; + } + xmlCleanupParser(); + + if (pd.key) free(pd.key); + if (pd.value) free(pd.value); + queue_free(&pd.stack); + queue_free(&pd.tag_stack); + + return pd.plist; +} + +hb_value_t* +hb_plist_parse_file(const char *filename) +{ + char *buffer; + size_t size; + hb_value_t *gval; + FILE *fd; + + fd = fopen(filename, "r"); + if (fd == NULL) + { + // File doesn't exist + return NULL; + } + fseek(fd, 0, SEEK_END); + size = ftell(fd); + fseek(fd, 0, SEEK_SET); + buffer = malloc(size+1); + size = fread(buffer, 1, size, fd); + buffer[size] = 0; + gval = hb_plist_parse(buffer, size); + free(buffer); + fclose(fd); + return gval; +} + +static void +indent_fprintf(FILE *file, int indent, const char *fmt, ...) +{ + va_list ap; + + for (; indent; indent--) + putc('\t', file); + va_start(ap, fmt); + vfprintf(file, fmt, ap); + va_end(ap); +} + +static void +gval_write(FILE *file, hb_value_t *gval) +{ + static int indent = 0; + int ii; + hb_value_type_t gtype; + + if (gval == NULL) return; + gtype = hb_value_type(gval); + if (gtype == HB_VALUE_TYPE_ARRAY) + { + hb_value_t *val; + int count; + + indent_fprintf(file, indent, "<array>\n"); + indent++; + count = hb_value_array_len(gval); + for (ii = 0; ii < count; ii++) + { + val = hb_value_array_get(gval, ii); + gval_write(file, val); + } + indent--; + indent_fprintf(file, indent, "</array>\n"); + } + else if (gtype == HB_VALUE_TYPE_DICT) + { + const char *key; + hb_value_t *val; + hb_dict_iter_t iter; + + indent_fprintf(file, indent, "<dict>\n"); + indent++; + + for (iter = hb_dict_iter_init(gval); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(gval, iter)) + { + key = hb_dict_iter_key(iter); + val = hb_dict_iter_value(iter); + indent_fprintf(file, indent, "<key>%s</key>\n", key); + gval_write(file, val); + } + + indent--; + indent_fprintf(file, indent, "</dict>\n"); + } + else if (gtype == HB_VALUE_TYPE_BOOL) + { + char *tag; + if (hb_value_get_bool(gval)) + { + tag = "true"; + } + else + { + tag = "false"; + } + indent_fprintf(file, indent, "<%s />\n", tag); + } + else if (gtype == HB_VALUE_TYPE_DOUBLE) + { + double val = hb_value_get_double(gval); + indent_fprintf(file, indent, "<real>%.17g</real>\n", val); + } + else if (gtype == HB_VALUE_TYPE_INT) + { + int64_t val = hb_value_get_int(gval); + indent_fprintf(file, indent, "<integer>%"PRId64"</integer>\n", val); + } + else if (gtype == HB_VALUE_TYPE_STRING) + { + const char *str = hb_value_get_string(gval); + char *esc = markup_escape_text(str); + indent_fprintf(file, indent, "<string>%s</string>\n", esc); + free(esc); + } + else + { + // Try to make anything thats unrecognized into a string + hb_error("Unhandled data type %d", gtype); + } +} + +void +hb_plist_write(FILE *file, hb_value_t *gval) +{ + fprintf(file, "%s", preamble); + gval_write(file, gval); + fprintf(file, "%s", postfix); +} + +void +hb_plist_write_file(const char *filename, hb_value_t *gval) +{ + FILE *file; + + file = fopen(filename, "w"); + if (file == NULL) + return; + + hb_plist_write(file, gval); + fclose(file); +} + + +#if defined(PL_TEST) +int +main(int argc, char *argv[]) +{ + hb_value_t *gval; + + file = fopen(argv[1], "r"); + gval = hb_plist_parse_file(file); + if (argc > 2) + hb_plist_write_file(argv[2], gval); + else + hb_plist_write(stdout, gval); + if (file) fclose (file); + return 0; +} +#endif diff --git a/libhb/plist.h b/libhb/plist.h new file mode 100644 index 000000000..901aeb4b0 --- /dev/null +++ b/libhb/plist.h @@ -0,0 +1,13 @@ +#if !defined(_HB_PLIST_H_) +#define _HB_PLIST_H_ + +#include <stdio.h> +#include "hb_dict.h" + +hb_value_t * hb_plist_parse(const char *buf, size_t len); +hb_value_t * hb_plist_parse_file(const char *filename); +void hb_plist_write(FILE *file, hb_value_t *val); +void hb_plist_write_file(const char *filename, hb_value_t *val); + +#endif // _HB_PLIST_H_ + diff --git a/libhb/preset.c b/libhb/preset.c new file mode 100644 index 000000000..3fef7c686 --- /dev/null +++ b/libhb/preset.c @@ -0,0 +1,2198 @@ +/* hb_preset.c + + Copyright (c) 2003-2015 HandBrake Team + This file is part of the HandBrake source code + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License v2. + For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ + +#include "builtin_presets.h" +#include "hb.h" +#include "hb_dict.h" +#include "plist.h" + +#if defined(SYS_LINUX) +#define HB_PRESET_PLIST_FILE "ghb/presets" +#define HB_PRESET_JSON_FILE "ghb/presets.json" +#elif defined(SYS_MINGW) +#define HB_PRESET_PLIST_FILE "HandBrake\\user_presets.xml" +#define HB_PRESET_JSON_FILE "HandBrake\\user_presets.json" +#elif defined(SYS_DARWIN) +#define HB_PRESET_PLIST_FILE "HandBrake/UserPresets.plist" +#endif + +int hb_preset_version_major; +int hb_preset_version_minor; +int hb_preset_version_micro; + +static hb_value_t *hb_preset_template = NULL; +static hb_value_t *hb_presets = NULL; +static hb_value_t *hb_presets_custom = NULL; +static hb_value_t *hb_presets_builtin = NULL; + +static int get_job_mux(hb_dict_t *job_dict) +{ + int mux; + + hb_dict_t *dest_dict = hb_dict_get(job_dict, "Destination"); + hb_value_t *mux_value = hb_dict_get(dest_dict, "Mux"); + if (hb_value_type(mux_value) == HB_VALUE_TYPE_STRING) + { + mux = hb_container_get_from_name(hb_value_get_string(mux_value)); + if (mux == 0) + mux = hb_container_get_from_extension( + hb_value_get_string(mux_value)); + } + else + { + mux = hb_value_get_int(mux_value); + } + hb_container_t *container = hb_container_get_from_format(mux); + if (container == NULL) + { + char *str = hb_value_get_string_xform(mux_value); + hb_error("Invalid container (%s)", str); + free(str); + return HB_MUX_INVALID; + } + return mux; +} + +static int get_audio_copy_mask(hb_dict_t * preset) +{ + int mask = HB_ACODEC_PASS_FLAG; + + hb_value_array_t *copy_mask_array = hb_dict_get(preset, "AudioCopyMask"); + if (copy_mask_array != NULL) + { + int count = hb_value_array_len(copy_mask_array); + int ii; + for (ii = 0; ii < count; ii++) + { + int codec; + hb_value_t *value; + value = hb_value_array_get(copy_mask_array, ii); + if (hb_value_type(value) == HB_VALUE_TYPE_STRING) + { + char *tmp = NULL; + const char * s = hb_value_get_string(value); + // Only codecs that start with 'copy:' can be copied + if (strncmp(s, "copy:", 5)) + { + s = tmp = hb_strdup_printf("copy:%s", s); + } + codec = hb_audio_encoder_get_from_name(s); + if (codec == 0) + { + hb_error("Invalid audio codec in autopassthru copy mask (%s)", s); + hb_error("Codec name is invalid or can not be copied"); + free(tmp); + return HB_ACODEC_INVALID; + } + free(tmp); + } + else + { + codec = hb_value_get_int(value); + } + mask |= codec; + } + } + else + { + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowMP3Pass")) * + HB_ACODEC_MP3; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowAACPass")) * + HB_ACODEC_FFAAC; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowAC3Pass")) * + HB_ACODEC_AC3; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowDTSPass")) * + HB_ACODEC_DCA; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowDTSHDPass")) * + HB_ACODEC_DCA_HD; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowEAC3Pass")) * + HB_ACODEC_FFEAC3; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowFLACPass")) * + HB_ACODEC_FFFLAC; + mask |= hb_value_get_bool(hb_dict_get(preset, "AudioAllowTRUEHDPass")) * + HB_ACODEC_FFTRUEHD; + } + return mask; +} + +static hb_dict_t * source_audio_track_used(hb_dict_t *track_dict, int track) +{ + // Kind of hacky, but keys must be strings + char key[8]; + snprintf(key, sizeof(key), "%d", track); + + hb_dict_t *used = hb_dict_get(track_dict, key); + if (used == NULL) + { + used = hb_dict_init(); + hb_dict_set(track_dict, key, used); + } + return used; +} + +// Find a source audio track matching given language +static int find_audio_track(const hb_title_t *title, + const char *lang, int start) +{ + hb_audio_config_t * audio; + int ii, count; + + count = hb_list_count(title->list_audio); + for (ii = start; ii < count; ii++) + { + audio = hb_list_audio_config_item(title->list_audio, ii); + // Ignore secondary audio types + if ((audio->lang.type == HB_AUDIO_TYPE_NONE || + audio->lang.type == HB_AUDIO_TYPE_NORMAL) && + (!strcmp(lang, audio->lang.iso639_2) || !strcmp(lang, "und"))) + { + return ii; + } + } + return -1; +} + +static int validate_audio_encoders(hb_dict_t *preset) +{ + hb_value_array_t * encoder_list = hb_dict_get(preset, "AudioList"); + int count = hb_value_array_len(encoder_list); + int ii; + for (ii = 0; ii < count; ii++) + { + hb_value_t *audio_dict = hb_value_array_get(encoder_list, ii); + hb_value_t *value; + int codec, mix, sr; + value = hb_dict_get(audio_dict, "AudioEncoder"); + if (hb_value_type(value) == HB_VALUE_TYPE_STRING) + { + codec = hb_audio_encoder_get_from_name(hb_value_get_string(value)); + } + else + { + codec = hb_value_get_int(value); + } + if (hb_audio_encoder_get_from_codec(codec) == NULL) + { + char *str = hb_value_get_string_xform(value); + hb_error("Invalid audio encoder (%s)", str); + free(str); + return -1; + } + + value = hb_dict_get(audio_dict, "AudioMixdown"); + if (hb_value_type(value) == HB_VALUE_TYPE_STRING) + { + mix = hb_audio_encoder_get_from_name(hb_value_get_string(value)); + } + else + { + mix = hb_value_get_int(value); + } + if (hb_mixdown_get_from_mixdown(mix) == NULL) + { + char *str = hb_value_get_string_xform(value); + hb_error("Invalid audio mixdown (%s)", str); + free(str); + return -1; + } + + value = hb_dict_get(audio_dict, "AudioSamplerate"); + if (hb_value_type(value) == HB_VALUE_TYPE_STRING) + { + const char *str = hb_value_get_string(value); + if (!strcasecmp(str, "source") || + !strcasecmp(str, "auto") || + !strcasecmp(str, "same as source")) + { + sr = 0; + } + else + { + sr = hb_audio_samplerate_get_from_name(str); + } + } + else + { + sr = hb_value_get_int(value); + } + if (sr != 0 && hb_audio_samplerate_get_name(sr) == NULL) + { + char *str = hb_value_get_string_xform(value); + hb_error("Invalid audio samplerate (%s)", str); + free(str); + return -1; + } + } + return 0; +} + +static int sanitize_audio_codec(int in_codec, int out_codec, + int copy_mask, int fallback, int mux) +{ + int codec = out_codec; + if (out_codec == HB_ACODEC_AUTO_PASS) + { + codec = hb_autopassthru_get_encoder(in_codec, copy_mask, fallback, mux); + } + else if ((out_codec & HB_ACODEC_PASS_FLAG) && + !(in_codec & out_codec & HB_ACODEC_PASS_MASK)) + { + codec = hb_audio_encoder_get_fallback_for_passthru(out_codec); + if (codec == 0) + codec = fallback; + } + + // Check that encoder is valid for mux + const hb_encoder_t *encoder = NULL; + while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL) + { + if (encoder->codec == codec && + !(encoder->muxers & mux)) + { + codec = hb_audio_encoder_get_default(mux); + break; + } + } + if (codec == 0) + codec = hb_audio_encoder_get_default(mux); + return codec; +} + +static void add_audio_for_lang(hb_value_array_t *list, hb_dict_t *preset, + hb_title_t *title, int mux, int copy_mask, + int fallback, const char *lang, + int behavior, int mode, hb_dict_t *track_dict) +{ + hb_value_array_t * encoder_list = hb_dict_get(preset, "AudioList"); + int count = hb_value_array_len(encoder_list); + int track = find_audio_track(title, lang, 0); + int current_mode = 0; + while (track >= 0) + { + char key[8]; + snprintf(key, sizeof(key), "%d", track); + + count = current_mode ? 1 : count; + int ii; + for (ii = 0; ii < count; ii++) + { + // Check if this source track has already been added using these + // same encoder settings. If so, continue to next track. + hb_dict_t *used = source_audio_track_used(track_dict, ii); + if (hb_value_get_bool(hb_dict_get(used, key))) + continue; + hb_dict_set(used, key, hb_value_bool(1)); + + // Create new audio output track settings + hb_dict_t *audio_dict = hb_dict_init(); + hb_value_t *acodec_value; + hb_dict_t *encoder_dict = hb_value_array_get(encoder_list, ii); + int out_codec; + + acodec_value = hb_dict_get(encoder_dict, "AudioEncoder"); + if (hb_value_type(acodec_value) == HB_VALUE_TYPE_STRING) + { + out_codec = hb_audio_encoder_get_from_name( + hb_value_get_string(acodec_value)); + } + else + { + out_codec = hb_value_get_int(acodec_value); + } + // Save the encoder value before sanitizing. This value is + // useful to the frontends. + hb_dict_set(audio_dict, "PresetEncoder", hb_value_int(out_codec)); + + hb_audio_config_t *aconfig; + aconfig = hb_list_audio_config_item(title->list_audio, track); + out_codec = sanitize_audio_codec(aconfig->in.codec, out_codec, + copy_mask, fallback, mux); + hb_dict_set(audio_dict, "Track", hb_value_int(track)); + hb_dict_set(audio_dict, "Encoder", hb_value_int(out_codec)); + if (hb_dict_get(encoder_dict, "AudioTrackName") != NULL) + { + hb_dict_set(audio_dict, "Name", hb_value_dup( + hb_dict_get(encoder_dict, "AudioTrackName"))); + } + if (!(out_codec & HB_ACODEC_PASS_FLAG)) + { + if (hb_dict_get(encoder_dict, "AudioTrackGainSlider") != NULL) + { + hb_dict_set(audio_dict, "Gain", hb_value_dup( + hb_dict_get(encoder_dict, "AudioTrackGainSlider"))); + } + if (hb_dict_get(encoder_dict, "AudioTrackDRCSlider") != NULL) + { + hb_dict_set(audio_dict, "DRC", hb_value_dup( + hb_dict_get(encoder_dict, "AudioTrackDRCSlider"))); + } + if (hb_dict_get(encoder_dict, "AudioMixdown") != NULL) + { + hb_dict_set(audio_dict, "Mixdown", hb_value_dup( + hb_dict_get(encoder_dict, "AudioMixdown"))); + } + if (hb_dict_get(encoder_dict, "AudioNormalizeMixLevel") != NULL) + { + hb_dict_set(audio_dict, "NormalizeMixLevel", hb_value_dup( + hb_dict_get(encoder_dict, "AudioNormalizeMixLevel"))); + } + if (hb_dict_get(encoder_dict, "AudioDitherMethod") != NULL) + { + hb_dict_set(audio_dict, "DitherMethod", hb_value_dup( + hb_dict_get(encoder_dict, "AudioDitherMethod"))); + } + if (hb_dict_get(encoder_dict, "AudioSamplerate") != NULL) + { + hb_dict_set(audio_dict, "Samplerate", hb_value_dup( + hb_dict_get(encoder_dict, "AudioSamplerate"))); + } + if (hb_dict_get(encoder_dict, "AudioCompressionLevel") != NULL) + { + hb_dict_set(audio_dict, "CompressionLevel", hb_value_dup( + hb_dict_get(encoder_dict, "AudioCompressionLevel"))); + } + if (hb_value_get_bool(hb_dict_get(encoder_dict, + "AudioTrackQualityEnable"))) + { + hb_dict_set(audio_dict, "Quality", hb_value_xform( + hb_dict_get(encoder_dict, "AudioTrackQuality"), + HB_VALUE_TYPE_DOUBLE)); + } + else + { + hb_dict_set(audio_dict, "Bitrate", hb_value_xform( + hb_dict_get(encoder_dict, "AudioBitrate"), + HB_VALUE_TYPE_INT)); + } + } + hb_value_array_append(list, audio_dict); + } + if (behavior == 2) + track = find_audio_track(title, lang, track + 1); + else + break; + } +} + +// This function assumes that Mux has already been initialized in +// the job_dict +int hb_preset_job_add_audio(hb_handle_t *h, int title_index, + hb_dict_t *preset, hb_dict_t *job_dict) +{ + hb_title_t *title = hb_find_title_by_index(h, title_index); + if (title == NULL) + { + // Can't create audio track list without knowing source audio tracks + hb_error("Invalid title index (%d)", title_index); + return -1; + } + if (hb_list_count(title->list_audio) <= 0) + { + // Source has no audio + return 0; + } + + int mux = get_job_mux(job_dict); + if (mux == HB_MUX_INVALID) + { + return -1; + } + + hb_dict_t *audio_dict = hb_dict_get(job_dict, "Audio"); + int copy_mask = get_audio_copy_mask(preset); + if (copy_mask == HB_ACODEC_INVALID) + { + return -1; + } + int fallback = 0; + hb_dict_set(audio_dict, "CopyMask", hb_value_int(copy_mask)); + hb_value_t *fallback_value = hb_dict_get(preset, "AudioEncoderFallback"); + if (fallback_value != NULL) + { + hb_dict_set(audio_dict, "FallbackEncoder", + hb_value_dup(fallback_value)); + if (hb_value_type(fallback_value) == HB_VALUE_TYPE_STRING) + { + const char * s = hb_value_get_string(fallback_value); + fallback = hb_audio_encoder_get_from_name(s); + if (fallback == 0) + { + hb_error("Invalid fallback audio codec (%s)", s); + return -1; + } + } + else + { + fallback = hb_value_get_int(fallback_value); + } + } + if (validate_audio_encoders(preset) < 0) + return -1; + + hb_value_array_t *list = hb_dict_get(audio_dict, "AudioList"); + if (list == NULL) + { + list = hb_value_array_init(); + hb_dict_set(audio_dict, "AudioList", list); + } + + int behavior = 1; // default first + const char *s; + s = hb_value_get_string(hb_dict_get(preset, "AudioTrackSelectionBehavior")); + if (s != NULL) + { + if (!strcasecmp(s, "none")) + return 0; + else if (!strcasecmp(s, "all")) + behavior = 2; + } + + // Create hash that is used to track which tracks have been already added + // We do not want to add the same track with the same settings twice + hb_dict_t *track_dict = hb_dict_init(); + + // Add tracks for all languages in the language list + int mode; + hb_value_array_t *lang_list = hb_dict_get(preset, "AudioLanguageList"); + mode = hb_value_get_bool(hb_dict_get(preset, "AudioSecondaryEncoderMode")); + int count = hb_value_array_len(lang_list); + int ii; + for (ii = 0; ii < count; ii++) + { + const char *lang; + lang = hb_value_get_string(hb_value_array_get(lang_list, ii)); + add_audio_for_lang(list, preset, title, mux, copy_mask, fallback, + lang, behavior, mode, track_dict); + } + // If no audios found, try "und" language option + if (hb_value_array_len(list) <= 0) + { + add_audio_for_lang(list, preset, title, mux, copy_mask, fallback, + "und", behavior, mode, track_dict); + } + hb_dict_free(&track_dict); + return 0; +} + +// Find a source audio track matching given language +static int find_subtitle_track(const hb_title_t *title, + const char *lang, int start) +{ + hb_subtitle_t * subtitle; + int ii, count; + + count = hb_list_count(title->list_subtitle); + for (ii = start; ii < count; ii++) + { + subtitle = hb_list_item(title->list_subtitle, ii); + if (!strcmp(lang, subtitle->iso639_2) || !strcmp(lang, "und")) + { + return ii; + } + } + return -1; +} + +static void add_subtitle(hb_value_array_t *list, int track, + int make_default, int force, int burn) +{ + hb_dict_t *subtitle_dict = hb_dict_init(); + hb_dict_set(subtitle_dict, "Track", hb_value_int(track)); + hb_dict_set(subtitle_dict, "Default", hb_value_bool(make_default)); + hb_dict_set(subtitle_dict, "Forced", hb_value_bool(force)); + hb_dict_set(subtitle_dict, "Burn", hb_value_bool(burn)); + hb_value_array_append(list, subtitle_dict); +} + +typedef struct subtitle_behavior_s +{ + int one; + int burn_foreign; + int make_default; + int burn_first; + int burn_dvd; + int burn_bd; + int one_burned; + uint8_t *used; +} subtitle_behavior_t; + +static void add_subtitle_for_lang(hb_value_array_t *list, hb_title_t *title, + int mux, const char *lang, + subtitle_behavior_t *behavior) +{ + int t; + t = find_subtitle_track(title, lang, 0); + for (t = find_subtitle_track(title, lang, 0); + t >= 0; + t = behavior->one ? -1 : find_subtitle_track(title, lang, t + 1)) + { + if (behavior->used[t]) + { + if (behavior->one) + break; + continue; + } + int burn, make_default; + hb_subtitle_t *subtitle; + subtitle = hb_list_item(title->list_subtitle, t); + burn = !behavior->one_burned && + ((subtitle->source == VOBSUB && behavior->burn_dvd) || + (subtitle->source == PGSSUB && behavior->burn_bd) || + !hb_subtitle_can_pass(subtitle->source, mux) || + behavior->burn_first || behavior->burn_foreign); + make_default = !burn && behavior->make_default; + behavior->burn_first &= !burn; + behavior->one_burned |= burn; + behavior->used[t] = 1; + add_subtitle(list, t, make_default, 0 /*!force*/, burn); + } +} + +// This function assumes that the AudioList and Mux have already been +// initialized in the job_dict +int hb_preset_job_add_subtitles(hb_handle_t *h, int title_index, + hb_dict_t *preset, hb_dict_t *job_dict) +{ + hb_title_t *title = hb_find_title_by_index(h, title_index); + if (title == NULL) + { + // Can't create subtitle track list without knowing source + hb_error("Invalid title index (%d)", title_index); + return -1; + } + + int mux = get_job_mux(job_dict); + if (mux == HB_MUX_INVALID) + { + return -1; + } + + // Get the language of the first audio output track + // Needed for subtitle track selection + hb_dict_t *audio_dict = hb_dict_get(job_dict, "Audio"); + hb_value_array_t *audio_list = hb_dict_get(audio_dict, "AudioList"); + const char *first_audio_lang = NULL; + if (hb_value_array_len(audio_list) > 0) + { + int track; + hb_value_t *audio = hb_value_array_get(audio_list, 0); + track = hb_value_get_int(hb_dict_get(audio, "Track")); + if (hb_list_count(title->list_audio) > track) + { + hb_audio_config_t *aconfig; + aconfig = hb_list_audio_config_item(title->list_audio, track); + if (aconfig != NULL) + first_audio_lang = aconfig->lang.iso639_2; + } + } + + int source_subtitle_count = hb_list_count(title->list_subtitle); + if (source_subtitle_count == 0) + return 0; + + hb_dict_t *subtitle_dict = hb_dict_get(job_dict, "Subtitle"); + hb_value_array_t *list = hb_dict_get(subtitle_dict, "SubtitleList"); + if (list == NULL) + { + list = hb_value_array_init(); + hb_dict_set(subtitle_dict, "SubtitleList", list); + } + + int track_behavior = 0; // default no subtitles + int burn_behavior = 0; + int burn_foreign; + + struct subtitle_behavior_s behavior; + behavior.one = 0; + behavior.burn_foreign = 0; + behavior.make_default = 0; + behavior.burn_first = 0; + behavior.burn_dvd = 0; + behavior.burn_bd = 0; + behavior.one_burned = 0; + // Create array that is used to track which tracks have been already added + // We do not want to add the same track with the same settings twice + behavior.used = calloc(source_subtitle_count, sizeof(*behavior.used)); + + const char *s; + s = hb_value_get_string(hb_dict_get(preset, + "SubtitleTrackSelectionBehavior")); + if (s != NULL) + { + if (!strcasecmp(s, "first")) + track_behavior = 1; + else if (!strcasecmp(s, "all")) + track_behavior = 2; + } + + s = hb_value_get_string(hb_dict_get(preset, "SubtitleBurnBehavior")); + if (s != NULL) + { + if (!strcasecmp(s, "foreign")) + burn_behavior = 1; + else if (!strcasecmp(s, "first")) + burn_behavior = 2; + else if (!strcasecmp(s, "foreign_first")) + burn_behavior = 3; + } + + behavior.burn_dvd = hb_value_get_int(hb_dict_get(preset, + "SubtitleBurnDVDSub")); + behavior.burn_bd = hb_value_get_int(hb_dict_get(preset, + "SubtitleBurnBDSub")); + + burn_foreign = burn_behavior == 1 || burn_behavior == 3; + behavior.burn_first = burn_behavior == 2 || burn_behavior == 3; + + int foreign_audio_search, foreign_first_audio; + foreign_audio_search = hb_value_get_bool(hb_dict_get(preset, + "SubtitleAddForeignAudioSearch")); + foreign_first_audio = hb_value_get_bool(hb_dict_get(preset, + "SubtitleAddForeignAudioSubtitle")); + + + // Add tracks for all languages in the language list + hb_value_array_t *lang_list = hb_dict_get(preset, "SubtitleLanguageList"); + int count = hb_value_array_len(lang_list); + const char *pref_lang = "und"; + if (count > 0) + { + pref_lang = hb_value_get_string(hb_value_array_get(lang_list, 0)); + } + if (!strcmp(pref_lang, "und")) + { + foreign_audio_search = foreign_first_audio = 0; + } + + int track; + if (first_audio_lang != NULL && + foreign_first_audio && strncmp(first_audio_lang, pref_lang, 4)) + { + // First audio lang does not match the preferred subittle lang. + // Preset says to add pref lang subtitle. + // Foreign audio search is not necessary since entire audio track + // is foreign. + foreign_audio_search = 0; + behavior.one = 1; + behavior.burn_foreign = burn_foreign; + behavior.make_default = 1; + add_subtitle_for_lang(list, title, mux, pref_lang, &behavior); + } + + hb_dict_t *search_dict = hb_dict_get(subtitle_dict, "Search"); + if (search_dict == NULL) + { + search_dict = hb_dict_init(); + hb_dict_set(subtitle_dict, "Search", search_dict); + } + if (first_audio_lang != NULL && + foreign_audio_search && !strncmp(first_audio_lang, pref_lang, 4)) + { + // First audio lang matches the preferred subittle lang. + // Preset says to add search for foreign audio subtitles. + int burn = burn_foreign || behavior.burn_first; + // If not burning, make this the default track. + hb_dict_set(search_dict, "Enable", hb_value_bool(1)); + hb_dict_set(search_dict, "Default", hb_value_bool(!burn)); + hb_dict_set(search_dict, "Forced", hb_value_bool(1)); + hb_dict_set(search_dict, "Burn", hb_value_bool(burn)); + } + else + { + hb_dict_set(search_dict, "Enable", hb_value_bool(0)); + } + + if (track_behavior > 0) + { + int ii; + behavior.one = track_behavior == 1; + behavior.burn_foreign = 0; + behavior.make_default = 0; + for (ii = 0; ii < count; ii++) + { + const char *lang; + lang = hb_value_get_string(hb_value_array_get(lang_list, ii)); + add_subtitle_for_lang(list, title, mux, lang, &behavior); + } + if (count <= 0) + { + add_subtitle_for_lang(list, title, mux, "und", &behavior); + } + } + + if (hb_value_get_bool(hb_dict_get(preset, "SubtitleAddCC"))) + { + // Add Closed Caption track + for (track = 0; track < source_subtitle_count; track++) + { + if (behavior.used[track]) + { + continue; + } + hb_subtitle_t *subtitle = hb_list_item(title->list_subtitle, track); + if (subtitle->source == CC608SUB || subtitle->source == CC708SUB) + { + int burn; + burn = !behavior.one_burned && + (!hb_subtitle_can_pass(subtitle->source, mux) || + behavior.burn_first); + behavior.used[track] = 1; + behavior.one_burned |= burn; + add_subtitle(list, track, 0 /*default*/, 0 /*!force*/, burn); + break; + } + } + } + free(behavior.used); + + return 0; +} + +static int get_video_framerate(hb_value_t *rate_value) +{ + int rate = 0; + if (hb_value_type(rate_value) != HB_VALUE_TYPE_STRING) + { + double d; + d = hb_value_get_double(rate_value); + if (d != 0 && d <= 600) + { + // Assume the value is an actual framerate and compute + // 27Mhz based denominator + rate = (int)(27000000 / d); + } + else + { + // Assume the value is a 27Mhz based denominator + rate = (int)d; + } + } + else + { + const char *rate_name = hb_value_get_string(rate_value); + if (strcasecmp(rate_name, "source") && + strcasecmp(rate_name, "auto") && + strcasecmp(rate_name, "same as source")) + { + rate = hb_video_framerate_get_from_name(rate_name); + if (rate < 0) + { + // No matching rate found. Error out. + rate = -1; + } + } + } + return rate; +} + +/** + * Initialize an hb_job_t and return a hb_dict_t representation of the job. + * This dict will have key/value pairs compatible with json jobs. + * @param h - Pointer to hb_handle_t instance that contains the + * specified title_index + * @param title_index - Index of hb_title_t to use for job initialization. + * Index comes from title->index or "Index" key + * in json representation of a title. + * @param preset - Preset to initialize job with + */ +hb_dict_t* hb_preset_job_init(hb_handle_t *h, int title_index, hb_dict_t *preset) +{ + hb_title_t *title = hb_find_title_by_index(h, title_index); + if (title == NULL) + { + hb_error("Invalid title index (%d)", title_index); + return NULL; + } + + hb_job_t *job = hb_job_init(title); + hb_dict_t *job_dict = hb_job_to_dict(job); + hb_job_close(&job); + + // Now apply preset settings to the job dict + + hb_value_t *mux_value = hb_dict_get(preset, "FileFormat"); + int mux; + if (hb_value_type(mux_value) == HB_VALUE_TYPE_STRING) + { + mux = hb_container_get_from_name(hb_value_get_string(mux_value)); + if (mux == 0) + mux = hb_container_get_from_extension( + hb_value_get_string(mux_value)); + } + else + { + mux = hb_value_get_int(mux_value); + } + hb_container_t *container = hb_container_get_from_format(mux); + if (container == NULL) + { + char *str = hb_value_get_string_xform(mux_value); + hb_error("Invalid container (%s)", str); + free(str); + goto fail; + } + + hb_value_t *vcodec_value = hb_dict_get(preset, "VideoEncoder"); + int vcodec; + if (hb_value_type(vcodec_value) == HB_VALUE_TYPE_STRING) + { + vcodec = hb_video_encoder_get_from_name( + hb_value_get_string(vcodec_value)); + } + else + { + vcodec = hb_value_get_int(vcodec_value); + } + hb_encoder_t *encoder = hb_video_encoder_get_from_codec(vcodec); + if (encoder == NULL) + { + char *str = hb_value_get_string_xform(vcodec_value); + hb_error("Invalid video encoder (%s)", str); + free(str); + goto fail; + } + if (!(encoder->muxers & mux)) + { + hb_error("Incompatible video encoder (%s) for muxer (%s)", + hb_video_encoder_get_name(vcodec), + hb_container_get_name(mux)); + goto fail; + } + + int chapters; + chapters = hb_value_get_bool(hb_dict_get(preset, "ChapterMarkers")); + if (hb_list_count(title->list_chapter) <= 1) + chapters = 0; + + // Set "Destination" settings in job + hb_dict_t *dest_dict = hb_dict_get(job_dict, "Destination"); + hb_dict_set(dest_dict, "ChapterMarkers", hb_value_bool(chapters)); + hb_dict_set(dest_dict, "Mux", hb_value_dup(mux_value)); + if (mux == HB_MUX_MASK_MP4) + { + hb_dict_t *mp4_dict = hb_dict_init(); + hb_dict_set(mp4_dict, "Mp4Optimize", + hb_value_xform(hb_dict_get(preset, "Mp4HttpOptimize"), + HB_VALUE_TYPE_BOOL)); + if (vcodec == HB_VCODEC_X264) + { + hb_dict_set(mp4_dict, "IpodAtom", + hb_value_xform(hb_dict_get(preset, "Mp4iPodCompatible"), + HB_VALUE_TYPE_BOOL)); + } + hb_dict_set(dest_dict, "Mp4Options", mp4_dict); + } + dest_dict = NULL; + + // Calculate default job geometry settings + hb_geometry_t srcGeo, resultGeo; + hb_geometry_settings_t geo; + int keep_aspect; + + srcGeo = title->geometry; + if (!hb_value_get_bool(hb_dict_get(preset, "PictureAutoCrop"))) + { + geo.crop[0] = hb_value_get_int(hb_dict_get(preset, "PictureTopCrop")); + geo.crop[1] = hb_value_get_int(hb_dict_get(preset, "PictureBottomCrop")); + geo.crop[2] = hb_value_get_int(hb_dict_get(preset, "PictureLeftCrop")); + geo.crop[3] = hb_value_get_int(hb_dict_get(preset, "PictureRightCrop")); + } + else + { + memcpy(geo.crop, title->crop, sizeof(geo.crop)); + } + geo.modulus = hb_value_get_int(hb_dict_get(preset, "PictureModulus")); + if (geo.modulus < 2) + geo.modulus = 2; + if (hb_value_get_bool(hb_dict_get(preset, "PictureLooseCrop"))) + { + // Crop a few extra pixels to avoid scaling to fit Modulus + int extra1, extra2, crop_width, crop_height, width, height; + + crop_width = srcGeo.width - geo.crop[2] - geo.crop[3]; + crop_height = srcGeo.height - geo.crop[0] - geo.crop[1]; + width = MULTIPLE_MOD_DOWN(crop_width, geo.modulus); + height = MULTIPLE_MOD_DOWN(crop_height, geo.modulus); + + extra1 = EVEN((crop_height - height) / 2); + extra2 = crop_height - height - extra1; + geo.crop[0] += extra1; + geo.crop[1] += extra2; + extra1 = EVEN((crop_width - width) / 2); + extra2 = crop_width - width - extra1; + geo.crop[2] += extra1; + geo.crop[3] += extra2; + } + hb_value_t *ana_mode_value = hb_dict_get(preset, "PicturePAR"); + if (hb_value_type(ana_mode_value) == HB_VALUE_TYPE_STRING) + { + const char *s = hb_value_get_string(ana_mode_value); + if (!strcasecmp(s, "none")) + geo.mode = 0; + else if (!strcasecmp(s, "strict")) + geo.mode = 1; + else if (!strcasecmp(s, "custom")) + geo.mode = 3; + else // default loose + geo.mode = 2; + } + else + { + geo.mode = hb_value_get_int(hb_dict_get(preset, "PicturePAR")); + } + keep_aspect = hb_value_get_bool(hb_dict_get(preset, "PictureKeepRatio")); + if (geo.mode == HB_ANAMORPHIC_STRICT || geo.mode == HB_ANAMORPHIC_LOOSE) + keep_aspect = 1; + geo.keep = keep_aspect * HB_KEEP_DISPLAY_ASPECT; + geo.itu_par = hb_value_get_bool(hb_dict_get(preset, "PictureItuPAR")); + geo.maxWidth = hb_value_get_int(hb_dict_get(preset, "PictureWidth")); + geo.maxHeight = hb_value_get_int(hb_dict_get(preset, "PictureHeight")); + geo.geometry = title->geometry; + int width = hb_value_get_int(hb_dict_get(preset, "PictureForceWidth")); + int height = hb_value_get_int(hb_dict_get(preset, "PictureForceHeight")); + if (width > 0) + geo.geometry.width = width; + else + geo.geometry.width -= geo.crop[2] + geo.crop[3]; + if (height > 0) + geo.geometry.height = height; + else + geo.geometry.height -= geo.crop[0] + geo.crop[1]; + if (geo.mode == HB_ANAMORPHIC_CUSTOM && !keep_aspect) + { + int dar_width; + dar_width = hb_value_get_int(hb_dict_get(preset, "PictureDARWidth")); + if (dar_width > 0) + { + geo.geometry.par.num = dar_width; + geo.geometry.par.num = geo.geometry.width; + } + else + { + geo.geometry.par.num = + hb_value_get_int(hb_dict_get(preset, "PicturePARWidth")); + geo.geometry.par.num = + hb_value_get_int(hb_dict_get(preset, "PicturePARHeight")); + } + } + hb_set_anamorphic_size2(&srcGeo, &geo, &resultGeo); + hb_dict_t *par_dict = hb_dict_get(job_dict, "PAR"); + hb_dict_set(par_dict, "Num", hb_value_int(resultGeo.par.num)); + hb_dict_set(par_dict, "Den", hb_value_int(resultGeo.par.den)); + par_dict = NULL; + + // Filters + hb_dict_t *filters_dict = hb_dict_get(job_dict, "Filters"); + if (filters_dict == NULL) + { + filters_dict = hb_dict_init(); + hb_dict_set(job_dict, "Filters", filters_dict); + } + hb_dict_set(filters_dict, "Grayscale", hb_value_xform( + hb_dict_get(preset, "VideoGrayScale"), HB_VALUE_TYPE_BOOL)); + hb_value_array_t *filter_list = hb_dict_get(filters_dict, "FilterList"); + if (filter_list == NULL) + { + filter_list = hb_value_array_init(); + hb_dict_set(filters_dict, "FilterList", filter_list); + } + + hb_dict_t *filter_dict; + char *filter_str; + + // Setup scale filter + filter_str = hb_strdup_printf("%d:%d:%d:%d:%d:%d", + resultGeo.width, resultGeo.height, + geo.crop[0], geo.crop[1], + geo.crop[2], geo.crop[3]); + + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_CROP_SCALE)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + free(filter_str); + hb_value_array_append(filter_list, filter_dict); + + // Detelecine filter + hb_value_t *detel_val = hb_dict_get(preset, "PictureDetelecine"); + if (detel_val != NULL) + { + const char *custom; + custom = hb_value_get_string(hb_dict_get(preset, + "PictureDetelecineCustom")); + if (hb_value_type(detel_val) == HB_VALUE_TYPE_STRING) + { + filter_str = hb_generate_filter_settings( + HB_FILTER_DETELECINE, hb_value_get_string(detel_val), custom); + } + else + { + filter_str = hb_generate_filter_settings_by_index( + HB_FILTER_DETELECINE, hb_value_get_int(detel_val), custom); + } + if (filter_str == NULL) + { + char *s = hb_value_get_string_xform(detel_val); + hb_error("Invalid detelecine filter settings (%s)", s); + free(s); + goto fail; + } + else if (filter_str != hb_filter_off) + { + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DETELECINE)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + } + } + + // Decomb or deinterlace filters + int decomb_or_deint; + decomb_or_deint = hb_value_get_bool(hb_dict_get(preset, + "PictureDecombDeinterlace")); + hb_value_t *decomb_val = hb_dict_get(preset, "PictureDecomb"); + if (decomb_or_deint && decomb_val != NULL) + { + const char *custom; + custom = hb_value_get_string(hb_dict_get(preset, + "PictureDecombCustom")); + if (hb_value_type(decomb_val) == HB_VALUE_TYPE_STRING) + { + filter_str = hb_generate_filter_settings( + HB_FILTER_DECOMB, hb_value_get_string(decomb_val), custom); + } + else + { + filter_str = hb_generate_filter_settings_by_index( + HB_FILTER_DECOMB, hb_value_get_int(decomb_val), custom); + } + if (filter_str == NULL) + { + char *s = hb_value_get_string_xform(decomb_val); + hb_error("Invalid decomb filter settings (%s)", s); + free(s); + goto fail; + } + else if (filter_str != hb_filter_off) + { + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DECOMB)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + } + } + + hb_value_t *deint_val = hb_dict_get(preset, "PictureDeinterlace"); + if (!decomb_or_deint && deint_val != NULL) + { + const char *custom; + custom = hb_value_get_string(hb_dict_get(preset, + "PictureDeinterlaceCustom")); + if (hb_value_type(deint_val) == HB_VALUE_TYPE_STRING) + { + filter_str = hb_generate_filter_settings( + HB_FILTER_DEINTERLACE, hb_value_get_string(deint_val), custom); + } + else + { + filter_str = hb_generate_filter_settings_by_index( + HB_FILTER_DEINTERLACE, hb_value_get_int(deint_val), custom); + } + if (filter_str == NULL) + { + char *s = hb_value_get_string_xform(deint_val); + hb_error("Invalid deinterlace filter settings (%s)", s); + free(s); + goto fail; + } + else if (filter_str != hb_filter_off) + { + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DECOMB)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + } + } + + // Denoise filter + int denoise; + hb_value_t *denoise_value = hb_dict_get(preset, "PictureDenoiseFilter"); + denoise = hb_value_type(denoise_value) == HB_VALUE_TYPE_STRING ? ( + !strcasecmp(hb_value_get_string(denoise_value), "off") ? 0 : + !strcasecmp(hb_value_get_string(denoise_value), "nlmeans") ? 1 : 2) : + hb_value_get_int(denoise_value); + + if (denoise != 0) + { + int filter_id = denoise == 1 ? HB_FILTER_NLMEANS : HB_FILTER_HQDN3D; + const char *denoise_preset, *denoise_tune; + denoise_preset = hb_value_get_string( + hb_dict_get(preset, "PictureDenoisePreset")); + if (denoise_preset != NULL) + { + if (strcasecmp(denoise_preset, "custom")) + denoise_tune = hb_value_get_string( + hb_dict_get(preset, "PictureDenoiseTune")); + else + denoise_tune = hb_value_get_string( + hb_dict_get(preset, "PictureDeinterlaceCustom")); + + filter_str = hb_generate_filter_settings( + filter_id, denoise_preset, denoise_tune); + if (filter_str == NULL) + { + hb_error("Invalid denoise filter settings (%s%s%s)", + denoise_preset, + denoise_tune ? "," : "", + denoise_tune ? denoise_tune : ""); + goto fail; + } + else if (filter_str != hb_filter_off) + { + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(filter_id)); + hb_dict_set(filter_dict, "Settings", + hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + } + } + } + + // Deblock filter + char *deblock = hb_value_get_string_xform( + hb_dict_get(preset, "PictureDeblock")); + if (deblock != NULL) + { + filter_str = hb_generate_filter_settings(HB_FILTER_DEBLOCK, + deblock, NULL); + if (filter_str == NULL) + { + hb_error("Invalid deblock filter settings (%s)", deblock); + goto fail; + } + else if (filter_str != hb_filter_off) + { + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_DEBLOCK)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + } + } + free(deblock); + + // Rotate filter + char *rotate = hb_value_get_string_xform( + hb_dict_get(preset, "PictureRotate")); + if (rotate != NULL) + { + filter_str = hb_generate_filter_settings(HB_FILTER_ROTATE, + rotate, NULL); + if (filter_str == NULL) + { + hb_error("Invalid rotate filter settings (%s)", rotate); + goto fail; + } + else if (filter_str != hb_filter_off) + { + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_ROTATE)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + } + } + free(rotate); + + hb_value_t *fr_value = hb_dict_get(preset, "VideoFramerate"); + int vrate_den = get_video_framerate(fr_value); + if (vrate_den < 0) + { + char *str = hb_value_get_string_xform(fr_value); + hb_error("Invalid video framerate (%s)", str); + free(str); + goto fail; + } + + int fr_mode; + hb_value_t *fr_mode_value = hb_dict_get(preset, "VideoFramerateMode"); + fr_mode = hb_value_type(fr_mode_value) == HB_VALUE_TYPE_STRING ? ( + !strcasecmp(hb_value_get_string(fr_mode_value), "cfr") ? 1 : + !strcasecmp(hb_value_get_string(fr_mode_value), "pfr") ? 2 : 0) : + hb_value_get_int(fr_mode_value); + + if (hb_value_get_bool(hb_dict_get(preset, "x264ZeroLatency"))) + fr_mode = 1; + + if (vrate_den == 0) + filter_str = hb_strdup_printf("%d", fr_mode); + else + filter_str = hb_strdup_printf("%d:%d:%d", fr_mode, 27000000, vrate_den); + + filter_dict = hb_dict_init(); + hb_dict_set(filter_dict, "ID", hb_value_int(HB_FILTER_VFR)); + hb_dict_set(filter_dict, "Settings", hb_value_string(filter_str)); + hb_value_array_append(filter_list, filter_dict); + free(filter_str); + + // Video encoder settings + hb_dict_t *video_dict = hb_dict_get(job_dict, "Video"); + hb_value_t *color_value; + if ((color_value = hb_dict_get(preset, "VideoColorMatrixCode")) != NULL) + hb_dict_set(video_dict, "ColorMatrixCode", hb_value_dup(color_value)); + hb_dict_set(video_dict, "Encoder", hb_value_dup(vcodec_value)); + switch (vcodec) + { + case HB_VCODEC_X264: + { + if (hb_value_get_bool( + hb_dict_get(preset, "x264UseAdvancedOptions"))) + { + hb_dict_set(video_dict, "Options", + hb_value_dup(hb_dict_get(preset, "x264Option"))); + break; + } + } + // Falling through to next case... + + case HB_VCODEC_X265: + { + hb_value_t *value, *array; + if ((value = hb_dict_get(preset, "VideoPreset")) != NULL) + hb_dict_set(video_dict, "Preset", hb_value_dup(value)); + if ((value = hb_dict_get(preset, "VideoProfile")) != NULL) + hb_dict_set(video_dict, "Profile", hb_value_dup(value)); + if ((value = hb_dict_get(preset, "VideoLevel")) != NULL) + hb_dict_set(video_dict, "Level", hb_value_dup(value)); + if ((value = hb_dict_get(preset, "VideoOptionExtra")) != NULL) + hb_dict_set(video_dict, "Options", hb_value_dup(value)); + array = hb_value_array_init(); + if ((value = hb_dict_get(preset, "VideoTune")) != NULL) + hb_value_array_append(array, hb_value_dup(value)); + if (vcodec == HB_VCODEC_X264) + { + if (hb_value_get_bool(hb_dict_get(preset, "x264FastDecode"))) + hb_value_array_append(array, hb_value_string("fastdecode")); + if (hb_value_get_bool(hb_dict_get(preset, "x264ZeroLatency"))) + hb_value_array_append(array, hb_value_string("zerolatency")); + } + if (hb_value_array_len(array) > 0) + hb_dict_set(video_dict, "Tune", + hb_value_xform(array, HB_VALUE_TYPE_STRING)); + hb_value_decref(array); + } break; + + case HB_VCODEC_FFMPEG_MPEG2: + case HB_VCODEC_FFMPEG_MPEG4: + case HB_VCODEC_FFMPEG_VP8: + { + hb_value_t *value; + if ((value = hb_dict_get(preset, "VideoOptionExtra")) != NULL) + hb_dict_set(video_dict, "Options", hb_value_dup(value)); + } break; + + case HB_VCODEC_THEORA: + default: + { + } break; + } + int vqtype = hb_value_get_int(hb_dict_get(preset, "VideoQualityType")); + if (vqtype == 2) // Constant quality + { + hb_dict_set(video_dict, "Quality", + hb_value_xform(hb_dict_get(preset, "VideoQualitySlider"), + HB_VALUE_TYPE_DOUBLE)); + } + else if (vqtype == 1) // ABR + { + hb_dict_set(video_dict, "Bitrate", + hb_value_xform(hb_dict_get(preset, "VideoAvgBitrate"), + HB_VALUE_TYPE_INT)); + hb_dict_set(video_dict, "TwoPass", + hb_value_xform(hb_dict_get(preset, "VideoTwoPass"), + HB_VALUE_TYPE_BOOL)); + hb_dict_set(video_dict, "Turbo", + hb_value_xform(hb_dict_get(preset, "VideoTurboTwoPass"), + HB_VALUE_TYPE_BOOL)); + } + else + { + hb_value_t *value = hb_dict_get(preset, "VideoQualitySlider"); + if (value != NULL && hb_value_get_double(value) >= 0) + hb_dict_set(video_dict, "Quality", + hb_value_xform(value, HB_VALUE_TYPE_DOUBLE)); + else + { + hb_dict_set(video_dict, "Bitrate", + hb_value_xform(hb_dict_get(preset, "VideoAvgBitrate"), + HB_VALUE_TYPE_INT)); + hb_dict_set(video_dict, "TwoPass", + hb_value_xform(hb_dict_get(preset, "VideoTwoPass"), + HB_VALUE_TYPE_BOOL)); + hb_dict_set(video_dict, "Turbo", + hb_value_xform(hb_dict_get(preset, "VideoTurboTwoPass"), + HB_VALUE_TYPE_BOOL)); + } + } + hb_dict_t *qsv = hb_dict_get(video_dict, "QSV"); + if (qsv == NULL) + { + qsv = hb_dict_init(); + hb_dict_set(video_dict, "QSV", qsv); + } + hb_value_t *value; + if ((value = hb_dict_get(preset, "VideoQSVDecode")) != NULL) + { + hb_dict_set(qsv, "Decode", + hb_value_xform(value, HB_VALUE_TYPE_BOOL)); + } + if ((value = hb_dict_get(preset, "VideoQSVAsyncDepth")) != NULL) + { + hb_dict_set(qsv, "AsyncDepth", + hb_value_xform(value, HB_VALUE_TYPE_INT)); + } + + if ((value = hb_dict_get(preset, "VideoScaler")) != NULL) + { + const char *s = hb_value_get_string(value); + if (strcasecmp(s, "opencl")) + { + hb_dict_set(video_dict, "OpenCL", hb_value_bool(1)); + } + } + if ((value = hb_dict_get(preset, "VideoHWDecode")) != NULL) + { + hb_dict_set(video_dict, "HWDecode", + hb_value_xform(value, HB_VALUE_TYPE_BOOL)); + } + video_dict = NULL; + + // Audio settings + if (hb_preset_job_add_audio(h, title_index, preset, job_dict) != 0) + { + goto fail; + } + + // Subtitle settings + if (hb_preset_job_add_subtitles(h, title_index, preset, job_dict) != 0) + { + goto fail; + } + + return job_dict; + +fail: + hb_dict_free(&job_dict); + return NULL; +} + +// Clean a dictionary of unwanted keys +// Used to make sure only valid keys are in output presets +static void +dict_clean(hb_value_t *dict, hb_value_t *template) +{ + hb_value_t *tmp = hb_value_dup(dict); + hb_dict_iter_t iter; + const char *key; + hb_value_t *val; + hb_value_t *template_val; + hb_value_type_t template_type, val_type; + const char *preset_name = NULL; + + val = hb_dict_get(dict, "PresetName"); + if (val != NULL) + preset_name = hb_value_get_string(val); + + for (iter = hb_dict_iter_init(tmp); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(tmp, iter)) + { + key = hb_dict_iter_key(iter); + val = hb_dict_iter_value(iter); + val_type = hb_value_type(val); + + template_val = hb_dict_get(template, key); + template_type = hb_value_type(template_val); + if (template_val == NULL) + { + // Unknown key. These can be keys used privately by the + // frontend. So don't make noise about them. + hb_dict_remove(dict, key); + } + else if (val_type != template_type) + { + if (val_type == HB_VALUE_TYPE_DICT || + val_type == HB_VALUE_TYPE_ARRAY || + template_type == HB_VALUE_TYPE_DICT || + template_type == HB_VALUE_TYPE_ARRAY) + { + hb_error("Preset %s: Incompatible value types for key %s. " + "Dropping.", preset_name, key); + hb_dict_remove(dict, key); + } + else if (hb_value_is_number(val) && + hb_value_is_number(template_val)) + { + // Silently convert compatible numbers + hb_value_t *v; + v = hb_value_xform(val, template_type); + hb_dict_set(dict, key, v); + } + else + { + hb_value_t *v; + hb_error("Preset %s: Incorrect value type for key %s. " + "Converting.", preset_name, key); + v = hb_value_xform(val, template_type); + hb_dict_set(dict, key, v); + } + } + else if (val_type == HB_VALUE_TYPE_DICT && + template_type == HB_VALUE_TYPE_DICT) + { + val = hb_dict_get(dict, key); + dict_clean(val, template_val); + } + else if (val_type == HB_VALUE_TYPE_ARRAY && + template_type == HB_VALUE_TYPE_ARRAY && + hb_value_array_len(template_val) > 0) + { + template_val = hb_value_array_get(template_val, 0); + if (hb_value_type(template_val) == HB_VALUE_TYPE_DICT) + { + val = hb_dict_get(dict, key); + int count = hb_value_array_len(val); + int ii; + for (ii = 0; ii < count; ii++) + { + hb_value_t *array_val; + array_val = hb_value_array_get(val, ii); + if (hb_value_type(array_val) == HB_VALUE_TYPE_DICT) + { + dict_clean(array_val, template_val); + } + } + } + } + } + hb_value_free(&tmp); +} + +static void preset_clean(hb_value_t *preset, hb_value_t *template) +{ + dict_clean(preset, template); + + // Check for proper "short name" values. + // Convert as necessary. + hb_value_t *val; + const char *preset_name = NULL; + int muxer; + + val = hb_dict_get(preset, "PresetName"); + if (val != NULL) + preset_name = hb_value_get_string(val); + + val = hb_dict_get(preset, "FileFormat"); + if (val != NULL) + { + const char *s, *mux; + s = hb_value_get_string(val); + muxer = hb_container_get_from_name(s); + if (muxer == HB_MUX_INVALID) + { + const hb_container_t *c = hb_container_get_next(NULL); + muxer = c->format; + hb_error("Preset %s: Invalid container (%s)", preset_name, s); + } + mux = hb_container_get_short_name(muxer); + val = hb_value_string(mux); + hb_dict_set(preset, "FileFormat", val); + } + val = hb_dict_get(preset, "VideoEncoder"); + if (val != NULL) + { + const char *s, *enc; + int vcodec; + s = hb_value_get_string(val); + vcodec = hb_video_encoder_get_from_name(s); + if (vcodec == HB_VCODEC_INVALID) + { + vcodec = hb_video_encoder_get_default(muxer); + hb_error("Preset %s: Invalid video encoder (%s)", preset_name, s); + } + enc = hb_video_encoder_get_short_name(vcodec); + val = hb_value_string(enc); + hb_dict_set(preset, "VideoEncoder", val); + } + val = hb_dict_get(preset, "VideoFramerate"); + if (val != NULL) + { + const char *s; + s = hb_value_get_string(val); + if (strcasecmp(s, "auto")) + { + int fr = hb_video_framerate_get_from_name(s); + if (fr < 0) + { + val = hb_value_string("auto"); + hb_dict_set(preset, "VideoFramerate", val); + hb_error("Preset %s: Invalid video framerate (%s)", + preset_name, s); + } + } + } + val = hb_dict_get(preset, "AudioEncoderFallback"); + if (val != NULL) + { + const char *s, *enc; + int acodec; + s = hb_value_get_string(val); + acodec = hb_audio_encoder_get_from_name(s); + if (acodec == HB_ACODEC_INVALID) + { + acodec = hb_audio_encoder_get_default(muxer); + hb_error("Preset %s: Invalid audio fallback encoder (%s)", + preset_name, s); + } + enc = hb_audio_encoder_get_short_name(acodec); + val = hb_value_string(enc); + hb_dict_set(preset, "AudioEncoderFallback", val); + } + hb_value_t *alist = hb_dict_get(preset, "AudioList"); + int count = hb_value_array_len(alist); + int ii; + for (ii = 0; ii < count; ii++) + { + hb_value_t *adict = hb_value_array_get(alist, ii); + val = hb_dict_get(adict, "AudioEncoder"); + if (val != NULL) + { + const char *s, *enc; + int acodec; + s = hb_value_get_string(val); + acodec = hb_audio_encoder_get_from_name(s); + if (acodec == HB_ACODEC_INVALID) + { + acodec = hb_audio_encoder_get_default(muxer); + hb_error("Preset %s: Invalid audio encoder (%s)", + preset_name, s); + } + enc = hb_audio_encoder_get_short_name(acodec); + val = hb_value_string(enc); + hb_dict_set(preset, "AudioEncoder", val); + } + val = hb_dict_get(adict, "AudioSamplerate"); + if (val != NULL) + { + const char *s; + s = hb_value_get_string(val); + if (strcasecmp(s, "auto")) + { + int sr = hb_video_framerate_get_from_name(s); + if (sr < 0) + { + val = hb_value_string("auto"); + hb_dict_set(preset, "AudioSamplerate", val); + hb_error("Preset %s: Invalid audio samplerate (%s)", + preset_name, s); + } + } + } + val = hb_dict_get(adict, "AudioMixdown"); + if (val != NULL) + { + const char *s, *mix; + s = hb_value_get_string(val); + int mixdown = hb_mixdown_get_from_name(s); + if (mixdown == HB_INVALID_AMIXDOWN) + { + // work.c do_job() sanitizes NONE to default mixdown + mixdown = HB_AMIXDOWN_NONE; + hb_error("Preset %s: Invalid audio mixdown (%s)", + preset_name, s); + } + mix = hb_mixdown_get_short_name(mixdown); + val = hb_value_string(mix); + hb_dict_set(adict, "AudioMixdown", val); + } + } +} + +static void presets_clean(hb_value_t *presets, hb_value_t *template) +{ + if (hb_value_type(presets) == HB_VALUE_TYPE_ARRAY) + { + // An array of presets, clean each one + int ii, count; + count = hb_value_array_len(presets); + for (ii = 0; ii < count; ii++) + { + hb_value_t *preset = hb_value_array_get(presets, ii); + preset_clean(preset, template); + } + } + else if (hb_value_type(presets) == HB_VALUE_TYPE_DICT && + hb_dict_get(presets, "VersionMajor") != NULL) + { + // A packaged preset list + hb_value_t *list = hb_dict_get(presets, "PresetList"); + presets_clean(list, template); + } + else if (hb_value_type(presets) == HB_VALUE_TYPE_DICT && + hb_dict_get(presets, "PresetName") != NULL) + { + // An individual preset + preset_clean(presets, template); + } + else + { + hb_error("Error: invalid preset format in presets_clean()"); + } +} + +// Note that unpackage does not make any copies. +// In one increases the reference count. +static hb_value_t * preset_unpackage(hb_value_t *packaged_presets) +{ + // TODO: Verify compatible version number. + // Do any desired legacy translations. + if (hb_value_type(packaged_presets) == HB_VALUE_TYPE_ARRAY) + { + // Not packaged + hb_value_incref(packaged_presets); + return packaged_presets; + } + hb_value_t *presets = hb_dict_get(packaged_presets, "PresetList"); + hb_value_incref(presets); + return presets; +} + +static hb_value_t * preset_package(hb_value_t *presets) +{ + hb_dict_t *packaged_presets; + if (hb_dict_get(presets, "VersionMajor") == NULL) + { + // Preset is not packaged + packaged_presets = hb_dict_init(); + hb_dict_set(packaged_presets, "VersionMajor", + hb_value_int(hb_preset_version_major)); + hb_dict_set(packaged_presets, "VersionMinor", + hb_value_int(hb_preset_version_minor)); + hb_dict_set(packaged_presets, "VersionMicro", + hb_value_int(hb_preset_version_micro)); + + // TODO: What else to we want in the preset containers header? + if (hb_value_type(presets) == HB_VALUE_TYPE_DICT) + { + hb_value_array_t *tmp = hb_value_array_init(); + hb_value_array_append(tmp, presets); + presets = tmp; + } + hb_dict_t *tmp = hb_value_dup(presets); + presets_clean(tmp, hb_preset_template); + hb_dict_set(packaged_presets, "PresetList", tmp); + } + else + { + // Preset is already packaged + hb_dict_t *tmp = hb_value_dup(presets); + presets_clean(tmp, hb_preset_template); + packaged_presets = tmp; + } + return packaged_presets; +} + +void hb_presets_builtin_init(void) +{ + hb_value_t * dict = hb_value_json(hb_builtin_presets_json); + hb_value_t * template = hb_dict_get(dict, "PresetTemplate"); + hb_preset_version_major = hb_value_get_int( + hb_dict_get(template, "VersionMajor")); + hb_preset_version_minor = hb_value_get_int( + hb_dict_get(template, "VersionMinor")); + hb_preset_version_micro = hb_value_get_int( + hb_dict_get(template, "VersionMicro")); + hb_preset_template = hb_value_dup(hb_dict_get(template, "Preset")); + + hb_presets_builtin = hb_value_dup(hb_dict_get(dict, "PresetBuiltin")); + hb_value_free(&dict); + + // Make a dup, never change contents of hb_presets_builtin + hb_presets = hb_value_dup(hb_presets_builtin); + hb_presets_custom = hb_value_array_init(); + +} + +int hb_presets_gui_init(void) +{ + char path[1024]; + hb_value_t * dict = NULL; + +#if defined(HB_PRESET_JSON_FILE) + hb_get_user_config_filename(path, "%s", HB_PRESET_JSON_FILE); + dict = hb_value_read_json(path); + if (dict != NULL) + { + hb_value_t *preset = preset_unpackage(dict); + // Unpackaging does some validity checks and can fail + if (preset == NULL) + return -1; + int result = hb_presets_add(preset); + hb_value_free(&preset); + hb_value_free(&dict); + return result; + } +#endif +#if defined(HB_PRESET_PLIST_FILE) + if (dict == NULL) + { + hb_get_user_config_filename(path, "%s", HB_PRESET_PLIST_FILE); + dict = hb_plist_parse_file(path); + if (dict != NULL) + { + int result = hb_presets_add(dict); + hb_value_free(&dict); + return result; + } + } +#endif + if (dict == NULL) + { + hb_error("Failed to load GUI presets file"); +#if defined(HB_PRESET_JSON_FILE) + hb_error("Attempted: %s", HB_PRESET_JSON_FILE); +#endif +#if defined(HB_PRESET_PLIST_FILE) + hb_error("Attempted: %s", HB_PRESET_PLIST_FILE); +#endif + return -1; + } + return -1; +} + +hb_value_t * hb_presets_builtin_get(void) +{ + return hb_value_dup(hb_presets_builtin); +} + +char * hb_presets_builtin_get_json(void) +{ + char *json = hb_value_get_json(hb_presets_builtin); + return json; +} + +static hb_value_t * preset_lookup(hb_value_t *list, const char *name, + int def, int folder, int recurse) +{ + int count = hb_value_array_len(list); + int ii; + for (ii = 0; ii < count; ii++) + { + int d; + const char *n; + hb_dict_t *preset_dict = hb_value_array_get(list, ii); + n = hb_value_get_string(hb_dict_get(preset_dict, "PresetName")); + d = hb_value_get_bool(hb_dict_get(preset_dict, "Default")); + if (hb_value_get_bool(hb_dict_get(preset_dict, "Folder"))) + { + if (folder && !def && n != NULL && !strncmp(name, n, 80)) + return preset_dict; + + if (recurse) + { + hb_value_array_t *children; + children = hb_dict_get(preset_dict, "ChildrenArray"); + if (children == NULL) + continue; + preset_dict = preset_lookup(children, name, def, + folder, recurse); + if (preset_dict != NULL) + return preset_dict; + } + } + else if (!folder) + { + if (!def && n != NULL && !strncmp(n, name, 80)) + { + // preset is not a folder and we found a matching preset name + return preset_dict; + } + else if (def && d) + { + return preset_dict; + } + } + } + return NULL; +} + +// Lookup a preset in the preset list. The "name" may contain '/' +// separators to explicitely specify a preset within the preset lists +// folder structure. +// +// If 'recurse' is specified, a recursive search for the first component +// in the name will be performed. +// +// I assume that the actual preset name does not include any '/' +hb_value_t * hb_preset_get(const char *name, int recurse) +{ + if (name == NULL || name[0] == 0) + { + // bad input. + return NULL; + } + + char *tmp = strdup(name); + char *part, *next; + hb_value_t *list; + + list = hb_presets; + part = tmp; + next = strchr(name, '/'); + if (next == NULL) + { + // Only preset name was specified, so do a recursive search + hb_value_t *preset = preset_lookup(list, part, 0, 0, recurse); + free(tmp); + if (preset == NULL) + { + return NULL; + } + return hb_value_dup(preset); + } + // Found folder separator in name, do explicit path search + while (part) + { + *next = 0; + next++; + if (next[0] == 0) + { + // name ends in a folder separator '/'. Invalid input + free(tmp); + return NULL; + } + + // We have a folder part. Lookup the folder. + // First try non-recursive so that we match top level folders first + hb_dict_t *folder = preset_lookup(list, part, 0, 1, 0); + if (folder == NULL && recurse) + { + // Try a recursive search for the folder + folder = preset_lookup(list, part, 0, 1, recurse); + } + if (folder == NULL) + { + // Not found + free(tmp); + return NULL; + } + list = hb_dict_get(folder, "ChildrenArray"); + if (list == NULL) + { + // Folder found, but it has no children + free(tmp); + return NULL; + } + // Folder found, continue the search + part = next; + next = strchr(name, '/'); + if (next == NULL) + { + // We have reached the final component of the path + // which is the preset name. Do a non-recursive search. + // If the preset is not in the specified folder, will + // return NULL + hb_value_t *preset = preset_lookup(list, part, 0, 0, 0); + free(tmp); + if (preset == NULL) + { + return NULL; + } + return hb_value_dup(preset); + } + } + // This should never be reached, but some compilers might complain + // without a final return. + free(tmp); + return NULL; +} + +char * hb_preset_get_json(const char *name, int recurse) +{ + hb_value_t * preset; + char *json; + preset = hb_preset_get(name, recurse); + if (preset == NULL) + return NULL; + json = hb_value_get_json(preset); + hb_value_free(&preset); + return json; +} + +static hb_dict_t * find_first_preset(hb_value_array_t *list) +{ + int count, ii; + count = hb_value_array_len(list); + for (ii = 0; ii < count; ii++) + { + hb_dict_t *preset_dict = hb_value_array_get(list, ii); + if (hb_value_get_bool(hb_dict_get(preset_dict, "Folder"))) + { + hb_value_array_t *children; + children = hb_dict_get(preset_dict, "ChildrenArray"); + if (children == NULL) + continue; + preset_dict = find_first_preset(children); + if (preset_dict != NULL) + return preset_dict; + } + else + { + return preset_dict; + } + } + return NULL; +} + +hb_dict_t * hb_presets_get_default(void) +{ + // Look for preset with 'Default' flag set + hb_value_t *preset = preset_lookup(hb_presets, NULL, 1, 0, 1); + if (preset == NULL) + { + // Look for preset named 'Normal' flag set + preset = preset_lookup(hb_presets, "Normal", 0, 0, 1); + if (preset == NULL) + { + // Just grab the first preset available + preset = find_first_preset(hb_presets); + if (preset == NULL) + return NULL; + } + } + return hb_value_dup(preset); +} + +char * hb_presets_get_default_json(void) +{ + hb_value_t *preset = preset_lookup(hb_presets, NULL, 1, 0, 1); + if (preset == NULL) + return NULL; + return hb_value_get_json(preset); +} + +// Return: +// 0 upon success +// 1 if preset name could not be found +int hb_presets_set_default(const char *name, int recurse) +{ + hb_value_t *preset = preset_lookup(hb_presets, NULL, 1, 0, 1); + if (preset != NULL) + { + // Mark old defalt as not + hb_dict_set(preset, "Default", hb_value_bool(0)); + } + preset = preset_lookup(hb_presets, name, 0, 0, recurse); + if (preset == NULL) + return -1; + hb_dict_set(preset, "Default", hb_value_bool(1)); + return 0; +} + +int hb_presets_add(hb_value_t *preset) +{ + if (preset == NULL) + return -1; + // TODO: validity checking of input preset + if (hb_value_type(preset) == HB_VALUE_TYPE_DICT) + { + // A standalone preset or folder of presets. Add to preset array. + // Only allow custom presets to be added + if (hb_value_get_int(hb_dict_get(preset, "Type")) == 1) + hb_value_array_append(hb_presets_custom, hb_value_dup(preset)); + } + else if (hb_value_type(preset) == HB_VALUE_TYPE_ARRAY) + { + // An array of presets. Add each element. + int count = hb_value_array_len(preset); + int ii; + for (ii = 0; ii < count; ii++) + { + hb_value_t *value = hb_value_array_get(preset, ii); + hb_value_array_append(hb_presets_custom, hb_value_dup(value)); + } + } + + // Reconstruct global list + hb_value_decref(hb_presets); + hb_presets = hb_value_dup(hb_presets_builtin); + // Append custom presets + int count = hb_value_array_len(hb_presets_custom); + int ii; + for (ii = 0; ii < count; ii++) + { + hb_value_t *value = hb_value_array_get(hb_presets_custom, ii); + // Only allow custom presets to be added + if (hb_value_get_int(hb_dict_get(value, "Type")) == 1) + hb_value_array_append(hb_presets, hb_value_dup(value)); + } + return 0; +} + +int hb_presets_add_json(const char *json) +{ + hb_value_t *packaged_preset = hb_value_json(json); + hb_value_t *preset = preset_unpackage(packaged_preset); + if (preset == NULL) + return -1; + int result = hb_presets_add(preset); + hb_value_free(&preset); + hb_value_free(&packaged_preset); + return result; +} + +int hb_presets_add_file(const char *filename) +{ + hb_value_t *packaged_preset = hb_value_read_json(filename); + hb_value_t *preset = preset_unpackage(packaged_preset); + // Unpackaging does some validity checks and can fail + if (preset == NULL) + return -1; + int result = hb_presets_add(preset); + hb_value_free(&preset); + hb_value_free(&packaged_preset); + return result; +} + +static int compare_str(const void *a, const void *b) +{ + return strncmp(*(const char**)a, *(const char**)b, PATH_MAX); +} + +int hb_presets_add_path(char * path) +{ + hb_stat_t sb; + HB_DIR * dir; + struct dirent * entry; + char * filename; + int count, ii; + char ** files; + int result = -1; + + if (hb_stat(path, &sb)) + return -1; + + if (S_ISREG(sb.st_mode)) + { + return hb_presets_add_file(path); + } + + if (!S_ISDIR(sb.st_mode)) + return -1; + + dir = hb_opendir(path); + if ( dir == NULL ) + return -1; + + // Count the total number of entries + count = 0; + while ((entry = hb_readdir(dir))) + { + count++; + } + files = malloc(count * sizeof(char*)); + + // Find all regular files + ii = 0; + hb_rewinddir(dir); + while ((entry = hb_readdir(dir))) + { + filename = hb_strdup_printf("%s" DIR_SEP_STR "%s", path, entry->d_name); + if (hb_stat(filename, &sb)) + { + free(filename); + continue; + } + + // Only load regular files + if (!S_ISREG(sb.st_mode)) + { + free(filename); + continue; + } + // Only load files with .json extension + if (strcmp(".json", filename + strlen(filename) - 5)) + { + free(filename); + continue; + } + + files[ii++] = filename; + } + count = ii; + + // Sort the files so presets get added in a consistent order + qsort(files, count, sizeof(char*), compare_str); + + // Add preset files to preset list + for (ii = 0; ii < count; ii++) + { + int res = hb_presets_add_file(files[ii]); + // return success if any one of the files is successfully loaded + if (res == 0) + result = res; + } + hb_closedir( dir ); + free(files); + + return result; +} + +hb_value_t * hb_presets_get(void) +{ + return hb_value_dup(hb_presets); +} + +char * hb_presets_get_json(void) +{ + return hb_value_get_json(hb_presets); +} + +int hb_preset_write_json(hb_value_t *preset, const char *path) +{ + hb_value_t *packaged_preset = preset_package(preset); + // Packaging does some validity checks and can fail + if (packaged_preset == NULL) + return -1; + int result = hb_value_write_json(packaged_preset, path); + hb_value_free(&packaged_preset); + return result; +} + +char * hb_preset_package_json(hb_value_t *preset) +{ + hb_value_t *packaged_preset = preset_package(preset); + // Packaging does some validity checks and can fail + if (packaged_preset == NULL) + return NULL; + char *json = hb_value_get_json(packaged_preset); + hb_value_free(&packaged_preset); + return json; +} + +void hb_presets_free(void) +{ + hb_value_free(&hb_preset_template); + hb_value_free(&hb_presets); + hb_value_free(&hb_presets_custom); + hb_value_free(&hb_presets_builtin); +} diff --git a/libhb/preset.h b/libhb/preset.h new file mode 100644 index 000000000..5e7c460b6 --- /dev/null +++ b/libhb/preset.h @@ -0,0 +1,84 @@ +/* hb_preset.h + + Copyright (c) 2003-2015 HandBrake Team + This file is part of the HandBrake source code + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License v2. + For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html + */ +#if !defined(HB_PRESET_H) +#define HB_PRESET_H + +#include "common.h" +#include "hb_dict.h" + +// Initialize the hb_value_array_t that holds HandBrake builtin presets +void hb_presets_builtin_init(void); + +// Load presets from GUI presets file if possible +int hb_presets_gui_init(void); + +// Free all libhb presets +void hb_presets_free(void); + +// Get list of HandBrake builtin presets as hb_value_array_t +hb_value_t * hb_presets_builtin_get(void); + +// Get list of HandBrake builtin presets as json string +char * hb_presets_builtin_get_json(void); + +// Register new presets with libhb from +// hb_dict_t (single preset) or hb_value_array_t (list of presets) +int hb_presets_add(hb_value_t *preset); + +// Register new presets with libhb from json string +int hb_presets_add_json(const char *json); + +// Register new presets with libhb from json file +int hb_presets_add_file(const char *filename); + +// Register new presets with libhb from json file(s) +// path can be a directory, in which case all *.json files in the +// directory will be added +int hb_presets_add_path(char * path); + +// Get list of all presets registered with libhb as hb_value_array_t +hb_value_t * hb_presets_get(void); + +// Get list of all presets registered with libhb as json string +char * hb_presets_get_json(void); + +// Initialize a job from the given title and preset +hb_dict_t * hb_preset_job_init(hb_handle_t *h, int title_index, + hb_dict_t *preset); +int hb_preset_job_add_subtitles(hb_handle_t *h, int title_index, + hb_dict_t *preset, hb_dict_t *job_dict); +int hb_preset_job_add_audio(hb_handle_t *h, int title_index, + hb_dict_t *preset, hb_dict_t *job_dict); + +// Lookup a preset in the preset list. The "name" may contain '/' +// separators to explicitely specify a preset within the preset lists +// folder structure. +// +// If 'recurse' is specified, a recursive search for the first component +// in the name will be performed. +// +// I assume that the actual preset name does not include any '/' +hb_value_t * hb_preset_get(const char *name, int recurse); +char * hb_preset_get_json(const char *name, int recurse); + +// Recursively lookup the preset that is marked as 'Default' +hb_dict_t * hb_presets_get_default(void); +char * hb_presets_get_default_json(void); + +// Set the preset that is marked as 'Default' +int hb_presets_set_default(const char *name, int recurse); + +// Package the provided preset (wrap in dict and add version etc) +// and write to json file +int hb_preset_write_json(hb_value_t *preset, const char *path); +// Package the provided preset (wrap in dict and add version etc) +// and return as json string +char * hb_preset_package_json(hb_value_t *preset); + +#endif // HB_PRESET_H diff --git a/libhb/preset_builtin.json b/libhb/preset_builtin.json new file mode 100644 index 000000000..5bf5d4d8a --- /dev/null +++ b/libhb/preset_builtin.json @@ -0,0 +1,855 @@ + [ + { + "ChildrenArray": [ + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + }, + { + "AudioBitrate": "160", + "AudioEncoder": "copy:ac3", + "AudioMixdown": "none", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 576, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 720, + "PresetDescription": "HandBrake's settings for compatibility with all Apple devices (including the iPod 6G and later). Includes Dolby Digital audio for surround sound.", + "PresetName": "Universal", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.0", + "VideoOptionExtra": "", + "VideoPreset": "fast", + "VideoProfile": "baseline", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 1, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 240, + "PictureKeepRatio": 1, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "off", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 320, + "PresetDescription": "HandBrake's settings for playback on the iPod with Video (all generations).", + "PresetName": "iPod", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "1.3", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "baseline", + "VideoQualitySlider": 22.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 640, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 960, + "PresetDescription": "HandBrake's settings for handheld iOS devices (iPhone 4, iPod touch 3G and later).", + "PresetName": "iPhone & iPod touch", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.1", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "high", + "VideoQualitySlider": 22.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 720, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 1280, + "PresetDescription": "HandBrake's settings for playback on the iPad (all generations).", + "PresetName": "iPad", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.1", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "high", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + }, + { + "AudioBitrate": "160", + "AudioEncoder": "copy:ac3", + "AudioMixdown": "none", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 720, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 960, + "PresetDescription": "HandBrake's settings for the original AppleTV. Includes Dolby Digital audio for surround sound. Also compatible with iOS devices released since 2009.", + "PresetName": "AppleTV", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.1", + "VideoOptionExtra": "qpmin=4:cabac=0:ref=2:b-pyramid=none:weightb=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500", + "VideoPreset": "medium", + "VideoProfile": "high", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + }, + { + "AudioBitrate": "160", + "AudioEncoder": "copy:ac3", + "AudioMixdown": "none", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 720, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 1280, + "PresetDescription": "HandBrake's settings for the second-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV.", + "PresetName": "AppleTV 2", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.1", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "high", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + }, + { + "AudioBitrate": "160", + "AudioEncoder": "copy:ac3", + "AudioMixdown": "none", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 3, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 1080, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 1920, + "PresetDescription": "HandBrake's settings for the third-generation AppleTV. Includes Dolby Digital audio for surround sound. NOT compatible with the original AppleTV. May stutter on the second-generation AppleTV.", + "PresetName": "AppleTV 3", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "4.0", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "high", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "128", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 0, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 576, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 720, + "PresetDescription": "HandBrake's settings for midrange devices running Android 2.3 or later.", + "PresetName": "Android", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.0", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "main", + "VideoQualitySlider": 22.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "128", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 0, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 720, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 1280, + "PresetDescription": "HandBrake's preset for tablets running Android 2.3 or later.", + "PresetName": "Android Tablet", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.1", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "main", + "VideoQualitySlider": 22.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "128", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 0, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 720, + "PictureKeepRatio": 1, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "off", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 1280, + "PresetDescription": "HandBrake's preset for Windows Phone 8 devices", + "PresetName": "Windows Phone 8", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "30", + "VideoFramerateMode": "pfr", + "VideoGrayScale": 0, + "VideoLevel": "3.1", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "main", + "VideoQualitySlider": 22.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + } + ], + "Default": 0, + "Folder": true, + "PresetName": "Devices", + "Type": 0 + }, + { + "ChildrenArray": [ + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 1, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 0, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 0, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 0, + "PresetDescription": "HandBrake's normal, default settings.", + "PresetName": "Normal", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "auto", + "VideoFramerateMode": "vfr", + "VideoGrayScale": 0, + "VideoLevel": "4.0", + "VideoOptionExtra": "", + "VideoPreset": "veryfast", + "VideoProfile": "main", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + }, + { + "AudioAllowAACPass": 1, + "AudioAllowAC3Pass": 1, + "AudioAllowDTSHDPass": 1, + "AudioAllowDTSPass": 1, + "AudioAllowMP3Pass": 1, + "AudioEncoderFallback": "ac3", + "AudioList": [ + { + "AudioBitrate": "160", + "AudioEncoder": "aac", + "AudioMixdown": "dpl2", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + }, + { + "AudioBitrate": "160", + "AudioEncoder": "copy:ac3", + "AudioMixdown": "none", + "AudioSamplerate": "auto", + "AudioTrack": 1, + "AudioTrackDRCSlider": 0.0, + "AudioTrackGainSlider": 0.0 + } + ], + "ChapterMarkers": 1, + "Default": 0, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": 0, + "Mp4iPodCompatible": 0, + "PictureAutoCrop": 1, + "PictureBottomCrop": 0, + "PictureDeblock": 0, + "PictureDecomb": 2, + "PictureDecombCustom": "", + "PictureDecombDeinterlace": 1, + "PictureDeinterlace": 0, + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDetelecine": 0, + "PictureDetelecineCustom": "", + "PictureHeight": 0, + "PictureKeepRatio": 0, + "PictureLeftCrop": 0, + "PictureModulus": 2, + "PicturePAR": "loose", + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureWidth": 0, + "PresetDescription": "HandBrake's general-purpose preset for High Profile H.264 video.", + "PresetName": "High Profile", + "Type": 0, + "UsesPictureFilters": 1, + "UsesPictureSettings": 1, + "VideoAvgBitrate": "2500", + "VideoEncoder": "x264", + "VideoFramerate": "auto", + "VideoFramerateMode": "vfr", + "VideoGrayScale": 0, + "VideoLevel": "4.1", + "VideoOptionExtra": "", + "VideoPreset": "medium", + "VideoProfile": "high", + "VideoQualitySlider": 20.0, + "VideoQualityType": 2, + "VideoTune": "", + "VideoTurboTwoPass": 0, + "VideoTwoPass": 0, + "x264Option": "", + "x264UseAdvancedOptions": 0 + } + ], + "Default": 0, + "Folder": true, + "PresetName": "Regular", + "Type": 0 + } + ] diff --git a/libhb/preset_template.json b/libhb/preset_template.json new file mode 100644 index 000000000..30449e437 --- /dev/null +++ b/libhb/preset_template.json @@ -0,0 +1,104 @@ + { + "AudioAllowMP3Pass": false, + "AudioAllowAACPass": false, + "AudioAllowAC3Pass": true, + "AudioAllowDTSPass": false, + "AudioAllowDTSHDPass": false, + "AudioAllowEAC3Pass": false, + "AudioAllowFLACPass": false, + "AudioAllowTRUEHDPass": false, + "AudioCopyMask": [ + ], + "AudioEncoderFallback": "ac3", + "AudioLanguageList": [ + "und" + ], + "AudioList": [ + { + "AudioBitrate": "192", + "AudioCompressionLevel": -1.0, + "AudioDitherMethod": "auto", + "AudioEncoder": "copy:ac3", + "AudioMixdown": "dpl2", + "AudioNormalizeMixLevel": false, + "AudioSamplerate": "auto", + "AudioTrackQualityEnable": false, + "AudioTrackQuality": -1.0, + "AudioTrackGainSlider": 0.0, + "AudioTrackDRCSlider": 0.0 + } + ], + "AudioSecondaryEncoderMode": true, + "AudioTrackSelectionBehavior": "first", + "ChapterMarkers": true, + "Default": false, + "FileFormat": "mp4", + "Folder": false, + "Mp4HttpOptimize": false, + "Mp4iPodCompatible": false, + "PictureAutoCrop": true, + "PictureBottomCrop": 0, + "PictureLeftCrop": 0, + "PictureRightCrop": 0, + "PictureTopCrop": 0, + "PictureDARWidth": 0, + "PictureDeblock": 0, + "PictureDecomb": "off", + "PictureDecombCustom": "", + "PictureDecombDeinterlace": true, + "PictureDeinterlace": "off", + "PictureDeinterlaceCustom": "", + "PictureDenoiseCustom": "", + "PictureDenoiseFilter": "off", + "PictureDenoisePreset": "medium", + "PictureDenoiseTune": "none", + "PictureDetelecine": "off", + "PictureDetelecineCustom": "", + "PictureItuPAR": false, + "PictureKeepRatio": true, + "PictureLooseCrop": false, + "PictureModulus": 2, + "PicturePAR": "loose", + "PicturePARWidth": 853, + "PicturePARHeight": 720, + "PictureRotate": 0, + "PictureWidth": 0, + "PictureHeight": 0, + "PictureForceHeight": 0, + "PictureForceWidth": 0, + "PresetDescription": "", + "PresetName": "Name Missing", + "Type": 1, + "UsesPictureFilters": true, + "UsesPictureSettings": 2, + "SubtitleAddCC": false, + "SubtitleAddForeignAudioSearch": false, + "SubtitleAddForeignAudioSubtitle": false, + "SubtitleBurnBehavior": "none", + "SubtitleBurnBDSub": false, + "SubtitleBurnDVDSub": false, + "SubtitleLanguageList": [ + ], + "SubtitleTrackSelectionBehavior": "none", + "VideoAvgBitrate": 1800, + "VideoColorMatrixCode": 0, + "VideoEncoder": "x264", + "VideoFramerate": "auto", + "VideoFramerateMode": "vfr", + "VideoGrayScale": false, + "VideoHWDecode": false, + "VideoScaler": "swscale", + "VideoPreset": "medium", + "VideoTune": "none", + "VideoProfile": "auto", + "VideoLevel": "auto", + "VideoOptionExtra": "", + "VideoQualityType": 2, + "VideoQualitySlider": 20.0, + "VideoQSVDecode": false, + "VideoQSVAsyncDepth": 4, + "VideoTwoPass": false, + "VideoTurboTwoPass": false, + "x264Option": "", + "x264UseAdvancedOptions": false + } |