From 559627ca29e60393c2198f3d1d4c3d1bfa07ef6a Mon Sep 17 00:00:00 2001 From: sr55 Date: Mon, 24 Jun 2013 18:59:35 +0000 Subject: [PATCH] QSV: Merging Trunk git-svn-id: svn://svn.handbrake.fr/HandBrake/branches/qsv@5607 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- contrib/ffmpeg/A04-aacenc.patch | 82 ++++ contrib/x264/A00-version-string.patch | 6 +- contrib/x264/module.defs | 4 +- gtk/configure.ac | 10 +- gtk/module.defs | 4 + gtk/src/audiohandler.c | 22 + gtk/src/callbacks.c | 29 ++ gtk/src/makedeps.py | 5 - gtk/src/presets.c | 377 +++++++++--------- gtk/src/standard_presets.xml | 137 ++++++- libhb/common.c | 61 ++- libhb/dvd.c | 16 +- libhb/dvdnav.c | 13 +- libhb/encfaac.c | 3 +- libhb/hb.c | 110 ++--- libhb/module.defs | 13 +- libhb/sync.c | 8 +- macosx/English.lproj/Preferences.xib | 343 ++++++---------- macosx/HBAudioController.m | 13 +- macosx/HBPreferencesController.m | 1 - macosx/HBPresets.m | 105 +++++ macosx/HandBrake.xcodeproj/project.pbxproj | 6 - macosx/module.defs | 7 +- make/configure.py | 15 +- make/include/main.defs | 5 +- scripts/manicure.rb | 272 +++++++------ test/module.defs | 6 +- test/test.c | 72 +++- .../HandBrake.ApplicationServices.csproj | 1 + .../LibHb/AudioVideoHelpers.cs | 18 + .../Model/Encoding/AudioTrack.cs | 6 +- .../Services/Interfaces/IPresetService.cs | 5 + .../Services/PresetService.cs | 46 +-- .../Utilities/Converters.cs | 111 ++---- .../Utilities/EnumHelper.cs | 19 + .../HandBrakeInterop/Attributes/ShortName.cs | 35 ++ .../HandBrakeInterop/Converters.cs | 69 ++-- .../HandBrakeInterop/HandBrakeInstance.cs | 31 +- .../HandBrakeInterop/HandBrakeInterop.csproj | 2 + .../HandBrakeInterop/HandBrakeUtils.cs | 89 ++++- .../HandBrakeInterop/HbLib/HbFunctions.cs | 141 ++++--- .../HandBrakeInterop/HbLib/Misc.cs | 13 +- .../HandBrakeInterop/HbLib/NativeConstants.cs | 59 +-- .../HandBrakeInterop/HbLib/hb_job_s.cs | 4 - .../HandBrakeInterop/InteropUtilities.cs | 40 +- .../HandBrakeInterop/Model/Encoders.cs | 138 ++++--- .../Model/Encoding/AudioEncoder.cs | 37 +- .../HandBrakeInterop/Model/Encoding/HBRate.cs | 24 ++ .../Model/Encoding/VideoEncoder.cs | 10 +- .../Properties/AssemblyInfo.cs | 4 +- .../HandBrakeInterop/SourceData/AudioCodec.cs | 2 +- .../Commands/SourceMenuCommand.cs | 4 - .../Converters/Audio/AudioBitrateConverter.cs | 21 +- .../Converters/Audio/AudioEncoderConverter.cs | 2 + win/CS/HandBrakeWPF/HandBrakeWPF.csproj | 2 + win/CS/HandBrakeWPF/Helpers/AppStyleHelper.cs | 37 ++ win/CS/HandBrakeWPF/Model/SourceMenuItem.cs | 5 + win/CS/HandBrakeWPF/UserSettingConstants.cs | 5 + .../HandBrakeWPF/ViewModels/MainViewModel.cs | 17 +- .../ViewModels/OptionsViewModel.cs | 24 ++ .../HandBrakeWPF/ViewModels/ShellViewModel.cs | 1 + .../HandBrakeWPF/ViewModels/VideoViewModel.cs | 1 - .../HandBrakeWPF/ViewModels/ViewModelBase.cs | 12 + win/CS/HandBrakeWPF/Views/AudioView.xaml | 20 +- win/CS/HandBrakeWPF/Views/MainView.xaml | 84 ++-- win/CS/HandBrakeWPF/Views/OptionsView.xaml | 15 +- win/CS/HandBrakeWPF/Views/QueueView.xaml | 63 +-- win/CS/HandBrakeWPF/Views/ShellView.xaml | 5 +- win/CS/HandBrakeWPF/Views/Styles/Styles.xaml | 35 +- win/CS/HandBrakeWPF/Views/SubtitlesView.xaml | 21 +- win/CS/HandBrakeWPF/defaultsettings.xml | 8 + .../GongSolutions.Wpf.DragDrop.XML | 5 + .../GongSolutions.Wpf.DragDrop.dll | Bin 49664 -> 50176 bytes .../GongSolutions.Wpf.DragDrop.pdb | Bin 97792 -> 89600 bytes 74 files changed, 1915 insertions(+), 1121 deletions(-) create mode 100644 contrib/ffmpeg/A04-aacenc.patch create mode 100644 win/CS/HandBrake.ApplicationServices/LibHb/AudioVideoHelpers.cs create mode 100644 win/CS/HandBrake.Interop/HandBrakeInterop/Attributes/ShortName.cs create mode 100644 win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/HBRate.cs create mode 100644 win/CS/HandBrakeWPF/Helpers/AppStyleHelper.cs diff --git a/contrib/ffmpeg/A04-aacenc.patch b/contrib/ffmpeg/A04-aacenc.patch new file mode 100644 index 000000000..b58441a17 --- /dev/null +++ b/contrib/ffmpeg/A04-aacenc.patch @@ -0,0 +1,82 @@ +commit 8bbdd20a293eab2cfac9f332613ead02a4e3c0c2 +Author: Claudio Freire +Date: Sun May 12 09:38:40 2013 +0200 + + aacenc: Fix erasure of surround channels + + This was due to a miscomputation of s->cur_channel, which led to + psy-based encoders using the psy coefficients for the wrong channel. + + Signed-off-by: Martin Storsjö + +diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c +index 60eca59..b2ad47b 100644 +--- a/libavcodec/aacenc.c ++++ b/libavcodec/aacenc.c +@@ -597,7 +597,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + coeffs[ch] = cpe->ch[ch].coeffs; + s->psy.model->analyze(&s->psy, start_ch, coeffs, wi); + for (ch = 0; ch < chans; ch++) { +- s->cur_channel = start_ch * 2 + ch; ++ s->cur_channel = start_ch + ch; + s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda); + } + cpe->common_window = 0; +@@ -613,7 +613,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + } + } + } +- s->cur_channel = start_ch * 2; ++ s->cur_channel = start_ch; + if (s->options.stereo_mode && cpe->common_window) { + if (s->options.stereo_mode > 0) { + IndividualChannelStream *ics = &cpe->ch[0].ics; + +commit f4d0a63b5b5c682c18df3bba730f97a9067408ba +Author: Claudio Freire +Date: Sat May 4 18:36:37 2013 -0300 + + aacenc: Fix target bitrate for twoloop quantiser search + + This fixes a case where multichannel bitrate isn't accurately + targetted by psy model alone, never achieving the target bitrate. + + Signed-off-by: Martin Storsjö + +diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c +index d65d8d9..35b98a9 100644 +--- a/libavcodec/aaccoder.c ++++ b/libavcodec/aaccoder.c +@@ -710,7 +710,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, + const float lambda) + { + int start = 0, i, w, w2, g; +- int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels; ++ int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels * (lambda / 120.f); + float dists[128] = { 0 }, uplims[128]; + float maxvals[128]; + int fflag, minscaler; + +commit 7c71ada4cad3c6aab5fa24155c379465c41cfd76 +Author: Claudio Freire +Date: Sat May 4 18:35:49 2013 -0300 + + aacenc: Fix a rounding bug in aacpsy channel bitrate computation + + Signed-off-by: Martin Storsjö + +diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c +index 6f1ac05..66cf6d5 100644 +--- a/libavcodec/aacpsy.c ++++ b/libavcodec/aacpsy.c +@@ -312,7 +312,7 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) { + AacPsyCoeffs *coeffs = pctx->psy_coef[j]; + const uint8_t *band_sizes = ctx->bands[j]; + float line_to_frequency = ctx->avctx->sample_rate / (j ? 256.f : 2048.0f); +- float avg_chan_bits = chan_bitrate / ctx->avctx->sample_rate * (j ? 128.0f : 1024.0f); ++ float avg_chan_bits = chan_bitrate * (j ? 128.0f : 1024.0f) / ctx->avctx->sample_rate; + /* reference encoder uses 2.4% here instead of 60% like the spec says */ + float bark_pe = 0.024f * PSY_3GPP_BITS_TO_PE(avg_chan_bits) / num_bark; + float en_spread_low = j ? PSY_3GPP_EN_SPREAD_LOW_S : PSY_3GPP_EN_SPREAD_LOW_L; + + diff --git a/contrib/x264/A00-version-string.patch b/contrib/x264/A00-version-string.patch index dcd4ec628..49a652256 100644 --- a/contrib/x264/A00-version-string.patch +++ b/contrib/x264/A00-version-string.patch @@ -6,7 +6,7 @@ index e5a1600..f635d9e 100644 #include "x264_config.h" --#define X264_BUILD 130 +-#define X264_BUILD 133 +/* + * Define the full version explicitly so that it survives a git --archive. + * @@ -16,8 +16,8 @@ index e5a1600..f635d9e 100644 +#ifdef X264_VERSION +#undef X264_VERSION +#endif -+#define X264_BUILD 130 -+#define X264_VERSION " r2273 b3065e6" ++#define X264_BUILD 133 ++#define X264_VERSION " r2334 a3ac64b" /* Application developers planning to link against a shared library version of * libx264 from a Microsoft Visual Studio or similar development environment diff --git a/contrib/x264/module.defs b/contrib/x264/module.defs index 097f88d42..458a6cddf 100644 --- a/contrib/x264/module.defs +++ b/contrib/x264/module.defs @@ -1,7 +1,7 @@ $(eval $(call import.MODULE.defs,X264,x264,YASM PTHREADW32)) $(eval $(call import.CONTRIB.defs,X264)) -X264.FETCH.url = http://download.handbrake.fr/handbrake/contrib/x264-r2273-b3065e6.tar.gz +X264.FETCH.url = http://download.handbrake.fr/handbrake/contrib/x264-r2334-a3ac64b.tar.gz X264.EXTRACT.tarbase = x264 X264.CONFIGURE.deps = @@ -9,7 +9,7 @@ X264.CONFIGURE.shared = X264.CONFIGURE.static = X264.CONFIGURE.extra = --disable-cli --enable-static --enable-strip -X264.CONFIGURE.extra += --disable-gpac --disable-avs --disable-lavf --disable-ffms --disable-swscale +X264.CONFIGURE.extra += --disable-gpac --disable-avs --disable-lavf --disable-ffms --disable-swscale --disable-opencl ifeq (1-mingw,$(BUILD.cross)-$(BUILD.system)) X264.CONFIGURE.extra += --cross-prefix=$(BUILD.spec)- diff --git a/gtk/configure.ac b/gtk/configure.ac index 6d013f935..64aa72744 100644 --- a/gtk/configure.ac +++ b/gtk/configure.ac @@ -60,6 +60,10 @@ AC_ARG_ENABLE(fdk-aac, AS_HELP_STRING([--enable-fdk-aac], [enable fdk aac encoder]), use_fdk_aac=yes, use_fdk_aac=no) +AC_ARG_ENABLE(faac, + AS_HELP_STRING([--enable-faac], [enable faac encoder]), + use_faac=yes, use_faac=no) + AC_ARG_ENABLE(gst, AS_HELP_STRING([--disable-gst], [disable gstreamer (live preview)]), gst_disable=yes, gst_disable=no) @@ -203,12 +207,16 @@ case $host in ;; esac -HB_LIBS="-lhb -la52 -lmkv -lavresample -lavformat -lavcodec -lavutil -ldvdnav -ldvdread -lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate -lx264 -lmp4v2 -lswscale -ltheoraenc -ltheoradec -lz -lbz2 -lpthread -lbluray -lass -lfontconfig -lfreetype -lxml2" +HB_LIBS="-lhb -la52 -lmkv -lavresample -lavformat -lavcodec -lavutil -ldvdnav -ldvdread -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate -lx264 -lmp4v2 -lswscale -ltheoraenc -ltheoradec -lz -lbz2 -lpthread -lbluray -lass -lfontconfig -lfreetype -lxml2" if test "x$use_fdk_aac" = "xyes" ; then HB_LIBS+=" -lfdk-aac" fi +if test "x$use_faac" = "xyes" ; then + HB_LIBS+=" -lfaac" +fi + AC_SUBST(HB_LIBS) AC_SUBST(GHB_TOOLS_CFLAGS) AC_SUBST(GHB_TOOLS_LIBS) diff --git a/gtk/module.defs b/gtk/module.defs index 8eddc6d91..cee9d7790 100644 --- a/gtk/module.defs +++ b/gtk/module.defs @@ -32,3 +32,7 @@ endif ifeq (1,$(FEATURE.fdk_aac)) GTK.CONFIGURE.extra += --enable-fdk-aac endif + +ifeq (1,$(FEATURE.faac)) + GTK.CONFIGURE.extra += --enable-faac +endif diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c index 72f58bfa7..c25cfe1f3 100644 --- a/gtk/src/audiohandler.c +++ b/gtk/src/audiohandler.c @@ -642,6 +642,27 @@ ghb_audio_list_refresh(signal_user_data_t *ud) } } +static void enable_quality_widget(signal_user_data_t *ud, int acodec) +{ + GtkWidget *widget1, *widget2, *widget3; + + widget1 = GHB_WIDGET(ud->builder, "AudioTrackQualityEnable"); + widget2 = GHB_WIDGET(ud->builder, "AudioTrackQualityValue"); + widget3 = GHB_WIDGET(ud->builder, "AudioTrackQuality"); + if (hb_audio_quality_get_default(acodec) == HB_INVALID_AUDIO_QUALITY) + { + gtk_widget_hide(widget1); + gtk_widget_hide(widget2); + gtk_widget_hide(widget3); + } + else + { + gtk_widget_show(widget1); + gtk_widget_show(widget2); + gtk_widget_show(widget3); + } +} + G_MODULE_EXPORT void audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { @@ -654,6 +675,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) acodec_code = ghb_lookup_combo_int("AudioEncoder", gval); ghb_value_free(gval); + enable_quality_widget(ud, acodec_code); if (block_updates) { prev_acodec = acodec_code; diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index e6b4714cb..eead66275 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -1600,6 +1600,35 @@ set_title_settings(GValue *settings, gint titleindex) ghb_set_scale_settings(settings, GHB_PIC_KEEP_PAR|GHB_PIC_USE_MAX); ghb_settings_set_int(settings, "angle_count", title->angle_count); + + ghb_settings_set_string(settings, "MetaName", title->name); + if (title->metadata) + { + if (title->metadata->name) + { + ghb_settings_set_string(settings, "MetaName", + title->metadata->name); + } + ghb_settings_set_string(settings, "MetaArtist", + title->metadata->artist); + ghb_settings_set_string(settings, "MetaReleaseDate", + title->metadata->release_date); + ghb_settings_set_string(settings, "MetaComment", + title->metadata->comment); + if (!title->metadata->name && title->metadata->album) + { + ghb_settings_set_string(settings, "MetaName", + title->metadata->album); + } + ghb_settings_set_string(settings, "MetaAlbumArtist", + title->metadata->album_artist); + ghb_settings_set_string(settings, "MetaGenre", + title->metadata->genre); + ghb_settings_set_string(settings, "MetaDescription", + title->metadata->description); + ghb_settings_set_string(settings, "MetaLongDescription", + title->metadata->long_description); + } } update_chapter_list_settings(settings); ghb_set_pref_audio_settings(titleindex, settings); diff --git a/gtk/src/makedeps.py b/gtk/src/makedeps.py index 9fecd37fe..07830237c 100644 --- a/gtk/src/makedeps.py +++ b/gtk/src/makedeps.py @@ -50,13 +50,8 @@ dep_map = ( DepEntry("VideoEncoder", "x264VideoSettings", "x264", False, True), DepEntry("VideoEncoder", "lavc_mpeg4_tab", "ffmpeg|ffmpeg4|ffmpeg2", False, True), DepEntry("VideoEncoder", "Mp4iPodCompatible", "x264", False, False), - DepEntry("AudioTrackQualityEnable", "AudioTrackQuality", "FALSE", True, False), - DepEntry("AudioTrackQualityEnable", "AudioTrackQualityValue", "FALSE", True, False), DepEntry("AudioTrackQualityEnable", "AudioBitrateLabel", "TRUE", True, False), DepEntry("AudioTrackQualityEnable", "AudioBitrate", "TRUE", True, False), - DepEntry("AudioEncoderActual", "AudioTrackQualityEnable", "lame|vorbis", False, True), - DepEntry("AudioEncoderActual", "AudioTrackQuality", "lame|vorbis", False, True), - DepEntry("AudioEncoderActual", "AudioTrackQualityValue", "lame|vorbis", False, True), DepEntry("AudioEncoderActual", "AudioBitrateLabel", "copy:mp3|copy:aac|copy:ac3|copy:dts|copy:dtshd", True, False), DepEntry("AudioEncoderActual", "AudioBitrate", "copy:mp3|copy:aac|copy:ac3|copy:dts|copy:dtshd", True, False), DepEntry("AudioEncoderActual", "AudioSamplerateLabel", "copy:mp3|copy:aac|copy:ac3|copy:dts|copy:dtshd", True, False), diff --git a/gtk/src/presets.c b/gtk/src/presets.c index 12fdfbd67..8562401e7 100644 --- a/gtk/src/presets.c +++ b/gtk/src/presets.c @@ -2018,158 +2018,6 @@ typedef struct const gchar *lin_val; } value_map_t; -static value_map_t vcodec_xlat_compat[] = -{ - {"MPEG-4 (FFmpeg)", "ffmpeg"}, - {"MPEG-4 (XviD)", "ffmpeg4"}, - {NULL,NULL} -}; - -static value_map_t *vcodec_xlat; - -static value_map_t acodec_xlat_compat[] = -{ - {"AAC (CoreAudio)", "faac"}, - {"HE-AAC (CoreAudio)", "faac"}, - {"AC3 (ffmpeg)", "ac3"}, - {"AC3", "ac3"}, - {"MP3 Passthru", "mp3pass"}, - {"AAC Passthru", "aacpass"}, - {"AC3 Passthru", "ac3pass"}, - {"DTS Passthru", "dtspass"}, - {"DTS-HD Passthru", "dtshdpass"}, - {"Auto Passthru", "auto"}, - {NULL,NULL} -}; - -static value_map_t *acodec_xlat; - -static value_map_t * create_video_encoder_xlat_tbl(value_map_t *compat) -{ - value_map_t *out; - int cc, ii, size = 0; - - for (cc = 0; compat[cc].mac_val != NULL; cc++); - - const hb_encoder_t *enc; - for (enc = hb_video_encoder_get_next(NULL); enc != NULL; - enc = hb_video_encoder_get_next(enc)) - { - size++; - } - out = calloc(cc + size + 1, sizeof(value_map_t)); - - for (ii = 0, enc = hb_video_encoder_get_next(NULL); enc != NULL; - ii++, enc = hb_video_encoder_get_next(enc)) - { - out[ii].mac_val = enc->name; - out[ii].lin_val = enc->short_name; - } - - for (ii = 0; ii < cc; ii++) - out[ii+size] = compat[ii]; - - return out; -} - -static value_map_t * create_audio_encoder_xlat_tbl(value_map_t *compat) -{ - value_map_t *out; - int cc, ii, size = 0; - - for (cc = 0; compat[cc].mac_val != NULL; cc++); - - const hb_encoder_t *enc; - for (enc = hb_audio_encoder_get_next(NULL); enc != NULL; - enc = hb_audio_encoder_get_next(enc)) - { - size++; - } - out = calloc(cc + size + 1, sizeof(value_map_t)); - - for (ii = 0, enc = hb_audio_encoder_get_next(NULL); enc != NULL; - ii++, enc = hb_audio_encoder_get_next(enc)) - { - out[ii].mac_val = enc->name; - out[ii].lin_val = enc->short_name; - } - - for (ii = 0; ii < cc; ii++) - out[ii+size] = compat[ii]; - - return out; -} - -static value_map_t * create_mix_xlat_tbl(value_map_t *compat) -{ - value_map_t *out; - int cc, ii, size = 0;; - - for (cc = 0; compat[cc].mac_val != NULL; cc++); - - const hb_mixdown_t *mix; - for (mix = hb_mixdown_get_next(NULL); mix != NULL; - mix = hb_mixdown_get_next(mix)) - { - size++; - } - out = calloc(cc + size + 1, sizeof(value_map_t)); - - for (ii = 0, mix = hb_mixdown_get_next(NULL); mix != NULL; - ii++, mix = hb_mixdown_get_next(mix)) - { - out[ii].mac_val = mix->name; - out[ii].lin_val = mix->short_name; - } - - for (ii = 0; ii < cc; ii++) - out[ii+size] = compat[ii]; - - return out; -} - -value_map_t framerate_xlat[] = -{ - {"Same as source", "source"}, - {"5", "5"}, - {"10", "10"}, - {"12", "12"}, - {"15", "15"}, - {"23.976 (NTSC Film)", "23.976"}, - {"24", "24"}, - {"25 (PAL Film/Video)", "25"}, - {"29.97 (NTSC Video)", "29.97"}, - {"30", "30"}, - {"50", "50"}, - {"59.94", "59.94"}, - {"60", "60"}, - {NULL, NULL} -}; - -value_map_t samplerate_xlat[] = -{ - {"Auto", "source"}, - {"22.05", "22.05"}, - {"24", "24"}, - {"32", "32"}, - {"44.1", "44.1"}, - {"48", "48"}, - {NULL, NULL} -}; - -// mix translation table filed in with hb_audio_mixdowns table contents -value_map_t *mix_xlat; - -// Backwards compatibility mappings for audio mix -value_map_t mix_xlat_compat[] = -{ - {"6-channel discrete", "5point1"}, - {"AC3 Passthru", "none"}, - {"DTS Passthru", "none"}, - {"DTS-HD Passthru", "none"}, - {NULL, NULL} -}; - value_map_t deint_xlat[] = { {"0", "off"}, @@ -2394,17 +2242,95 @@ export_value_xlat2(value_map_t *value_map, GValue *lin_val, GType mac_type) } static GValue* -export_value_xlat_container(GValue *lin_val) +export_value_video_framerate(GValue *lin_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *fr; + + str = ghb_value_string(lin_val); + fr = hb_video_framerate_get_name(hb_video_framerate_get_from_name(str)); + g_free(str); + if (fr != NULL) + sval = ghb_string_value_new(fr); + + return sval; +} + +static GValue* +export_value_audio_samplerate(GValue *lin_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *sr; + + str = ghb_value_string(lin_val); + sr = hb_audio_samplerate_get_name(hb_audio_samplerate_get_from_name(str)); + g_free(str); + if (sr != NULL) + sval = ghb_string_value_new(sr); + + return sval; +} + +static GValue* +export_value_mixdown(GValue *lin_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *mix; + + str = ghb_value_string(lin_val); + mix = hb_mixdown_get_name(hb_mixdown_get_from_name(str)); + g_free(str); + if (mix != NULL) + sval = ghb_string_value_new(mix); + + return sval; +} + +static GValue* +export_value_video_encoder(GValue *lin_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *enc; + + str = ghb_value_string(lin_val); + enc = hb_video_encoder_get_name(hb_video_encoder_get_from_name(str)); + g_free(str); + if (enc != NULL) + sval = ghb_string_value_new(enc); + + return sval; +} + +static GValue* +export_value_audio_encoder(GValue *lin_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *enc; + + str = ghb_value_string(lin_val); + enc = hb_audio_encoder_get_name(hb_audio_encoder_get_from_name(str)); + g_free(str); + if (enc != NULL) + sval = ghb_string_value_new(enc); + + return sval; +} + +static GValue* +export_value_container(GValue *lin_val) { GValue *sval = NULL; gchar *str; const gchar *mux; - int imux; str = ghb_value_string(lin_val); - imux = hb_container_get_from_name(str); + mux = hb_container_get_name(hb_container_get_from_name(str)); g_free(str); - mux = hb_container_get_name(imux); if (mux != NULL) sval = ghb_string_value_new(mux); @@ -2419,17 +2345,17 @@ export_value_xlat(GValue *dict) key = "VideoEncoder"; lin_val = ghb_dict_lookup(dict, key); - gval = export_value_xlat2(vcodec_xlat, lin_val, G_TYPE_STRING); + gval = export_value_video_encoder(lin_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); key = "FileFormat"; lin_val = ghb_dict_lookup(dict, key); - gval = export_value_xlat_container(lin_val); + gval = export_value_container(lin_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); key = "VideoFramerate"; lin_val = ghb_dict_lookup(dict, key); - gval = export_value_xlat2(framerate_xlat, lin_val, G_TYPE_STRING); + gval = export_value_video_framerate(lin_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); key = "PictureDetelecine"; @@ -2474,7 +2400,7 @@ export_value_xlat(GValue *dict) key = "AudioEncoderFallback"; lin_val = ghb_dict_lookup(dict, key); - gval = export_value_xlat2(acodec_xlat, lin_val, G_TYPE_STRING); + gval = export_value_audio_encoder(lin_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); @@ -2490,17 +2416,17 @@ export_value_xlat(GValue *dict) ghb_dict_insert(adict, g_strdup(key), gval); key = "AudioEncoder"; lin_val = ghb_dict_lookup(adict, key); - gval = export_value_xlat2(acodec_xlat, lin_val, G_TYPE_STRING); + gval = export_value_audio_encoder(lin_val); if (gval) ghb_dict_insert(adict, g_strdup(key), gval); key = "AudioSamplerate"; lin_val = ghb_dict_lookup(adict, key); - gval = export_value_xlat2(samplerate_xlat, lin_val, G_TYPE_STRING); + gval = export_value_audio_samplerate(lin_val); if (gval) ghb_dict_insert(adict, g_strdup(key), gval); key = "AudioMixdown"; lin_val = ghb_dict_lookup(adict, key); - gval = export_value_xlat2(mix_xlat, lin_val, G_TYPE_STRING); + gval = export_value_mixdown(lin_val); if (gval) ghb_dict_insert(adict, g_strdup(key), gval); } @@ -2579,26 +2505,100 @@ import_value_xlat2( } static GValue* -import_value_xlat_container(GValue *mac_val) +import_value_video_framerate(GValue *mac_val) { GValue *sval = NULL; gchar *str; - const gchar *mux; - int imux; + const gchar *fr; str = ghb_value_string(mac_val); - mux = hb_container_sanitize_name(str); + fr = hb_video_framerate_get_name(hb_video_framerate_get_from_name(str)); g_free(str); - if (mux == NULL) - { - imux = hb_container_get_from_extension("mp4"); - } - else - { - imux = hb_container_get_from_name(mux); - } - mux = hb_container_get_short_name(imux); + if (fr != NULL) + sval = ghb_string_value_new(fr); + + return sval; +} + +static GValue* +import_value_audio_samplerate(GValue *mac_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *sr; + + str = ghb_value_string(mac_val); + sr = hb_audio_samplerate_get_name(hb_audio_samplerate_get_from_name(str)); + g_free(str); + + if (sr != NULL) + sval = ghb_string_value_new(sr); + + return sval; +} + +static GValue* +import_value_mixdown(GValue *mac_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *mix; + + str = ghb_value_string(mac_val); + mix = hb_mixdown_get_short_name(hb_mixdown_get_from_name(str)); + g_free(str); + + if (mix != NULL) + sval = ghb_string_value_new(mix); + + return sval; +} + +static GValue* +import_value_video_encoder(GValue *mac_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *enc; + + str = ghb_value_string(mac_val); + enc = hb_video_encoder_get_short_name(hb_video_encoder_get_from_name(str)); + g_free(str); + + if (enc != NULL) + sval = ghb_string_value_new(enc); + + return sval; +} + +static GValue* +import_value_audio_encoder(GValue *mac_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *enc; + + str = ghb_value_string(mac_val); + enc = hb_audio_encoder_get_short_name(hb_audio_encoder_get_from_name(str)); + g_free(str); + + if (enc != NULL) + sval = ghb_string_value_new(enc); + + return sval; +} + +static GValue* +import_value_container(GValue *mac_val) +{ + GValue *sval = NULL; + gchar *str; + const gchar *mux; + + str = ghb_value_string(mac_val); + mux = hb_container_get_short_name(hb_container_get_from_name(str)); + g_free(str); if (mux != NULL) sval = ghb_string_value_new(mux); @@ -2615,17 +2615,17 @@ import_value_xlat(GValue *dict) defaults = plist_get_dict(internalPlist, "Presets"); key = "VideoEncoder"; mac_val = ghb_dict_lookup(dict, key); - gval = import_value_xlat2(defaults, vcodec_xlat, key, mac_val); + gval = import_value_video_encoder(mac_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); key = "FileFormat"; mac_val = ghb_dict_lookup(dict, key); - gval = import_value_xlat_container(mac_val); + gval = import_value_container(mac_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); key = "VideoFramerate"; mac_val = ghb_dict_lookup(dict, key); - gval = import_value_xlat2(defaults, framerate_xlat, key, mac_val); + gval = import_value_video_framerate(mac_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); key = "PictureDetelecine"; @@ -2725,7 +2725,7 @@ import_value_xlat(GValue *dict) key = "AudioEncoderFallback"; mac_val = ghb_dict_lookup(dict, key); - gval = import_value_xlat2(defaults, acodec_xlat, key, mac_val); + gval = import_value_audio_encoder(mac_val); if (gval) ghb_dict_insert(dict, g_strdup(key), gval); @@ -2745,17 +2745,23 @@ import_value_xlat(GValue *dict) ghb_dict_insert(adict, g_strdup(key), gval); key = "AudioEncoder"; mac_val = ghb_dict_lookup(adict, key); - gval = import_value_xlat2(adefaults, acodec_xlat, key, mac_val); + gval = import_value_audio_encoder(mac_val); + if (gval == NULL) + gval = ghb_value_dup(ghb_dict_lookup(adefaults, key)); if (gval) ghb_dict_insert(adict, g_strdup(key), gval); key = "AudioSamplerate"; mac_val = ghb_dict_lookup(adict, key); - gval = import_value_xlat2(adefaults, samplerate_xlat, key, mac_val); + gval = import_value_audio_samplerate(mac_val); + if (gval == NULL) + gval = ghb_value_dup(ghb_dict_lookup(adefaults, key)); if (gval) ghb_dict_insert(adict, g_strdup(key), gval); key = "AudioMixdown"; mac_val = ghb_dict_lookup(adict, key); - gval = import_value_xlat2(adefaults, mix_xlat, key, mac_val); + gval = import_value_mixdown(mac_val); + if (gval == NULL) + gval = ghb_value_dup(ghb_dict_lookup(adefaults, key)); if (gval) ghb_dict_insert(adict, g_strdup(key), gval); @@ -3381,11 +3387,6 @@ update_standard_presets(signal_user_data_t *ud) void ghb_presets_load(signal_user_data_t *ud) { - // Create translation tables from libhb tables - mix_xlat = create_mix_xlat_tbl(mix_xlat_compat); - acodec_xlat = create_audio_encoder_xlat_tbl(acodec_xlat_compat); - vcodec_xlat = create_video_encoder_xlat_tbl(vcodec_xlat_compat); - presetsPlist = load_plist("presets"); if (presetsPlist == NULL) { diff --git a/gtk/src/standard_presets.xml b/gtk/src/standard_presets.xml index f73475bd8..989f892de 100644 --- a/gtk/src/standard_presets.xml +++ b/gtk/src/standard_presets.xml @@ -1266,13 +1266,146 @@ x264UseAdvancedOptions 0 + + AudioAllowAACPass + 1 + AudioAllowAC3Pass + 1 + AudioAllowDTSHDPass + 1 + AudioAllowDTSPass + 1 + AudioAllowMP3Pass + 1 + AudioEncoderFallback + AC3 (ffmpeg) + AudioList + + + AudioBitrate + 128 + AudioEncoder + AAC (faac) + AudioMixdown + Dolby Pro Logic II + AudioSamplerate + Auto + AudioTrack + 1 + AudioTrackDRCSlider + 0.0 + AudioTrackGainSlider + 0.0 + + + ChapterMarkers + 0 + Default + 0 + FileFormat + MP4 file + Folder + + Mp4HttpOptimize + 0 + Mp4LargeFile + 0 + Mp4iPodCompatible + 0 + PictureAutoCrop + 1 + PictureBottomCrop + 0 + PictureDeblock + 0 + PictureDecomb + 0 + PictureDecombCustom + + PictureDecombDeinterlace + 1 + PictureDeinterlace + 0 + PictureDeinterlaceCustom + + PictureDenoise + 0 + PictureDenoiseCustom + + PictureDetelecine + 0 + PictureDetelecineCustom + + PictureHeight + 720 + PictureKeepRatio + 0 + PictureLeftCrop + 0 + PictureModulus + 2 + PicturePAR + 2 + PictureRightCrop + 0 + PictureTopCrop + 0 + PictureWidth + 1280 + PresetDescription + HandBrake's preset for Windows Phone 8 devices + PresetName + Windows Phone 8 + Subtitles + None + Type + 0 + UsesPictureFilters + 1 + UsesPictureSettings + 1 + VideoAvgBitrate + 2500 + VideoEncoder + H.264 (x264) + VideoFramerate + 30 + VideoFramerateMode + pfr + VideoGrayScale + 0 + VideoQualitySlider + 22 + VideoQualityType + 2 + VideoTurboTwoPass + 0 + VideoTwoPass + 0 + h264Level + 3.1 + h264Profile + main + lavcOption + + x264Option + + x264OptionExtra + + x264Preset + medium + x264Tune + + x264UseAdvancedOptions + 0 + Default 0 Folder PresetBuildNumber - 2013030401 + 2013061301 PresetName Devices Type @@ -1569,7 +1702,7 @@ Folder PresetBuildNumber - 2013030401 + 2013061301 PresetName Regular Type diff --git a/libhb/common.c b/libhb/common.c index 074d2a135..225bc9c2b 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -153,10 +153,10 @@ hb_mixdown_t *hb_audio_mixdowns_first_item = NULL; hb_mixdown_t *hb_audio_mixdowns_last_item = NULL; hb_mixdown_internal_t hb_audio_mixdowns[] = { - // legacy mixdowns (disabled) - { { "AC3 Passthru", "ac3pass", HB_AMIXDOWN_NONE, }, NULL, 0, }, - { { "DTS Passthru", "dtspass", HB_AMIXDOWN_NONE, }, NULL, 0, }, - { { "DTS-HD Passthru", "dtshdpass", HB_AMIXDOWN_NONE, }, NULL, 0, }, + // legacy mixdowns, back to HB 0.9.4 whenever possible (disabled) + { { "AC3 Passthru", "", HB_AMIXDOWN_NONE, }, NULL, 0, }, + { { "DTS Passthru", "", HB_AMIXDOWN_NONE, }, NULL, 0, }, + { { "DTS-HD Passthru", "", HB_AMIXDOWN_NONE, }, NULL, 0, }, { { "6-channel discrete", "6ch", HB_AMIXDOWN_5POINT1, }, NULL, 0, }, // actual mixdowns { { "None", "none", HB_AMIXDOWN_NONE, }, NULL, 1, }, @@ -184,22 +184,17 @@ hb_encoder_t *hb_video_encoders_first_item = NULL; hb_encoder_t *hb_video_encoders_last_item = NULL; hb_encoder_internal_t hb_video_encoders[] = { - // legacy encoders, all the way back to HB 0.7.1 (disabled) - { { "x264 (Main profile)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "x264 (Baseline profile)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "x264 (h.264 Main)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "x264 (h.264 iPod)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "", "x264b13", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "", "x264b30", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "XviD", "xvid", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, - { { "MPEG-4 (XviD)", "", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, + // legacy encoders, back to HB 0.9.4 whenever possible (disabled) { { "FFmpeg", "ffmpeg", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, + { { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, + { { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG2, }, + { { "VP3 (Theora)", "libtheora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_THEORA, }, // actual encoders { { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, { { "H.264 (Intel QSV)", "qsv_h264",HB_VCODEC_QSV_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, - { { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4, }, - { { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2, }, - { { "VP3 (Theora)", "theora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_THEORA, }, + { { "MPEG-4", "mpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4, }, + { { "MPEG-2", "mpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2, }, + { { "Theora", "theora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_THEORA, }, }; int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_video_encoders[0]); static int hb_video_encoder_is_enabled(int encoder) @@ -227,28 +222,31 @@ hb_encoder_t *hb_audio_encoders_first_item = NULL; hb_encoder_t *hb_audio_encoders_last_item = NULL; hb_encoder_internal_t hb_audio_encoders[] = { - // legacy encoders (disabled) - { { "AC3", "ac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AC3, }, - { { "AC3 (pass-thru)", "ac3pass", HB_ACODEC_AC3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AC3_PASS, }, - { { "DTS (pass-thru)", "dtspass", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_DTS_PASS, }, + // legacy encoders, back to HB 0.9.4 whenever possible (disabled) { { "", "dts", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_DTS_PASS, }, + { { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AAC, }, + { { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AC3, }, + { { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_MP3, }, + { { "Vorbis (vorbis)", "libvorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_VORBIS, }, + { { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, }, + { { "FLAC (24-bit)", "ffflac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, }, // actual encoders { { "AAC (CoreAudio)", "ca_aac", HB_ACODEC_CA_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "HE-AAC (CoreAudio)", "ca_haac", HB_ACODEC_CA_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_HE, }, + { { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, + { { "AAC (avcodec)", "av_aac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "AAC (FDK)", "fdk_aac", HB_ACODEC_FDK_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "HE-AAC (FDK)", "fdk_haac", HB_ACODEC_FDK_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_HE, }, - { { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, - { { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "AAC Passthru", "copy:aac", HB_ACODEC_AAC_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_PASS, }, - { { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AC3, }, + { { "AC3", "ac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AC3, }, { { "AC3 Passthru", "copy:ac3", HB_ACODEC_AC3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AC3_PASS, }, { { "DTS Passthru", "copy:dts", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_DTS_PASS, }, { { "DTS-HD Passthru", "copy:dtshd", HB_ACODEC_DCA_HD_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_DTSHD_PASS, }, - { { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3, }, + { { "MP3", "mp3", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3, }, { { "MP3 Passthru", "copy:mp3", HB_ACODEC_MP3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3_PASS, }, - { { "Vorbis (vorbis)", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_VORBIS, }, - { { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, - { { "FLAC (24-bit)", "ffflac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, + { { "Vorbis", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_VORBIS, }, + { { "FLAC 16-bit", "flac16", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, + { { "FLAC 24-bit", "flac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, { { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AUTO_PASS, }, }; int hb_audio_encoders_count = sizeof(hb_audio_encoders) / sizeof(hb_audio_encoders[0]); @@ -267,12 +265,12 @@ static int hb_audio_encoder_is_enabled(int encoder) return 1; #endif -#if 1 //#ifdef USE_FAAC +#ifdef USE_FAAC case HB_ACODEC_FAAC: return 1; #endif -#if 1 //#ifdef USE_LIBAV_AAC +#ifdef USE_LIBAV_AAC case HB_ACODEC_FFAAC: return 1; #endif @@ -307,11 +305,9 @@ hb_container_t *hb_containers_first_item = NULL; hb_container_t *hb_containers_last_item = NULL; hb_container_internal_t hb_containers[] = { - // legacy muxers (disabled) - { { "AVI file", "avi", "avi", 0, }, NULL, 0, HB_GID_MUX_MP4, }, + // legacy muxers, back to HB 0.9.4 whenever possible (disabled) { { "M4V file", "m4v", "m4v", 0, }, NULL, 0, HB_GID_MUX_MP4, }, { { "MP4 file", "mp4", "mp4", 0, }, NULL, 0, HB_GID_MUX_MP4, }, - { { "OGM file", "ogm", "ogm", 0, }, NULL, 0, HB_GID_MUX_MKV, }, { { "MKV file", "mkv", "mkv", 0, }, NULL, 0, HB_GID_MUX_MKV, }, // actual muxers { { "MPEG-4 (mp4v2)", "mp4v2", "mp4", HB_MUX_MP4V2, }, NULL, 1, HB_GID_MUX_MP4, }, @@ -1320,7 +1316,6 @@ int hb_mixdown_has_codec_support(int mixdown, uint32_t codec) return (mixdown <= HB_AMIXDOWN_7POINT1); case HB_ACODEC_LAME: - case HB_ACODEC_FFAAC: return (mixdown <= HB_AMIXDOWN_DOLBYPLII); case HB_ACODEC_FAAC: diff --git a/libhb/dvd.c b/libhb/dvd.c index 56c1ba571..240582a52 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -173,8 +173,6 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur ifo_handle_t * vts = NULL; int pgc_id, pgn, i; hb_chapter_t * chapter; - uint64_t duration; - float duration_correction; unsigned char unused[1024]; const char * codec_name; @@ -609,19 +607,9 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur hb_list_add( title->list_chapter, chapter ); } - /* The durations we get for chapters aren't precise. Scale them so - the total matches the title duration */ - duration = 0; - for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) - { - chapter = hb_list_item( title->list_chapter, i ); - duration += chapter->duration; - } - duration_correction = (float) title->duration / (float) duration; for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) { chapter = hb_list_item( title->list_chapter, i ); - chapter->duration = duration_correction * chapter->duration; int seconds = ( chapter->duration + 45000 ) / 90000; chapter->hours = ( seconds / 3600 ); @@ -1270,8 +1258,8 @@ static int dvdtime2msec(dvd_time_t * dt) if( fps > 0 ) { - ms += ((dt->frame_u & 0x30) >> 3) * 5 + - (dt->frame_u & 0x0f) * 1000.0 / fps; + ms += (((dt->frame_u & 0x30) >> 3) * 5 + + (dt->frame_u & 0x0f)) * 1000.0 / fps; } return ms; diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 9217f7dba..ef80bf541 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -318,7 +318,6 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura int count; uint64_t duration, longest; int longest_pgcn, longest_pgn, longest_pgcn_end; - float duration_correction; const char * name; const char * codec_name; @@ -758,7 +757,6 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura hb_log( "scan: title %d has %d chapters", t, c ); - duration = 0; count = hb_list_count( title->list_chapter ); for (i = 0; i < count; i++) { @@ -797,16 +795,11 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura #undef cp cell_cur = FindNextCell( pgc, cell_cur ); } - duration += chapter->duration; } - /* The durations we get for chapters aren't precise. Scale them so - the total matches the title duration */ - duration_correction = (float) title->duration / (float) duration; for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) { chapter = hb_list_item( title->list_chapter, i ); - chapter->duration = duration_correction * chapter->duration; int seconds = ( chapter->duration + 45000 ) / 90000; chapter->hours = ( seconds / 3600 ); @@ -1979,7 +1972,7 @@ static int NextPgcn( ifo_handle_t *ifo, int pgcn, uint32_t pgcn_map[MAX_PGCN/32] **********************************************************************/ static void PgcWalkInit( uint32_t pgcn_map[MAX_PGCN/32] ) { - memset(pgcn_map, 0, sizeof(pgcn_map) ); + memset(pgcn_map, 0, sizeof(uint32_t) * MAX_PGCN/32); } /*********************************************************************** @@ -1998,8 +1991,8 @@ static int dvdtime2msec(dvd_time_t * dt) if( fps > 0 ) { - ms += ((dt->frame_u & 0x30) >> 3) * 5 + - (dt->frame_u & 0x0f) * 1000.0 / fps; + ms += (((dt->frame_u & 0x30) >> 3) * 5 + + (dt->frame_u & 0x0f)) * 1000.0 / fps; } return ms; diff --git a/libhb/encfaac.c b/libhb/encfaac.c index ffdddc8d4..3bdd7cee0 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -7,6 +7,7 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ +#ifdef USE_FAAC #include "hb.h" #include "audio_remap.h" @@ -286,4 +287,4 @@ int encfaacWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_OK; } - +#endif // USE_FAAC diff --git a/libhb/hb.c b/libhb/hb.c index 6fbb60fb5..4c2eb32e4 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -666,9 +666,6 @@ hb_handle_t * hb_init( int verbose, int update_check ) h->interjob = calloc( sizeof( hb_interjob_t ), 1 ); - /* libavcodec */ - hb_avcodec_init(); - #ifdef USE_QSV /* Intel Quick Sync Video */ hb_qsv_info_print(); @@ -679,37 +676,6 @@ hb_handle_t * hb_init( int verbose, int update_check ) h->die = 0; h->main_thread = hb_thread_init( "libhb", thread_func, h, HB_NORMAL_PRIORITY ); - hb_register( &hb_sync_video ); - hb_register( &hb_sync_audio ); - hb_register( &hb_decmpeg2 ); - hb_register( &hb_decvobsub ); - hb_register( &hb_encvobsub ); - hb_register( &hb_deccc608 ); - hb_register( &hb_decsrtsub ); - hb_register( &hb_decutf8sub ); - hb_register( &hb_dectx3gsub ); - hb_register( &hb_decssasub ); - hb_register( &hb_decpgssub ); - hb_register( &hb_encavcodec ); - hb_register( &hb_encx264 ); -#ifdef USE_QSV - hb_register(&hb_encqsv); -#endif - hb_register( &hb_enctheora ); - hb_register( &hb_deca52 ); - hb_register( &hb_decavcodeca ); - hb_register( &hb_decavcodecv ); - hb_register( &hb_declpcm ); - hb_register( &hb_encfaac ); - hb_register( &hb_enclame ); - hb_register( &hb_encvorbis ); - hb_register( &hb_muxer ); -#ifdef __APPLE__ - hb_register( &hb_encca_aac ); - hb_register( &hb_encca_haac ); -#endif - hb_register( &hb_encavcodeca ); - hb_register( &hb_reader ); return h; } @@ -775,9 +741,6 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) h->pause_lock = hb_lock_init(); - /* libavcodec */ - hb_avcodec_init(); - #ifdef USE_QSV /* Intel Quick Sync Video */ hb_qsv_info_print(); @@ -789,37 +752,6 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) h->main_thread = hb_thread_init( "libhb", thread_func, h, HB_NORMAL_PRIORITY ); - hb_register( &hb_sync_video ); - hb_register( &hb_sync_audio ); - hb_register( &hb_decmpeg2 ); - hb_register( &hb_decvobsub ); - hb_register( &hb_encvobsub ); - hb_register( &hb_deccc608 ); - hb_register( &hb_decsrtsub ); - hb_register( &hb_decutf8sub ); - hb_register( &hb_dectx3gsub ); - hb_register( &hb_decssasub ); - hb_register( &hb_encavcodec ); - hb_register( &hb_encx264 ); -#ifdef USE_QSV - hb_register(&hb_encqsv); -#endif - hb_register( &hb_enctheora ); - hb_register( &hb_deca52 ); - hb_register( &hb_decavcodeca ); - hb_register( &hb_decavcodecv ); - hb_register( &hb_declpcm ); - hb_register( &hb_encfaac ); - hb_register( &hb_enclame ); - hb_register( &hb_encvorbis ); - hb_register( &hb_muxer ); -#ifdef __APPLE__ - hb_register( &hb_encca_aac ); - hb_register( &hb_encca_haac ); -#endif - hb_register( &hb_encavcodeca ); - hb_register( &hb_reader ); - return h; } @@ -1926,6 +1858,46 @@ int hb_global_init() return -1; } + /* libavcodec */ + hb_avcodec_init(); + + /* HB work objects */ + hb_register(&hb_muxer); + hb_register(&hb_reader); + hb_register(&hb_sync_video); + hb_register(&hb_sync_audio); +ifdef USE_QSV + hb_register(&hb_encqsv); +#endif + hb_register(&hb_deca52); + hb_register(&hb_decavcodecv); + hb_register(&hb_decavcodeca); + hb_register(&hb_declpcm); + hb_register(&hb_deccc608); + hb_register(&hb_decmpeg2); + hb_register(&hb_decpgssub); + hb_register(&hb_decsrtsub); + hb_register(&hb_decssasub); + hb_register(&hb_dectx3gsub); + hb_register(&hb_decutf8sub); + hb_register(&hb_decvobsub); + hb_register(&hb_encvobsub); + hb_register(&hb_encavcodec); + hb_register(&hb_encavcodeca); +#ifdef __APPLE__ + hb_register(&hb_encca_aac); + hb_register(&hb_encca_haac); +#endif +#ifdef USE_FAAC + hb_register(&hb_encfaac); +#endif + hb_register(&hb_enclame); + hb_register(&hb_enctheora); + hb_register(&hb_encvorbis); + hb_register(&hb_encx264); + + hb_common_global_init(); + #ifdef USE_QSV result = hb_qsv_info_init(); if (result < 0) @@ -1935,8 +1907,6 @@ int hb_global_init() } #endif - hb_common_global_init(); - return result; } diff --git a/libhb/module.defs b/libhb/module.defs index 7b9073134..24e2a6ebe 100644 --- a/libhb/module.defs +++ b/libhb/module.defs @@ -45,7 +45,12 @@ endif ifeq (1,$(FEATURE.fdk_aac)) LIBHB.GCC.D += USE_FDK_AAC endif - +ifeq (1,$(FEATURE.libav_aac)) +LIBHB.GCC.D += USE_LIBAV_AAC +endif +ifeq (1,$(FEATURE.faac)) +LIBHB.GCC.D += USE_FAAC +endif LIBHB.GCC.D += __LIBHB__ USE_PTHREAD LIBHB.GCC.D += __LIBHB__ USE_PTHREAD HAVE_THREADS=1 LIBHB.GCC.I += $(LIBHB.build/) $(CONTRIB.build/)include @@ -106,7 +111,7 @@ LIBHB.dll = $(LIBHB.build/)hb.dll LIBHB.lib = $(LIBHB.build/)hb.lib LIBHB.dll.libs = $(foreach n, \ - a52 ass avcodec avformat avutil avresample dvdnav dvdread faac \ + a52 ass avcodec avformat avutil avresample dvdnav dvdread \ fontconfig freetype mkv mpeg2 mp3lame mp4v2 \ ogg samplerate swscale theora vorbis vorbisenc x264 xml2 bluray, \ $(CONTRIB.build/)lib/lib$(n).a ) @@ -115,6 +120,10 @@ ifeq (1,$(FEATURE.fdk_aac)) LIBHB.dll.libs += $(CONTRIB.build/)lib/libfdk-aac.a endif +ifeq (1,$(FEATURE.faac)) +LIBHB.dll.libs += $(CONTRIB.build/)lib/libfaac.a +endif + ifeq (1,$(FEATURE.qsv)) LIBHB.dll.libs += $(CONTRIB.build/)lib/libmfx.a endif diff --git a/libhb/sync.c b/libhb/sync.c index 6b2f65b90..dee737c19 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -273,7 +273,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { pv->common->first_pts[0] = next->s.start; hb_lock( pv->common->mutex ); - while( pv->common->pts_offset == INT64_MIN ) + while( pv->common->pts_offset == INT64_MIN && !*w->done ) { // Full fifos will make us wait forever, so get the // pts offset from the available streams if full @@ -765,7 +765,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { pv->common->first_pts[sync->index+1] = buf->s.start; hb_lock( pv->common->mutex ); - while( pv->common->pts_offset == INT64_MIN ) + while( pv->common->pts_offset == INT64_MIN && !*w->done) { // Full fifos will make us wait forever, so get the // pts offset from the available streams if full @@ -785,7 +785,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, /* Wait for start frame if doing point-to-point */ hb_lock( pv->common->mutex ); start = buf->s.start - pv->common->audio_pts_slip; - while ( !pv->common->start_found ) + while ( !pv->common->start_found && !*w->done ) { if ( pv->common->audio_pts_thresh < 0 ) { @@ -801,7 +801,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_OK; } while ( !pv->common->start_found && - buf->s.start >= pv->common->audio_pts_thresh ) + buf->s.start >= pv->common->audio_pts_thresh && !*w->done ) { hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 10 ); // There is an unfortunate unavoidable deadlock that can occur. diff --git a/macosx/English.lproj/Preferences.xib b/macosx/English.lproj/Preferences.xib index ab9a908bf..405e613fd 100644 --- a/macosx/English.lproj/Preferences.xib +++ b/macosx/English.lproj/Preferences.xib @@ -2,31 +2,31 @@ 1050 - 11G63 - 1938 - 1138.51 - 569.00 + 12D78 + 3084 + 1187.37 + 626.00 com.apple.InterfaceBuilder.CocoaPlugin - 1938 + 3084 YES - NSPopUpButtonCell - NSComboBoxCell - NSPopUpButton NSButton - NSMenu - NSTextFieldCell NSButtonCell - NSMenuItem NSComboBox - NSCustomView + NSComboBoxCell NSCustomObject - NSView - NSWindowTemplate + NSCustomView + NSMenu + NSMenuItem + NSPopUpButton + NSPopUpButtonCell NSTextField + NSTextFieldCell NSUserDefaultsController + NSView + NSWindowTemplate YES @@ -64,8 +64,6 @@ 256 {500, 200} - - {{0, 0}, {1440, 878}} {213, 129} @@ -76,7 +74,7 @@ YES - + 256 YES @@ -88,7 +86,7 @@ YES - -2076049856 + -2076180416 133120 LucidaGrande @@ -96,7 +94,7 @@ 3100 - 109199615 + 109199360 129 @@ -194,6 +192,7 @@ YES 2 + NO @@ -203,12 +202,12 @@ YES - -2080244224 + -2080374784 131072 Play System Alert Sound - 1211912703 + 1211912448 2 NSImage @@ -222,6 +221,7 @@ 200 25 + NO @@ -231,7 +231,7 @@ YES - 67239424 + 67108864 134479872 Browse ... @@ -240,13 +240,14 @@ 3614 - -2038284033 + -2038284288 129 200 25 + NO @@ -256,7 +257,7 @@ YES - 68288064 + 68157504 272761856 None @@ -280,6 +281,7 @@ + NO @@ -289,12 +291,12 @@ YES - 67239424 + 67108864 131072 Show Presets Drawer - 1211912703 + 1211912448 2 @@ -302,6 +304,7 @@ 200 25 + NO @@ -311,12 +314,12 @@ YES - 67239424 + 67108864 131072 Use Auto Naming (uses DVD name and title number) - 1211912703 + 1211912448 2 @@ -324,6 +327,7 @@ 200 25 + NO @@ -333,7 +337,7 @@ YES - 67239424 + 67108864 272760832 When Done: @@ -341,6 +345,7 @@ + NO @@ -350,12 +355,12 @@ YES - 67239424 + 67108864 131072 Automatically check for updates - 1211912703 + 1211912448 2 @@ -363,6 +368,7 @@ 200 25 + NO @@ -372,12 +378,12 @@ YES - 67239424 + 67108864 131072 Send file to: - 1211912703 + 1211912448 2 @@ -386,6 +392,7 @@ 200 25 + NO @@ -395,7 +402,7 @@ YES - 67239424 + 67108864 272760832 At launch: @@ -403,6 +410,7 @@ + NO @@ -412,7 +420,7 @@ YES - 67239424 + 67108864 71434240 Default MP4 Extension: @@ -420,6 +428,7 @@ + NO @@ -429,7 +438,7 @@ YES - 67239424 + 67108864 71434240 Source selection: @@ -437,6 +446,7 @@ + NO @@ -446,7 +456,7 @@ YES - 67239424 + 67108864 272760832 Output files: @@ -454,6 +464,7 @@ + NO @@ -462,11 +473,11 @@ YES - 71433792 + 71303232 264192 - 109199615 + 109199360 1 LucidaGrande @@ -528,6 +539,7 @@ YES 1 + NO @@ -537,11 +549,11 @@ YES - 71433792 + 71303232 133120 - 109199615 + 109199360 1 LucidaGrande @@ -607,6 +619,7 @@ YES 1 + NO @@ -616,11 +629,11 @@ YES - 71433792 + 71303232 133120 - 109199615 + 109199360 1 @@ -679,9 +692,11 @@ YES 1 + NO {460, 256} + NSView NSControl @@ -696,11 +711,9 @@ 268 {{34, 42}, {432, 17}} - - YES - 67239488 + 67108928 138413056 Nothing here right now, but I am sure we will think of something @@ -708,11 +721,11 @@ + NO {496, 82} - NSView NSResponder @@ -731,7 +744,7 @@ YES - 67239424 + 67108864 272760832 Alternate Language: @@ -739,6 +752,7 @@ + NO @@ -746,10 +760,10 @@ {{169, 87}, {247, 22}} - + YES - 343014976 + 342884416 272761856 @@ -943,6 +957,8 @@ YES + NO + YES YES @@ -950,7 +966,7 @@ 10 1000 - 75628032 + 75497472 0 @@ -967,7 +983,7 @@ - 338820672 + 338690112 1024 @@ -1011,6 +1027,7 @@ 1 + NO @@ -1021,7 +1038,7 @@ YES - 67239424 + 67108864 272760832 Native Language: @@ -1029,24 +1046,7 @@ - - - - 256 - {{90, 55}, {31, 14}} - - - - YES - - 67239424 - 272760832 - AAC: - - - - - + NO @@ -1057,7 +1057,7 @@ YES - 343014976 + 342884416 272761856 English @@ -1243,6 +1243,8 @@ YES + NO + YES YES @@ -1250,7 +1252,7 @@ 10 1000 - 75628032 + 75497472 0 @@ -1263,7 +1265,7 @@ - 338820672 + 338690112 1024 @@ -1294,22 +1296,22 @@ 1 + NO 256 - {{91, 18}, {292, 26}} + {{122, 45}, {248, 26}} - YES - 67239424 + 67108864 0 Show advanced options for Auto Passthru - 1211912703 + 1211912448 2 @@ -1317,30 +1319,7 @@ 200 25 - - - - 268 - {{123, 53}, {333, 18}} - - - - YES - - -2080244224 - 131072 - Use CoreAudio instead of FAAC for Built-In Presets - - - 1211912703 - 130 - - - - - 200 - 25 - + NO {492, 157} @@ -1353,7 +1332,7 @@ NSResponder - + 256 YES @@ -1362,11 +1341,10 @@ 268 {{302, 172}, {48, 19}} - YES - -1804468671 + -1804599231 272761856 @@ -1380,17 +1358,17 @@ + NO 256 {{17, 207}, {280, 14}} - YES - 67239424 + 67108864 71434240 x264 Constant Quality fractional granularity: @@ -1398,17 +1376,17 @@ + NO 256 {{48, 175}, {249, 14}} - YES - 67239424 + 67108864 71434240 Minimum length of title to scan (seconds): @@ -1416,17 +1394,17 @@ + NO 256 {{99, 145}, {198, 14}} - YES - 67239424 + 67108864 71434240 Number of picture previews to scan: @@ -1434,17 +1412,17 @@ + NO 256 {{137, 53}, {160, 15}} - YES - 67239424 + 67108864 4325376 Activity Log Verbosity Level: @@ -1452,17 +1430,17 @@ + NO 256 {{108, 76}, {27, 14}} - YES - 67239424 + 67108864 272760832 Log: @@ -1470,17 +1448,17 @@ + NO 256 {{70, 110}, {65, 14}} - YES - 67239424 + 67108864 272760832 Dvd-Video: @@ -1488,22 +1466,22 @@ + NO 256 {{137, 74}, {304, 18}} - YES - 67239424 + 67108864 131072 Put individual encode logs in same location as movie - 1211912703 + 1211912448 2 @@ -1511,22 +1489,22 @@ 200 25 + NO 256 {{137, 108}, {220, 18}} - YES - 67239424 + 67108864 131072 Use libdvdnav (instead of libdvdread) - 1211912703 + 1211912448 2 @@ -1534,22 +1512,21 @@ 200 25 + NO 256 {{137, 18}, {217, 18}} - - YES - 67239424 + 67108864 131072 Alert when updating built-in presets - 1211912703 + 1211912448 2 @@ -1557,43 +1534,44 @@ 200 25 + NO 268 {{299, 140}, {73, 22}} - YES - -2076049856 + -2076180416 133120 - 109199615 + 109199360 129 400 75 - + + + 10 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + YES OtherViews YES - - - 10 - - 1048576 - 2147483647 - - - _popUpItemAction: - - + 15 @@ -1704,21 +1682,21 @@ YES 2 + NO 268 {{299, 202}, {76, 22}} - YES - -2076049856 + -2076180416 133120 - 109199615 + 109199360 129 @@ -1781,21 +1759,21 @@ YES 2 + NO 268 {{303, 49}, {66, 22}} - YES - -2076049856 + -2076180416 133120 - 109199615 + 109199360 129 @@ -1849,17 +1827,17 @@ YES 2 + NO 256 {{89, 20}, {46, 14}} - YES - 67239424 + 67108864 272760832 Presets: @@ -1867,11 +1845,10 @@ + NO {495, 241} - - NSView @@ -2173,22 +2150,6 @@ 403 - - - value: values.UseCoreAudio - - - - - - value: values.UseCoreAudio - value - values.UseCoreAudio - 2 - - - 409 - enabled: automaticallyChecksForUpdates @@ -2478,9 +2439,7 @@ - - Audio @@ -2942,20 +2901,6 @@ - - 406 - - - YES - - - - - - 407 - - - 410 @@ -3034,20 +2979,6 @@ - - 446 - - - YES - - - - - - 447 - - - 448 @@ -3344,8 +3275,6 @@ 399.IBPluginDependency 401.IBPluginDependency 402.IBPluginDependency - 406.IBPluginDependency - 407.IBPluginDependency 410.IBPluginDependency 414.IBPluginDependency 415.IBPluginDependency @@ -3357,8 +3286,6 @@ 443.IBPluginDependency 444.IBPluginDependency 445.IBPluginDependency - 446.IBPluginDependency - 447.IBPluginDependency 448.IBPluginDependency 449.IBPluginDependency 450.IBPluginDependency @@ -3397,7 +3324,7 @@ 6.IBPluginDependency 61.IBPluginDependency - + YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3510,10 +3437,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin {{69, 656}, {500, 200}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3570,7 +3493,7 @@ fPictureView fSendEncodeToAppField - + YES NSView NSView @@ -3589,7 +3512,7 @@ fPictureView fSendEncodeToAppField - + YES fAdvancedView @@ -3670,7 +3593,7 @@ NSMenuMixedState NSSwitch - + YES {11, 11} {10, 3} diff --git a/macosx/HBAudioController.m b/macosx/HBAudioController.m index 52cc8284b..30a2f5e95 100644 --- a/macosx/HBAudioController.m +++ b/macosx/HBAudioController.m @@ -295,19 +295,8 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification"; [newAudio setVideoContainerTag: [self videoContainerTag]]; [newAudio setTrackFromIndex: trackIndex]; - // map faac to ca_aac for built-in presets (can be disabled in preferences) - if (0 == aType && - [[NSUserDefaults standardUserDefaults] boolForKey:@"UseCoreAudio"] && - [[dict objectForKey:@"AudioEncoder"] isEqualToString:@"AAC (faac)"]) - { - key = @"AAC (CoreAudio)"; - } - else - { - key = [dict objectForKey:@"AudioEncoder"]; - } - // map legacy encoder names via libhb + key = [dict objectForKey:@"AudioEncoder"]; if (key != nil) { const char *name; diff --git a/macosx/HBPreferencesController.m b/macosx/HBPreferencesController.m index 4e5baccd1..82bdc4d7b 100644 --- a/macosx/HBPreferencesController.m +++ b/macosx/HBPreferencesController.m @@ -45,7 +45,6 @@ @"YES", @"CheckForUpdates", @"Open Source", @"LaunchSourceBehavior", @"English", @"DefaultLanguage", - @"YES", @"UseCoreAudio", @"Auto", @"DefaultMpegExtension", @"YES", @"UseDvdNav", @"", @"DefAdvancedx264Flags", diff --git a/macosx/HBPresets.m b/macosx/HBPresets.m index 0281a4365..a97284b11 100644 --- a/macosx/HBPresets.m +++ b/macosx/HBPresets.m @@ -60,6 +60,7 @@ [childrenArray addObject:[self createAppleTV3Preset]]; [childrenArray addObject:[self createAndroidPreset]]; [childrenArray addObject:[self createAndroidTabletPreset]]; + [childrenArray addObject:[self createW8PhonePreset]]; /* Add the individual presets to the folder */ [preset setObject:[NSMutableArray arrayWithArray:childrenArray] @@ -1081,6 +1082,110 @@ return preset; } +- (NSDictionary *)createW8PhonePreset +{ + NSMutableDictionary *preset = [[NSMutableDictionary alloc] init]; + + /* Preset properties (name, type: factory/user, default, folder, tooltip) */ + [preset setObject:@"Windows Phone 8" forKey:@"PresetName"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"Type"]; //factory + [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; + [preset setObject:[NSNumber numberWithBool:NO] forKey:@"Folder"]; + [preset setObject:@"HandBrake's preset for Windows Phone 8 devices" + forKey:@"PresetDescription"]; + + /* Container format and related settings */ + [preset setObject:@"MP4 file" forKey:@"FileFormat"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"Mp4LargeFile"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"Mp4HttpOptimize"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"Mp4iPodCompatible"]; + + /* Chapter markers */ + [preset setObject:[NSNumber numberWithInt:0] forKey:@"ChapterMarkers"]; + + /* Video encoder and advanced options */ + [preset setObject:@"H.264 (x264)" forKey:@"VideoEncoder"]; + [preset setObject:@"" forKey:@"lavcOption"]; + [preset setObject:@"" forKey:@"x264Option"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"x264UseAdvancedOptions"]; + [preset setObject:@"medium" forKey:@"x264Preset"]; + [preset setObject:@"" forKey:@"x264Tune"]; + [preset setObject:@"" forKey:@"x264OptionExtra"]; + [preset setObject:@"main" forKey:@"h264Profile"]; + [preset setObject:@"3.1" forKey:@"h264Level"]; + + /* Video rate control */ + [preset setObject:@"2500" forKey:@"VideoAvgBitrate"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoTwoPass"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoTurboTwoPass"]; + [preset setObject:[NSNumber numberWithInt:2] forKey:@"VideoQualityType"]; //cq + [preset setObject:[NSNumber numberWithFloat:22.0] forKey:@"VideoQualitySlider"]; + + /* Video frame rate */ + [preset setObject:@"30" forKey:@"VideoFramerate"]; + [preset setObject:@"pfr" forKey:@"VideoFramerateMode"]; + + /* Picture size */ + [preset setObject:[NSNumber numberWithInt:1] forKey:@"UsesPictureSettings"]; + [preset setObject:[NSNumber numberWithInt:1280] forKey:@"PictureWidth"]; + [preset setObject:[NSNumber numberWithInt:720] forKey:@"PictureHeight"]; + [preset setObject:[NSNumber numberWithInt:2] forKey:@"PicturePAR"]; //loose + [preset setObject:[NSNumber numberWithInt:2] forKey:@"PictureModulus"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureKeepRatio"]; //set to 0 for Loose (FIXME: why?) + + /* Picture filters */ + [preset setObject:[NSNumber numberWithInt:1] forKey:@"UsesPictureFilters"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDecomb"]; //off + [preset setObject:@"" forKey:@"PictureDecombCustom"]; + [preset setObject:[NSNumber numberWithInt:1] forKey:@"PictureDecombDeinterlace"]; //decomb + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDeinterlace"]; + [preset setObject:@"" forKey:@"PictureDeinterlaceCustom"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDetelecine"]; + [preset setObject:@"" forKey:@"PictureDetelecineCustom"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDenoise"]; + [preset setObject:@"" forKey:@"PictureDenoiseCustom"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureDeblock"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"VideoGrayScale"]; + + /* Picture crop */ + [preset setObject:[NSNumber numberWithInt:1] forKey:@"PictureAutoCrop"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureTopCrop"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureBottomCrop"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureLeftCrop"]; + [preset setObject:[NSNumber numberWithInt:0] forKey:@"PictureRightCrop"]; + + /* Auto Passthru */ + [preset setObject:@"AC3 (ffmpeg)" forKey:@"AudioEncoderFallback"]; + [preset setObject:[NSNumber numberWithInt:1] forKey:@"AudioAllowAACPass"]; + [preset setObject:[NSNumber numberWithInt:1] forKey:@"AudioAllowAC3Pass"]; + [preset setObject:[NSNumber numberWithInt:1] forKey:@"AudioAllowDTSHDPass"]; + [preset setObject:[NSNumber numberWithInt:1] forKey:@"AudioAllowDTSPass"]; + [preset setObject:[NSNumber numberWithInt:1] forKey:@"AudioAllowMP3Pass"]; + + /* Audio track list - no need to add "None" at the end */ + NSMutableArray *audioListArray = [[NSMutableArray alloc] init]; + /* Track 1 */ + NSMutableDictionary *audioTrack1Array = [[NSMutableDictionary alloc] init]; + [audioTrack1Array setObject:[NSNumber numberWithInt:1] forKey:@"AudioTrack"]; + [audioTrack1Array setObject:@"AAC (faac)" forKey:@"AudioEncoder"]; + [audioTrack1Array setObject:@"Dolby Pro Logic II" forKey:@"AudioMixdown"]; + [audioTrack1Array setObject:@"Auto" forKey:@"AudioSamplerate"]; + [audioTrack1Array setObject:@"128" forKey:@"AudioBitrate"]; + [audioTrack1Array setObject:[NSNumber numberWithFloat:0.0] forKey:@"AudioTrackGainSlider"]; + [audioTrack1Array setObject:[NSNumber numberWithFloat:0.0] forKey:@"AudioTrackDRCSlider"]; + [audioTrack1Array autorelease]; + [audioListArray addObject:audioTrack1Array]; + /* Add the audio track(s) to the preset's audio list */ + [preset setObject:[NSMutableArray arrayWithArray:audioListArray] forKey:@"AudioList"]; + + /* Subtitles (note: currently ignored) */ + [preset setObject:@"None" forKey:@"Subtitles"]; + + /* Clean up and return the preset */ + [preset autorelease]; + return preset; +} + - (NSDictionary *)createNormalPreset { NSMutableDictionary *preset = [[NSMutableDictionary alloc] init]; diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index df3329743..6762c87e8 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -92,8 +92,6 @@ 27D6C75014B102DA00B785E4 /* libdvdnav.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72E14B102DA00B785E4 /* libdvdnav.a */; }; 27D6C75114B102DA00B785E4 /* libdvdread.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72F14B102DA00B785E4 /* libdvdread.a */; }; 27D6C75214B102DA00B785E4 /* libdvdread.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72F14B102DA00B785E4 /* libdvdread.a */; }; - 27D6C75314B102DA00B785E4 /* libfaac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73014B102DA00B785E4 /* libfaac.a */; }; - 27D6C75414B102DA00B785E4 /* libfaac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73014B102DA00B785E4 /* libfaac.a */; }; 27D6C75514B102DA00B785E4 /* libfontconfig.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73114B102DA00B785E4 /* libfontconfig.a */; }; 27D6C75614B102DA00B785E4 /* libfontconfig.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73114B102DA00B785E4 /* libfontconfig.a */; }; 27D6C75714B102DA00B785E4 /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73214B102DA00B785E4 /* libfreetype.a */; }; @@ -294,7 +292,6 @@ 27D6C72C14B102DA00B785E4 /* libbluray.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbluray.a; path = external/contrib/lib/libbluray.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72E14B102DA00B785E4 /* libdvdnav.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdvdnav.a; path = external/contrib/lib/libdvdnav.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72F14B102DA00B785E4 /* libdvdread.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdvdread.a; path = external/contrib/lib/libdvdread.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 27D6C73014B102DA00B785E4 /* libfaac.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfaac.a; path = external/contrib/lib/libfaac.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73114B102DA00B785E4 /* libfontconfig.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfontconfig.a; path = external/contrib/lib/libfontconfig.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73214B102DA00B785E4 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = external/contrib/lib/libfreetype.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73314B102DA00B785E4 /* libfribidi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfribidi.a; path = external/contrib/lib/libfribidi.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -368,7 +365,6 @@ 27D6C74C14B102DA00B785E4 /* libbluray.a in Frameworks */, 27D6C75014B102DA00B785E4 /* libdvdnav.a in Frameworks */, 27D6C75214B102DA00B785E4 /* libdvdread.a in Frameworks */, - 27D6C75414B102DA00B785E4 /* libfaac.a in Frameworks */, 27D6C75614B102DA00B785E4 /* libfontconfig.a in Frameworks */, 27D6C75814B102DA00B785E4 /* libfreetype.a in Frameworks */, 27D6C75A14B102DA00B785E4 /* libfribidi.a in Frameworks */, @@ -411,7 +407,6 @@ 27D6C74B14B102DA00B785E4 /* libbluray.a in Frameworks */, 27D6C74F14B102DA00B785E4 /* libdvdnav.a in Frameworks */, 27D6C75114B102DA00B785E4 /* libdvdread.a in Frameworks */, - 27D6C75314B102DA00B785E4 /* libfaac.a in Frameworks */, 27D6C75514B102DA00B785E4 /* libfontconfig.a in Frameworks */, 27D6C75714B102DA00B785E4 /* libfreetype.a in Frameworks */, 27D6C75914B102DA00B785E4 /* libfribidi.a in Frameworks */, @@ -446,7 +441,6 @@ 27D6C72C14B102DA00B785E4 /* libbluray.a */, 27D6C72E14B102DA00B785E4 /* libdvdnav.a */, 27D6C72F14B102DA00B785E4 /* libdvdread.a */, - 27D6C73014B102DA00B785E4 /* libfaac.a */, 27D6C73114B102DA00B785E4 /* libfontconfig.a */, 27D6C73214B102DA00B785E4 /* libfreetype.a */, 27D6C73314B102DA00B785E4 /* libfribidi.a */, diff --git a/macosx/module.defs b/macosx/module.defs index 1870d5fe9..1a2b6f81d 100644 --- a/macosx/module.defs +++ b/macosx/module.defs @@ -26,9 +26,14 @@ MACOSX.map.g.std = debug MACOSX.map.g.max = debug ifeq (1,$(FEATURE.fdk_aac)) -MACOSX.extra_ldflags = OTHER_LDFLAGS='$(abspath $(BUILD))/contrib/lib/libfdk-aac.a' + extra_libs += $(abspath $(BUILD))/contrib/lib/libfdk-aac.a endif +ifeq (1,$(FEATURE.faac)) + extra_libs += $(abspath $(BUILD))/contrib/lib/libfaac.a +endif +MACOSX.extra_ldflags = OTHER_LDFLAGS='$(extra_libs)' + ## xcconfig: must be one of macosx/xcconfig/*.xcconfig MACOSX.xcconfig = $(foreach x,$(XCODE.xcconfig),-xcconfig $(MACOSX.src/)xcconfig/$(x)) MACOSX.sdk = $(foreach sdk,$(GCC.sysroot),-sdk $(sdk)) diff --git a/make/configure.py b/make/configure.py index 8dbe78a56..2cb3d391d 100644 --- a/make/configure.py +++ b/make/configure.py @@ -1179,7 +1179,16 @@ def createCLI(): grp.add_option( '--enable-qsv', default=False, action='store_true', help=h ) h = IfHost( 'enable use of fdk-aac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value - grp.add_option( '--enable-fdk-aac', default=False, action='store_true', help=h ) + grp.add_option( '--enable-fdk-aac', dest="enable_fdk_aac", default=not host.match( '*-*-darwin*' ), action='store_true', help=h ) + grp.add_option( '--disable-fdk-aac', dest="enable_fdk_aac", action='store_false' ) + + h = IfHost( 'enable use of libav aac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-libav-aac', dest="enable_libav_aac", default=not host.match( '*-*-darwin*' ), action='store_true', help=h ) + grp.add_option( '--disable-libav-aac', dest="enable_libav_aac", action='store_false' ) + + h = IfHost( 'enable use of faac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-faac', dest="enable_faac", default=False, action='store_true', help=h ) + grp.add_option( '--disable-faac', dest="enable_faac", action='store_false' ) cli.add_option_group( grp ) @@ -1620,7 +1629,9 @@ int main () doc.add( 'FEATURE.gtk.mingw', int( options.enable_gtk_mingw )) doc.add( 'FEATURE.gst', int( not options.disable_gst )) doc.add( 'FEATURE.ff.mpeg2', int( options.enable_ff_mpeg2 )) - doc.add( 'FEATURE.fdk_aac', int( options.enable_fdk_aac )) + doc.add( 'FEATURE.fdk_aac', int( options.enable_fdk_aac )) + doc.add( 'FEATURE.libav_aac', int( options.enable_libav_aac )) + doc.add( 'FEATURE.faac', int( options.enable_faac )) doc.add( 'FEATURE.qsv', int( options.enable_qsv )) doc.add( 'FEATURE.xcode', int( not (Tools.xcodebuild.fail or options.disable_xcode or options.cross) )) diff --git a/make/include/main.defs b/make/include/main.defs index 703118856..d4d3ee0fb 100644 --- a/make/include/main.defs +++ b/make/include/main.defs @@ -43,8 +43,11 @@ ifeq (1,$(FEATURE.fdk_aac)) MODULES += contrib/fdk-aac endif +ifeq (1,$(FEATURE.faac)) + MODULES += contrib/faac +endif + MODULES += contrib/lame -MODULES += contrib/faac MODULES += contrib/ffmpeg MODULES += contrib/libdvdread MODULES += contrib/libdvdnav diff --git a/scripts/manicure.rb b/scripts/manicure.rb index b8be37432..83b991dd9 100755 --- a/scripts/manicure.rb +++ b/scripts/manicure.rb @@ -280,16 +280,16 @@ class Display end #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << " -e " - case hash["VideoEncoder"] - when /x264/ - commandString << "x264" - when /Theora/ - commandString << "theora" - when /MPEG/ - commandString << "ffmpeg2" - end + commandString << " -e " + case hash["VideoEncoder"] + when /x264/ + commandString << "x264" + when /Theora/ + commandString << "theora" + when /MPEG-4/ + commandString << "ffmpeg4" + when /MPEG-2/ + commandString << "ffmpeg2" end #VideoRateControl @@ -342,23 +342,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -366,11 +366,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -467,17 +467,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when /AAC/ + audioEncoderFallback << "ac3" + when "AAC (faac)" audioEncoderFallback << "faac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" + when "HE-AAC (FDK)" + audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" + when "HE-AAC (CoreAudio)" + audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when /FLAC/ - audioEncoderFallback << "ffflac" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 @@ -678,16 +688,16 @@ class Display commandString << '+ ' << hash["PresetName"] << ":" #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << " -e " - case hash["VideoEncoder"] - when /x264/ - commandString << "x264" - when /Theora/ - commandString << "theora" - when /MPEG/ - commandString << "ffmpeg2" - end + commandString << " -e " + case hash["VideoEncoder"] + when /x264/ + commandString << "x264" + when /Theora/ + commandString << "theora" + when /MPEG-4/ + commandString << "ffmpeg4" + when /MPEG-2/ + commandString << "ffmpeg2" end #VideoRateControl @@ -740,23 +750,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -764,11 +774,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -865,17 +875,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when /AAC/ + audioEncoderFallback << "ac3" + when "AAC (faac)" audioEncoderFallback << "faac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" + when "HE-AAC (FDK)" + audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" + when "HE-AAC (CoreAudio)" + audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when /FLAC/ - audioEncoderFallback << "ffflac" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 @@ -1080,16 +1100,16 @@ class Display end #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << "vcodec = " - case hash["VideoEncoder"] - when /x264/ - commandString << "HB_VCODEC_X264;\n " - when /Theora/ - commandString << "HB_VCODEC_THEORA;\n " - when /MPEG/ - commandString << "HB_VCODEC_FFMPEG_MPEG2;\n " - end + commandString << "vcodec = " + case hash["VideoEncoder"] + when /x264/ + commandString << "HB_VCODEC_X264;\n " + when /Theora/ + commandString << "HB_VCODEC_THEORA;\n " + when /MPEG-4/ + commandString << "HB_VCODEC_FFMPEG_MPEG4;\n " + when /MPEG-2/ + commandString << "HB_VCODEC_FFMPEG_MPEG2;\n " end #VideoRateControl @@ -1144,23 +1164,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -1168,11 +1188,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -1287,27 +1307,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (FDK)" - audioEncoderFallback << "fdk_aac" + audioEncoderFallback << "ac3" when "AAC (faac)" audioEncoderFallback << "faac" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when "AAC (CoreAudio)" - audioEncoderFallback << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" when "HE-AAC (FDK)" audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when "FLAC (ffmpeg)" - audioEncoderFallback << "ffflac" - when "FLAC (24-bit)" - audioEncoderFallback << "ffflac24" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 @@ -1538,16 +1558,16 @@ class Display commandString << "+ " << hash["PresetName"] << ": " #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << " -e " - case hash["VideoEncoder"] - when /x264/ - commandString << "x264 " - when /Theora/ - commandString << "theora " - when /MPEG/ - commandString << "ffmpeg2 " - end + commandString << " -e " + case hash["VideoEncoder"] + when /x264/ + commandString << "x264 " + when /Theora/ + commandString << "theora " + when /MPEG-4/ + commandString << "ffmpeg4 " + when /MPEG-2/ + commandString << "ffmpeg2 " end #VideoRateControl @@ -1600,23 +1620,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -1624,11 +1644,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -1725,17 +1745,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when /AAC/ + audioEncoderFallback << "ac3" + when "AAC (faac)" audioEncoderFallback << "faac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" + when "HE-AAC (FDK)" + audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" + when "HE-AAC (CoreAudio)" + audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when /FLAC/ - audioEncoderFallback << "ffflac" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 diff --git a/test/module.defs b/test/module.defs index 61444c6c5..25bc99991 100644 --- a/test/module.defs +++ b/test/module.defs @@ -14,7 +14,7 @@ TEST.GCC.L = $(CONTRIB.build/)lib TEST.libs = $(LIBHB.a) TEST.GCC.l = \ - a52 ass avcodec avformat avutil avresample dvdnav dvdread faac \ + a52 ass avcodec avformat avutil avresample dvdnav dvdread \ fontconfig freetype fribidi mkv mpeg2 mp3lame mp4v2 ogg \ samplerate swscale theoraenc theoradec vorbis vorbisenc x264 \ bluray xml2 bz2 z @@ -28,6 +28,10 @@ ifeq (1,$(FEATURE.fdk_aac)) TEST.GCC.l += fdk-aac endif +ifeq (1,$(FEATURE.faac)) +TEST.GCC.l += faac +endif + TEST.install.exe = $(DESTDIR)$(PREFIX/)bin/$(notdir $(TEST.exe)) ############################################################################### diff --git a/test/test.c b/test/test.c index fc1c6cff7..cc72983b2 100644 --- a/test/test.c +++ b/test/test.c @@ -1333,6 +1333,74 @@ static int HandleEvents( hb_handle_t * h ) } modulus = 2; } + if (!strcasecmp(preset_name, "Windows Phone 8")) + { + if( !mux ) + { + mux = HB_MUX_MP4; + } + vcodec = HB_VCODEC_X264; + job->vquality = 22.0; + filter_vrate_base = 900000; + filter_cfr = 2; + if( !atracks ) + { + atracks = strdup("1"); + } + if( !acodecs ) + { + acodecs = strdup("faac"); + } + if( !abitrates ) + { + abitrates = str_split("128", ','); + } + if( !mixdowns ) + { + mixdowns = strdup("dpl2"); + } + if( !arates ) + { + arates = strdup("Auto"); + } + if( !dynamic_range_compression ) + { + dynamic_range_compression = strdup("0.0"); + } + if( allowed_audio_copy == -1 ) + { + allowed_audio_copy = 0; + allowed_audio_copy |= HB_ACODEC_AAC_PASS; + allowed_audio_copy |= HB_ACODEC_AC3_PASS; + allowed_audio_copy |= HB_ACODEC_DCA_HD_PASS; + allowed_audio_copy |= HB_ACODEC_DCA_PASS; + allowed_audio_copy |= HB_ACODEC_MP3_PASS; + allowed_audio_copy &= HB_ACODEC_PASS_MASK; + } + if( acodec_fallback == NULL ) + { + acodec_fallback = "ffac3"; + } + maxWidth = 1280; + maxHeight = 720; + if (x264_preset == NULL) + { + x264_preset = strdup("medium"); + } + if (h264_profile == NULL) + { + h264_profile = strdup("main"); + } + if (h264_level == NULL) + { + h264_level = strdup("3.1"); + } + if( !anamorphic_mode ) + { + anamorphic_mode = 2; + } + modulus = 2; + } if (!strcasecmp(preset_name, "Normal")) { if( !mux ) @@ -2977,6 +3045,7 @@ static void ShowHelp() "### Video Options------------------------------------------------------------\n\n" " -e, --encoder Set video library encoder\n" " Options: " ); + name = NULL; encoder = NULL; while ((encoder = hb_video_encoder_get_next(encoder)) != NULL) { @@ -3445,7 +3514,8 @@ static void ShowPresets() printf("\n + AppleTV 3: -e x264 -q 20.0 -r 30 --pfr -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -4 -X 1920 -Y 1080 --decomb=fast --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 4.0\n"); printf("\n + Android: -e x264 -q 22.0 -r 30 --pfr -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 720 -Y 576 --loose-anamorphic --modulus 2 --x264-preset medium --h264-profile main --h264-level 3.0\n"); printf("\n + Android Tablet: -e x264 -q 22.0 -r 30 --pfr -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1280 -Y 720 --loose-anamorphic --modulus 2 --x264-preset medium --h264-profile main --h264-level 3.1\n"); - printf("\n>\n"); + printf("\n + Windows Phone 8: -e x264 -q 22.0 -r 30 --pfr -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -X 1280 -Y 720 --loose-anamorphic --modulus 2 --x264-preset medium --h264-profile main --h264-level 3.1\n"); + printf("\n>\n"); printf("\n< Regular\n"); printf("\n + Normal: -e x264 -q 20.0 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 --loose-anamorphic --modulus 2 -m --x264-preset veryfast --h264-profile main --h264-level 4.0\n"); printf("\n + High Profile: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,none -R Auto,Auto -D 0.0,0.0 --audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 -f mp4 -4 --decomb --loose-anamorphic --modulus 2 -m --x264-preset medium --h264-profile high --h264-level 4.1\n"); diff --git a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj index 445b09c36..4888c9e9b 100644 --- a/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj +++ b/win/CS/HandBrake.ApplicationServices/HandBrake.ApplicationServices.csproj @@ -95,6 +95,7 @@ + diff --git a/win/CS/HandBrake.ApplicationServices/LibHb/AudioVideoHelpers.cs b/win/CS/HandBrake.ApplicationServices/LibHb/AudioVideoHelpers.cs new file mode 100644 index 000000000..022d78180 --- /dev/null +++ b/win/CS/HandBrake.ApplicationServices/LibHb/AudioVideoHelpers.cs @@ -0,0 +1,18 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// Defines the AudioVideoHelpers type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrake.ApplicationServices.LibHb +{ + /// + /// The audio video helpers. + /// + class AudioVideoHelpers + { + } +} diff --git a/win/CS/HandBrake.ApplicationServices/Model/Encoding/AudioTrack.cs b/win/CS/HandBrake.ApplicationServices/Model/Encoding/AudioTrack.cs index c8238927f..fcbaddf6f 100644 --- a/win/CS/HandBrake.ApplicationServices/Model/Encoding/AudioTrack.cs +++ b/win/CS/HandBrake.ApplicationServices/Model/Encoding/AudioTrack.cs @@ -75,7 +75,7 @@ namespace HandBrake.ApplicationServices.Model.Encoding public AudioTrack() { // Default Values - this.Encoder = AudioEncoder.Faac; + this.Encoder = AudioEncoder.ffaac; this.MixDown = Mixdown.DolbyProLogicII; this.SampleRate = 48; this.Bitrate = 160; @@ -341,7 +341,7 @@ namespace HandBrake.ApplicationServices.Model.Encoding { get { - return this.IsPassthru || this.Encoder == AudioEncoder.ffflac; + return this.IsPassthru || this.Encoder == AudioEncoder.ffflac || this.Encoder == AudioEncoder.ffflac24; } } @@ -352,7 +352,7 @@ namespace HandBrake.ApplicationServices.Model.Encoding { get { - return this.IsPassthru || this.Encoder == AudioEncoder.ffflac; + return this.IsPassthru || this.Encoder == AudioEncoder.ffflac || this.Encoder == AudioEncoder.ffflac24; } } diff --git a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IPresetService.cs b/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IPresetService.cs index 63fe25158..83e1206b2 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IPresetService.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/Interfaces/IPresetService.cs @@ -28,6 +28,11 @@ namespace HandBrake.ApplicationServices.Services.Interfaces /// Preset DefaultPreset { get; } + /// + /// The load. + /// + void Load(); + /// /// Add a new preset to the system /// diff --git a/win/CS/HandBrake.ApplicationServices/Services/PresetService.cs b/win/CS/HandBrake.ApplicationServices/Services/PresetService.cs index efdce5240..e40c44033 100644 --- a/win/CS/HandBrake.ApplicationServices/Services/PresetService.cs +++ b/win/CS/HandBrake.ApplicationServices/Services/PresetService.cs @@ -38,11 +38,6 @@ namespace HandBrake.ApplicationServices.Services /// private static readonly XmlSerializer Ser = new XmlSerializer(typeof(List)); - /// - /// The User Setting Service - /// - private readonly IUserSettingService userSettingService; - /// /// User Preset Default Catgory Name /// @@ -61,30 +56,10 @@ namespace HandBrake.ApplicationServices.Services /// /// A Collection of presets /// - private ObservableCollection presets = new ObservableCollection(); + private readonly ObservableCollection presets = new ObservableCollection(); #endregion - - /// - /// Initializes a new instance of the class. - /// - /// - /// The user Setting Service. - /// - public PresetService(IUserSettingService userSettingService) - { - this.userSettingService = userSettingService; - - // If the preset file doesn't exist. Create it. - if (!File.Exists(this.builtInPresetFile)) - { - this.UpdateBuiltInPresets(); - } - - this.LoadPresets(); - } - /// /// Gets a Collection of presets. /// @@ -114,6 +89,20 @@ namespace HandBrake.ApplicationServices.Services #region Public Methods + /// + /// The load. + /// + public void Load() + { + // If the preset file doesn't exist. Create it. + if (!File.Exists(this.builtInPresetFile)) + { + this.UpdateBuiltInPresets(); + } + + this.LoadPresets(); + } + /// /// Add a new preset to the system. /// Performs an Update if it already exists @@ -413,7 +402,7 @@ namespace HandBrake.ApplicationServices.Services // Recover from Error. if (File.Exists(file)) { - string disabledFile = file + ".old"; + string disabledFile = string.Format("{0}.{1}", file, GeneralUtilities.ProcessId); File.Move(file, disabledFile); if (File.Exists(file)) { @@ -458,7 +447,6 @@ namespace HandBrake.ApplicationServices.Services { RecoverFromCorruptedPresetFile(this.builtInPresetFile); this.UpdateBuiltInPresets(); - throw new GeneralApplicationException("HandBrake has detected corruption in the presets file and has attempted to rebuild this file.", "Please restart HandBrake before continuing.", exc); } // Load in the users Presets from UserPresets.xml @@ -479,7 +467,7 @@ namespace HandBrake.ApplicationServices.Services catch (Exception exc) { RecoverFromCorruptedPresetFile(this.userPresetFile); - throw new GeneralApplicationException("HandBrake has detected corruption in the presets file and has attempted to rebuild this file.", "Please restart HandBrake before continuing.", exc); + throw new GeneralApplicationException("HandBrake has detected a problem with your presets.", "Your old presets file has been renamed so that it doesn't get loaded on next launch.", exc); } } diff --git a/win/CS/HandBrake.ApplicationServices/Utilities/Converters.cs b/win/CS/HandBrake.ApplicationServices/Utilities/Converters.cs index c69320e1f..10d5fc231 100644 --- a/win/CS/HandBrake.ApplicationServices/Utilities/Converters.cs +++ b/win/CS/HandBrake.ApplicationServices/Utilities/Converters.cs @@ -25,7 +25,7 @@ namespace HandBrake.ApplicationServices.Utilities * TODO: * - Many of these converters can be ditched at a later point. Should be able to model all this within the enums themsevles. * - **/ + **/ /// /// Convert HandBrakes time remaining into a TimeSpan @@ -155,46 +155,6 @@ namespace HandBrake.ApplicationServices.Utilities } } - /// - /// Get the GUI equiv to a CLI audio encoder - /// - /// The Audio Encoder - /// The GUI representation of that audio encoder - public static string GetGUIAudioEncoder(string audioEnc) - { - switch (audioEnc) - { - case "faac": - return "AAC (faac)"; - case "lame": - return "MP3 (lame)"; - case "vorbis": - return "Vorbis (vorbis)"; - case "ffac3": - return "AC3 (ffmpeg)"; - case "copy:ac3": - return "AC3 Passthru"; - case "copy:dts": - return "DTS Passthru"; - case "copy:dtshd": - return "MP3 Passthru"; - case "copy:mp3": - return "AAC Passthru"; - case "copy:aac": - return "DTS-HD Passthru"; - case "ffaac": - return "AAC (ffmpeg)"; - case "ffflac": - return "FLAC (ffmpeg)"; - case "ffflac24": - return "FLAC (24-bit)"; - case "copy": - return "Auto Passthru"; - default: - return "AAC (faac)"; - } - } - /// /// Get the GUI equiv to a CLI audio encoder /// @@ -205,17 +165,24 @@ namespace HandBrake.ApplicationServices.Utilities switch (audioEnc) { case "faac": - return AudioEncoder.Faac; case "ffaac": return AudioEncoder.ffaac; + case "fdk_aac": + return AudioEncoder.fdkaac; + case "fdk_haac": + return AudioEncoder.fdkheaac; + case "mp3": case "lame": return AudioEncoder.Lame; case "vorbis": return AudioEncoder.Vorbis; + case "ac3": case "ffac3": return AudioEncoder.Ac3; + case "flac16": case "ffflac": return AudioEncoder.ffflac; + case "flac24": case "ffflac24": return AudioEncoder.ffflac24; case "copy:ac3": @@ -231,7 +198,7 @@ namespace HandBrake.ApplicationServices.Utilities case "copy": return AudioEncoder.Passthrough; default: - return AudioEncoder.Faac; + return AudioEncoder.ffaac; } } @@ -245,16 +212,22 @@ namespace HandBrake.ApplicationServices.Utilities switch (audioEnc) { case "AAC (faac)": - return AudioEncoder.Faac; + case "AAC (CoreAudio)": case "AAC (ffmpeg)": + case "AAC (avcodec)": return AudioEncoder.ffaac; - case "AAC (CoreAudio)": - return AudioEncoder.Faac; + case "AAC (FDK)": + return AudioEncoder.fdkaac; + case "HE-AAC (FDK)": + return AudioEncoder.fdkheaac; case "MP3 (lame)": + case "MP3": return AudioEncoder.Lame; case "Vorbis (vorbis)": + case "Vorbis": return AudioEncoder.Vorbis; case "AC3 (ffmpeg)": + case "AC3": return AudioEncoder.Ac3; case "AC3 Passthru": return AudioEncoder.Ac3Passthrough; @@ -267,13 +240,15 @@ namespace HandBrake.ApplicationServices.Utilities case "MP3 Passthru": return AudioEncoder.Mp3Passthru; case "FLAC (ffmpeg)": + case "FLAC 16-bit": return AudioEncoder.ffflac; case "FLAC (24-bit)": + case "FLAC 24-bit": return AudioEncoder.ffflac24; case "Auto Passthru": return AudioEncoder.Passthrough; default: - return AudioEncoder.Faac; + return AudioEncoder.ffaac; } } @@ -288,43 +263,12 @@ namespace HandBrake.ApplicationServices.Utilities /// public static string GetCliAudioEncoder(AudioEncoder selectedEncoder) { - switch (selectedEncoder) - { - case AudioEncoder.Faac: - return "faac"; - case AudioEncoder.ffaac: - return "ffaac"; - - case AudioEncoder.Lame: - return "lame"; - case AudioEncoder.Vorbis: - return "vorbis"; - case AudioEncoder.Ac3Passthrough: - return "copy:ac3"; - case AudioEncoder.DtsPassthrough: - return "copy:dts"; - case AudioEncoder.DtsHDPassthrough: - return "copy:dtshd"; - case AudioEncoder.Ac3: - return "ffac3"; - case AudioEncoder.AacPassthru: - return "copy:aac"; - case AudioEncoder.Mp3Passthru: - return "copy:mp3"; - case AudioEncoder.Passthrough: - return "copy"; - case AudioEncoder.ffflac: - return "ffflac"; - case AudioEncoder.ffflac24: - return "ffflac24"; - default: - return "faac"; - } + return EnumHelper.GetShortName(selectedEncoder); } #endregion - #region Video + #region Video /// /// Get the Video Encoder for a given string @@ -339,11 +283,12 @@ namespace HandBrake.ApplicationServices.Utilities { switch (encoder) { - case "": case "ffmpeg": case "ffmpeg4": + case "mpeg4": return VideoEncoder.FFMpeg; case "ffmpeg2": + case "mpeg2": return VideoEncoder.FFMpeg2; case "x264": return VideoEncoder.X264; @@ -370,9 +315,9 @@ namespace HandBrake.ApplicationServices.Utilities switch (encoder) { case VideoEncoder.FFMpeg: - return "ffmpeg4"; + return "mpeg4"; case VideoEncoder.FFMpeg2: - return "ffmpeg2"; + return "mpeg2"; case VideoEncoder.X264: return "x264"; case VideoEncoder.Theora: diff --git a/win/CS/HandBrake.ApplicationServices/Utilities/EnumHelper.cs b/win/CS/HandBrake.ApplicationServices/Utilities/EnumHelper.cs index c854e5a05..43667557b 100644 --- a/win/CS/HandBrake.ApplicationServices/Utilities/EnumHelper.cs +++ b/win/CS/HandBrake.ApplicationServices/Utilities/EnumHelper.cs @@ -17,6 +17,8 @@ namespace HandBrake.ApplicationServices.Utilities using System.Linq; using System.Reflection; + using HandBrake.Interop.Attributes; + /// /// Enum Helpers /// @@ -93,6 +95,23 @@ namespace HandBrake.ApplicationServices.Utilities throw new ArgumentOutOfRangeException("The Description for the enum was not recognized."); } + /// + /// The get short name. + /// + /// + /// The value. + /// + /// + /// The . + /// + public static string GetShortName(T value) + { + FieldInfo fieldInfo = value.GetType().GetField(value.ToString()); + ShortName[] attributes = (ShortName[])fieldInfo.GetCustomAttributes(typeof(ShortName), false); + + return (attributes.Length > 0) ? attributes[0].Name : value.ToString(); + } + /// /// Return a list of all the enum values. /// diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Attributes/ShortName.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Attributes/ShortName.cs new file mode 100644 index 000000000..cf32cb802 --- /dev/null +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Attributes/ShortName.cs @@ -0,0 +1,35 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// A Short Name for an enum value +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrake.Interop.Attributes +{ + using System; + + /// + /// A Short Name for an enum value + /// + public class ShortName : Attribute + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The short name. + /// + public ShortName(string shortName) + { + this.Name = shortName; + } + + /// + /// Gets or sets the short name. + /// + public string Name { get; set; } + } +} diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs index e7f172e32..42d200e57 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Converters.cs @@ -25,21 +25,21 @@ namespace HandBrake.Interop /// /// Video Frame Rates /// - private static readonly Dictionary VideoRates = new Dictionary + private static readonly Dictionary VideoRates; + + /// + /// Initializes static members of the Converters class. + /// + static Converters() { - {5, 5400000}, - {10, 2700000}, - {12, 2250000}, - {15, 1800000}, - {23.976, 1126125}, - {24, 1125000}, - {25, 1080000}, - {29.97, 900900}, - {30, 900000}, - {50, 540000}, - {59.94, 450450}, - {60, 450000} - }; + HandBrakeUtils.EnsureGlobalInit(); + + VideoRates = new Dictionary(); + foreach (var framerate in Encoders.VideoFramerates) + { + VideoRates.Add(double.Parse(framerate.Name), framerate.Rate); + } + } /// /// Convert Framerate to Video Rates @@ -78,10 +78,12 @@ namespace HandBrake.Interop return NativeConstants.HB_ACODEC_AC3_PASS; case AudioEncoder.Ac3: return NativeConstants.HB_ACODEC_AC3; - case AudioEncoder.Faac: - return NativeConstants.HB_ACODEC_FAAC; case AudioEncoder.ffaac: return NativeConstants.HB_ACODEC_FFAAC; + case AudioEncoder.fdkaac: + return NativeConstants.HB_ACODEC_FDK_AAC; + case AudioEncoder.fdkheaac: + return NativeConstants.HB_ACODEC_FDK_HAAC; case AudioEncoder.AacPassthru: return NativeConstants.HB_ACODEC_AAC_PASS; case AudioEncoder.Lame: @@ -127,9 +129,12 @@ namespace HandBrake.Interop case NativeConstants.HB_ACODEC_FFAAC: case NativeConstants.HB_ACODEC_CA_AAC: case NativeConstants.HB_ACODEC_CA_HAAC: + case NativeConstants.HB_ACODEC_FDK_HAAC: // TODO Check this is correct + case NativeConstants.HB_ACODEC_FDK_AAC: // TODO Check this is correct return AudioCodec.Aac; case NativeConstants.HB_ACODEC_FFFLAC: return AudioCodec.Flac; + default: return AudioCodec.Other; } @@ -144,9 +149,9 @@ namespace HandBrake.Interop { var result = new HBVideoEncoder { - Id = encoder.encoder, + Id = encoder.codec, ShortName = encoder.short_name, - DisplayName = encoder.human_readable_name, + DisplayName = encoder.name, CompatibleContainers = Container.None }; @@ -172,9 +177,9 @@ namespace HandBrake.Interop { var result = new HBAudioEncoder { - Id = encoder.encoder, + Id = encoder.codec, ShortName = encoder.short_name, - DisplayName = encoder.human_readable_name, + DisplayName = encoder.name, CompatibleContainers = Container.None }; @@ -188,14 +193,28 @@ namespace HandBrake.Interop result.CompatibleContainers = result.CompatibleContainers | Container.Mp4; } - result.QualityLimits = Encoders.GetAudioQualityLimits(encoder.encoder); - result.DefaultQuality = HBFunctions.hb_get_default_audio_quality((uint)encoder.encoder); - result.CompressionLimits = Encoders.GetAudioCompressionLimits(encoder.encoder); - result.DefaultCompression = HBFunctions.hb_get_default_audio_compression((uint) encoder.encoder); + result.QualityLimits = Encoders.GetAudioQualityLimits(encoder.codec); + result.DefaultQuality = HBFunctions.hb_audio_quality_get_default((uint)encoder.codec); + result.CompressionLimits = Encoders.GetAudioCompressionLimits(encoder.codec); + result.DefaultCompression = HBFunctions.hb_audio_compression_get_default((uint)encoder.codec); return result; } + /// + /// Converts a native HB rate structure to an HBRate object. + /// + /// The structure to convert. + /// The converted rate object. + public static HBRate NativeToRate(hb_rate_s rate) + { + return new HBRate + { + Name = rate.name, + Rate = rate.rate + }; + } + /// /// Converts a native HB mixdown structure to a Mixdown model. /// @@ -207,7 +226,7 @@ namespace HandBrake.Interop { Id = mixdown.amixdown, ShortName = mixdown.short_name, - DisplayName = mixdown.human_readable_name + DisplayName = mixdown.name }; } diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs index a65ca3e10..18beda7cc 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInstance.cs @@ -49,16 +49,6 @@ namespace HandBrake.Interop /// private const string TurboX264Opts = "ref=1:subme=2:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0"; - /// - /// Lock for creation of handbrake instances; - /// - private static object instanceCreationLock = new object(); - - /// - /// True if a handbrake instance has been created. - /// - private static bool globalInitialized; - /// /// The native handle to the HandBrake instance. /// @@ -181,13 +171,7 @@ namespace HandBrake.Interop /// The code for the logging verbosity to use. public void Initialize(int verbosity) { - lock (instanceCreationLock) - { - if (!globalInitialized) - { - globalInitialized = true; - } - } + HandBrakeUtils.EnsureGlobalInit(); HandBrakeUtils.RegisterLogger(); this.hbHandle = HBFunctions.hb_init(verbosity, update_check: 0); @@ -406,6 +390,11 @@ namespace HandBrake.Interop public void StartEncode(EncodeJob job, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds) { EncodingProfile profile = job.EncodingProfile; + if (job.ChosenAudioTracks == null) + { + throw new ArgumentException("job.ChosenAudioTracks cannot be null."); + } + this.currentJob = job; IntPtr nativeJobPtr = HBFunctions.hb_job_init_by_index(this.hbHandle, this.GetTitleIndex(job.Title)); @@ -414,7 +403,7 @@ namespace HandBrake.Interop this.encodeAllocatedMemory = this.ApplyJob(ref nativeJob, job, preview, previewNumber, previewSeconds, overallSelectedLengthSeconds); this.subtitleScan = false; - if (job.Subtitles.SourceSubtitles != null) + if (job.Subtitles != null && job.Subtitles.SourceSubtitles != null) { foreach (SourceSubtitle subtitle in job.Subtitles.SourceSubtitles) { @@ -1267,7 +1256,7 @@ namespace HandBrake.Interop } else { - displayWidth = (int)((double)cropHeight * displayAspect); + displayWidth = (int)((double)height * displayAspect); } nativeJob.anamorphic.dar_width = displayWidth; @@ -1454,7 +1443,7 @@ namespace HandBrake.Interop } } - bool hasBurnedSubtitle = job.Subtitles.SourceSubtitles.Any(s => s.BurnedIn); + bool hasBurnedSubtitle = job.Subtitles.SourceSubtitles != null && job.Subtitles.SourceSubtitles.Any(s => s.BurnedIn); if (hasBurnedSubtitle) { this.AddFilter(filterList, (int)hb_filter_ids.HB_FILTER_RENDER_SUB, string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}:{3}", crop.Top, crop.Bottom, crop.Left, crop.Right), allocatedMemory); @@ -1684,7 +1673,7 @@ namespace HandBrake.Interop if (encoding.Bitrate == 0) { // Bitrate of 0 means auto: choose the default for this codec, sample rate and mixdown. - nativeAudio.config.output.bitrate = HBFunctions.hb_get_default_audio_bitrate( + nativeAudio.config.output.bitrate = HBFunctions.hb_audio_bitrate_get_default( nativeAudio.config.output.codec, nativeAudio.config.output.samplerate, nativeAudio.config.output.mixdown); diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj index b1a84f48f..9b3c84f4e 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeInterop.csproj @@ -132,6 +132,7 @@ + @@ -168,6 +169,7 @@ + diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs index 6833dfc36..48e8117be 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HandBrakeUtils.cs @@ -39,6 +39,11 @@ namespace HandBrake.Interop /// private static LoggingCallback errorCallback; + /// + /// True if the global initialize function has been called. + /// + private static bool globalInitialized; + /// /// Fires when HandBrake has logged a message. /// @@ -49,6 +54,30 @@ namespace HandBrake.Interop /// public static event EventHandler ErrorLogged; + /// + /// Initializes static members of the HandBrakeUtils class. + /// + static HandBrakeUtils() + { + if (!globalInitialized) + { + if (HBFunctions.hb_global_init() == -1) + { + throw new InvalidOperationException("HB global init failed."); + } + + globalInitialized = true; + } + } + + /// + /// Ensures the HB global initialize method has been called. + /// + public static void EnsureGlobalInit() + { + // Does nothing, but invokes static ctor. + } + /// /// Enables or disables LibDVDNav. If disabled libdvdread will be used instead. /// @@ -94,12 +123,17 @@ namespace HandBrake.Interop if (messageParts.Length > 0) { - if (MessageLogged != null) + message = messageParts[0]; + + // When MP4 muxing fails (for example when the file is too big without Large File Size) + // a message is logged but it isn't marked as an error. + if (message.StartsWith("MP4ERROR", StringComparison.Ordinal)) { - MessageLogged(null, new MessageLoggedEventArgs { Message = messageParts[0] }); + SendErrorEvent(message); + return; } - System.Diagnostics.Debug.WriteLine(messageParts[0]); + SendMessageEvent(message); } } } @@ -115,20 +149,11 @@ namespace HandBrake.Interop // This error happens in normal operations. Log it as a message. if (message == "dvd: ifoOpen failed") { - if (MessageLogged != null) - { - MessageLogged(null, new MessageLoggedEventArgs { Message = message }); - } - + SendMessageEvent(message); return; } - if (ErrorLogged != null) - { - ErrorLogged(null, new MessageLoggedEventArgs { Message = message }); - } - - System.Diagnostics.Debug.WriteLine("ERROR: " + message); + SendErrorEvent(message); } } @@ -197,8 +222,8 @@ namespace HandBrake.Interop throw new ArgumentException("height must be positive."); } - HBFunctions.hb_init(0, 0); - IntPtr ptr = HBFunctions.hb_x264_param_unparse( + HBFunctions.hb_init(0, 0); + IntPtr ptr = HBFunctions.hb_x264_param_unparse( preset, string.Join(",", tunes), extraOptions, @@ -207,10 +232,10 @@ namespace HandBrake.Interop width, height); - string x264Settings = Marshal.PtrToStringAnsi(ptr); + string x264Settings = Marshal.PtrToStringAnsi(ptr); - return x264Settings; + return x264Settings; } /// @@ -331,5 +356,33 @@ namespace HandBrake.Interop return audioBytes; } + + /// + /// Sends the message logged event to any registered listeners. + /// + /// The message to send. + private static void SendMessageEvent(string message) + { + if (MessageLogged != null) + { + MessageLogged(null, new MessageLoggedEventArgs { Message = message }); + } + + System.Diagnostics.Debug.WriteLine(message); + } + + /// + /// Sends the error logged event to any registered listeners. + /// + /// The message to send + private static void SendErrorEvent(string message) + { + if (ErrorLogged != null) + { + ErrorLogged(null, new MessageLoggedEventArgs { Message = message }); + } + + System.Diagnostics.Debug.WriteLine("ERROR: " + message); + } } } diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs index 00130a902..25f595995 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/HbFunctions.cs @@ -21,6 +21,9 @@ namespace HandBrake.Interop.HbLib [DllImport("hb.dll", EntryPoint = "hb_register_error_handler", CallingConvention = CallingConvention.Cdecl)] public static extern void hb_register_error_handler(LoggingCallback callback); + [DllImport("hb.dll", EntryPoint = "hb_global_init", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_global_init(); + /// Return Type: hb_handle_t* ///verbose: int ///update_check: int @@ -210,81 +213,119 @@ namespace HandBrake.Interop.HbLib public static extern int hb_srt_add(ref hb_job_s job, ref hb_subtitle_config_s subtitleConfig, string lang); - [DllImport("hb.dll", EntryPoint = "hb_mixdown_is_supported", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_mixdown_is_supported(int mixdown, uint codec, ulong layout); - [DllImport("hb.dll", EntryPoint = "hb_mixdown_has_remix_support", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_mixdown_has_remix_support(int mixdown, ulong layout); +//int hb_video_framerate_get_from_name(const char *name); +//const char* hb_video_framerate_get_name(int framerate); +//const char* hb_video_framerate_sanitize_name(const char *name); - [DllImport("hb.dll", EntryPoint = "hb_mixdown_has_codec_support", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_mixdown_has_codec_support(int mixdown, uint codec); + // returns hb_rate_s + [DllImport("hb.dll", EntryPoint = "hb_video_framerate_get_next", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr hb_video_framerate_get_next(IntPtr last); + + +//int hb_audio_samplerate_get_best(uint32_t codec, int samplerate, int *sr_shift); +//int hb_audio_samplerate_get_from_name(const char *name); +//const char* hb_audio_samplerate_get_name(int samplerate); + + // returns hb_rate_s + [DllImport("hb.dll", EntryPoint = "hb_audio_samplerate_get_next", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr hb_audio_samplerate_get_next(IntPtr last); + + + [DllImport("hb.dll", EntryPoint = "hb_audio_bitrate_get_best", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_audio_bitrate_get_best(uint codec, int bitrate, int samplerate, int mixdown); + + [DllImport("hb.dll", EntryPoint = "hb_audio_bitrate_get_default", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_audio_bitrate_get_default(uint codec, int samplerate, int mixdown); - [DllImport("hb.dll", EntryPoint = "hb_get_default_mixdown", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_default_mixdown(uint codec, ulong layout); + [DllImport("hb.dll", EntryPoint = "hb_audio_bitrate_get_limits", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_audio_bitrate_get_limits(uint codec, int samplerate, int mixdown, ref int low, ref int high); - [DllImport("hb.dll", EntryPoint = "hb_get_best_mixdown", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_best_mixdown(uint codec, ulong layout, int mixdown); + [DllImport("hb.dll", EntryPoint = "hb_audio_bitrate_get_next", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr hb_audio_bitrate_get_next(IntPtr last); - [DllImport("hb.dll", EntryPoint = "hb_get_best_audio_bitrate", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_best_audio_bitrate(uint codec, int bitrate, int samplerate, int mixdown); - [DllImport("hb.dll", EntryPoint = "hb_get_default_audio_bitrate", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_default_audio_bitrate(uint codec, int samplerate, int mixdown); + [DllImport("hb.dll", EntryPoint = "hb_audio_quality_get_limits", CallingConvention = CallingConvention.Cdecl)] + public static extern void hb_audio_quality_get_limits(uint codec, ref float low, ref float high, ref float granularity, ref int direction); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_bitrate_limits", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_audio_bitrate_limits(uint codec, int samplerate, int mixdown, ref int low, ref int high); +//float hb_audio_quality_get_best(uint32_t codec, float quality); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_quality_limits", CallingConvention = CallingConvention.Cdecl)] - public static extern void hb_get_audio_quality_limits(uint codec, ref float low, ref float high, ref float granularity, ref int direction); + [DllImport("hb.dll", EntryPoint = "hb_audio_quality_get_default", CallingConvention = CallingConvention.Cdecl)] + public static extern float hb_audio_quality_get_default(uint codec); - [DllImport("hb.dll", EntryPoint = "hb_get_default_audio_quality", CallingConvention = CallingConvention.Cdecl)] - public static extern float hb_get_default_audio_quality(uint codec); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_compression_limits", CallingConvention = CallingConvention.Cdecl)] - public static extern void hb_get_audio_compression_limits(uint codec, ref float low, ref float high, ref float granularity, ref int direction); + [DllImport("hb.dll", EntryPoint = "hb_audio_compression_get_limits", CallingConvention = CallingConvention.Cdecl)] + public static extern void hb_audio_compression_get_limits(uint codec, ref float low, ref float high, ref float granularity, ref int direction); - [DllImport("hb.dll", EntryPoint = "hb_get_default_audio_compression", CallingConvention = CallingConvention.Cdecl)] - public static extern float hb_get_default_audio_compression(uint codec); +//float hb_audio_compression_get_best(uint32_t codec, float compression); + + [DllImport("hb.dll", EntryPoint = "hb_audio_compression_get_default", CallingConvention = CallingConvention.Cdecl)] + public static extern float hb_audio_compression_get_default(uint codec); + + +//int hb_audio_dither_get_default(); +//int hb_audio_dither_get_default_method(); // default method, if enabled && supported +//int hb_audio_dither_is_supported(uint32_t codec); +//int hb_audio_dither_get_from_name(const char *name); +//const char* hb_audio_dither_get_description(int method); +//const hb_dither_t* hb_audio_dither_get_next(const hb_dither_t *last); + + [DllImport("hb.dll", EntryPoint = "hb_mixdown_is_supported", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_mixdown_is_supported(int mixdown, uint codec, ulong layout); + + [DllImport("hb.dll", EntryPoint = "hb_mixdown_has_codec_support", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_mixdown_has_codec_support(int mixdown, uint codec); + + [DllImport("hb.dll", EntryPoint = "hb_mixdown_has_remix_support", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_mixdown_has_remix_support(int mixdown, ulong layout); +//int hb_mixdown_get_discrete_channel_count(int mixdown); +//int hb_mixdown_get_low_freq_channel_count(int mixdown); - [DllImport("hb.dll", EntryPoint = "hb_get_video_rates", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr hb_get_video_rates(); + [DllImport("hb.dll", EntryPoint = "hb_mixdown_get_best", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_mixdown_get_best(uint codec, ulong layout, int mixdown); - [DllImport("hb.dll", EntryPoint = "hb_get_video_rates_count", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_video_rates_count(); + [DllImport("hb.dll", EntryPoint = "hb_mixdown_get_default", CallingConvention = CallingConvention.Cdecl)] + public static extern int hb_mixdown_get_default(uint codec, ulong layout); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_rates", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr hb_get_audio_rates(); +//int hb_mixdown_get_from_name(const char *name); +//const char* hb_mixdown_get_name(int mixdown); +//const char* hb_mixdown_get_short_name(int mixdown); +//const char* hb_mixdown_sanitize_name(const char *name); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_rates_count", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_audio_rates_count(); + [DllImport("hb.dll", EntryPoint = "hb_mixdown_get_next", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr hb_mixdown_get_next(IntPtr last); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_rates_default", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_audio_rates_default(); +//int hb_video_encoder_get_default(int muxer); +//int hb_video_encoder_get_from_name(const char *name); +//const char* hb_video_encoder_get_name(int encoder); +//const char* hb_video_encoder_get_short_name(int encoder); +//const char* hb_video_encoder_sanitize_name(const char *name); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_bitrates", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr hb_get_audio_bitrates(); + [DllImport("hb.dll", EntryPoint = "hb_video_encoder_get_next", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr hb_video_encoder_get_next(IntPtr last); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_bitrates_count", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_audio_bitrates_count(); +/* + * hb_audio_encoder_get_fallback_for_passthru() will sanitize a passthru codec + * to the matching audio encoder (if any is available). + * + * hb_audio_encoder_get_from_name(), hb_audio_encoder_sanitize_name() will + * sanitize legacy encoder names, but won't convert passthru to an encoder. + */ +//int hb_audio_encoder_get_fallback_for_passthru(int passthru); +//int hb_audio_encoder_get_default(int muxer); +//int hb_audio_encoder_get_from_name(const char *name); +//const char* hb_audio_encoder_get_name(int encoder); +//const char* hb_audio_encoder_get_short_name(int encoder); +//const char* hb_audio_encoder_sanitize_name(const char *name); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_mixdowns", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr hb_get_audio_mixdowns(); + [DllImport("hb.dll", EntryPoint = "hb_audio_encoder_get_next", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr hb_audio_encoder_get_next(IntPtr last); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_mixdowns_count", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_audio_mixdowns_count(); - [DllImport("hb.dll", EntryPoint = "hb_get_video_encoders", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr hb_get_video_encoders(); - [DllImport("hb.dll", EntryPoint = "hb_get_video_encoders_count", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_video_encoders_count(); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_encoders", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr hb_get_audio_encoders(); - [DllImport("hb.dll", EntryPoint = "hb_get_audio_encoders_count", CallingConvention = CallingConvention.Cdecl)] - public static extern int hb_get_audio_encoders_count(); /// void hb_autopassthru_apply_settings( hb_job_t * job ) diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs index c34f5daf5..6d6e62a34 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/Misc.cs @@ -56,7 +56,7 @@ namespace HandBrake.Interop.HbLib { /// char* [MarshalAs(UnmanagedType.LPStr)] - public string @string; + public string name; /// int public int rate; @@ -65,13 +65,8 @@ namespace HandBrake.Interop.HbLib [StructLayout(LayoutKind.Sequential)] public struct hb_mixdown_s { - /// char* [MarshalAs(UnmanagedType.LPStr)] - public string human_readable_name; - - /// char* - [MarshalAs(UnmanagedType.LPStr)] - public string internal_name; + public string name; /// char* [MarshalAs(UnmanagedType.LPStr)] @@ -85,12 +80,12 @@ namespace HandBrake.Interop.HbLib public struct hb_encoder_s { [MarshalAs(UnmanagedType.LPStr)] - public string human_readable_name; + public string name; [MarshalAs(UnmanagedType.LPStr)] public string short_name; - public int encoder; + public int codec; public int muxers; } diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs index 23181e7fe..ae7fcd704 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/NativeConstants.cs @@ -12,38 +12,42 @@ namespace HandBrake.Interop.HbLib { public partial class NativeConstants { - public const uint HB_ACODEC_MASK = 0x00FFFF00; - public const uint HB_ACODEC_FAAC = 0x00000100; - public const uint HB_ACODEC_LAME = 0x00000200; - public const uint HB_ACODEC_VORBIS = 0x00000400; - public const uint HB_ACODEC_AC3 = 0x00000800; - public const uint HB_ACODEC_LPCM = 0x00001000; - public const uint HB_ACODEC_DCA = 0x00002000; - public const uint HB_ACODEC_CA_AAC = 0x00004000; - public const uint HB_ACODEC_CA_HAAC = 0x00008000; - public const uint HB_ACODEC_FFAAC = 0x00010000; - public const uint HB_ACODEC_FFMPEG = 0x00020000; - public const uint HB_ACODEC_DCA_HD = 0x00040000; - public const uint HB_ACODEC_MP3 = 0x00080000; - public const uint HB_ACODEC_FFFLAC = 0x00100000; - public const uint HB_ACODEC_FDK_AAC = 0x00400000; - public const uint HB_ACODEC_FDK_HAAC = 0x00800000; - public const uint HB_ACODEC_FF_MASK = 0x00FF2000; - public const uint HB_ACODEC_PASS_FLAG = 0x40000000; - public const uint HB_ACODEC_PASS_MASK = (HB_ACODEC_MP3 | HB_ACODEC_FFAAC | HB_ACODEC_DCA_HD | HB_ACODEC_AC3 | HB_ACODEC_DCA); - public const uint HB_ACODEC_AUTO_PASS = (HB_ACODEC_PASS_MASK | HB_ACODEC_PASS_FLAG); - public const uint HB_ACODEC_MP3_PASS = (HB_ACODEC_MP3 | HB_ACODEC_PASS_FLAG); - public const uint HB_ACODEC_AAC_PASS = (HB_ACODEC_FFAAC | HB_ACODEC_PASS_FLAG); - public const uint HB_ACODEC_AC3_PASS = (HB_ACODEC_AC3 | HB_ACODEC_PASS_FLAG); - public const uint HB_ACODEC_DCA_PASS = (HB_ACODEC_DCA | HB_ACODEC_PASS_FLAG); - public const uint HB_ACODEC_DCA_HD_PASS = (HB_ACODEC_DCA_HD | HB_ACODEC_PASS_FLAG); - public const uint HB_ACODEC_ANY = (HB_ACODEC_MASK | HB_ACODEC_PASS_FLAG); + // Audio Encoders + public const uint HB_ACODEC_MASK = 0x00FFFF00; + public const uint HB_ACODEC_FAAC = 0x00000100; + public const uint HB_ACODEC_LAME = 0x00000200; + public const uint HB_ACODEC_VORBIS = 0x00000400; + public const uint HB_ACODEC_AC3 = 0x00000800; + public const uint HB_ACODEC_LPCM = 0x00001000; + public const uint HB_ACODEC_DCA = 0x00002000; + public const uint HB_ACODEC_CA_AAC = 0x00004000; + public const uint HB_ACODEC_CA_HAAC = 0x00008000; + public const uint HB_ACODEC_FFAAC = 0x00010000; + public const uint HB_ACODEC_FFMPEG = 0x00020000; + public const uint HB_ACODEC_DCA_HD = 0x00040000; + public const uint HB_ACODEC_MP3 = 0x00080000; + public const uint HB_ACODEC_FFFLAC = 0x00100000; + public const uint HB_ACODEC_FFFLAC24 = 0x00200000; + public const uint HB_ACODEC_FDK_AAC = 0x00400000; + public const uint HB_ACODEC_FDK_HAAC = 0x00800000; + public const uint HB_ACODEC_FF_MASK = 0x00FF2000; + public const uint HB_ACODEC_PASS_FLAG = 0x40000000; + public const uint HB_ACODEC_PASS_MASK = (HB_ACODEC_MP3 | HB_ACODEC_FFAAC | HB_ACODEC_DCA_HD | HB_ACODEC_AC3 | HB_ACODEC_DCA); + public const uint HB_ACODEC_AUTO_PASS = (HB_ACODEC_PASS_MASK | HB_ACODEC_PASS_FLAG); + public const uint HB_ACODEC_MP3_PASS = (HB_ACODEC_MP3 | HB_ACODEC_PASS_FLAG); + public const uint HB_ACODEC_AAC_PASS = (HB_ACODEC_FFAAC | HB_ACODEC_PASS_FLAG); + public const uint HB_ACODEC_AC3_PASS = (HB_ACODEC_AC3 | HB_ACODEC_PASS_FLAG); + public const uint HB_ACODEC_DCA_PASS = (HB_ACODEC_DCA | HB_ACODEC_PASS_FLAG); + public const uint HB_ACODEC_DCA_HD_PASS = (HB_ACODEC_DCA_HD | HB_ACODEC_PASS_FLAG); + public const uint HB_ACODEC_ANY = (HB_ACODEC_MASK | HB_ACODEC_PASS_FLAG); + // Subtitle Types public const int HB_SUBSTREAM_BD_TRUEHD = 0x72; public const int HB_SUBSTREAM_BD_AC3 = 0x76; public const int HB_SUBSTREAM_BD_DTSHD = 0x72; public const int HB_SUBSTREAM_BD_DTS = 0x71; + // Video Encoders public const int HB_VCODEC_MASK = 0x0000FF; public const int HB_VCODEC_X264 = 0x000001; public const int HB_VCODEC_THEORA = 0x000002; @@ -52,9 +56,10 @@ namespace HandBrake.Interop.HbLib public const int HB_VCODEC_FFMPEG_MPEG2 = 0x000020; public const int HB_VCODEC_FFMPEG_MASK = 0x0000F0; + // Muxers public const int HB_MUX_MASK = 0xFF0000; public const int HB_MUX_MP4 = 0x010000; - public const int HB_MUX_MKV = 0x200000; + public const int HB_MUX_MKV = 0x100000; public const int HBTF_NO_IDR = 1 << 0; diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs index e9f08fe47..44f9e5ba8 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/HbLib/hb_job_s.cs @@ -74,10 +74,6 @@ namespace HandBrake.Interop.HbLib /// int public int vbitrate; - public int pfr_vrate; - - public int pfr_vrate_base; - /// int public int vrate; diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs index 8bf68b2e1..bd58ec6a0 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/InteropUtilities.cs @@ -11,9 +11,11 @@ namespace HandBrake.Interop { using System; using System.Collections.Generic; + using System.Linq; using System.Runtime.InteropServices; using HandBrake.Interop.HbLib; + using Model.Encoding; /// /// Helper utilities for native interop. @@ -91,7 +93,7 @@ namespace HandBrake.Interop } return result; - } + } /// /// Creats a new, empty native HandBrake list. @@ -182,6 +184,42 @@ namespace HandBrake.Interop return returnList; } + /// + /// Reads in a list of objects given an interator and a conversion function. + /// + /// The type of the struct given by the iterator. + /// The object type to convert to. + /// The iterator to use to build the list. + /// The converter to convert from the struct to the object. + /// The list of objects. + public static List GetListFromIterator(Func iterator, Func converter) + { + return ReadStructureListFromIterator(iterator).Select(converter).ToList(); + } + + /// + /// Reads in a list of structs given an iterator. + /// + /// The type of the struct. + /// The iterator to use to build the list. + /// The list of structs. + public static List ReadStructureListFromIterator(Func iterator) + { + var structureList = new List(); + IntPtr current = IntPtr.Zero; + + current = iterator(current); + while (current != IntPtr.Zero) + { + T encoder = ReadStructure(current); + structureList.Add(encoder); + + current = iterator(current); + } + + return structureList; + } + /// /// Closes the given job. /// diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoders.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoders.cs index 9f877cd9b..ebfefff0a 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoders.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoders.cs @@ -17,30 +17,48 @@ namespace HandBrake.Interop.Model using HandBrake.Interop.Model.Encoding; using HandBrake.Interop.SourceData; - /// - /// The encoders. - /// - public static class Encoders + /// + /// The encoders. + /// + public static class Encoders { - /// - /// The audio encoders. - /// - private static List audioEncoders; - - /// - /// The video encoders. - /// - private static List videoEncoders; - - /// - /// The mixdowns. - /// - private static List mixdowns; - - /// - /// The audio bitrates. - /// - private static List audioBitrates; + /// + /// The audio encoders. + /// + private static List audioEncoders; + + /// + /// The video encoders. + /// + private static List videoEncoders; + + /// + /// Video framerates in pts. + /// + private static List videoFramerates; + + /// + /// The mixdowns. + /// + private static List mixdowns; + + /// + /// The audio bitrates. + /// + private static List audioBitrates; + + /// + /// Audio sample rates in Hz. + /// + private static List audioSampleRates; + + /// + /// Initializes static members of the Encoders class. + /// + static Encoders() + { + HandBrakeUtils.EnsureGlobalInit(); + } /// /// Gets a list of supported audio encoders. @@ -51,12 +69,7 @@ namespace HandBrake.Interop.Model { if (audioEncoders == null) { - IntPtr encodersPtr = HBFunctions.hb_get_audio_encoders(); - int encoderCount = HBFunctions.hb_get_audio_encoders_count(); - - audioEncoders = InteropUtilities.ConvertArray(encodersPtr, encoderCount) - .Select(Converters.NativeToAudioEncoder) - .ToList(); + audioEncoders = InteropUtilities.GetListFromIterator(HBFunctions.hb_audio_encoder_get_next, Converters.NativeToAudioEncoder); } return audioEncoders; @@ -72,18 +85,29 @@ namespace HandBrake.Interop.Model { if (videoEncoders == null) { - IntPtr encodersPtr = HBFunctions.hb_get_video_encoders(); - int encoderCount = HBFunctions.hb_get_video_encoders_count(); - - videoEncoders = InteropUtilities.ConvertArray(encodersPtr, encoderCount) - .Select(Converters.NativeToVideoEncoder) - .ToList(); + videoEncoders = InteropUtilities.GetListFromIterator(HBFunctions.hb_video_encoder_get_next, Converters.NativeToVideoEncoder); } return videoEncoders; } } + /// + /// Gets a list of supported video framerates (in pts). + /// + public static List VideoFramerates + { + get + { + if (videoFramerates == null) + { + videoFramerates = InteropUtilities.GetListFromIterator(HBFunctions.hb_video_framerate_get_next, Converters.NativeToRate); + } + + return videoFramerates; + } + } + /// /// Gets a list of supported mixdowns. /// @@ -93,12 +117,7 @@ namespace HandBrake.Interop.Model { if (mixdowns == null) { - IntPtr mixdownsPtr = HBFunctions.hb_get_audio_mixdowns(); - int mixdownsCount = HBFunctions.hb_get_audio_mixdowns_count(); - - mixdowns = InteropUtilities.ConvertArray(mixdownsPtr, mixdownsCount) - .Select(Converters.NativeToMixdown) - .ToList(); + mixdowns = InteropUtilities.GetListFromIterator(HBFunctions.hb_mixdown_get_next, Converters.NativeToMixdown); } return mixdowns; @@ -114,18 +133,29 @@ namespace HandBrake.Interop.Model { if (audioBitrates == null) { - IntPtr audioBitratesPtr = HBFunctions.hb_get_audio_bitrates(); - int audioBitratesCount = HBFunctions.hb_get_audio_bitrates_count(); - - audioBitrates = InteropUtilities.ConvertArray(audioBitratesPtr, audioBitratesCount) - .Select(b => b.rate) - .ToList(); + audioBitrates = InteropUtilities.GetListFromIterator(HBFunctions.hb_audio_bitrate_get_next, b => b.rate); } return audioBitrates; } } + /// + /// Gets a list of supported audio sample rates (in Hz). + /// + public static List AudioSampleRates + { + get + { + if (audioSampleRates == null) + { + audioSampleRates = InteropUtilities.GetListFromIterator(HBFunctions.hb_audio_samplerate_get_next, Converters.NativeToRate); + } + + return audioSampleRates; + } + } + /// /// Gets the audio encoder with the specified short name. /// @@ -199,7 +229,7 @@ namespace HandBrake.Interop.Model /// A sanitized mixdown value. public static HBMixdown SanitizeMixdown(HBMixdown mixdown, HBAudioEncoder encoder, ulong layout) { - int sanitizedMixdown = HBFunctions.hb_get_best_mixdown((uint)encoder.Id, layout, mixdown.Id); + int sanitizedMixdown = HBFunctions.hb_mixdown_get_best((uint)encoder.Id, layout, mixdown.Id); return Mixdowns.Single(m => m.Id == sanitizedMixdown); } @@ -211,7 +241,7 @@ namespace HandBrake.Interop.Model /// The default mixdown for the given codec and channel layout. public static HBMixdown GetDefaultMixdown(HBAudioEncoder encoder, ulong layout) { - int defaultMixdown = HBFunctions.hb_get_default_mixdown((uint)encoder.Id, layout); + int defaultMixdown = HBFunctions.hb_mixdown_get_default((uint)encoder.Id, layout); return Mixdowns.Single(m => m.Id == defaultMixdown); } @@ -227,7 +257,7 @@ namespace HandBrake.Interop.Model int low = 0; int high = 0; - HBFunctions.hb_get_audio_bitrate_limits((uint)encoder.Id, sampleRate, mixdown.Id, ref low, ref high); + HBFunctions.hb_audio_bitrate_get_limits((uint)encoder.Id, sampleRate, mixdown.Id, ref low, ref high); return new BitrateLimits { Low = low, High = high }; } @@ -242,7 +272,7 @@ namespace HandBrake.Interop.Model /// A sanitized audio bitrate. public static int SanitizeAudioBitrate(int audioBitrate, HBAudioEncoder encoder, int sampleRate, HBMixdown mixdown) { - return HBFunctions.hb_get_best_audio_bitrate((uint)encoder.Id, audioBitrate, sampleRate, mixdown.Id); + return HBFunctions.hb_audio_bitrate_get_best((uint)encoder.Id, audioBitrate, sampleRate, mixdown.Id); } /// @@ -254,7 +284,7 @@ namespace HandBrake.Interop.Model /// The default bitrate for these parameters. public static int GetDefaultBitrate(HBAudioEncoder encoder, int sampleRate, HBMixdown mixdown) { - return HBFunctions.hb_get_default_audio_bitrate((uint) encoder.Id, sampleRate, mixdown.Id); + return HBFunctions.hb_audio_bitrate_get_default((uint) encoder.Id, sampleRate, mixdown.Id); } /// @@ -266,7 +296,7 @@ namespace HandBrake.Interop.Model { float low = 0, high = 0, granularity = 0; int direction = 0; - HBFunctions.hb_get_audio_quality_limits((uint)encoderId, ref low, ref high, ref granularity, ref direction); + HBFunctions.hb_audio_quality_get_limits((uint)encoderId, ref low, ref high, ref granularity, ref direction); return new RangeLimits { @@ -286,7 +316,7 @@ namespace HandBrake.Interop.Model { float low = 0, high = 0, granularity = 0; int direction = 0; - HBFunctions.hb_get_audio_compression_limits((uint)encoderId, ref low, ref high, ref granularity, ref direction); + HBFunctions.hb_audio_compression_get_limits((uint)encoderId, ref low, ref high, ref granularity, ref direction); return new RangeLimits { diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs index 8fb242ac6..bc7b5bf20 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs @@ -11,48 +11,71 @@ namespace HandBrake.Interop.Model.Encoding { using System.ComponentModel.DataAnnotations; + using HandBrake.Interop.Attributes; + /// /// The audio encoder. /// public enum AudioEncoder { [Display(Name = "AAC (faac)")] - Faac = 0, + [ShortName("faac")] + faac = 0, - [Display(Name = "AAC (ffmpeg)")] + [Display(Name = "AAC (avcodec)")] + [ShortName("av_aac")] ffaac, - [Display(Name = "MP3 (lame)")] + [Display(Name = "AAC (FDK)")] + [ShortName("fdk_aac")] + fdkaac, + + [Display(Name = "HE-AAC (FDK)")] + [ShortName("fdk_haac")] + fdkheaac, + + [Display(Name = "MP3")] + [ShortName("mp3")] Lame, - [Display(Name = "AC3 (ffmpeg)")] + [Display(Name = "AC3")] + [ShortName("ac3")] Ac3, [Display(Name = "Auto Passthru")] + [ShortName("copy")] Passthrough, [Display(Name = "AC3 Passthru")] + [ShortName("copy:ac3")] Ac3Passthrough, [Display(Name = "DTS Passthru")] + [ShortName("copy:dts")] DtsPassthrough, [Display(Name = "DTS-HD Passthru")] + [ShortName("copy:dtshd")] DtsHDPassthrough, [Display(Name = "AAC Passthru")] + [ShortName("copy:aac")] AacPassthru, [Display(Name = "MP3 Passthru")] + [ShortName("copy:mp3")] Mp3Passthru, - [Display(Name = "Vorbis (vorbis)")] + [Display(Name = "Vorbis")] + [ShortName("vorbis")] Vorbis, - [Display(Name = "FLAC (ffmpeg)")] + [Display(Name = "FLAC 16-bit")] + [ShortName("flac16")] ffflac, - [Display(Name = "FLAC (24-bit)")] + [Display(Name = "FLAC 24-bit")] + [ShortName("flac24")] ffflac24, } } diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/HBRate.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/HBRate.cs new file mode 100644 index 000000000..2862574dc --- /dev/null +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/HBRate.cs @@ -0,0 +1,24 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrake.Interop.Model.Encoding +{ + /// + /// Represents a rate in HandBrake: audio sample rate or video framerate. + /// + public class HBRate + { + /// + /// Gets or sets the name to use for this rate. + /// + public string Name { get; set; } + + /// + /// Gets or sets the raw rate. + /// + public int Rate { get; set; } + } +} diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs index afdb83148..b355d5038 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/VideoEncoder.cs @@ -3,7 +3,7 @@ // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // -// Defines the VideoEncoder type. +// The video encoder. // // -------------------------------------------------------------------------------------------------------------------- @@ -11,24 +11,30 @@ namespace HandBrake.Interop.Model.Encoding { using System.ComponentModel.DataAnnotations; + using HandBrake.Interop.Attributes; + /// /// The video encoder. /// public enum VideoEncoder { [Display(Name = "H.264 (x264)")] + [ShortName("x264")] X264 = 0, [Display(Name = "H.264 (Intel QSV)")] QuickSync, [Display(Name = "MPEG-4 (FFmpeg)")] + [ShortName("mpeg4")] FFMpeg, [Display(Name = "MPEG-2 (FFmpeg)")] + [ShortName("mpeg2")] FFMpeg2, [Display(Name = "VP3 (Theora)")] - Theora, + [ShortName("theora")] + Theora } } diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs index 936eb0fa9..2902f4f11 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.40.0.0")] -[assembly: AssemblyFileVersion("1.40.0.0")] +[assembly: AssemblyVersion("1.43.0.0")] +[assembly: AssemblyFileVersion("1.43.0.0")] diff --git a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs index dce947311..d24c9998b 100644 --- a/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs +++ b/win/CS/HandBrake.Interop/HandBrakeInterop/SourceData/AudioCodec.cs @@ -48,6 +48,6 @@ namespace HandBrake.Interop.SourceData /// /// The flac. /// - Flac + Flac, } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Commands/SourceMenuCommand.cs b/win/CS/HandBrakeWPF/Commands/SourceMenuCommand.cs index 661ef7fe3..8edc537fc 100644 --- a/win/CS/HandBrakeWPF/Commands/SourceMenuCommand.cs +++ b/win/CS/HandBrakeWPF/Commands/SourceMenuCommand.cs @@ -52,8 +52,6 @@ namespace HandBrakeWPF.Commands #region Implemented Interfaces - #region ICommand - /// /// The can execute. /// @@ -80,7 +78,5 @@ namespace HandBrakeWPF.Commands } #endregion - - #endregion } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Converters/Audio/AudioBitrateConverter.cs b/win/CS/HandBrakeWPF/Converters/Audio/AudioBitrateConverter.cs index f4e805957..bd7aeffca 100644 --- a/win/CS/HandBrakeWPF/Converters/Audio/AudioBitrateConverter.cs +++ b/win/CS/HandBrakeWPF/Converters/Audio/AudioBitrateConverter.cs @@ -70,14 +70,10 @@ namespace HandBrakeWPF.Converters.Audio int samplerate = this.GetBestSampleRate(track); int srShift = this.GetSamplerateShift(samplerate); int lfeCount = this.GetLowFreqChannelCount(track.MixDown); - int channels = this.GetChannelCount(track.MixDown) - lfeCount; + int channels = this.GetDiscreteChannelCount(track.MixDown) - lfeCount; switch (track.Encoder) { - case AudioEncoder.Faac: - low = (channels + lfeCount) * 32; - max = (channels + lfeCount) * (192 >> srShift); - break; case AudioEncoder.ffaac: low = ((channels + lfeCount) * 32); max = ((channels + lfeCount) * ((192 + (64 * ((samplerate << srShift) >= 44100 ? 1 : 0))) >> srShift)); @@ -101,8 +97,17 @@ namespace HandBrakeWPF.Converters.Audio case AudioEncoder.Mp3Passthru: case AudioEncoder.Passthrough: case AudioEncoder.ffflac: + case AudioEncoder.ffflac24: max = 1536; // Since we don't care, just set it to the max. break; + case AudioEncoder.fdkaac: + low = channels * samplerate * 2 / 3000; + max = channels * samplerate * 6 / 1000; + break; + case AudioEncoder.fdkheaac: + low = (channels * (12 + (4 * (samplerate >= 44100 ? 1 : 0)))); + max = (channels - (channels > 2 ? 1 : 0)) * (48 + (16 * (samplerate >= 22050 ? 1 : 0))); + break; default: max = 768; break; @@ -132,7 +137,7 @@ namespace HandBrakeWPF.Converters.Audio /// /// The System.Int32. /// - private int GetChannelCount(Mixdown mixdown) + private int GetDiscreteChannelCount(Mixdown mixdown) { switch (mixdown) { @@ -228,6 +233,10 @@ namespace HandBrakeWPF.Converters.Audio { // AC-3 < 32 kHz suffers from poor hardware compatibility bestSamplerate = 32000; + } + else if ((samplerate < 16000) && (track.Encoder == AudioEncoder.fdkheaac)) + { + bestSamplerate = 16000; } else { diff --git a/win/CS/HandBrakeWPF/Converters/Audio/AudioEncoderConverter.cs b/win/CS/HandBrakeWPF/Converters/Audio/AudioEncoderConverter.cs index 1db7a7c0a..27cb2e5de 100644 --- a/win/CS/HandBrakeWPF/Converters/Audio/AudioEncoderConverter.cs +++ b/win/CS/HandBrakeWPF/Converters/Audio/AudioEncoderConverter.cs @@ -51,6 +51,8 @@ namespace HandBrakeWPF.Converters.Audio List encoders = EnumHelper.GetEnumList().ToList(); EncodeTask task = values[1] as EncodeTask; + encoders.Remove(AudioEncoder.faac); + if (task != null && task.OutputFormat != OutputFormat.Mkv) { encoders.Remove(AudioEncoder.Vorbis); diff --git a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj index 85ee06fb7..83535814b 100644 --- a/win/CS/HandBrakeWPF/HandBrakeWPF.csproj +++ b/win/CS/HandBrakeWPF/HandBrakeWPF.csproj @@ -157,6 +157,7 @@ + @@ -432,6 +433,7 @@ Always + Designer diff --git a/win/CS/HandBrakeWPF/Helpers/AppStyleHelper.cs b/win/CS/HandBrakeWPF/Helpers/AppStyleHelper.cs new file mode 100644 index 000000000..9b67f97e2 --- /dev/null +++ b/win/CS/HandBrakeWPF/Helpers/AppStyleHelper.cs @@ -0,0 +1,37 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. +// +// +// Defines the AppStyleHelper type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace HandBrakeWPF.Helpers +{ + using System.Windows; + + using Caliburn.Micro; + + using HandBrake.ApplicationServices.Services.Interfaces; + + /// + /// The AppStyle Helper. + /// + public class AppStyleHelper + { + /// + /// Gets a value indicating whether use system colours. + /// + public static bool UseSystemColours + { + get + { + IUserSettingService userSettingService = IoC.Get(); + bool useSystemColours = userSettingService.GetUserSetting(UserSettingConstants.UseSystemColours); + + return useSystemColours || SystemParameters.HighContrast; + } + } + } +} diff --git a/win/CS/HandBrakeWPF/Model/SourceMenuItem.cs b/win/CS/HandBrakeWPF/Model/SourceMenuItem.cs index f0b809849..4be52964e 100644 --- a/win/CS/HandBrakeWPF/Model/SourceMenuItem.cs +++ b/win/CS/HandBrakeWPF/Model/SourceMenuItem.cs @@ -55,5 +55,10 @@ namespace HandBrakeWPF.Model /// Gets or sets the tag. /// public object Tag { get; set; } + + /// + /// Gets or sets the input gesture text. + /// + public string InputGestureText { get; set; } } } diff --git a/win/CS/HandBrakeWPF/UserSettingConstants.cs b/win/CS/HandBrakeWPF/UserSettingConstants.cs index b01134b91..b9ce40b0c 100644 --- a/win/CS/HandBrakeWPF/UserSettingConstants.cs +++ b/win/CS/HandBrakeWPF/UserSettingConstants.cs @@ -236,6 +236,11 @@ namespace HandBrakeWPF /// public const string ShowPresetPanel = "ShowPresetPanel"; + /// + /// The use system colours. + /// + public const string UseSystemColours = "UseSystemColours"; + #endregion } } \ No newline at end of file diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs index c7fcbd0ae..81ac6a688 100644 --- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs @@ -922,6 +922,8 @@ namespace HandBrakeWPF.ViewModels } } + public int ProgressPercentage { get; set; } + #endregion #region Load and Shutdown Handling @@ -936,7 +938,11 @@ namespace HandBrakeWPF.ViewModels // Perform an update check if required this.updateService.PerformStartupUpdateCheck(this.HandleUpdateCheckResults); + // Show or Hide the Preset Panel. + this.IsPresetPanelShowing = this.userSettingService.GetUserSetting(UserSettingConstants.ShowPresetPanel); + // Setup the presets. + this.presetService.Load(); if (this.presetService.CheckIfPresetsAreOutOfDate()) if (!this.userSettingService.GetUserSetting(UserSettingConstants.PresetNotification)) this.errorService.ShowMessageBox("HandBrake has determined your built-in presets are out of date... These presets will now be updated." + Environment.NewLine + @@ -951,9 +957,6 @@ namespace HandBrakeWPF.ViewModels // Populate the Source menu with drives. this.SourceMenu = new BindingList(this.GenerateSourceMenu()); - // Show or Hide the Preset Panel. - this.IsPresetPanelShowing = this.userSettingService.GetUserSetting(UserSettingConstants.ShowPresetPanel); - // Log Cleaning if (userSettingService.GetUserSetting(UserSettingConstants.ClearOldLogs)) { @@ -1910,6 +1913,8 @@ namespace HandBrakeWPF.ViewModels } lastEncodePercentage = percent; + this.ProgressPercentage = percent; + this.NotifyOfPropertyChange(() => ProgressPercentage); } else { @@ -2016,14 +2021,16 @@ namespace HandBrakeWPF.ViewModels Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/folder.png")), Width = 16, Height = 16 }, Text = "Open Folder", Command = new SourceMenuCommand(this.FolderScan), - IsDrive = false + IsDrive = false, + InputGestureText = "Ctrl + R" }; SourceMenuItem fileScan = new SourceMenuItem { Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/Movies.png")), Width = 16, Height = 16 }, Text = "Open File", Command = new SourceMenuCommand(this.FileScan), - IsDrive = false + IsDrive = false, + InputGestureText = "Ctrl + F" }; SourceMenuItem titleSpecific = new SourceMenuItem { Text = "Title Specific Scan" }; diff --git a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs index dc9f6806b..e1376363a 100644 --- a/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs @@ -358,6 +358,11 @@ namespace HandBrakeWPF.ViewModels /// private bool removePunctuation; + /// + /// The use system colours for styles. + /// + private bool useSystemColoursForStyles; + #endregion #region Constructors and Destructors @@ -604,6 +609,23 @@ namespace HandBrakeWPF.ViewModels this.NotifyOfPropertyChange("WhenDoneOptions"); } } + + /// + /// Gets or sets a value indicating whether use system colours. + /// + public bool UseSystemColoursForStylesForStyles + { + get + { + return this.useSystemColoursForStyles; + } + set + { + this.useSystemColoursForStyles = value; + this.NotifyOfPropertyChange(() => UseSystemColoursForStylesForStyles); + } + } + #endregion #region Output Files @@ -1514,6 +1536,7 @@ namespace HandBrakeWPF.ViewModels this.SendFileTo = Path.GetFileNameWithoutExtension(this.userSettingService.GetUserSetting(UserSettingConstants.SendFileTo)) ?? string.Empty; this.SendFileToPath = this.userSettingService.GetUserSetting(UserSettingConstants.SendFileTo) ?? string.Empty; this.Arguments = this.userSettingService.GetUserSetting(UserSettingConstants.SendFileToArgs) ?? string.Empty; + this.UseSystemColoursForStylesForStyles = this.userSettingService.GetUserSetting(UserSettingConstants.UseSystemColours); // ############################# // Output Settings @@ -1850,6 +1873,7 @@ namespace HandBrakeWPF.ViewModels this.userSettingService.SetUserSetting(UserSettingConstants.SendFileTo, this.SendFileToPath); this.userSettingService.SetUserSetting(UserSettingConstants.SendFile, this.SendFileAfterEncode); this.userSettingService.SetUserSetting(UserSettingConstants.SendFileToArgs, this.Arguments); + this.userSettingService.SetUserSetting(UserSettingConstants.UseSystemColours, this.UseSystemColoursForStylesForStyles); /* Output Files */ this.userSettingService.SetUserSetting(UserSettingConstants.AutoNaming, this.AutomaticallyNameFiles); diff --git a/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs index a64378a49..39fee77fd 100644 --- a/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/ShellViewModel.cs @@ -15,6 +15,7 @@ namespace HandBrakeWPF.ViewModels using HandBrake.ApplicationServices.Services.Interfaces; + using HandBrakeWPF.Helpers; using HandBrakeWPF.Model; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.ViewModels.Interfaces; diff --git a/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs index 5d07e2321..60e152a10 100644 --- a/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs @@ -1142,7 +1142,6 @@ namespace HandBrakeWPF.ViewModels width = 720; } - // TODO figure out what is wrong with this?? return HandBrakeUtils.CreateX264OptionsString(preset, tunes, this.ExtraArguments, profile, this.H264Level, width, height); } diff --git a/win/CS/HandBrakeWPF/ViewModels/ViewModelBase.cs b/win/CS/HandBrakeWPF/ViewModels/ViewModelBase.cs index f1766741e..7a13881dc 100644 --- a/win/CS/HandBrakeWPF/ViewModels/ViewModelBase.cs +++ b/win/CS/HandBrakeWPF/ViewModels/ViewModelBase.cs @@ -13,6 +13,7 @@ namespace HandBrakeWPF.ViewModels using HandBrake.ApplicationServices.Services.Interfaces; + using HandBrakeWPF.Helpers; using HandBrakeWPF.ViewModels.Interfaces; /// @@ -64,6 +65,17 @@ namespace HandBrakeWPF.ViewModels } } + /// + /// Gets a value indicating whether use system colours. + /// + public bool UseSystemColours + { + get + { + return AppStyleHelper.UseSystemColours; + } + } + /// /// Gets or sets WindowManager. /// diff --git a/win/CS/HandBrakeWPF/Views/AudioView.xaml b/win/CS/HandBrakeWPF/Views/AudioView.xaml index 28d17d776..c71f71858 100644 --- a/win/CS/HandBrakeWPF/Views/AudioView.xaml +++ b/win/CS/HandBrakeWPF/Views/AudioView.xaml @@ -12,7 +12,8 @@ xmlns:dropButton="clr-namespace:HandBrakeWPF.Controls.DropButton" d:DesignHeight="170" d:DesignWidth="616" - mc:Ignorable="d"> + mc:Ignorable="d" + x:Name="audioTab"> @@ -105,17 +106,30 @@ + + + + diff --git a/win/CS/HandBrakeWPF/Views/MainView.xaml b/win/CS/HandBrakeWPF/Views/MainView.xaml index fd95a5b53..67ac70c21 100644 --- a/win/CS/HandBrakeWPF/Views/MainView.xaml +++ b/win/CS/HandBrakeWPF/Views/MainView.xaml @@ -7,7 +7,6 @@ xmlns:Micro="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro" xmlns:attachedProperties="clr-namespace:HandBrakeWPF.AttachedProperties" AllowDrop="True" - Background="#FFF0F0F0" FontSize="11" Micro:Message.Attach="[Event Loaded] = [Action Load]" SnapsToDevicePixels="True" @@ -22,8 +21,7 @@ - - + @@ -160,21 +165,21 @@ - - + + - + - + - - - + + + @@ -203,10 +208,10 @@ @@ -553,9 +558,8 @@ VerticalAlignment="Stretch" Header="Presets" Margin="0,0,0,5" - Background="White" - Visibility="{Binding IsPresetPanelShowing, Converter={StaticResource boolToVisConverter}}" - > + Visibility="{Binding IsPresetPanelShowing, Converter={StaticResource boolToVisConverter}}"> + @@ -664,18 +668,12 @@ /> - + + + diff --git a/win/CS/HandBrakeWPF/Views/OptionsView.xaml b/win/CS/HandBrakeWPF/Views/OptionsView.xaml index dcf9994c8..64d7389ad 100644 --- a/win/CS/HandBrakeWPF/Views/OptionsView.xaml +++ b/win/CS/HandBrakeWPF/Views/OptionsView.xaml @@ -4,7 +4,7 @@ xmlns:Options="clr-namespace:HandBrakeWPF.Converters.Options" xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop" xmlns:Converters="clr-namespace:HandBrakeWPF.Converters" xmlns:local="clr-namespace:HandBrakeWPF.Model" - Background="White"> + Style="{StaticResource whiteUserControlStyle}"> + + + + @@ -14,6 +39,14 @@ + + + + diff --git a/win/CS/HandBrakeWPF/defaultsettings.xml b/win/CS/HandBrakeWPF/defaultsettings.xml index 7ba21e103..30eebc778 100644 --- a/win/CS/HandBrakeWPF/defaultsettings.xml +++ b/win/CS/HandBrakeWPF/defaultsettings.xml @@ -464,4 +464,12 @@ true + + + UseSystemColours + + + false + + \ No newline at end of file diff --git a/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.XML b/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.XML index 297f4bf28..e46d7093d 100644 --- a/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.XML +++ b/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.XML @@ -366,6 +366,11 @@ Gets a flag enumeration indicating the current state of the SHIFT, CTRL, and ALT keys, as well as the state of the mouse buttons. + + + Indicates if the drop info should be handled by itself (useful for child elements) + + Holds information about a the target of a drag drop operation. diff --git a/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.dll b/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.dll index 3e9615082e957635a35ca6f5b107928e1509293d..395aac56db91a32682db5d9928f3a58052ee7058 100644 GIT binary patch delta 17629 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 H@3sE}#USV7 delta 17082 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 diff --git a/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.pdb b/win/CS/libraries/WPFDragDrop/GongSolutions.Wpf.DragDrop.pdb index 997730460e5dac0910dc4f6de37527397194fe4f..5b01a61e87e05f43b24547c4ce4ce363702c6547 100644 GIT binary patch delta 21062 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

WN4@;!G%cWoG6`Q2Ch4@RPm7H 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 -- 2.49.0