]> granicus.if.org Git - handbrake/commitdiff
Merging Trunk into QSV branch.
authorsr55 <sr55.hb@outlook.com>
Sat, 1 Jun 2013 18:33:26 +0000 (18:33 +0000)
committersr55 <sr55.hb@outlook.com>
Sat, 1 Jun 2013 18:33:26 +0000 (18:33 +0000)
git-svn-id: svn://svn.handbrake.fr/HandBrake/branches/qsv@5540 b64f7644-9d1e-0410-96f1-a4d463321fa5

73 files changed:
gtk/src/audiohandler.c
gtk/src/hb-backend.c
gtk/src/hb-backend.h
gtk/src/presets.c
libhb/common.c
libhb/common.h
libhb/cropscale.c
libhb/encavcodec.c
libhb/scan.c
libhb/vfr.c
libhb/work.c
macosx/Controller.m
macosx/HBAudio.m
macosx/HBAudioController.m
macosx/HBPreviewController.m
macosx/HBSubtitles.m
pkg/linux/module.rules
scripts/manicure.rb
test/test.c
win/CS/HandBrake.ApplicationServices/ASUserSettingConstants.cs
win/CS/HandBrake.ApplicationServices/EventArgs/EncodeCompletedEventArgs.cs
win/CS/HandBrake.ApplicationServices/Model/EncodeTask.cs
win/CS/HandBrake.ApplicationServices/Model/PresetPictureSettingsMode.cs
win/CS/HandBrake.ApplicationServices/Parsing/Subtitle.cs
win/CS/HandBrake.ApplicationServices/Services/Encode.cs
win/CS/HandBrake.ApplicationServices/Services/LibEncode.cs
win/CS/HandBrake.ApplicationServices/Services/PresetService.cs
win/CS/HandBrake.ApplicationServices/Services/QueueProcessor.cs
win/CS/HandBrake.ApplicationServices/Utilities/Converters.cs
win/CS/HandBrake.ApplicationServices/Utilities/GeneralUtilities.cs
win/CS/HandBrake.ApplicationServices/Utilities/LanguageUtilities.cs
win/CS/HandBrake.ApplicationServices/Utilities/PlistUtility.cs
win/CS/HandBrake.Interop/HandBrakeInterop/Model/Encoding/AudioEncoder.cs
win/CS/HandBrake.Server/Program.cs
win/CS/HandBrakeWPF/AttachedProperties/DriveMenu.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Constants.cs
win/CS/HandBrakeWPF/Controls/DropButton/DropButton.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Converters/Audio/AudioEncoderConverter.cs
win/CS/HandBrakeWPF/HandBrakeWPF.csproj
win/CS/HandBrakeWPF/Helpers/AutoNameHelper.cs
win/CS/HandBrakeWPF/Helpers/CliCheckHelper.cs
win/CS/HandBrakeWPF/Installer/Installer.nsi
win/CS/HandBrakeWPF/Installer/Installer64.nsi
win/CS/HandBrakeWPF/Model/SourceMenuItem.cs
win/CS/HandBrakeWPF/Properties/Resources.Designer.cs
win/CS/HandBrakeWPF/Properties/Resources.resx
win/CS/HandBrakeWPF/Services/DriveDetectService.cs [deleted file]
win/CS/HandBrakeWPF/Services/Interfaces/IDriveDetectService.cs [deleted file]
win/CS/HandBrakeWPF/Services/Interfaces/INotificationService.cs
win/CS/HandBrakeWPF/Services/Interfaces/IPrePostActionService.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Services/PrePostActionService.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Startup/CastleBootstrapper.cs
win/CS/HandBrakeWPF/UserSettingConstants.cs
win/CS/HandBrakeWPF/ViewModels/AddPresetViewModel.cs
win/CS/HandBrakeWPF/ViewModels/AudioViewModel.cs
win/CS/HandBrakeWPF/ViewModels/Interfaces/IAddPresetViewModel.cs
win/CS/HandBrakeWPF/ViewModels/Interfaces/IQueueSelectionViewModel.cs
win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs
win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs
win/CS/HandBrakeWPF/ViewModels/PictureSettingsViewModel.cs
win/CS/HandBrakeWPF/ViewModels/QueueSelectionViewModel.cs
win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs
win/CS/HandBrakeWPF/ViewModels/SubtitlesViewModel.cs
win/CS/HandBrakeWPF/ViewModels/VideoViewModel.cs
win/CS/HandBrakeWPF/Views/AddPresetView.xaml
win/CS/HandBrakeWPF/Views/AudioView.xaml
win/CS/HandBrakeWPF/Views/MainView.xaml
win/CS/HandBrakeWPF/Views/QueueSelectionView.xaml
win/CS/HandBrakeWPF/Views/QueueView.xaml
win/CS/HandBrakeWPF/Views/Styles/Styles.xaml
win/CS/HandBrakeWPF/Views/SubtitlesView.xaml
win/CS/HandBrakeWPF/Views/VideoView.xaml
win/CS/HandBrakeWPF/defaultsettings.xml

index 2a7b619e49df4d8d19352a0bcdcf912a61d9e5a3..72f58bfa73162228c68bf0393350e4bac69c75f1 100644 (file)
@@ -63,12 +63,13 @@ ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint f
         return hb_autopassthru_get_encoder(in_codec, copy_mask, fallback, mux);
     }
 
-    gint ii;
     // Sanitize fallback
-    for (ii = 0; ii < hb_audio_encoders_count; ii++)
+    const hb_encoder_t *enc;
+    for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+         enc = hb_audio_encoder_get_next(enc))
     {
-        if (hb_audio_encoders[ii].encoder == fallback &&
-            !(hb_audio_encoders[ii].muxers & mux))
+        if (enc->codec == fallback &&
+            !(enc->muxers & mux))
         {
             if ( mux == HB_MUX_MKV )
                 fallback = HB_ACODEC_LAME;
@@ -82,10 +83,11 @@ ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint f
     {
         return fallback;
     }
-    for (ii = 0; ii < hb_audio_encoders_count; ii++)
+    for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+         enc = hb_audio_encoder_get_next(enc))
     {
-        if (hb_audio_encoders[ii].encoder == acodec &&
-            !(hb_audio_encoders[ii].muxers & mux))
+        if (enc->codec == acodec &&
+            !(enc->muxers & mux))
         {
             return fallback;
         }
@@ -198,7 +200,7 @@ ghb_sanitize_audio(GValue *settings, GValue *asettings)
     {
         if (mix == 0)
             mix = ghb_get_best_mix( aconfig, select_acodec, 0);
-        bitrate = hb_get_best_audio_bitrate(select_acodec, bitrate, sr, mix);
+        bitrate = hb_audio_bitrate_get_best(select_acodec, bitrate, sr, mix);
         ghb_settings_set_string(asettings, "AudioMixdown",
             ghb_lookup_combo_string("AudioMixdown", ghb_int_value(mix)));
     }
@@ -206,7 +208,7 @@ ghb_sanitize_audio(GValue *settings, GValue *asettings)
         ghb_lookup_combo_string("AudioBitrate", ghb_int_value(bitrate)));
 
     ghb_settings_take_value(asettings, "AudioEncoderActual", 
-                            ghb_lookup_acodec_value(select_acodec));
+                            ghb_lookup_audio_encoder_value(select_acodec));
 }
 
 void
@@ -283,25 +285,25 @@ ghb_adjust_audio_rate_combos(signal_user_data_t *ud)
     {
         if (mix == 0)
             mix = ghb_get_best_mix( aconfig, select_acodec, 0);
-        bitrate = hb_get_best_audio_bitrate(select_acodec, bitrate, sr, mix);
+        bitrate = hb_audio_bitrate_get_best(select_acodec, bitrate, sr, mix);
         ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix));
     }
     if (!codec_defined_bitrate)
     {
         int low, high;
         mix = ghb_get_best_mix( aconfig, select_acodec, mix);
-        hb_get_audio_bitrate_limits(select_acodec, sr, mix, &low, &high);
+        hb_audio_bitrate_get_limits(select_acodec, sr, mix, &low, &high);
         ghb_set_bitrate_opts (ud->builder, low, high, -1);
     }
     ghb_ui_update(ud, "AudioBitrate", ghb_int64_value(bitrate));
 
     ghb_settings_take_value(ud->settings, "AudioEncoderActual", 
-                            ghb_lookup_acodec_value(select_acodec));
+                            ghb_lookup_audio_encoder_value(select_acodec));
     GValue *asettings = get_selected_asettings(ud);
     if (asettings)
     {
         ghb_settings_take_value(asettings, "AudioEncoderActual", 
-                            ghb_lookup_acodec_value(select_acodec));
+                            ghb_lookup_audio_encoder_value(select_acodec));
     }
     ghb_audio_list_refresh_selected(ud);
     ghb_check_dependency(ud, NULL, "AudioEncoderActual");
@@ -423,7 +425,7 @@ ghb_set_pref_audio_settings(gint titleindex, GValue *settings)
             ghb_settings_set_string(asettings, "AudioEncoder", 
                 ghb_lookup_combo_string("AudioEncoder", ghb_int_value(acodec)));
             ghb_settings_set_value(asettings, "AudioEncoderActual", 
-                                    ghb_lookup_acodec_value(select_acodec));
+                                    ghb_lookup_audio_encoder_value(select_acodec));
             ghb_settings_set_value(asettings, "AudioTrackQualityEnable", enable_qual);
             ghb_settings_set_double(asettings, "AudioTrackQuality", quality);
 
@@ -687,7 +689,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
         track = ghb_settings_combo_int(ud->settings, "AudioTrack");
         if (sr)
         {
-            sr = ghb_find_closest_audio_rate(sr);
+            sr = ghb_find_closest_audio_samplerate(sr);
         }
         ghb_ui_update(ud, "AudioSamplerate", ghb_int64_value(sr));
 
@@ -698,7 +700,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
             sr = aconfig ? aconfig->in.samplerate : 48000;
         }
         mix_code = ghb_get_best_mix( aconfig, acodec_code, mix_code);
-        br = hb_get_best_audio_bitrate(acodec_code, br, sr, mix_code);
+        br = hb_audio_bitrate_get_best(acodec_code, br, sr, mix_code);
         ghb_ui_update(ud, "AudioBitrate", ghb_int64_value(br));
 
         ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix_code));
@@ -717,8 +719,8 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
 
     float low, high, gran, defval;
     int dir;
-    hb_get_audio_quality_limits(acodec_code, &low, &high, &gran, &dir);
-    defval = hb_get_default_audio_quality(acodec_code);
+    hb_audio_quality_get_limits(acodec_code, &low, &high, &gran, &dir);
+    defval = hb_audio_quality_get_default(acodec_code);
     GtkScaleButton *sb;
     GtkAdjustment *adj;
     sb = GTK_SCALE_BUTTON(GHB_WIDGET(ud->builder, "AudioTrackQuality"));
@@ -843,7 +845,7 @@ char * ghb_format_quality( const char *prefix, int codec, double quality )
 {
     float low, high, gran;
     int dir;
-    hb_get_audio_quality_limits(codec, &low, &high, &gran, &dir);
+    hb_audio_quality_get_limits(codec, &low, &high, &gran, &dir);
 
     int digits = 0;
     float tmp = gran;
@@ -868,7 +870,7 @@ quality_widget_changed_cb(GtkWidget *widget, gdouble quality, signal_user_data_t
     float low, high, gran;
     int dir;
     int codec = ghb_settings_combo_int(ud->settings, "AudioEncoderActual");
-    hb_get_audio_quality_limits(codec, &low, &high, &gran, &dir);
+    hb_audio_quality_get_limits(codec, &low, &high, &gran, &dir);
     if (dir)
     {
         // Quality values are inverted
index 689c3b7e0af280b685039259dbc09d41544d020f..b3f82067c7f794b7803edcc54e14573a932bbcdb 100644 (file)
@@ -173,17 +173,6 @@ combo_opts_t vqual_granularity_opts =
     d_vqual_granularity_opts
 };
 
-static options_map_t d_container_opts[] =
-{
-    {"MKV", "mkv", HB_MUX_MKV, "mkv"},
-    {"MP4", "mp4", HB_MUX_MP4, "mp4"},
-};
-combo_opts_t container_opts =
-{
-    sizeof(d_container_opts)/sizeof(options_map_t),
-    d_container_opts
-};
-
 static options_map_t d_detel_opts[] =
 {
     {"Off",    "off",   0, ""},
@@ -383,7 +372,6 @@ combo_name_map_t combo_name_map[] =
     {"LogLongevity", &log_longevity_opts},
     {"check_updates", &appcast_update_opts},
     {"VideoQualityGranularity", &vqual_granularity_opts},
-    {"FileFormat", &container_opts},
     {"PictureDeinterlace", &deint_opts},
     {"PictureDecomb", &decomb_opts},
     {"PictureDetelecine", &detel_opts},
@@ -842,529 +830,532 @@ lookup_generic_option(combo_opts_t *opts, const GValue *gval)
     return result;
 }
 
-static gint
-lookup_mix_int(const GValue *mix)
+static const hb_mixdown_t *
+lookup_mixdown_by_int(int imix)
 {
-    gint ii;
-    gint result = 0;
-
-
-    if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
+    const hb_mixdown_t *mix;
+    for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+         mix = hb_mixdown_get_next(mix))
     {
-        gchar * str = ghb_value_string(mix);
-        for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+        if (mix->amixdown == imix)
         {
-            if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
-            {
-                result = hb_audio_mixdowns[ii].amixdown;
-                break;
-            }
-        }
-        g_free(str);
-    }
-    else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
-             G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
-    {
-        gint val = ghb_value_int(mix);
-        for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
-        {
-            if (hb_audio_mixdowns[ii].amixdown == val)
-            {
-                result = hb_audio_mixdowns[ii].amixdown;
-                break;
-            }
+            return mix;
         }
     }
-    return result;
+    return NULL;
 }
 
-static const gchar*
-lookup_mix_option(const GValue *mix)
+static const hb_mixdown_t *
+lookup_mixdown(const GValue *gmix)
 {
-    gint ii;
-    const gchar *result = "None";
+    const hb_mixdown_t *mix;
 
-
-    if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
+    if (G_VALUE_TYPE(gmix) == G_TYPE_STRING)
     {
-        gchar *str = ghb_value_string(mix);
-        for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+        gchar * str = ghb_value_string(gmix);
+        for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+             mix = hb_mixdown_get_next(mix))
         {
-            if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
+            if (strcmp(mix->short_name, str) == 0)
             {
-                result = hb_audio_mixdowns[ii].human_readable_name;
-                break;
+                g_free(str);
+                return mix;
             }
         }
         g_free(str);
     }
-    else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
-             G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
+    else if (G_VALUE_TYPE(gmix) == G_TYPE_INT ||
+             G_VALUE_TYPE(gmix) == G_TYPE_INT64 ||
+             G_VALUE_TYPE(gmix) == G_TYPE_DOUBLE)
     {
-        gint val = ghb_value_int(mix);
-        for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
-        {
-            if (hb_audio_mixdowns[ii].amixdown == val)
-            {
-                result = hb_audio_mixdowns[ii].human_readable_name;
-                break;
-            }
-        }
+        return lookup_mixdown_by_int(ghb_value_int(gmix));
     }
-    return result;
+    return NULL;
 }
 
-static const gchar*
-lookup_mix_string(const GValue *mix)
+static gint
+lookup_mixdown_int(const GValue *gmix)
 {
-    gint ii;
-    const gchar *result = "none";
+    const hb_mixdown_t *mix = lookup_mixdown(gmix);
+    if (mix != NULL)
+        return mix->amixdown;
+    return 0;
+}
 
+static const gchar*
+lookup_mixdown_option(const GValue *gmix)
+{
+    const hb_mixdown_t *mix = lookup_mixdown(gmix);
+    if (mix != NULL)
+        return mix->name;
+    return "None";
+}
 
-    if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
-    {
-        gchar *str = ghb_value_string(mix);
-        for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
-        {
-            if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
-            {
-                result = hb_audio_mixdowns[ii].short_name;
-                break;
-            }
-        }
-        g_free(str);
-    }
-    else if (G_VALUE_TYPE(mix) == G_TYPE_INT ||
-             G_VALUE_TYPE(mix) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(mix) == G_TYPE_DOUBLE)
-    {
-        gint val = ghb_value_int(mix);
-        for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
-        {
-            if (hb_audio_mixdowns[ii].amixdown == val)
-            {
-                result = hb_audio_mixdowns[ii].short_name;
-                break;
-            }
-        }
-    }
-    return result;
+static const gchar*
+lookup_mixdown_string(const GValue *gmix)
+{
+    const hb_mixdown_t *mix = lookup_mixdown(gmix);
+    if (mix != NULL)
+        return mix->short_name;
+    return "none";
 }
 
-static gint
-lookup_video_rate_int(const GValue *vrate)
+static const hb_rate_t *
+lookup_video_framerate(const GValue *grate)
 {
-    gint ii;
     gchar *str;
-    gint result = 0;
+    const hb_rate_t *rate;
 
-    str = ghb_value_string(vrate);
-    for (ii = 0; ii < hb_video_rates_count; ii++)
+    str = ghb_value_string(grate);
+    for (rate = hb_video_framerate_get_next(NULL); rate != NULL;
+         rate = hb_video_framerate_get_next(rate))
     {
-        if (strcmp(hb_video_rates[ii].string, str) == 0)
+        if (strcmp(rate->name, str) == 0)
         {
-            result = hb_video_rates[ii].rate;
-            break;
+            g_free(str);
+            return rate;
         }
     }
     g_free(str);
     // Default to "same as source"
-    return result;
+    return NULL;
 }
 
-static const gchar*
-lookup_video_rate_option(const GValue *vrate)
+static gint
+lookup_video_framerate_int(const GValue *grate)
 {
-    gint ii;
-    gchar *str;
-    const gchar *result = "Same as source";
+    const hb_rate_t *rate = lookup_video_framerate(grate);
+    if (rate != NULL)
+        return rate->rate;
+    return 0;
+}
 
-    str = ghb_value_string(vrate);
-    for (ii = 0; ii < hb_video_rates_count; ii++)
-    {
-        if (strcmp(hb_video_rates[ii].string, str) == 0)
-        {
-            result = hb_video_rates[ii].string;
-            break;
-        }
-    }
-    g_free(str);
-    // Default to "same as source"
-    return result;
+static const gchar*
+lookup_video_framerate_option(const GValue *grate)
+{
+    const hb_rate_t *rate = lookup_video_framerate(grate);
+    if (rate != NULL)
+        return rate->name;
+    return "Same as source";
 }
 
-static gint
-lookup_audio_rate_int(const GValue *rate)
+static const hb_rate_t *
+lookup_audio_samplerate(const GValue *grate)
 {
-    gint ii;
-    gint result = 0;
+    const hb_rate_t *rate;
 
-    if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
+    if (G_VALUE_TYPE(grate) == G_TYPE_STRING)
     {
         // Coincidentally, the string "source" will return 0
         // which is our flag to use "same as source"
-        gchar * str = ghb_value_string(rate);
-        for (ii = 0; ii < hb_audio_rates_count; ii++)
+        gchar * str = ghb_value_string(grate);
+        for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+             rate = hb_audio_samplerate_get_next(rate))
         {
-            if (strcmp(hb_audio_rates[ii].string, str) == 0)
+            if (strcmp(rate->name, str) == 0)
             {
-                result = hb_audio_rates[ii].rate;
-                break;
+                g_free(str);
+                return rate;
             }
         }
         g_free(str);
     }
-    else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
-             G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
+    else if (G_VALUE_TYPE(grate) == G_TYPE_INT ||
+             G_VALUE_TYPE(grate) == G_TYPE_INT64 ||
+             G_VALUE_TYPE(grate) == G_TYPE_DOUBLE)
     {
-        for (ii = 0; ii < hb_audio_rates_count; ii++)
+        gint val = ghb_value_int(grate);
+        for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+             rate = hb_audio_samplerate_get_next(rate))
         {
-            gint val = ghb_value_int(rate);
-            if (val == hb_audio_rates[ii].rate)
+            if (val == rate->rate)
             {
-                result = hb_audio_rates[ii].rate;
-                break;
+                return rate;
             }
         }
     }
-    return result;
+    return NULL;
+}
+
+static gint
+lookup_audio_samplerate_int(const GValue *grate)
+{
+    const hb_rate_t *rate = lookup_audio_samplerate(grate);
+    if (rate != NULL)
+        return rate->rate;
+    return 0;
 }
 
 static const gchar*
-lookup_audio_rate(const GValue *rate, const char *def)
+lookup_audio_samplerate_def(const GValue *grate, const char *def)
 {
-    gint ii;
     const gchar *result = def;
-
-    if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
-    {
-        // Coincidentally, the string "source" will return 0
-        // which is our flag to use "same as source"
-        gchar *str = ghb_value_string(rate);
-        for (ii = 0; ii < hb_audio_rates_count; ii++)
-        {
-            if (strcmp(hb_audio_rates[ii].string, str) == 0)
-            {
-                result = hb_audio_rates[ii].string;
-                break;
-            }
-        }
-        g_free(str);
-    }
-    else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
-             G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
-    {
-        for (ii = 0; ii < hb_audio_rates_count; ii++)
-        {
-            gint val = ghb_value_int(rate);
-            if (val == hb_audio_rates[ii].rate)
-            {
-                result = hb_audio_rates[ii].string;
-                break;
-            }
-        }
-    }
+    const hb_rate_t *rate = lookup_audio_samplerate(grate);
+    if (rate != NULL)
+        return rate->name;
     return result;
 }
 
 static const gchar*
-lookup_audio_rate_option(const GValue *rate)
+lookup_audio_samplerate_option(const GValue *grate)
 {
-    return lookup_audio_rate(rate, "Same as Source");
+    return lookup_audio_samplerate_def(grate, "Same as Source");
 }
 
 static const gchar*
-lookup_audio_rate_string(const GValue *rate)
+lookup_audio_samplerate_string(const GValue *grate)
 {
-    return lookup_audio_rate(rate, "source");
+    return lookup_audio_samplerate_def(grate, "source");
 }
 
 gint
-ghb_find_closest_audio_rate(gint rate)
+ghb_find_closest_audio_samplerate(gint irate)
 {
-    gint ii;
     gint result;
+    const hb_rate_t *rate;
 
     result = 0;
-    for (ii = 0; ii < hb_audio_rates_count; ii++)
+    for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+         rate = hb_audio_samplerate_get_next(rate))
     {
-        if (rate <= hb_audio_rates[ii].rate)
+        if (irate <= rate->rate)
         {
-            result = hb_audio_rates[ii].rate;
+            result = rate->rate;
             break;
         }
     }
     return result;
 }
 
-hb_rate_t *ghb_audio_bitrates;
-int ghb_audio_bitrates_count;
+hb_rate_t *ghb_audio_bitrates = NULL;
+int ghb_audio_bitrates_count = 0;
+int ghb_abr_count = 0;
 
-static gint
-lookup_audio_bitrate_int(const GValue *rate)
+static const hb_rate_t *
+lookup_audio_bitrate(const GValue *grate)
 {
     gint ii;
-    gint result = 160;
+    const hb_rate_t *result = NULL;
 
-    if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
+    if (G_VALUE_TYPE(grate) == G_TYPE_STRING)
     {
         // Coincidentally, the string "source" will return 0
         // which is our flag to use "same as source"
-        gchar *str = ghb_value_string(rate);
+        gchar *str = ghb_value_string(grate);
         for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
         {
-            if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
+            if (strcmp(ghb_audio_bitrates[ii].name, str) == 0)
             {
-                result = ghb_audio_bitrates[ii].rate;
-                break;
+                g_free(str);
+                return &ghb_audio_bitrates[ii];
             }
         }
         g_free(str);
     }
-    else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
-             G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
+    else if (G_VALUE_TYPE(grate) == G_TYPE_INT ||
+             G_VALUE_TYPE(grate) == G_TYPE_INT64 ||
+             G_VALUE_TYPE(grate) == G_TYPE_DOUBLE)
     {
-        gint val = ghb_value_int(rate);
+        gint val = ghb_value_int(grate);
         for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
         {
             if (ghb_audio_bitrates[ii].rate == val)
             {
-                result = ghb_audio_bitrates[ii].rate;
-                break;
+                return &ghb_audio_bitrates[ii];
             }
         }
     }
     return result;
 }
 
+static gint
+lookup_audio_bitrate_int(const GValue *grate)
+{
+    const hb_rate_t *rate = lookup_audio_bitrate(grate);
+    if (rate != NULL)
+        return rate->rate;
+    return 160;
+}
+
 static const gchar*
-lookup_audio_bitrate_option(const GValue *rate)
+lookup_audio_bitrate_option(const GValue *grate)
 {
-    gint ii;
-    const gchar *result = "160";
+    const hb_rate_t *rate = lookup_audio_bitrate(grate);
+    if (rate != NULL)
+        return rate->name;
+    return "160";
+}
 
-    if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
-    {
-        // Coincidentally, the string "source" will return 0
-        // which is our flag to use "same as source"
-        gchar *str = ghb_value_string(rate);
-        for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
-        {
-            if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
-            {
-                result = ghb_audio_bitrates[ii].string;
-                break;
-            }
-        }
-        g_free(str);
-    }
-    else if (G_VALUE_TYPE(rate) == G_TYPE_INT ||
-             G_VALUE_TYPE(rate) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(rate) == G_TYPE_DOUBLE)
+static const hb_encoder_t *
+lookup_audio_encoder_by_int(int ienc)
+{
+    const hb_encoder_t *enc;
+    for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+         enc = hb_audio_encoder_get_next(enc))
     {
-        gint val = ghb_value_int(rate);
-        for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
+        if (enc->codec == ienc)
         {
-            if (ghb_audio_bitrates[ii].rate == val)
-            {
-                result = ghb_audio_bitrates[ii].string;
-                break;
-            }
+            return enc;
         }
     }
-    return result;
+    return NULL;
 }
 
-static gint
-lookup_hb_encoder_int(const GValue *enc, hb_encoder_t *encoders, int len)
+static const hb_encoder_t *
+lookup_audio_encoder(const GValue *genc)
 {
-    gint ii;
+    const hb_encoder_t *enc;
 
-    if (G_VALUE_TYPE(enc) == G_TYPE_STRING)
+    if (G_VALUE_TYPE(genc) == G_TYPE_STRING)
     {
-        gchar *str = ghb_value_string(enc);
-        for (ii = 0; ii < len; ii++)
+        gchar *str = ghb_value_string(genc);
+        for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+             enc = hb_audio_encoder_get_next(enc))
         {
-            if (strcmp(encoders[ii].human_readable_name, str) == 0 ||
-                strcmp(encoders[ii].short_name, str) == 0)
+            if (strcmp(enc->name, str) == 0 ||
+                strcmp(enc->short_name, str) == 0)
             {
                 g_free(str);
-                return encoders[ii].encoder;
+                return enc;
             }
         }
         g_free(str);
     }
-    else if (G_VALUE_TYPE(enc) == G_TYPE_INT ||
-             G_VALUE_TYPE(enc) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(enc) == G_TYPE_DOUBLE)
+    else if (G_VALUE_TYPE(genc) == G_TYPE_INT ||
+             G_VALUE_TYPE(genc) == G_TYPE_INT64 ||
+             G_VALUE_TYPE(genc) == G_TYPE_DOUBLE)
     {
-        int val = ghb_value_int(enc);
-        for (ii = 0; ii < len; ii++)
-        {
-            if (encoders[ii].encoder == val)
-            {
-                return encoders[ii].encoder;
-            }
-        }
+        return lookup_audio_encoder_by_int(ghb_value_int(genc));
     }
-    return 0;
+    return NULL;
 }
 
-static const gchar*
-lookup_hb_encoder_option(const GValue *enc, hb_encoder_t *encoders, int len)
+static const hb_encoder_t *
+lookup_video_encoder_by_int(int ienc)
 {
-    gint ii;
-
-    if (G_VALUE_TYPE(enc) == G_TYPE_STRING)
+    const hb_encoder_t *enc;
+    for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+         enc = hb_video_encoder_get_next(enc))
     {
-        gchar *str = ghb_value_string(enc);
-        for (ii = 0; ii < len; ii++)
+        if (enc->codec == ienc)
         {
-            if (strcmp(encoders[ii].human_readable_name, str) == 0 ||
-                strcmp(encoders[ii].short_name, str) == 0)
-            {
-                g_free(str);
-                return encoders[ii].human_readable_name;
-            }
+            return enc;
         }
-        g_free(str);
     }
-    else if (G_VALUE_TYPE(enc) == G_TYPE_INT ||
-             G_VALUE_TYPE(enc) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(enc) == G_TYPE_DOUBLE)
-    {
-        int val = ghb_value_int(enc);
-        for (ii = 0; ii < len; ii++)
-        {
-            if (encoders[ii].encoder == val)
-            {
-                return encoders[ii].human_readable_name;
-            }
-        }
-    }
-    return 0;
+    return NULL;
 }
 
-static const gchar*
-lookup_hb_encoder_string(const GValue *enc, hb_encoder_t *encoders, int len)
+static const hb_encoder_t *
+lookup_video_encoder(const GValue *genc)
 {
-    gint ii;
+    const hb_encoder_t *enc;
 
-    if (G_VALUE_TYPE(enc) == G_TYPE_STRING)
+    if (G_VALUE_TYPE(genc) == G_TYPE_STRING)
     {
-        gchar *str = ghb_value_string(enc);
-        for (ii = 0; ii < len; ii++)
+        gchar *str = ghb_value_string(genc);
+        for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+             enc = hb_video_encoder_get_next(enc))
         {
-            if (strcmp(encoders[ii].human_readable_name, str) == 0 ||
-                strcmp(encoders[ii].short_name, str) == 0)
+            if (strcmp(enc->name, str) == 0 ||
+                strcmp(enc->short_name, str) == 0)
             {
                 g_free(str);
-                return encoders[ii].short_name;
+                return enc;
             }
         }
         g_free(str);
     }
-    else if (G_VALUE_TYPE(enc) == G_TYPE_INT ||
-             G_VALUE_TYPE(enc) == G_TYPE_INT64 ||
-             G_VALUE_TYPE(enc) == G_TYPE_DOUBLE)
+    else if (G_VALUE_TYPE(genc) == G_TYPE_INT ||
+             G_VALUE_TYPE(genc) == G_TYPE_INT64 ||
+             G_VALUE_TYPE(genc) == G_TYPE_DOUBLE)
     {
-        int val = ghb_value_int(enc);
-        for (ii = 0; ii < len; ii++)
-        {
-            if (encoders[ii].encoder == val)
-            {
-                return encoders[ii].short_name;
-            }
-        }
+        return lookup_video_encoder_by_int(ghb_value_int(genc));
     }
+    return NULL;
+}
+
+static gint
+lookup_audio_encoder_int(const GValue *genc)
+{
+    const hb_encoder_t *enc = lookup_audio_encoder(genc);
+    if (enc != NULL)
+        return enc->codec;
     return 0;
 }
 
 static gint
-lookup_audio_lang_int(const GValue *rate)
+lookup_video_encoder_int(const GValue *genc)
+{
+    const hb_encoder_t *enc = lookup_video_encoder(genc);
+    if (enc != NULL)
+        return enc->codec;
+    return 0;
+}
+
+static const gchar*
+lookup_audio_encoder_option(const GValue *genc)
+{
+    const hb_encoder_t *enc = lookup_audio_encoder(genc);
+    if (enc != NULL)
+        return enc->name;
+    return NULL;
+}
+
+static const gchar*
+lookup_video_encoder_option(const GValue *genc)
+{
+    const hb_encoder_t *enc = lookup_video_encoder(genc);
+    if (enc != NULL)
+        return enc->name;
+    return NULL;
+}
+
+static const gchar*
+lookup_audio_encoder_string(const GValue *genc)
+{
+    const hb_encoder_t *enc = lookup_audio_encoder(genc);
+    if (enc != NULL)
+        return enc->short_name;
+    return NULL;
+}
+
+static const gchar*
+lookup_video_encoder_string(const GValue *genc)
+{
+    const hb_encoder_t *enc = lookup_video_encoder(genc);
+    if (enc != NULL)
+        return enc->short_name;
+    return NULL;
+}
+
+static int
+lookup_audio_lang(const GValue *glang)
 {
     gint ii;
     gchar *str;
-    gint result = 0;
 
-    // Coincidentally, the string "source" will return 0
-    // which is our flag to use "same as source"
-    str = ghb_value_string(rate);
+    str = ghb_value_string(glang);
     for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
     {
         if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
         {
-            result = ii;
-            break;
+            g_free(str);
+            return ii;
         }
     }
     g_free(str);
-    return result;
+    return -1;
 }
 
-static const gchar*
-lookup_audio_lang_option(const GValue *rate)
+static int
+lookup_audio_lang_int(const GValue *glang)
 {
-    gint ii;
-    gchar *str;
-    const gchar *result = "Same as source";
+    gint ii = lookup_audio_lang(glang);
+    if (ii >= 0)
+        return ii;
+    return 0;
+}
 
-    // Coincidentally, the string "source" will return 0
-    // which is our flag to use "same as source"
-    str = ghb_value_string(rate);
-    for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
+static const gchar*
+lookup_audio_lang_option(const GValue *glang)
+{
+    gint ii = lookup_audio_lang(glang);
+    if (ii >= 0)
     {
-        if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
-        {
-            if (ghb_language_table[ii].native_name[0] != 0)
-                result = ghb_language_table[ii].native_name;
-            else
-                result = ghb_language_table[ii].eng_name;
-            break;
-        }
+        if (ghb_language_table[ii].native_name[0] != 0)
+            return ghb_language_table[ii].native_name;
+        else
+            return ghb_language_table[ii].eng_name;
     }
-    g_free(str);
-    return result;
+    return "Same as source";
 }
 
 GValue*
-ghb_lookup_acodec_value(gint val)
+ghb_lookup_audio_encoder_value(gint ienc)
 {
-    GValue *value = NULL;
-    gint ii;
+    const hb_encoder_t *enc = lookup_audio_encoder_by_int(ienc);
+    if (enc != NULL)
+        return ghb_string_value_new(enc->short_name);
+    return ghb_string_value_new("copy");
+}
 
-    for (ii = 0; ii < hb_audio_encoders_count; ii++)
+static GValue*
+lookup_mixdown_value(gint imix)
+{
+    const hb_mixdown_t *mix = lookup_mixdown_by_int(imix);
+    if (mix != NULL)
+        return ghb_string_value_new(mix->short_name);
+    return NULL;
+}
+static const hb_container_t *
+lookup_container_by_int(int imux)
+{
+    const hb_container_t *mux;
+    for (mux = hb_container_get_next(NULL); mux != NULL;
+         mux = hb_container_get_next(mux))
     {
-        if ((int)hb_audio_encoders[ii].encoder == val)
+        if (mux->format == imux)
         {
-            value = ghb_string_value_new(hb_audio_encoders[ii].short_name);
-            return value;
+            return mux;
         }
     }
-    value = ghb_string_value_new("copy");
-    return value;
+    return NULL;
 }
 
-static GValue*
-get_amix_value(gint val)
+static const hb_container_t *
+lookup_container(const GValue *gmux)
 {
-    GValue *value = NULL;
-    gint ii;
+    const hb_container_t *mux;
 
-    for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+    if (G_VALUE_TYPE(gmux) == G_TYPE_STRING)
     {
-        if (hb_audio_mixdowns[ii].amixdown == val)
+        gchar *str = ghb_value_string(gmux);
+        for (mux = hb_container_get_next(NULL); mux != NULL;
+             mux = hb_container_get_next(mux))
         {
-            value = ghb_string_value_new(hb_audio_mixdowns[ii].short_name);
-            break;
+            if (strcmp(mux->name, str) == 0 ||
+                strcmp(mux->short_name, str) == 0)
+            {
+                g_free(str);
+                return mux;
+            }
         }
+        g_free(str);
+    }
+    else if (G_VALUE_TYPE(gmux) == G_TYPE_INT ||
+             G_VALUE_TYPE(gmux) == G_TYPE_INT64 ||
+             G_VALUE_TYPE(gmux) == G_TYPE_DOUBLE)
+    {
+        return lookup_container_by_int(ghb_value_int(gmux));
     }
-    return value;
+    return NULL;
+}
+
+static gint
+lookup_container_int(const GValue *gmux)
+{
+    const hb_container_t *mux = lookup_container(gmux);
+    if (mux != NULL)
+        return mux->format;
+    return 0;
+}
+
+static const gchar*
+lookup_container_option(const GValue *gmux)
+{
+    const hb_container_t *mux = lookup_container(gmux);
+    if (mux != NULL)
+        return mux->name;
+    return 0;
+}
+
+static const gchar*
+lookup_container_string(const GValue *gmux)
+{
+    const hb_container_t *mux = lookup_container(gmux);
+    if (mux != NULL)
+        return mux->short_name;
+    return 0;
 }
 
 // Handle for libhb.  Gets set by ghb_backend_init()
@@ -1561,15 +1552,14 @@ grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean
 static void
 grey_mix_opts(signal_user_data_t *ud, gint acodec, gint64 layout)
 {
-    gint ii;
-    
     g_debug("grey_mix_opts()\n");
-    for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+
+    const hb_mixdown_t *mix;
+    for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+         mix = hb_mixdown_get_next(mix))
     {
-        grey_combo_box_item(ud->builder, "AudioMixdown",
-                hb_audio_mixdowns[ii].amixdown,
-                !hb_mixdown_is_supported(hb_audio_mixdowns[ii].amixdown,
-                                        acodec, layout));
+        grey_combo_box_item(ud->builder, "AudioMixdown", mix->amixdown,
+                !hb_mixdown_is_supported(mix->amixdown, acodec, layout));
     }
 }
 
@@ -1580,7 +1570,6 @@ ghb_grey_combo_options(signal_user_data_t *ud)
     gint mux, track, titleindex, acodec, fallback;
     hb_audio_config_t *aconfig = NULL;
     GValue *gval;
-    int ii;
 
     widget = GHB_WIDGET (ud->builder, "title");
     gval = ghb_widget_value(widget);
@@ -1597,34 +1586,38 @@ ghb_grey_combo_options(signal_user_data_t *ud)
     ghb_value_free(gval);
 
     grey_combo_box_item(ud->builder, "x264_analyse", 4, TRUE);
-    for (ii = 0; ii < hb_audio_encoders_count; ii++)
+
+    const hb_encoder_t *enc;
+    for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+         enc = hb_audio_encoder_get_next(enc))
     {
-        if (!(mux & hb_audio_encoders[ii].muxers))
+        if (!(mux & enc->muxers))
         {
             grey_combo_box_item(ud->builder, "AudioEncoder", 
-                hb_audio_encoders[ii].encoder, TRUE);
+                enc->codec, TRUE);
             grey_combo_box_item(ud->builder, "AudioEncoderFallback",
-                hb_audio_encoders[ii].encoder, TRUE);
+                enc->codec, TRUE);
         }
         else
         {
             grey_combo_box_item(ud->builder, "AudioEncoder", 
-                hb_audio_encoders[ii].encoder, FALSE);
+                enc->codec, FALSE);
             grey_combo_box_item(ud->builder, "AudioEncoderFallback",
-                hb_audio_encoders[ii].encoder, FALSE);
+                enc->codec, FALSE);
         }
     }
-    for (ii = 0; ii < hb_video_encoders_count; ii++)
+    for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+         enc = hb_video_encoder_get_next(enc))
     {
-        if (!(mux & hb_video_encoders[ii].muxers))
+        if (!(mux & enc->muxers))
         {
             grey_combo_box_item(ud->builder, "VideoEncoder", 
-                hb_video_encoders[ii].encoder, TRUE);
+                enc->codec, TRUE);
         }
         else
         {
             grey_combo_box_item(ud->builder, "VideoEncoder", 
-                hb_video_encoders[ii].encoder, FALSE);
+                enc->codec, FALSE);
         }
     }
 
@@ -1668,9 +1661,9 @@ ghb_get_best_mix(hb_audio_config_t *aconfig, gint acodec, gint mix)
     layout = aconfig ? aconfig->in.channel_layout : AV_CH_LAYOUT_5POINT1;
 
     if (mix == HB_AMIXDOWN_NONE)
-        mix = hb_audio_mixdowns[hb_audio_mixdowns_count-1].amixdown;
+        mix = HB_INVALID_AMIXDOWN;
     
-    return hb_get_best_mixdown( acodec, layout, mix );
+    return hb_mixdown_get_best( acodec, layout, mix );
 }
 
 // Set up the model for the combo box
@@ -1711,11 +1704,10 @@ init_combo_box(GtkBuilder *builder, const gchar *name)
 }   
 
 static void
-audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
+audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name)
 {
     GtkTreeIter iter;
     GtkListStore *store;
-    gint ii;
     gchar *str;
     
     g_debug("audio_samplerate_opts_set ()\n");
@@ -1730,29 +1722,31 @@ audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rat
                        3, 0.0, 
                        4, "source", 
                        -1);
-    for (ii = 0; ii < count; ii++)
+
+    const hb_rate_t *rate;
+    for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL;
+         rate = hb_audio_samplerate_get_next(rate))
     {
         gtk_list_store_append(store, &iter);
-        str = g_strdup_printf("<small>%s</small>", rates[ii].string);
+        str = g_strdup_printf("<small>%s</small>", rate->name);
         gtk_list_store_set(store, &iter, 
                            0, str,
                            1, TRUE, 
-                           2, rates[ii].string
-                           3, (gdouble)rates[ii].rate, 
-                           4, rates[ii].string, 
+                           2, rate->name
+                           3, (gdouble)rate->rate, 
+                           4, rate->name,
                            -1);
         g_free(str);
     }
 }
 
 static void
-video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
+video_framerate_opts_set(GtkBuilder *builder, const gchar *name)
 {
     GtkTreeIter iter;
     GtkListStore *store;
-    gint ii;
     
-    g_debug("video_rate_opts_set ()\n");
+    g_debug("video_framerate_opts_set ()\n");
     store = get_combo_box_store(builder, name);
     gtk_list_store_clear(store);
     // Add an item for "Same As Source"
@@ -1764,66 +1758,97 @@ video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gi
                        3, 0.0, 
                        4, "source", 
                        -1);
-    for (ii = 0; ii < count; ii++)
+
+    const hb_rate_t *rate;
+    for (rate = hb_video_framerate_get_next(NULL); rate != NULL;
+         rate = hb_video_framerate_get_next(rate))
     {
         gchar *desc = "";
         gchar *option;
-        if (strcmp(rates[ii].string, "23.976") == 0)
+        if (strcmp(rate->name, "23.976") == 0)
         {
             desc = "(NTSC Film)";
         }
-        else if (strcmp(rates[ii].string, "25") == 0)
+        else if (strcmp(rate->name, "25") == 0)
         {
             desc = "(PAL Film/Video)";
         }
-        else if (strcmp(rates[ii].string, "29.97") == 0)
+        else if (strcmp(rate->name, "29.97") == 0)
         {
             desc = "(NTSC Video)";
         }
-        option = g_strdup_printf ("%s %s", rates[ii].string, desc);
+        option = g_strdup_printf ("%s %s", rate->name, desc);
         gtk_list_store_append(store, &iter);
         gtk_list_store_set(store, &iter, 
                            0, option, 
                            1, TRUE, 
-                           2, rates[ii].string
-                           3, (gdouble)rates[ii].rate, 
-                           4, rates[ii].string
+                           2, rate->name
+                           3, (gdouble)rate->rate, 
+                           4, rate->name
                            -1);
         g_free(option);
     }
 }
 
 static void
-hb_encoder_opts_set_with_mask(
+video_encoder_opts_set(
+    GtkBuilder *builder,
+    const gchar *name)
+{
+    GtkTreeIter iter;
+    GtkListStore *store;
+    gchar *str;
+    
+    g_debug("video_encoder_opts_set ()\n");
+    store = get_combo_box_store(builder, name);
+    gtk_list_store_clear(store);
+
+    const hb_encoder_t *enc;
+    for (enc = hb_video_encoder_get_next(NULL); enc != NULL;
+         enc = hb_video_encoder_get_next(enc))
+    {
+        gtk_list_store_append(store, &iter);
+        str = g_strdup_printf("<small>%s</small>", enc->name);
+        gtk_list_store_set(store, &iter, 
+                           0, str,
+                           1, TRUE, 
+                           2, enc->short_name, 
+                           3, (gdouble)enc->codec,
+                           4, enc->short_name, 
+                           -1);
+        g_free(str);
+    }
+}
+
+static void
+audio_encoder_opts_set_with_mask(
     GtkBuilder *builder,
     const gchar *name,
-    hb_encoder_t *encoders,
-    int len,
     int mask,
     int neg_mask)
 {
     GtkTreeIter iter;
     GtkListStore *store;
-    gint ii;
     gchar *str;
     
-    g_debug("hb_encoder_opts_set ()\n");
+    g_debug("audio_encoder_opts_set ()\n");
     store = get_combo_box_store(builder, name);
     gtk_list_store_clear(store);
-    for (ii = 0; ii < len; ii++)
+
+    const hb_encoder_t *enc;
+    for (enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+         enc = hb_audio_encoder_get_next(enc))
     {
-        if ((mask & encoders[ii].encoder) &&
-            !(neg_mask & encoders[ii].encoder))
+        if ((mask & enc->codec) && !(neg_mask & enc->codec))
         {
             gtk_list_store_append(store, &iter);
-            str = g_strdup_printf("<small>%s</small>",
-                encoders[ii].human_readable_name);
+            str = g_strdup_printf("<small>%s</small>", enc->name);
             gtk_list_store_set(store, &iter, 
                                0, str,
                                1, TRUE, 
-                               2, encoders[ii].short_name, 
-                               3, (gdouble)encoders[ii].encoder, 
-                               4, encoders[ii].short_name, 
+                               2, enc->short_name, 
+                               3, (gdouble)enc->codec,
+                               4, enc->short_name, 
                                -1);
             g_free(str);
         }
@@ -1831,20 +1856,17 @@ hb_encoder_opts_set_with_mask(
 }
 
 static void
-hb_encoder_opts_set(
+audio_encoder_opts_set(
     GtkBuilder *builder,
-    const gchar *name,
-    hb_encoder_t *encoders,
-    int len)
+    const gchar *name)
 {
-    hb_encoder_opts_set_with_mask(builder, name, encoders, len, ~0, 0);
+    audio_encoder_opts_set_with_mask(builder, name, ~0, 0);
 }
 
 static void
 acodec_fallback_opts_set(GtkBuilder *builder, const gchar *name)
 {
-    hb_encoder_opts_set_with_mask(builder, name, hb_audio_encoders, 
-                            hb_audio_encoders_count, ~0, HB_ACODEC_PASS_FLAG);
+    audio_encoder_opts_set_with_mask(builder, name, ~0, HB_ACODEC_PASS_FLAG);
 }
 
 static void
@@ -1852,23 +1874,54 @@ mix_opts_set(GtkBuilder *builder, const gchar *name)
 {
     GtkTreeIter iter;
     GtkListStore *store;
-    gint ii;
     gchar *str;
     
     g_debug("mix_opts_set ()\n");
     store = get_combo_box_store(builder, name);
     gtk_list_store_clear(store);
-    for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+
+    const hb_mixdown_t *mix;
+    for (mix = hb_mixdown_get_next(NULL); mix != NULL;
+         mix = hb_mixdown_get_next(mix))
     {
         gtk_list_store_append(store, &iter);
-        str = g_strdup_printf("<small>%s</small>",
-            hb_audio_mixdowns[ii].human_readable_name);
+        str = g_strdup_printf("<small>%s</small>", mix->name);
         gtk_list_store_set(store, &iter, 
                            0, str,
                            1, TRUE, 
-                           2, hb_audio_mixdowns[ii].short_name, 
-                           3, (gdouble)hb_audio_mixdowns[ii].amixdown, 
-                           4, hb_audio_mixdowns[ii].internal_name, 
+                           2, mix->short_name, 
+                           3, (gdouble)mix->amixdown, 
+                           4, mix->internal_name, 
+                           -1);
+        g_free(str);
+    }
+}
+
+static void
+container_opts_set(
+    GtkBuilder *builder,
+    const gchar *name)
+{
+    GtkTreeIter iter;
+    GtkListStore *store;
+    gchar *str;
+    
+    g_debug("hb_container_opts_set ()\n");
+    store = get_combo_box_store(builder, name);
+    gtk_list_store_clear(store);
+
+    const hb_container_t *mux;
+    for (mux = hb_container_get_next(NULL); mux != NULL;
+         mux = hb_container_get_next(mux))
+    {
+        gtk_list_store_append(store, &iter);
+        str = g_strdup_printf("<small>%s</small>", mux->name);
+        gtk_list_store_set(store, &iter, 
+                           0, str,
+                           1, TRUE, 
+                           2, mux->short_name, 
+                           3, (gdouble)mux->format,
+                           4, mux->short_name, 
                            -1);
         g_free(str);
     }
@@ -2821,23 +2874,25 @@ ghb_lookup_combo_int(const gchar *name, const GValue *gval)
     if (strcmp(name, "AudioBitrate") == 0)
         return lookup_audio_bitrate_int(gval);
     else if (strcmp(name, "AudioSamplerate") == 0)
-        return lookup_audio_rate_int(gval);
+        return lookup_audio_samplerate_int(gval);
     else if (strcmp(name, "VideoFramerate") == 0)
-        return lookup_video_rate_int(gval);
+        return lookup_video_framerate_int(gval);
     else if (strcmp(name, "AudioMixdown") == 0)
-        return lookup_mix_int(gval);
+        return lookup_mixdown_int(gval);
     else if (strcmp(name, "SrtLanguage") == 0)
         return lookup_audio_lang_int(gval);
     else if (strcmp(name, "PreferredLanguage") == 0)
         return lookup_audio_lang_int(gval);
     else if (strcmp(name, "VideoEncoder") == 0)
-        return lookup_hb_encoder_int(gval, hb_video_encoders, hb_video_encoders_count);
+        return lookup_video_encoder_int(gval);
     else if (strcmp(name, "AudioEncoder") == 0)
-        return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_int(gval);
     else if (strcmp(name, "AudioEncoderFallback") == 0)
-        return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_int(gval);
     else if (strcmp(name, "AudioEncoderActual") == 0)
-        return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_int(gval);
+    else if (strcmp(name, "FileFormat") == 0)
+        return lookup_container_int(gval);
     else
     {
         return lookup_generic_int(find_combo_table(name), gval);
@@ -2854,23 +2909,25 @@ ghb_lookup_combo_double(const gchar *name, const GValue *gval)
     if (strcmp(name, "AudioBitrate") == 0)
         return lookup_audio_bitrate_int(gval);
     else if (strcmp(name, "AudioSamplerate") == 0)
-        return lookup_audio_rate_int(gval);
+        return lookup_audio_samplerate_int(gval);
     else if (strcmp(name, "VideoFramerate") == 0)
-        return lookup_video_rate_int(gval);
+        return lookup_video_framerate_int(gval);
     else if (strcmp(name, "AudioMixdown") == 0)
-        return lookup_mix_int(gval);
+        return lookup_mixdown_int(gval);
     else if (strcmp(name, "SrtLanguage") == 0)
         return lookup_audio_lang_int(gval);
     else if (strcmp(name, "PreferredLanguage") == 0)
         return lookup_audio_lang_int(gval);
     else if (strcmp(name, "VideoEncoder") == 0)
-        return lookup_hb_encoder_int(gval, hb_video_encoders, hb_video_encoders_count);
+        return lookup_video_encoder_int(gval);
     else if (strcmp(name, "AudioEncoder") == 0)
-        return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_int(gval);
     else if (strcmp(name, "AudioEncoderFallback") == 0)
-        return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_int(gval);
     else if (strcmp(name, "AudioEncoderActual") == 0)
-        return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_int(gval);
+    else if (strcmp(name, "FileFormat") == 0)
+        return lookup_container_int(gval);
     else
     {
         return lookup_generic_double(find_combo_table(name), gval);
@@ -2887,23 +2944,25 @@ ghb_lookup_combo_option(const gchar *name, const GValue *gval)
     if (strcmp(name, "AudioBitrate") == 0)
         return lookup_audio_bitrate_option(gval);
     else if (strcmp(name, "AudioSamplerate") == 0)
-        return lookup_audio_rate_option(gval);
+        return lookup_audio_samplerate_option(gval);
     else if (strcmp(name, "VideoFramerate") == 0)
-        return lookup_video_rate_option(gval);
+        return lookup_video_framerate_option(gval);
     else if (strcmp(name, "AudioMixdown") == 0)
-        return lookup_mix_option(gval);
+        return lookup_mixdown_option(gval);
     else if (strcmp(name, "SrtLanguage") == 0)
         return lookup_audio_lang_option(gval);
     else if (strcmp(name, "PreferredLanguage") == 0)
         return lookup_audio_lang_option(gval);
     else if (strcmp(name, "VideoEncoder") == 0)
-        return lookup_hb_encoder_option(gval, hb_video_encoders, hb_video_encoders_count);
+        return lookup_video_encoder_option(gval);
     else if (strcmp(name, "AudioEncoder") == 0)
-        return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_option(gval);
     else if (strcmp(name, "AudioEncoderFallback") == 0)
-        return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_option(gval);
     else if (strcmp(name, "AudioEncoderActual") == 0)
-        return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_option(gval);
+    else if (strcmp(name, "FileFormat") == 0)
+        return lookup_container_option(gval);
     else
     {
         return lookup_generic_option(find_combo_table(name), gval);
@@ -2920,23 +2979,25 @@ ghb_lookup_combo_string(const gchar *name, const GValue *gval)
     if (strcmp(name, "AudioBitrate") == 0)
         return lookup_audio_bitrate_option(gval);
     else if (strcmp(name, "AudioSamplerate") == 0)
-        return lookup_audio_rate_string(gval);
+        return lookup_audio_samplerate_string(gval);
     else if (strcmp(name, "VideoFramerate") == 0)
-        return lookup_video_rate_option(gval);
+        return lookup_video_framerate_option(gval);
     else if (strcmp(name, "AudioMixdown") == 0)
-        return lookup_mix_string(gval);
+        return lookup_mixdown_string(gval);
     else if (strcmp(name, "SrtLanguage") == 0)
         return lookup_audio_lang_option(gval);
     else if (strcmp(name, "PreferredLanguage") == 0)
         return lookup_audio_lang_option(gval);
     else if (strcmp(name, "VideoEncoder") == 0)
-        return lookup_hb_encoder_string(gval, hb_video_encoders, hb_video_encoders_count);
+        return lookup_video_encoder_string(gval);
     else if (strcmp(name, "AudioEncoder") == 0)
-        return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_string(gval);
     else if (strcmp(name, "AudioEncoderFallback") == 0)
-        return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_string(gval);
     else if (strcmp(name, "AudioEncoderActual") == 0)
-        return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count);
+        return lookup_audio_encoder_string(gval);
+    else if (strcmp(name, "FileFormat") == 0)
+        return lookup_container_string(gval);
     else
     {
         return lookup_generic_string(find_combo_table(name), gval);
@@ -2979,11 +3040,11 @@ ghb_update_ui_combo_box(
     if (all)
     {
         audio_bitrate_opts_set(ud->builder, "AudioBitrate");
-        audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
-        video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
+        audio_samplerate_opts_set(ud->builder, "AudioSamplerate");
+        video_framerate_opts_set(ud->builder, "VideoFramerate");
         mix_opts_set(ud->builder, "AudioMixdown");
-        hb_encoder_opts_set(ud->builder, "VideoEncoder", hb_video_encoders, hb_video_encoders_count);
-        hb_encoder_opts_set(ud->builder, "AudioEncoder", hb_audio_encoders, hb_audio_encoders_count);
+        video_encoder_opts_set(ud->builder, "VideoEncoder");
+        audio_encoder_opts_set(ud->builder, "AudioEncoder");
         acodec_fallback_opts_set(ud->builder, "AudioEncoderFallback");
         language_opts_set(ud->builder, "SrtLanguage");
         language_opts_set(ud->builder, "PreferredLanguage");
@@ -2999,7 +3060,6 @@ ghb_update_ui_combo_box(
         generic_opts_set(ud->builder, "LoggingLevel", &logging_opts);
         generic_opts_set(ud->builder, "LogLongevity", &log_longevity_opts);
         generic_opts_set(ud->builder, "check_updates", &appcast_update_opts);
-        generic_opts_set(ud->builder, "FileFormat", &container_opts);
         generic_opts_set(ud->builder, "PictureDeinterlace", &deint_opts);
         generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts);
         generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts);
@@ -3015,21 +3075,22 @@ ghb_update_ui_combo_box(
         x264_tune_opts_set(ud->builder, "x264Tune");
         h264_profile_opts_set(ud->builder, "h264Profile");
         h264_level_opts_set(ud->builder, "h264Level");
+        container_opts_set(ud->builder, "FileFormat");
     }
     else
     {
         if (strcmp(name, "AudioBitrate") == 0)
             audio_bitrate_opts_set(ud->builder, "AudioBitrate");
         else if (strcmp(name, "AudioSamplerate") == 0)
-            audio_samplerate_opts_set(ud->builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
+            audio_samplerate_opts_set(ud->builder, "AudioSamplerate");
         else if (strcmp(name, "VideoFramerate") == 0)
-            video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
+            video_framerate_opts_set(ud->builder, "VideoFramerate");
         else if (strcmp(name, "AudioMixdown") == 0)
             mix_opts_set(ud->builder, "AudioMixdown");
         else if (strcmp(name, "VideoEncoder") == 0)
-            hb_encoder_opts_set(ud->builder, "VideoEncoder", hb_video_encoders, hb_video_encoders_count);
+            video_encoder_opts_set(ud->builder, "VideoEncoder");
         else if (strcmp(name, "AudioEncoder") == 0)
-            hb_encoder_opts_set(ud->builder, "AudioEncoder", hb_audio_encoders, hb_audio_encoders_count);
+            audio_encoder_opts_set(ud->builder, "AudioEncoder");
         else if (strcmp(name, "AudioEncoderFallback") == 0)
             acodec_fallback_opts_set(ud->builder, "AudioEncoderFallback");
         else if (strcmp(name, "SrtLanguage") == 0)
@@ -3050,6 +3111,8 @@ ghb_update_ui_combo_box(
             h264_profile_opts_set(ud->builder, "h264Profile");
         else if (strcmp(name, "h264Level") == 0)
             h264_level_opts_set(ud->builder, "h264Level");
+        else if (strcmp(name, "FileFormat") == 0)
+            container_opts_set(ud->builder, "FileFormat");
         else
             generic_opts_set(ud->builder, name, find_combo_table(name));
     }
@@ -3079,6 +3142,7 @@ init_ui_combo_boxes(GtkBuilder *builder)
     init_combo_box(builder, "x264Tune");
     init_combo_box(builder, "h264Profile");
     init_combo_box(builder, "h264Level");
+    init_combo_box(builder, "FileFormat");
     for (ii = 0; combo_name_map[ii].name != NULL; ii++)
     {
         init_combo_box(builder, combo_name_map[ii].name);
@@ -3325,35 +3389,33 @@ audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
 
     if (rate >= 0 && rate < 8) return;
 
-    if (ghb_audio_bitrates[hb_audio_bitrates_count].string)
+    if (ghb_audio_bitrates[ghb_abr_count].name)
     {
-        g_free((char*)ghb_audio_bitrates[hb_audio_bitrates_count].string);
+        g_free((char*)ghb_audio_bitrates[ghb_abr_count].name);
     }
-    ghb_audio_bitrates[hb_audio_bitrates_count].rate = rate;
+    ghb_audio_bitrates[ghb_abr_count].rate = rate;
     if (rate < 0)
     {
-        ghb_audio_bitrates[hb_audio_bitrates_count].string = 
-            g_strdup_printf("N/A");
+        ghb_audio_bitrates[ghb_abr_count].name = g_strdup_printf("N/A");
     }
     else
     {
-        ghb_audio_bitrates[hb_audio_bitrates_count].string = 
-            g_strdup_printf("%d", rate);
+        ghb_audio_bitrates[ghb_abr_count].name = g_strdup_printf("%d", rate);
     }
-    ghb_audio_bitrates_count = hb_audio_bitrates_count + 1;
+    ghb_audio_bitrates_count = ghb_abr_count + 1;
 
     store = get_combo_box_store(builder, name);
     if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
     {
         str = g_strdup_printf ("<small>%s</small>",
-                        ghb_audio_bitrates[hb_audio_bitrates_count].string);
+                        ghb_audio_bitrates[ghb_abr_count].name);
         gtk_list_store_append(store, &iter);
         gtk_list_store_set(store, &iter, 
                            0, str, 
                            1, TRUE, 
-                           2, ghb_audio_bitrates[hb_audio_bitrates_count].string
+                           2, ghb_audio_bitrates[ghb_abr_count].name
                            3, (gdouble)rate, 
-                           4, ghb_audio_bitrates[hb_audio_bitrates_count].string
+                           4, ghb_audio_bitrates[ghb_abr_count].name
                            -1);
         g_free(str);
     }
@@ -3375,7 +3437,7 @@ audio_bitrate_opts_update(
     guint last = (guint)last_rate;
     guint first = (guint)first_rate;
     
-    ghb_audio_bitrates_count = hb_audio_bitrates_count;
+    ghb_audio_bitrates_count = ghb_abr_count;
 
     g_debug("audio_bitrate_opts_clean ()\n");
     store = get_combo_box_store(builder, name);
@@ -3414,15 +3476,29 @@ audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
 {
     GtkTreeIter iter;
     GtkListStore *store;
-    gint ii;
+    gint count = 0;
     gchar *str;
+    int ii;
     
-    ghb_audio_bitrates_count = hb_audio_bitrates_count;
-    ghb_audio_bitrates = calloc(hb_audio_bitrates_count+1, sizeof(hb_rate_t));
+    const hb_rate_t *rate;
 
-    for (ii = 0; ii < hb_audio_bitrates_count; ii++)
+    if (ghb_audio_bitrates == NULL)
     {
-        ghb_audio_bitrates[ii] = hb_audio_bitrates[ii];
+        // Count rates
+        for (rate = hb_audio_bitrate_get_next(NULL); rate != NULL;
+             rate = hb_audio_bitrate_get_next(rate))
+        {
+            count++;
+        }
+
+        ghb_audio_bitrates_count = ghb_abr_count = count;
+        ghb_audio_bitrates = calloc(count+1, sizeof(hb_rate_t));
+
+        for (ii = 0, rate = hb_audio_bitrate_get_next(NULL); rate != NULL;
+             ii++, rate = hb_audio_bitrate_get_next(rate))
+        {
+            ghb_audio_bitrates[ii] = *rate;
+        }
     }
 
     g_debug("audio_bitrate_opts_set ()\n");
@@ -3432,13 +3508,13 @@ audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
     {
         gtk_list_store_append(store, &iter);
         str = g_strdup_printf ("<small>%s</small>", 
-            ghb_audio_bitrates[ii].string);
+            ghb_audio_bitrates[ii].name);
         gtk_list_store_set(store, &iter, 
                            0, str,
                            1, TRUE, 
-                           2, ghb_audio_bitrates[ii].string
+                           2, ghb_audio_bitrates[ii].name
                            3, (gdouble)ghb_audio_bitrates[ii].rate, 
-                           4, ghb_audio_bitrates[ii].string
+                           4, ghb_audio_bitrates[ii].name
                            -1);
         g_free(str);
     }
@@ -4513,7 +4589,7 @@ ghb_validate_audio(GValue *settings)
             {
                 codec = HB_ACODEC_FAAC;
             }
-            value = ghb_lookup_acodec_value(codec);
+            value = ghb_lookup_audio_encoder_value(codec);
             ghb_settings_take_value(asettings, "AudioEncoder", value);
         }
         gchar *a_unsup = NULL;
@@ -4540,25 +4616,18 @@ ghb_validate_audio(GValue *settings)
                 return FALSE;
             }
             g_free(message);
-            value = ghb_lookup_acodec_value(codec);
+            value = ghb_lookup_audio_encoder_value(codec);
             ghb_settings_take_value(asettings, "AudioEncoder", value);
         }
 
         gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
 
-        gint jj;
         const gchar *mix_unsup = NULL;
         if (!hb_mixdown_is_supported(mix, codec, aconfig->in.channel_layout))
         {
-            for (jj = 0; jj < hb_audio_mixdowns_count; jj++)
-            {
-                if (mix == hb_audio_mixdowns[jj].amixdown)
-                {
-                    {
-                        mix_unsup = hb_audio_mixdowns[jj].human_readable_name;
-                    }
-                }
-            }
+            const hb_mixdown_t *hb_mix = lookup_mixdown_by_int(mix);
+            if (hb_mix != NULL)
+                mix_unsup = hb_mix->name;
         }
         if (mix_unsup)
         {
@@ -4573,7 +4642,7 @@ ghb_validate_audio(GValue *settings)
             }
             g_free(message);
             mix = ghb_get_best_mix(aconfig, codec, mix);
-            value = get_amix_value(mix);
+            value = lookup_mixdown_value(mix);
             ghb_settings_take_value(asettings, "AudioMixdown", value);
         }
     }
@@ -5017,7 +5086,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                 audio.out.bitrate = 
                     ghb_settings_combo_int(asettings, "AudioBitrate");
 
-                audio.out.bitrate = hb_get_best_audio_bitrate(
+                audio.out.bitrate = hb_audio_bitrate_get_best(
                     audio.out.codec, audio.out.bitrate, 
                     audio.out.samplerate, audio.out.mixdown);
             }
index 242a3e3b7bbaffb2dc87d4c418a2d2c1ae0c6673..03d0ce4ed50bca7191724068ed83a1436c5c964d 100644 (file)
@@ -156,7 +156,7 @@ gdouble ghb_lookup_combo_double(const gchar *name, const GValue *gval);
 const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *gval);
 const gchar* ghb_lookup_combo_string(const gchar *name, const GValue *gval);
 gchar* ghb_get_tmp_dir();
-gint ghb_find_closest_audio_rate(gint rate);
-GValue* ghb_lookup_acodec_value(gint val);
+gint ghb_find_closest_audio_samplerate(gint rate);
+GValue* ghb_lookup_audio_encoder_value(gint val);
 
 #endif // _HBBACKEND_H_
index d76d5d280c47f01289b7f0b9c92554b9c5f1893c..12fdfbd67ed99b963811e4cb54e9a90e145afefb 100644 (file)
@@ -2044,19 +2044,26 @@ static value_map_t acodec_xlat_compat[] =
 
 static value_map_t *acodec_xlat;
 
-static value_map_t * create_encoder_xlat_tbl(value_map_t *compat, hb_encoder_t *enc, int size)
+static value_map_t * create_video_encoder_xlat_tbl(value_map_t *compat)
 {
     value_map_t *out;
-    int cc, ii;
+    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; ii < size; ii++)
+    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[ii].human_readable_name;
-        out[ii].lin_val = enc[ii].short_name;
+        out[ii].mac_val = enc->name;
+        out[ii].lin_val = enc->short_name;
     }
 
     for (ii = 0; ii < cc; ii++)
@@ -2065,19 +2072,26 @@ static value_map_t * create_encoder_xlat_tbl(value_map_t *compat, hb_encoder_t *
     return out;
 }
 
-static value_map_t * create_mix_xlat_tbl(value_map_t *compat, hb_mixdown_t * mix, int size)
+static value_map_t * create_audio_encoder_xlat_tbl(value_map_t *compat)
 {
     value_map_t *out;
-    int cc, ii;
+    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; ii < size; ii++)
+    for (ii = 0, enc = hb_audio_encoder_get_next(NULL); enc != NULL;
+         ii++, enc = hb_audio_encoder_get_next(enc))
     {
-        out[ii].mac_val = mix[ii].human_readable_name;
-        out[ii].lin_val = mix[ii].short_name;
+        out[ii].mac_val = enc->name;
+        out[ii].lin_val = enc->short_name;
     }
 
     for (ii = 0; ii < cc; ii++)
@@ -2086,15 +2100,33 @@ static value_map_t * create_mix_xlat_tbl(value_map_t *compat, hb_mixdown_t * mix
     return out;
 }
 
-value_map_t container_xlat[] =
+static value_map_t * create_mix_xlat_tbl(value_map_t *compat)
 {
-    {"MP4 file", "mp4"},
-    {"M4V file", "mp4"},
-    {"MKV file", "mkv"},
-    {"AVI file", "mkv"},
-    {"OGM file", "mkv"},
-    {NULL, NULL}
-};
+    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[] =
 {
@@ -2361,6 +2393,24 @@ export_value_xlat2(value_map_t *value_map, GValue *lin_val, GType mac_type)
     return NULL;
 }
 
+static GValue*
+export_value_xlat_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);
+    g_free(str);
+    mux = hb_container_get_name(imux);
+    if (mux != NULL)
+        sval = ghb_string_value_new(mux);
+
+    return sval;
+}
+
 static void
 export_value_xlat(GValue *dict)
 {
@@ -2374,7 +2424,7 @@ export_value_xlat(GValue *dict)
         ghb_dict_insert(dict, g_strdup(key), gval);
     key = "FileFormat";
     lin_val = ghb_dict_lookup(dict, key);
-    gval = export_value_xlat2(container_xlat, lin_val, G_TYPE_STRING);
+    gval = export_value_xlat_container(lin_val);
     if (gval)
         ghb_dict_insert(dict, g_strdup(key), gval);
     key = "VideoFramerate";
@@ -2528,6 +2578,34 @@ import_value_xlat2(
     return NULL;
 }
 
+static GValue*
+import_value_xlat_container(GValue *mac_val)
+{
+    GValue *sval = NULL;
+    gchar *str;
+    const gchar *mux;
+    int imux;
+
+    str = ghb_value_string(mac_val);
+    mux = hb_container_sanitize_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 (mux != NULL)
+        sval = ghb_string_value_new(mux);
+
+    return sval;
+}
+
 static void
 import_value_xlat(GValue *dict)
 {
@@ -2542,7 +2620,7 @@ import_value_xlat(GValue *dict)
         ghb_dict_insert(dict, g_strdup(key), gval);
     key = "FileFormat";
     mac_val = ghb_dict_lookup(dict, key);
-    gval = import_value_xlat2(defaults, container_xlat, key, mac_val);
+    gval = import_value_xlat_container(mac_val);
     if (gval)
         ghb_dict_insert(dict, g_strdup(key), gval);
     key = "VideoFramerate";
@@ -3304,9 +3382,9 @@ void
 ghb_presets_load(signal_user_data_t *ud)
 {
     // Create translation tables from libhb tables
-    mix_xlat = create_mix_xlat_tbl(mix_xlat_compat, hb_audio_mixdowns, hb_audio_mixdowns_count);
-    acodec_xlat = create_encoder_xlat_tbl(acodec_xlat_compat, hb_audio_encoders, hb_audio_encoders_count);
-    vcodec_xlat = create_encoder_xlat_tbl(vcodec_xlat_compat, hb_video_encoders, hb_video_encoders_count);
+    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)
index a34b7c08d69e77d0feb8fecd925172c2f414b587..eb214e6a5b9389dd63c22eb71a94f898984bb02d 100644 (file)
@@ -19,6 +19,8 @@
 /**********************************************************************
  * Global variables
  *********************************************************************/
+static hb_error_handler_t *error_handler = NULL;
+
 hb_rate_t hb_video_rates[] =
 {
     {  "5",     5400000 },
@@ -81,8 +83,6 @@ hb_rate_t hb_audio_bitrates[] =
 };
 int hb_audio_bitrates_count = sizeof(hb_audio_bitrates) / sizeof(hb_rate_t);
 
-static hb_error_handler_t *error_handler = NULL;
-
 hb_dither_t hb_audio_dithers[] =
 {
     { "default",                       "auto",          AV_RESAMPLE_DITHER_NONE - 1,      },
@@ -112,13 +112,13 @@ int hb_audio_mixdowns_count = sizeof(hb_audio_mixdowns) / sizeof(hb_mixdown_t);
 
 hb_encoder_t hb_video_encoders[] =
 {
-    { "H.264 (x264)",    "x264",    HB_VCODEC_X264,         HB_MUX_MP4|HB_MUX_MKV },
+    { "H.264 (x264)",    "x264",    HB_VCODEC_X264,         HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
 #ifdef USE_QSV
-    { "H.264 (Intel QSV)", "qsv_h264", HB_VCODEC_QSV_H264,  HB_MUX_MP4|HB_MUX_MKV },
+    { "H.264 (Intel QSV)", "qsv_h264", HB_VCODEC_QSV_H264,  HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
 #endif
-    { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MP4|HB_MUX_MKV },
-    { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MP4|HB_MUX_MKV },
-    { "VP3 (Theora)",    "theora",  HB_VCODEC_THEORA,                  HB_MUX_MKV },
+    { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "VP3 (Theora)",    "theora",  HB_VCODEC_THEORA,                       HB_MUX_MASK_MKV },
 };
 int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_encoder_t);
 
@@ -126,566 +126,420 @@ int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_encoder_t);
 hb_encoder_t hb_audio_encoders[] =
 {
 #ifdef __APPLE__
-    { "AAC (CoreAudio)",    "ca_aac",     HB_ACODEC_CA_AAC,       HB_MUX_MP4|HB_MUX_MKV },
-    { "HE-AAC (CoreAudio)", "ca_haac",    HB_ACODEC_CA_HAAC,      HB_MUX_MP4|HB_MUX_MKV },
+    { "AAC (CoreAudio)",    "ca_aac",     HB_ACODEC_CA_AAC,       HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "HE-AAC (CoreAudio)", "ca_haac",    HB_ACODEC_CA_HAAC,      HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
 #endif
-    { "AAC (faac)",         "faac",       HB_ACODEC_FAAC,         HB_MUX_MP4|HB_MUX_MKV },
+    { "AAC (faac)",         "faac",       HB_ACODEC_FAAC,         HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
 #ifdef USE_FDK_AAC
-    { "AAC (FDK)",          "fdk_aac",    HB_ACODEC_FDK_AAC,      HB_MUX_MP4|HB_MUX_MKV },
-    { "HE-AAC (FDK)",       "fdk_haac",   HB_ACODEC_FDK_HAAC,     HB_MUX_MP4|HB_MUX_MKV },
+    { "AAC (FDK)",          "fdk_aac",    HB_ACODEC_FDK_AAC,      HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "HE-AAC (FDK)",       "fdk_haac",   HB_ACODEC_FDK_HAAC,     HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
 #endif
-    { "AAC (ffmpeg)",       "ffaac",      HB_ACODEC_FFAAC,        HB_MUX_MP4|HB_MUX_MKV },
-    { "AAC Passthru",       "copy:aac",   HB_ACODEC_AAC_PASS,     HB_MUX_MP4|HB_MUX_MKV },
-    { "AC3 (ffmpeg)",       "ffac3",      HB_ACODEC_AC3,          HB_MUX_MP4|HB_MUX_MKV },
-    { "AC3 Passthru",       "copy:ac3",   HB_ACODEC_AC3_PASS,     HB_MUX_MP4|HB_MUX_MKV },
-    { "DTS Passthru",       "copy:dts",   HB_ACODEC_DCA_PASS,     HB_MUX_MP4|HB_MUX_MKV },
-    { "DTS-HD Passthru",    "copy:dtshd", HB_ACODEC_DCA_HD_PASS,  HB_MUX_MP4|HB_MUX_MKV },
-    { "MP3 (lame)",         "lame",       HB_ACODEC_LAME,         HB_MUX_MP4|HB_MUX_MKV },
-    { "MP3 Passthru",       "copy:mp3",   HB_ACODEC_MP3_PASS,     HB_MUX_MP4|HB_MUX_MKV },
-    { "Vorbis (vorbis)",    "vorbis",     HB_ACODEC_VORBIS,                  HB_MUX_MKV },
-    { "FLAC (ffmpeg)",      "ffflac",     HB_ACODEC_FFFLAC,                  HB_MUX_MKV },
-    { "FLAC (24-bit)",      "ffflac24",   HB_ACODEC_FFFLAC24,                HB_MUX_MKV },
-    { "Auto Passthru",      "copy",       HB_ACODEC_AUTO_PASS,    HB_MUX_MP4|HB_MUX_MKV },
+    { "AAC (ffmpeg)",       "ffaac",      HB_ACODEC_FFAAC,        HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "AAC Passthru",       "copy:aac",   HB_ACODEC_AAC_PASS,     HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "AC3 (ffmpeg)",       "ffac3",      HB_ACODEC_AC3,          HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "AC3 Passthru",       "copy:ac3",   HB_ACODEC_AC3_PASS,     HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "DTS Passthru",       "copy:dts",   HB_ACODEC_DCA_PASS,     HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "DTS-HD Passthru",    "copy:dtshd", HB_ACODEC_DCA_HD_PASS,  HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "MP3 (lame)",         "lame",       HB_ACODEC_LAME,         HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "MP3 Passthru",       "copy:mp3",   HB_ACODEC_MP3_PASS,     HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
+    { "Vorbis (vorbis)",    "vorbis",     HB_ACODEC_VORBIS,                       HB_MUX_MASK_MKV },
+    { "FLAC (ffmpeg)",      "ffflac",     HB_ACODEC_FFFLAC,                       HB_MUX_MASK_MKV },
+    { "FLAC (24-bit)",      "ffflac24",   HB_ACODEC_FFFLAC24,                     HB_MUX_MASK_MKV },
+    { "Auto Passthru",      "copy",       HB_ACODEC_AUTO_PASS,    HB_MUX_MASK_MP4|HB_MUX_MASK_MKV },
 };
 int hb_audio_encoders_count = sizeof(hb_audio_encoders) / sizeof(hb_encoder_t);
 
-/* Expose values for PInvoke */
-hb_rate_t*    hb_get_video_rates()          { return hb_video_rates;          }
-int           hb_get_video_rates_count()    { return hb_video_rates_count;    }
-hb_rate_t*    hb_get_audio_rates()          { return hb_audio_rates;          }
-int           hb_get_audio_rates_count()    { return hb_audio_rates_count;    }
-hb_rate_t*    hb_get_audio_bitrates()       { return hb_audio_bitrates;       }
-int           hb_get_audio_bitrates_count() { return hb_audio_bitrates_count; }
-hb_dither_t*  hb_get_audio_dithers()        { return hb_audio_dithers;        }
-int           hb_get_audio_dithers_count()  { return hb_audio_dithers_count;  }
-hb_mixdown_t* hb_get_audio_mixdowns()       { return hb_audio_mixdowns;       }
-int           hb_get_audio_mixdowns_count() { return hb_audio_mixdowns_count; }
-hb_encoder_t* hb_get_video_encoders()       { return hb_video_encoders;       }
-int           hb_get_video_encoders_count() { return hb_video_encoders_count; }
-hb_encoder_t* hb_get_audio_encoders()       { return hb_audio_encoders;       }
-int           hb_get_audio_encoders_count() { return hb_audio_encoders_count; }
+// note: for each container, the muxer nearer the top is the default
+hb_container_t hb_containers[] =
+{
+    { "MPEG-4 (mp4v2)",    "mp4v2",  "mp4", HB_MUX_MP4V2,  },
+    { "Matroska (libmkv)", "libmkv", "mkv", HB_MUX_LIBMKV, },
+};
+int hb_containers_count = sizeof(hb_containers) / sizeof(hb_container_t);
 
-int hb_audio_dither_get_default()
+int hb_video_framerate_get_from_name(const char *name)
 {
-    // "auto"
-    return hb_audio_dithers[0].method;
-}
+    if (name == NULL || *name == '\0')
+        goto fail;
 
-int hb_audio_dither_get_default_method()
+    // TODO: implement something more flexible
+    if (!strcasecmp(name, "23.976 (NTSC Film)"))
 {
-    /*
-     * input could be s16 (possibly already dithered) converted to flt, so
-     * let's use a "low-risk" dither algorithm (standard triangular).
-     */
-    return AV_RESAMPLE_DITHER_TRIANGULAR;
+        return 1126125;
 }
-
-int hb_audio_dither_is_supported(uint32_t codec)
+    if (!strcasecmp(name, "25 (PAL Film/Video)"))
 {
-    // encoder's input sample format must be s16(p)
-    switch (codec)
+        return 1080000;
+    }
+    if (!strcasecmp(name, "29.97 (NTSC Video)"))
     {
-        case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FDK_AAC:
-        case HB_ACODEC_FDK_HAAC:
-            return 1;
-        default:
-            return 0;
+        return 900900;
     }
-}
 
-const char* hb_audio_dither_get_description(int method)
-{
     int i;
-    for (i = 0; i < hb_audio_dithers_count; i++)
+    for (i = 0; i < hb_video_rates_count; i++)
     {
-        if (hb_audio_dithers[i].method == method)
+        if (!strcasecmp(hb_video_rates[i].name, name))
         {
-            return hb_audio_dithers[i].description;
+            return hb_video_rates[i].rate;
         }
     }
-    return "";
-}
 
-
-int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout)
-{
-    return (hb_mixdown_has_codec_support(mixdown, codec) &&
-            hb_mixdown_has_remix_support(mixdown, layout));
+fail:
+    return -1;
 }
 
-int hb_mixdown_has_codec_support(int mixdown, uint32_t codec)
+const char* hb_video_framerate_get_name(int framerate)
 {
-    // Passthru, only "None" mixdown is supported
-    if (codec & HB_ACODEC_PASS_FLAG)
-        return (mixdown == HB_AMIXDOWN_NONE);
-
-    // Not passthru, "None" mixdown never supported
-    if (mixdown == HB_AMIXDOWN_NONE)
-        return 0;
+    if (framerate > hb_video_rates[0].rate ||
+        framerate < hb_video_rates[hb_video_rates_count - 1].rate)
+        goto fail;
 
-    switch (codec)
+    int i;
+    for (i = 0; i < hb_video_rates_count; i++)
     {
-        case HB_ACODEC_VORBIS:
-        case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FFFLAC24:
-            return (mixdown <= HB_AMIXDOWN_7POINT1);
-
-        case HB_ACODEC_LAME:
-        case HB_ACODEC_FFAAC:
-            return (mixdown <= HB_AMIXDOWN_DOLBYPLII);
-
-        case HB_ACODEC_FAAC:
-        case HB_ACODEC_CA_AAC:
-        case HB_ACODEC_CA_HAAC:
-            return ((mixdown <= HB_AMIXDOWN_5POINT1) ||
-                    (mixdown == HB_AMIXDOWN_5_2_LFE));
-
-        default:
-            return (mixdown <= HB_AMIXDOWN_5POINT1);
-    }
-}
-
-int hb_mixdown_has_remix_support(int mixdown, uint64_t layout)
+        if (hb_video_rates[i].rate == framerate)
 {
-    switch (mixdown)
-    {
-        // stereo + front left/right of center
-        case HB_AMIXDOWN_5_2_LFE:
-            return ((layout & AV_CH_FRONT_LEFT_OF_CENTER) &&
-                    (layout & AV_CH_FRONT_RIGHT_OF_CENTER) &&
-                    (layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO);
-
-        // 7.0 or better
-        case HB_AMIXDOWN_7POINT1:
-            return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0);
-
-        // 6.0 or better
-        case HB_AMIXDOWN_6POINT1:
-            return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0 ||
-                    (layout & AV_CH_LAYOUT_6POINT0) == AV_CH_LAYOUT_6POINT0 ||
-                    (layout & AV_CH_LAYOUT_HEXAGONAL) == AV_CH_LAYOUT_HEXAGONAL);
-
-        // stereo + either of front center, side or back left/right, back center
-        case HB_AMIXDOWN_5POINT1:
-            return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
-                    (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
-                    (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
-                    (layout & AV_CH_LAYOUT_SURROUND) == AV_CH_LAYOUT_SURROUND);
-
-        // stereo + either of side or back left/right, back center
-        // also, allow Dolby Surrounbd output if the input is already Dolby
-        case HB_AMIXDOWN_DOLBY:
-        case HB_AMIXDOWN_DOLBYPLII:
-            return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
-                    (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
-                    (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
-                    (layout == AV_CH_LAYOUT_STEREO_DOWNMIX &&
-                     mixdown == HB_AMIXDOWN_DOLBY));
-
-        // more than 1 channel
-        case HB_AMIXDOWN_STEREO:
-            return (av_get_channel_layout_nb_channels(layout) > 1);
-
-        // regular stereo (not Dolby)
-        case HB_AMIXDOWN_LEFT:
-        case HB_AMIXDOWN_RIGHT:
-            return (layout == AV_CH_LAYOUT_STEREO);
-
-        // mono remix always supported
-        // HB_AMIXDOWN_NONE always supported (for Passthru)
-        case HB_AMIXDOWN_MONO:
-        case HB_AMIXDOWN_NONE:
-            return 1;
-
-        // unknown mixdown, should never happen
-        default:
-            return 0;
+            return hb_video_rates[i].name;
     }
 }
 
-int hb_mixdown_get_discrete_channel_count(int amixdown)
-{
-    switch (amixdown)
-    {
-        case HB_AMIXDOWN_5_2_LFE:
-        case HB_AMIXDOWN_7POINT1:
-            return 8;
-
-        case HB_AMIXDOWN_6POINT1:
-            return 7;
-
-        case HB_AMIXDOWN_5POINT1:
-            return 6;
-
-        case HB_AMIXDOWN_MONO:
-        case HB_AMIXDOWN_LEFT:
-        case HB_AMIXDOWN_RIGHT:
-            return 1;
-
-        case HB_AMIXDOWN_NONE:
-            return 0;
-
-        default:
-            return 2;
+fail:
+    return NULL;
     }
-}
 
-int hb_mixdown_get_low_freq_channel_count(int amixdown)
+const char* hb_video_framerate_sanitize_name(const char *name)
 {
-    switch (amixdown)
-    {
-        case HB_AMIXDOWN_5POINT1:
-        case HB_AMIXDOWN_6POINT1:
-        case HB_AMIXDOWN_7POINT1:
-        case HB_AMIXDOWN_5_2_LFE:
-            return 1;
-
-        default:
-            return 0;
+    return hb_video_framerate_get_name(hb_video_framerate_get_from_name(name));
     }
-}
 
-int hb_mixdown_get_mixdown_from_short_name(const char *short_name)
+const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *last)
 {
-    int i;
-    for (i = 0; i < hb_audio_mixdowns_count; i++)
+    if (last == NULL)
     {
-        if (!strcmp(hb_audio_mixdowns[i].short_name, short_name))
-        {
-            return hb_audio_mixdowns[i].amixdown;
+        return  &hb_video_rates[0];
         }
-    }
-    return 0;
-}
-
-const char* hb_mixdown_get_short_name_from_mixdown(int amixdown)
+    if (last <  &hb_video_rates[0] ||
+        last >= &hb_video_rates[hb_video_rates_count - 1])
 {
-    int i;
-    for (i = 0; i < hb_audio_mixdowns_count; i++)
-    {
-        if (hb_audio_mixdowns[i].amixdown == amixdown)
-        {
-            return hb_audio_mixdowns[i].short_name;
+        return NULL;
         }
+    return last + 1;
     }
-    return "";
-}
 
-void hb_autopassthru_apply_settings( hb_job_t * job )
+int hb_audio_samplerate_get_best(uint32_t codec, int samplerate, int *sr_shift)
 {
-    int i, j, already_printed;
-    hb_audio_t * audio;
-    for( i = 0, already_printed = 0; i < hb_list_count( job->list_audio ); )
+    int ii, best_samplerate, samplerate_shift;
+    if ((samplerate < 32000) &&
+        (codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_AC3))
     {
-        audio = hb_list_item( job->list_audio, i );
-        if( audio->config.out.codec == HB_ACODEC_AUTO_PASS )
-        {
-            if( !already_printed )
-                hb_autopassthru_print_settings( job );
-            already_printed = 1;
-            audio->config.out.codec = hb_autopassthru_get_encoder( audio->config.in.codec,
-                                                                   job->acodec_copy_mask,
-                                                                   job->acodec_fallback,
-                                                                   job->mux );
-            if( !( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) &&
-                !( audio->config.out.codec & HB_ACODEC_MASK ) )
-            {
-                hb_log( "Auto Passthru: passthru not possible and no valid fallback specified, dropping track %d",
-                        audio->config.out.track );
-                hb_list_rem( job->list_audio, audio );
-                hb_audio_close( &audio );
-                continue;
+        // ca_haac can't do samplerates < 32 kHz
+        // AC-3 < 32 kHz suffers from poor hardware compatibility
+        best_samplerate  = 32000;
+        samplerate_shift = 0;
             }
-            audio->config.out.samplerate = audio->config.in.samplerate;
-            if( !( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) )
+    else if (samplerate < 16000 && codec == HB_ACODEC_FDK_HAAC)
             {
-                if( audio->config.out.codec == job->acodec_fallback )
-                {
-                    hb_log( "Auto Passthru: passthru not possible for track %d, using fallback",
-                            audio->config.out.track );
+        // fdk_haac can't do samplerates < 16 kHz
+        best_samplerate  = 16000;
+        samplerate_shift = 1;
                 }
                 else
                 {
-                    hb_log( "Auto Passthru: passthru and fallback not possible for track %d, using default encoder",
-                            audio->config.out.track );
-                }
-                audio->config.out.mixdown = hb_get_default_mixdown( audio->config.out.codec,
-                                                                    audio->config.in.channel_layout );
-                audio->config.out.bitrate = hb_get_default_audio_bitrate( audio->config.out.codec,
-                                                                          audio->config.out.samplerate,
-                                                                          audio->config.out.mixdown );
-                audio->config.out.compression_level = hb_get_default_audio_compression( audio->config.out.codec );
-            }
-            else
+        best_samplerate = samplerate;
+        for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
             {
-                for( j = 0; j < hb_audio_encoders_count; j++ )
+            // valid samplerate
+            if (best_samplerate == hb_audio_rates[ii].rate)
+                break;
+
+            // samplerate is higher than the next valid samplerate,
+            // or lower than the lowest valid samplerate
+            if (best_samplerate > hb_audio_rates[ii].rate || ii == 0)
                 {
-                    if( hb_audio_encoders[j].encoder == audio->config.out.codec )
-                    {
-                        hb_log( "Auto Passthru: using %s for track %d",
-                                hb_audio_encoders[j].human_readable_name,
-                                audio->config.out.track );
+                best_samplerate = hb_audio_rates[ii].rate;
                         break;
                     }
                 }
+        /* sr_shift: 0 -> 48000, 44100, 32000 Hz
+         *           1 -> 24000, 22050, 16000 Hz
+         *           2 -> 12000, 11025,  8000 Hz
+         *
+         * also, since samplerates are sanitized downwards:
+         *
+         * (samplerate < 32000) implies (samplerate <= 24000)
+         */
+        samplerate_shift = ((best_samplerate < 16000) ? 2 :
+                            (best_samplerate < 32000) ? 1 : 0);
             }
+    if (sr_shift != NULL)
+    {
+        *sr_shift = samplerate_shift;
         }
-        /* Adjust output track number, in case we removed one.
-         * Output tracks sadly still need to be in sequential order.
-         * Note: out.track starts at 1, i starts at 0 */
-        audio->config.out.track = ++i;
+    return best_samplerate;
     }
-}
 
-void hb_autopassthru_print_settings( hb_job_t * job )
+int hb_audio_samplerate_get_from_name(const char *name)
 {
-    int i, codec_len;
-    char *mask = NULL, *tmp;
-    const char *fallback = NULL;
-    for( i = 0; i < hb_audio_encoders_count; i++ )
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    // TODO: implement something more flexible
+    int i = atoi(name);
+    if (i >= hb_audio_rates[0].rate &&
+        i <= hb_audio_rates[hb_audio_rates_count - 1].rate)
     {
-        if( ( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
-            ( hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS ) &&
-            ( hb_audio_encoders[i].encoder & job->acodec_copy_mask ) )
-        {
-            if( mask )
-            {
-                tmp = hb_strncat_dup( mask, ", ", 2 );
-                if( tmp )
-                {
-                    free( mask );
-                    mask = tmp;
+        return i;
                 }
-            }
-            // passthru name without " Passthru"
-            codec_len = strlen( hb_audio_encoders[i].human_readable_name ) - 9;
-            tmp = hb_strncat_dup( mask, hb_audio_encoders[i].human_readable_name, codec_len );
-            if( tmp )
+
+    for (i = 0; i < hb_audio_rates_count; i++)
             {
-                free( mask );
-                mask = tmp;
-            }
-        }
-        else if( !( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
-                  ( hb_audio_encoders[i].encoder == job->acodec_fallback ) )
+        if (!strcasecmp(hb_audio_rates[i].name, name))
         {
-            fallback = hb_audio_encoders[i].human_readable_name;
+            return hb_audio_rates[i].rate;
         }
     }
-    if( !mask )
-        hb_log( "Auto Passthru: no codecs allowed" );
-    else
-        hb_log( "Auto Passthru: allowed codecs are %s", mask );
-    if( !fallback )
-        hb_log( "Auto Passthru: no valid fallback specified" );
-    else
-        hb_log( "Auto Passthru: fallback is %s", fallback );
+
+fail:
+    return -1;
 }
 
-int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer )
+const char* hb_audio_samplerate_get_name(int samplerate)
 {
+    if (samplerate < hb_audio_rates[0].rate ||
+        samplerate > hb_audio_rates[hb_audio_rates_count - 1].rate)
+        goto fail;
+
     int i;
-    int out_codec = ( copy_mask & in_codec ) | HB_ACODEC_PASS_FLAG;
-    // sanitize fallback encoder and selected passthru
-    // note: invalid fallbacks are caught in hb_autopassthru_apply_settings
-    for( i = 0; i < hb_audio_encoders_count; i++ )
+    for (i = 0; i < hb_audio_rates_count; i++)
     {
-        if( ( hb_audio_encoders[i].encoder == fallback ) &&
-           !( hb_audio_encoders[i].muxers & muxer ) )
+        if (hb_audio_rates[i].rate == samplerate)
         {
-            // fallback not possible with current muxer
-            // use the default audio encoder instead
-            fallback = hb_get_default_audio_encoder(muxer);
-            break;
+            return hb_audio_rates[i].name;
         }
     }
-    for( i = 0; i < hb_audio_encoders_count; i++ )
-    {
-        if( ( hb_audio_encoders[i].encoder == out_codec ) &&
-           !( hb_audio_encoders[i].muxers & muxer ) )
-        {
-            // selected passthru not possible with current muxer
-            out_codec = fallback;
-            break;
+
+fail:
+    return NULL;
         }
-    }
-    if( !( out_codec & HB_ACODEC_PASS_MASK ) )
-        return fallback;
-    return out_codec;
-}
 
-int hb_get_default_audio_encoder(int muxer)
+const hb_rate_t* hb_audio_samplerate_get_next(const hb_rate_t *last)
 {
-#ifndef __APPLE__
-    if (muxer == HB_MUX_MKV)
+    if (last == NULL)
     {
-        return HB_ACODEC_LAME;
+        return  &hb_audio_rates[0];
     }
-#endif
-    return hb_audio_encoders[0].encoder;
+    if (last <  &hb_audio_rates[0] ||
+        last >= &hb_audio_rates[hb_audio_rates_count - 1])
+    {
+        return NULL;
+}
+    return last + 1;
 }
 
 // Given an input bitrate, find closest match in the set of allowed bitrates
-int hb_find_closest_audio_bitrate(int bitrate)
+static int hb_audio_bitrate_find_closest(int bitrate)
 {
     // Check if bitrate mode was disabled
     if (bitrate <= 0)
         return bitrate;
 
-    int ii, result;
     // result is highest rate if none found during search.
     // rate returned will always be <= rate asked for.
-    result = hb_audio_bitrates[0].rate;
-    for (ii = hb_audio_bitrates_count - 1; ii > 0; ii--)
+    int i, result = hb_audio_bitrates[0].rate;
+    for (i = hb_audio_bitrates_count - 1; i > 0; i--)
     {
-        if (bitrate >= hb_audio_bitrates[ii].rate)
+        if (bitrate >= hb_audio_bitrates[i].rate)
         {
-            result = hb_audio_bitrates[ii].rate;
+            result = hb_audio_bitrates[i].rate;
             break;
         }
     }
     return result;
 }
 
-/* Get the bitrate low and high limits for a codec/samplerate/mixdown triplet.
-
-Encoder    1.0 channel    2.0 channels    5.1 channels    6.1 channels    7.1 channels
---------------------------------------------------------------------------------------
-
-faac
-----
-supported samplerates: 8 - 48 kHz
-libfaac/util.c defines the bitrate limits:
-MinBitrate() -> 8000 bps (per channel, incl. LFE).
-MaxBitrate() -> (6144 * samplerate / 1024) bps (per channel, incl. LFE).
-But output bitrates don't go as high as the theoretical maximums:
-12 kHz        43  (72)        87 (144)      260  (432)      303  (504)      342  (576)
-24 kHz        87 (144)       174 (288)      514  (864)      595 (1008)      669 (1152)
-48 kHz       174 (288)       347 (576)      970 (1728)     1138 (2016)     1287 (2304)
-Also, faac isn't a great encoder, so you don't want to allow too low a bitrate.
-Limits: minimum of  32 Kbps per channel
-        maximum of 192 Kbps per channel at 32-48 kHz, adjusted for sr_shift
-
-
-ffaac
------
-supported samplerates: 8 - 48 kHz
-libavcodec/aacenc.c defines a maximum bitrate:
--> 6144 * samplerate / 1024 bps (per channel, incl. LFE).
-But output bitrates don't go as high as the theoretical maximums:
-12 kHz        61  (72)       123 (144)
-24 kHz       121 (144)       242 (288)
-48 kHz       236 (288)       472 (576)
-Also, ffaac isn't a great encoder, so you don't want to allow too low a bitrate.
-Limits: minimum of  32 Kbps per channel
-        maximum of 192 Kbps per channel at 32 kHz, adjusted for sr_shift
-        maximum of 256 Kbps per channel at 44.1-48 kHz, adjusted for sr_shift
-
-vorbis
-------
-supported samplerates: 8 - 48 kHz
-lib/modes/setup_*.h provides a range of allowed bitrates for various configurations.
-for each samplerate, the highest minimums and lowest maximums are:
- 8 kHz        Minimum  8 Kbps, maximum  32 Kbps (per channel, incl. LFE).
-12 kHz        Minimum 14 Kbps, maximum  44 Kbps (per channel, incl. LFE).
-16 kHz        Minimum 16 Kbps, maximum  86 Kbps (per channel, incl. LFE).
-24 kHz        Minimum 22 Kbps, maximum  86 Kbps (per channel, incl. LFE).
-32 kHz        Minimum 26 Kbps, maximum 190 Kbps (per channel, incl. LFE).
-48 kHz        Minimum 28 Kbps, maximum 240 Kbps (per channel, incl. LFE).
-Limits: minimum of 14/22/28 Kbps per channel (8-12, 16-24, 32-48 kHz)
-        maximum of 32/86/190/240 Kbps per channel (8-12, 16-24, 32, 44.1-48 kHz)
-
-lame
-----
-supported samplerates: 8 - 48 kHz
-lame_init_params() allows the following bitrates:
-12 kHz        Minimum  8 Kbps, maximum  64 Kbps
-24 kHz        Minimum  8 Kbps, maximum 160 Kbps
-48 kHz        Minimum 32 Kbps, maximum 320 Kbps
-Limits: minimum of 8/8/32 Kbps (8-12, 16-24, 32-48 kHz)
-        maximum of 64/160/320 Kbps (8-12, 16-24, 32-48 kHz)
-
-ffac3
------
-supported samplerates: 32 - 48 kHz (< 32 kHz disabled for compatibility reasons)
-Dolby's encoder has a min. of 224 Kbps for 5 full-bandwidth channels (5.0, 5.1)
-The maximum AC3 bitrate is 640 Kbps
-Limits: minimum of 224/5 Kbps per full-bandwidth channel, maximum of 640 Kbps
-
-ca_aac
-------
-supported samplerates: 8 - 48 kHz
-Core Audio API provides a range of allowed bitrates:
- 8 kHz         8 -  24        16 -  48        40 - 112        48 - 144        56 - 160
-12 kHz        12 -  32        24 -  64        64 - 160        72 - 192        96 - 224
-16 kHz        12 -  48        24 -  96        64 - 224        72 - 288        96 - 320
-24 kHz        16 -  64        32 - 128        80 - 320        96 - 384       112 - 448
-32 kHz        24 -  96        48 - 192       128 - 448       144 - 576       192 - 640
-48 kHz        32 - 256        64 - 320       160 - 768       192 - 960       224 - 960
-Limits:
- 8 kHz -> minimum of  8 Kbps and maximum of  24 Kbps per full-bandwidth channel
-12 kHz -> minimum of 12 Kbps and maximum of  32 Kbps per full-bandwidth channel
-16 kHz -> minimum of 12 Kbps and maximum of  48 Kbps per full-bandwidth channel
-24 kHz -> minimum of 16 Kbps and maximum of  64 Kbps per full-bandwidth channel
-32 kHz -> minimum of 24 Kbps and maximum of  96 Kbps per full-bandwidth channel
-48 kHz -> minimum of 32 Kbps and maximum of 160 Kbps per full-bandwidth channel
-48 kHz ->                        maximum of +96 Kbps for Mono
-Note: encCoreAudioInit() will sanitize any mistake made here.
-
-ca_haac
--------
-supported samplerates: 32 - 48 kHz
-Core Audio API provides a range of allowed bitrates:
-32 kHz         12 - 40         24 - 80        64 - 192          N/A           96 - 256
-48 kHz         16 - 40         32 - 80        80 - 192          N/A          112 - 256
-Limits: minimum of 12 Kbps per full-bandwidth channel (<= 32 kHz)
-        minimum of 16 Kbps per full-bandwidth channel ( > 32 kHz)
-        maximum of 40 Kbps per full-bandwidth channel
-Note: encCoreAudioInit() will sanitize any mistake made here.
-
-fdk_aac
--------
-supported samplerates: 8 - 48 kHz
-libfdk limits the bitrate to the following values:
- 8 kHz              48              96             240
-12 kHz              72             144             360
-16 kHz              96             192             480
-24 kHz             144             288             720
-32 kHz             192             384             960
-48 kHz             288             576            1440
-Limits: minimum of samplerate * 2/3 Kbps per full-bandwidth channel (see ca_aac)
-        maximum of samplerate * 6.0 Kbps per full-bandwidth channel
-fdk_haac
---------
-supported samplerates: 16 - 48 kHz
-libfdk limits the bitrate to the following values:
-16 kHz         8 -  48        16 -  96        45 - 199
-24 kHz         8 -  63        16 - 127        45 - 266
-32 kHz         8 -  63        16 - 127        45 - 266
-48 kHz        12 -  63        16 - 127        50 - 266
-Limits: minimum of 12 Kbps per full-bandwidth channel  (<= 32 kHz) (see ca_haac)
-        minimum of 16 Kbps per full-bandwidth channel  ( > 32 kHz) (see ca_haac)
-        maximum of 48,  96 or 192 Kbps (1.0, 2.0, 5.1) (<= 16 kHz)
-        maximum of 64, 128 or 256 Kbps (1.0, 2.0, 5.1) ( > 16 kHz)
-*/
+// Given an input bitrate, sanitize it.
+// Check low and high limits and make sure it is in the set of allowed bitrates.
+int hb_audio_bitrate_get_best(uint32_t codec, int bitrate, int samplerate,
+                              int mixdown)
+{
+    int low, high;
+    hb_audio_bitrate_get_limits(codec, samplerate, mixdown, &low, &high);
+    if (bitrate > high)
+        bitrate = high;
+    if (bitrate < low)
+        bitrate = low;
+    return hb_audio_bitrate_find_closest(bitrate);
+}
 
-void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
-                                 int *low, int *high)
+// Get the default bitrate for a given codec/samplerate/mixdown triplet.
+int hb_audio_bitrate_get_default(uint32_t codec, int samplerate, int mixdown)
 {
-    if (codec & HB_ACODEC_PASS_FLAG)
+    if ((codec & HB_ACODEC_PASS_FLAG) || !(codec & HB_ACODEC_MASK))
+        goto fail;
+
+    int bitrate, nchannels, sr_shift;
+    /* full-bandwidth channels, sr_shift */
+    nchannels = (hb_mixdown_get_discrete_channel_count(mixdown) -
+                 hb_mixdown_get_low_freq_channel_count(mixdown));
+    hb_audio_samplerate_get_best(codec, samplerate, &sr_shift);
+
+    switch (codec)
     {
-        // Bitrates don't apply to passthrough audio, but may apply if we
-        // fallback to an encoder when the source can't be passed through.
-        *low = hb_audio_bitrates[0].rate;
-        *high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
-        return;
+        case HB_ACODEC_FFFLAC:
+        case HB_ACODEC_FFFLAC24:
+            goto fail;
+
+        // 96, 224, 640 Kbps
+        case HB_ACODEC_AC3:
+            bitrate = (nchannels * 128) - (32 * (nchannels < 5));
+            break;
+
+        case HB_ACODEC_CA_HAAC:
+        case HB_ACODEC_FDK_HAAC:
+            bitrate = nchannels * 32;
+            break;
+
+        default:
+            bitrate = nchannels * 80;
+            break;
     }
+    // sample_rate adjustment
+    bitrate >>= sr_shift;
+    return hb_audio_bitrate_get_best(codec, bitrate, samplerate, mixdown);
 
+fail:
+    return -1;
+}
+
+/* Get the bitrate low and high limits for a codec/samplerate/mixdown triplet.
+ *
+ * Encoder    1.0 channel    2.0 channels    5.1 channels    6.1 channels    7.1 channels
+ * --------------------------------------------------------------------------------------
+ *
+ * faac
+ * ----
+ * supported samplerates: 8 - 48 kHz
+ * libfaac/util.c defines the bitrate limits:
+ * MinBitrate() -> 8000 bps (per channel, incl. LFE).
+ * MaxBitrate() -> (6144 * samplerate / 1024) bps (per channel, incl. LFE).
+ * But output bitrates don't go as high as the theoretical maximums:
+ * 12 kHz        43  (72)        87 (144)      260  (432)      303  (504)      342  (576)
+ * 24 kHz        87 (144)       174 (288)      514  (864)      595 (1008)      669 (1152)
+ * 48 kHz       174 (288)       347 (576)      970 (1728)     1138 (2016)     1287 (2304)
+ * Also, faac isn't a great encoder, so you don't want to allow too low a bitrate.
+ * Limits: minimum of  32 Kbps per channel
+ *         maximum of 192 Kbps per channel at 32-48 kHz, adjusted for sr_shift
+ *
+ *
+ * ffaac
+ * -----
+ * supported samplerates: 8 - 48 kHz
+ * libavcodec/aacenc.c defines a maximum bitrate:
+ * -> 6144 * samplerate / 1024 bps (per channel, incl. LFE).
+ * But output bitrates don't go as high as the theoretical maximums:
+ * 12 kHz        61  (72)       123 (144)
+ * 24 kHz       121 (144)       242 (288)
+ * 48 kHz       236 (288)       472 (576)
+ * Also, ffaac isn't a great encoder, so you don't want to allow too low a bitrate.
+ * Limits: minimum of  32 Kbps per channel
+ *         maximum of 192 Kbps per channel at 32 kHz, adjusted for sr_shift
+ *         maximum of 256 Kbps per channel at 44.1-48 kHz, adjusted for sr_shift
+ *
+ * vorbis
+ * ------
+ * supported samplerates: 8 - 48 kHz
+ * lib/modes/setup_*.h provides a range of allowed bitrates for various configurations.
+ * for each samplerate, the highest minimums and lowest maximums are:
+ *  8 kHz        Minimum  8 Kbps, maximum  32 Kbps (per channel, incl. LFE).
+ * 12 kHz        Minimum 14 Kbps, maximum  44 Kbps (per channel, incl. LFE).
+ * 16 kHz        Minimum 16 Kbps, maximum  86 Kbps (per channel, incl. LFE).
+ * 24 kHz        Minimum 22 Kbps, maximum  86 Kbps (per channel, incl. LFE).
+ * 32 kHz        Minimum 26 Kbps, maximum 190 Kbps (per channel, incl. LFE).
+ * 48 kHz        Minimum 28 Kbps, maximum 240 Kbps (per channel, incl. LFE).
+ * Limits: minimum of 14/22/28 Kbps per channel (8-12, 16-24, 32-48 kHz)
+ *         maximum of 32/86/190/240 Kbps per channel (8-12, 16-24, 32, 44.1-48 kHz)
+ *
+ * lame
+ * ----
+ * supported samplerates: 8 - 48 kHz
+ * lame_init_params() allows the following bitrates:
+ * 12 kHz        Minimum  8 Kbps, maximum  64 Kbps
+ * 24 kHz        Minimum  8 Kbps, maximum 160 Kbps
+ * 48 kHz        Minimum 32 Kbps, maximum 320 Kbps
+ * Limits: minimum of 8/8/32 Kbps (8-12, 16-24, 32-48 kHz)
+ *         maximum of 64/160/320 Kbps (8-12, 16-24, 32-48 kHz)
+ *
+ * ffac3
+ * -----
+ * supported samplerates: 32 - 48 kHz (< 32 kHz disabled for compatibility reasons)
+ * Dolby's encoder has a min. of 224 Kbps for 5 full-bandwidth channels (5.0, 5.1)
+ * The maximum AC3 bitrate is 640 Kbps
+ * Limits: minimum of 224/5 Kbps per full-bandwidth channel, maximum of 640 Kbps
+ *
+ * ca_aac
+ * ------
+ * supported samplerates: 8 - 48 kHz
+ * Core Audio API provides a range of allowed bitrates:
+ *  8 kHz         8 -  24        16 -  48        40 - 112        48 - 144        56 - 160
+ * 12 kHz        12 -  32        24 -  64        64 - 160        72 - 192        96 - 224
+ * 16 kHz        12 -  48        24 -  96        64 - 224        72 - 288        96 - 320
+ * 24 kHz        16 -  64        32 - 128        80 - 320        96 - 384       112 - 448
+ * 32 kHz        24 -  96        48 - 192       128 - 448       144 - 576       192 - 640
+ * 48 kHz        32 - 256        64 - 320       160 - 768       192 - 960       224 - 960
+ * Limits:
+ *  8 kHz -> minimum of  8 Kbps and maximum of  24 Kbps per full-bandwidth channel
+ * 12 kHz -> minimum of 12 Kbps and maximum of  32 Kbps per full-bandwidth channel
+ * 16 kHz -> minimum of 12 Kbps and maximum of  48 Kbps per full-bandwidth channel
+ * 24 kHz -> minimum of 16 Kbps and maximum of  64 Kbps per full-bandwidth channel
+ * 32 kHz -> minimum of 24 Kbps and maximum of  96 Kbps per full-bandwidth channel
+ * 48 kHz -> minimum of 32 Kbps and maximum of 160 Kbps per full-bandwidth channel
+ * 48 kHz ->                        maximum of +96 Kbps for Mono
+ * Note: encCoreAudioInit() will sanitize any mistake made here.
+ *
+ * ca_haac
+ * -------
+ * supported samplerates: 32 - 48 kHz
+ * Core Audio API provides a range of allowed bitrates:
+ * 32 kHz         12 - 40         24 - 80        64 - 192          N/A           96 - 256
+ * 48 kHz         16 - 40         32 - 80        80 - 192          N/A          112 - 256
+ * Limits: minimum of 12 Kbps per full-bandwidth channel (<= 32 kHz)
+ *         minimum of 16 Kbps per full-bandwidth channel ( > 32 kHz)
+ *         maximum of 40 Kbps per full-bandwidth channel
+ * Note: encCoreAudioInit() will sanitize any mistake made here.
+ *
+ * fdk_aac
+ * -------
+ * supported samplerates: 8 - 48 kHz
+ * libfdk limits the bitrate to the following values:
+ *  8 kHz              48              96             240
+ * 12 kHz              72             144             360
+ * 16 kHz              96             192             480
+ * 24 kHz             144             288             720
+ * 32 kHz             192             384             960
+ * 48 kHz             288             576            1440
+ * Limits: minimum of samplerate * 2/3 Kbps per full-bandwidth channel (see ca_aac)
+ *         maximum of samplerate * 6.0 Kbps per full-bandwidth channel
+ *
+ * fdk_haac
+ * --------
+ * supported samplerates: 16 - 48 kHz
+ * libfdk limits the bitrate to the following values:
+ * 16 kHz         8 -  48        16 -  96        45 - 199
+ * 24 kHz         8 -  63        16 - 127        45 - 266
+ * 32 kHz         8 -  63        16 - 127        45 - 266
+ * 48 kHz        12 -  63        16 - 127        50 - 266
+ * Limits: minimum of 12 Kbps per full-bandwidth channel  (<= 32 kHz) (see ca_haac)
+ *         minimum of 16 Kbps per full-bandwidth channel  ( > 32 kHz) (see ca_haac)
+ *         maximum of 48,  96 or 192 Kbps (1.0, 2.0, 5.1) (<= 16 kHz)
+ *         maximum of 64, 128 or 256 Kbps (1.0, 2.0, 5.1) ( > 16 kHz)
+*/
+void hb_audio_bitrate_get_limits(uint32_t codec, int samplerate, int mixdown,
+                                 int *low, int *high)
+{
     /* samplerate, sr_shift */
     int sr_shift;
-    samplerate = hb_get_best_samplerate(codec, samplerate, &sr_shift);
+    samplerate = hb_audio_samplerate_get_best(codec, samplerate, &sr_shift);
 
     /* LFE, full-bandwidth channels */
     int lfe_count, nchannels;
@@ -713,32 +567,37 @@ void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
                     *low  = nchannels *  8;
                     *high = nchannels * 24;
                     break;
+
                 case 11025:
                 case 12000:
                     *low  = nchannels * 12;
                     *high = nchannels * 32;
                     break;
+
                 case 16000:
                     *low  = nchannels * 12;
                     *high = nchannels * 48;
                     break;
+
                 case 22050:
                 case 24000:
                     *low  = nchannels * 16;
                     *high = nchannels * 64;
                     break;
+
                 case 32000:
                     *low  = nchannels * 24;
                     *high = nchannels * 96;
                     break;
+
                 case 44100:
                 case 48000:
                 default:
                     *low  = nchannels * 32;
                     *high = nchannels * (160 + (96 * (nchannels == 1)));
                     break;
+            } break;
             }
-        } break;
 
         case HB_ACODEC_CA_HAAC:
             *low  = nchannels * (12 + (4 * (samplerate >= 44100)));
@@ -784,11 +643,14 @@ void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
                                                ( 50 * (samplerate >= 44100)));
             break;
 
+        // Bitrates don't apply to passthrough audio, but may apply if we
+        // fall back to an encoder when the source can't be passed through.
         default:
             *low  = hb_audio_bitrates[0].rate;
             *high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
             break;
     }
+
     // sanitize max. bitrate
     if (*high < hb_audio_bitrates[0].rate)
         *high = hb_audio_bitrates[0].rate;
@@ -796,57 +658,18 @@ void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
         *high = hb_audio_bitrates[hb_audio_bitrates_count-1].rate;
 }
 
-// Given an input bitrate, sanitize it.
-// Check low and high limits and make sure it is in the set of allowed bitrates.
-int hb_get_best_audio_bitrate(uint32_t codec, int bitrate, int samplerate,
-                              int mixdown)
+const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last)
 {
-    int low, high;
-    hb_get_audio_bitrate_limits(codec, samplerate, mixdown, &low, &high);
-    if (bitrate > high)
-        bitrate = high;
-    if (bitrate < low)
-        bitrate = low;
-    return hb_find_closest_audio_bitrate(bitrate);
-}
-
-// Get the default bitrate for a given codec/samplerate/mixdown triplet.
-int hb_get_default_audio_bitrate(uint32_t codec, int samplerate, int mixdown)
+    if (last == NULL)
 {
-    if (codec & HB_ACODEC_PASS_FLAG)
-    {
-        return -1;
+        return  &hb_audio_bitrates[0];
     }
-
-    int bitrate, nchannels, sr_shift;
-    /* full-bandwidth channels, sr_shift */
-    nchannels = (hb_mixdown_get_discrete_channel_count(mixdown) -
-                 hb_mixdown_get_low_freq_channel_count(mixdown));
-    hb_get_best_samplerate(codec, samplerate, &sr_shift);
-
-    switch (codec)
+    if (last <  &hb_audio_bitrates[0] ||
+        last >= &hb_audio_bitrates[hb_audio_bitrates_count - 1])
     {
-        case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FFFLAC24:
-            return -1;
-
-        // 96, 224, 640 Kbps
-        case HB_ACODEC_AC3:
-            bitrate = (nchannels * 128) - (32 * (nchannels < 5));
-            break;
-
-        case HB_ACODEC_CA_HAAC:
-        case HB_ACODEC_FDK_HAAC:
-            bitrate = nchannels * 32;
-            break;
-
-        default:
-            bitrate = nchannels * 80;
-            break;
+        return NULL;
     }
-    // sample_rate adjustment
-    bitrate >>= sr_shift;
-    return hb_get_best_audio_bitrate(codec, bitrate, samplerate, mixdown);
+    return last + 1;
 }
 
 // Get limits and hints for the UIs.
@@ -856,7 +679,7 @@ int hb_get_default_audio_bitrate(uint32_t codec, int samplerate, int mixdown)
 //
 // direction says whether 'low' limit is highest or lowest 
 // quality (direction 0 == lowest value is worst quality)
-void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high,
+void hb_audio_quality_get_limits(uint32_t codec, float *low, float *high,
                                  float *granularity, int *direction)
 {
     switch (codec)
@@ -865,36 +688,36 @@ void hb_get_audio_quality_limits(uint32_t codec, float *low, float *high,
             *direction = 1;
             *granularity = 0.5;
             *low = 0.;
-            *high = 10.0;
+            *high        = 10.;
             break;
 
         case HB_ACODEC_VORBIS:
             *direction = 0;
             *granularity = 0.5;
-            *low = -2.0;
-            *high = 10.0;
+            *low         = -2.;
+            *high        = 10.;
             break;
 
         case HB_ACODEC_CA_AAC:
             *direction = 0;
-            *granularity = 9;
+            *granularity = 9.;
             *low = 1.;
-            *high = 127.0;
+            *high        = 127.;
             break;
 
         default:
             *direction = 0;
-            *granularity = 1;
+            *granularity = 1.;
             *low = *high = HB_INVALID_AUDIO_QUALITY;
             break;
     }
 }
 
-float hb_get_best_audio_quality(uint32_t codec, float quality)
+float hb_audio_quality_get_best(uint32_t codec, float quality)
 {
-    float low, high, granularity;
     int direction;
-    hb_get_audio_quality_limits(codec, &low, &high, &granularity, &direction);
+    float low, high, granularity;
+    hb_audio_quality_get_limits(codec, &low, &high, &granularity, &direction);
     if (quality > high)
         quality = high;
     if (quality < low)
@@ -902,28 +725,22 @@ float hb_get_best_audio_quality(uint32_t codec, float quality)
     return quality;
 }
 
-float hb_get_default_audio_quality( uint32_t codec )
+float hb_audio_quality_get_default(uint32_t codec)
 {
-    float quality;
     switch( codec )
     {
         case HB_ACODEC_LAME:
-            quality = 2.;
-            break;
+            return 2.;
 
         case HB_ACODEC_VORBIS:
-            quality = 5.;
-            break;
+            return 5.;
 
         case HB_ACODEC_CA_AAC:
-            quality = 91.;
-            break;
+            return 91.;
 
         default:
-            quality = HB_INVALID_AUDIO_QUALITY;
-            break;
+            return HB_INVALID_AUDIO_QUALITY;
     }
-    return quality;
 }
 
 // Get limits and hints for the UIs.
@@ -933,7 +750,7 @@ float hb_get_default_audio_quality( uint32_t codec )
 //
 // direction says whether 'low' limit is highest or lowest 
 // compression level (direction 0 == lowest value is worst compression level)
-void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high,
+void hb_audio_compression_get_limits(uint32_t codec, float *low, float *high,
                                      float *granularity, int *direction)
 {
     switch (codec)
@@ -941,31 +758,31 @@ void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high,
         case HB_ACODEC_FFFLAC:
         case HB_ACODEC_FFFLAC24:
             *direction = 0;
-            *granularity = 1;
-            *high = 12;
-            *low = 0;
+            *granularity = 1.;
+            *high        = 12.;
+            *low         = 0.;
             break;
 
         case HB_ACODEC_LAME:
             *direction = 1;
-            *granularity = 1;
-            *high = 9;
-            *low = 0;
+            *granularity = 1.;
+            *high        = 9.;
+            *low         = 0.;
             break;
 
         default:
             *direction = 0;
-            *granularity = 1;
-            *low = *high = -1;
+            *granularity = 1.;
+            *low = *high = -1.;
             break;
     }
 }
 
-float hb_get_best_audio_compression(uint32_t codec, float compression)
+float hb_audio_compression_get_best(uint32_t codec, float compression)
 {
-    float low, high, granularity;
     int direction;
-    hb_get_audio_compression_limits(codec, &low, &high, &granularity, &direction);
+    float low, high, granularity;
+    hb_audio_compression_get_limits(codec, &low, &high, &granularity, &direction);
     if( compression > high )
         compression = high;
     if( compression < low )
@@ -973,7 +790,7 @@ float hb_get_best_audio_compression(uint32_t codec, float compression)
     return compression;
 }
 
-float hb_get_default_audio_compression(uint32_t codec)
+float hb_audio_compression_get_default(uint32_t codec)
 {
     switch (codec)
     {
@@ -989,99 +806,890 @@ float hb_get_default_audio_compression(uint32_t codec)
     }
 }
 
-int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown)
+int hb_audio_dither_get_default()
 {
-    // Passthru, only "None" mixdown is supported
-    if (codec & HB_ACODEC_PASS_FLAG)
-        return HB_AMIXDOWN_NONE;
-
-    // caller requested the best available mixdown
-    if (mixdown == HB_INVALID_AMIXDOWN)
-        mixdown  = hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown;
+    // "auto"
+    return hb_audio_dithers[0].method;
+}
 
-    int ii;
-    // test all mixdowns until an authorized, supported mixdown is found
-    // stop before we reach the "worst" non-None mixdown (index == 1)
-    for (ii = hb_audio_mixdowns_count - 1; ii > 1; ii--)
-        if (hb_audio_mixdowns[ii].amixdown <= mixdown &&
-            hb_mixdown_is_supported(hb_audio_mixdowns[ii].amixdown, codec, layout))
-            break;
-    return hb_audio_mixdowns[ii].amixdown;
+int hb_audio_dither_get_default_method()
+{
+    /*
+     * input could be s16 (possibly already dithered) converted to flt, so
+     * let's use a "low-risk" dither algorithm (standard triangular).
+     */
+    return AV_RESAMPLE_DITHER_TRIANGULAR;
 }
 
-int hb_get_default_mixdown(uint32_t codec, uint64_t layout)
+int hb_audio_dither_is_supported(uint32_t codec)
 {
-    int mixdown;
+    // encoder's input sample format must be s16(p)
     switch (codec)
     {
-        // the FLAC encoder defaults to the best mixdown up to 7.1
         case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FFFLAC24:
-            mixdown = HB_AMIXDOWN_7POINT1;
-            break;
-        // the AC3 encoder defaults to the best mixdown up to 5.1
-        case HB_ACODEC_AC3:
-            mixdown = HB_AMIXDOWN_5POINT1;
-            break;
-        // other encoders default to the best mixdown up to DPLII
+        case HB_ACODEC_FDK_AAC:
+        case HB_ACODEC_FDK_HAAC:
+            return 1;
+
         default:
-            mixdown = HB_AMIXDOWN_DOLBYPLII;
-            break;
+            return 0;
     }
-    // return the best available mixdown up to the selected default
-    return hb_get_best_mixdown(codec, layout, mixdown);
 }
 
-int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift)
+int hb_audio_dither_get_from_name(const char *name)
 {
-    int ii, best_samplerate, samplerate_shift;
-    if ((samplerate < 32000) &&
-        (codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_AC3))
-    {
-        // ca_haac can't do samplerates < 32 kHz
-        // AC-3 < 32 kHz suffers from poor hardware compatibility
-        best_samplerate  = 32000;
-        samplerate_shift = 0;
-    }
-    else if (samplerate < 16000 && codec == HB_ACODEC_FDK_HAAC)
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    int i;
+    for ( i = 0; i < hb_audio_dithers_count; i++)
     {
-        // fdk_haac can't do samplerates < 16 kHz
-        best_samplerate  = 16000;
-        samplerate_shift = 1;
+        if (!strcasecmp(hb_audio_dithers[i].short_name, name))
+        {
+            return hb_audio_dithers[i].method;
+        }
     }
-    else
+
+fail:
+    return hb_audio_dither_get_default();
+}
+
+const char* hb_audio_dither_get_description(int method)
+{
+    if (method < hb_audio_dithers[0].method ||
+        method > hb_audio_dithers[hb_audio_dithers_count - 1].method)
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_audio_dithers_count; i++)
     {
-        best_samplerate = samplerate;
-        for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
+        if (hb_audio_dithers[i].method == method)
         {
-            // valid samplerate
-            if (best_samplerate == hb_audio_rates[ii].rate)
-                break;
-
-            // samplerate is higher than the next valid samplerate,
-            // or lower than the lowest valid samplerate
-            if (best_samplerate > hb_audio_rates[ii].rate || ii == 0)
-            {
-                best_samplerate = hb_audio_rates[ii].rate;
-                break;
-            }
+            return hb_audio_dithers[i].description;
         }
-        /* sr_shift: 0 -> 48000, 44100, 32000 Hz
-         *           1 -> 24000, 22050, 16000 Hz
-         *           2 -> 12000, 11025,  8000 Hz
-         *
-         * also, since samplerates are sanitized downwards:
-         *
-         * (samplerate < 32000) implies (samplerate <= 24000)
-         */
-        samplerate_shift = ((best_samplerate < 16000) ? 2 :
-                            (best_samplerate < 32000) ? 1 : 0);
     }
-    if (sr_shift != NULL)
+
+fail:
+    return NULL;
+}
+
+const hb_dither_t* hb_audio_dither_get_next(const hb_dither_t *last)
+{
+    if (last == NULL)
     {
-        *sr_shift = samplerate_shift;
+        return  &hb_audio_dithers[0];
     }
-    return best_samplerate;
+    if (last <  &hb_audio_dithers[0] ||
+        last >= &hb_audio_dithers[hb_audio_dithers_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
+}
+
+int hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout)
+{
+    return (hb_mixdown_has_codec_support(mixdown, codec) &&
+            hb_mixdown_has_remix_support(mixdown, layout));
+}
+
+int hb_mixdown_has_codec_support(int mixdown, uint32_t codec)
+{
+    // Passthru, only "None" mixdown is supported
+    if (codec & HB_ACODEC_PASS_FLAG)
+        return (mixdown == HB_AMIXDOWN_NONE);
+
+    // Not passthru, "None" mixdown never supported
+    if (mixdown == HB_AMIXDOWN_NONE)
+        return 0;
+
+    switch (codec)
+    {
+        case HB_ACODEC_VORBIS:
+        case HB_ACODEC_FFFLAC:
+        case HB_ACODEC_FFFLAC24:
+            return (mixdown <= HB_AMIXDOWN_7POINT1);
+
+        case HB_ACODEC_LAME:
+        case HB_ACODEC_FFAAC:
+            return (mixdown <= HB_AMIXDOWN_DOLBYPLII);
+
+        case HB_ACODEC_FAAC:
+        case HB_ACODEC_CA_AAC:
+        case HB_ACODEC_CA_HAAC:
+            return ((mixdown <= HB_AMIXDOWN_5POINT1) ||
+                    (mixdown == HB_AMIXDOWN_5_2_LFE));
+
+        default:
+            return (mixdown <= HB_AMIXDOWN_5POINT1);
+    }
+}
+
+int hb_mixdown_has_remix_support(int mixdown, uint64_t layout)
+{
+    switch (mixdown)
+    {
+        // stereo + front left/right of center
+        case HB_AMIXDOWN_5_2_LFE:
+            return ((layout & AV_CH_FRONT_LEFT_OF_CENTER) &&
+                    (layout & AV_CH_FRONT_RIGHT_OF_CENTER) &&
+                    (layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO);
+
+        // 7.0 or better
+        case HB_AMIXDOWN_7POINT1:
+            return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0);
+
+        // 6.0 or better
+        case HB_AMIXDOWN_6POINT1:
+            return ((layout & AV_CH_LAYOUT_7POINT0) == AV_CH_LAYOUT_7POINT0 ||
+                    (layout & AV_CH_LAYOUT_6POINT0) == AV_CH_LAYOUT_6POINT0 ||
+                    (layout & AV_CH_LAYOUT_HEXAGONAL) == AV_CH_LAYOUT_HEXAGONAL);
+
+        // stereo + either of front center, side or back left/right, back center
+        case HB_AMIXDOWN_5POINT1:
+            return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
+                    (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
+                    (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
+                    (layout & AV_CH_LAYOUT_SURROUND) == AV_CH_LAYOUT_SURROUND);
+
+        // stereo + either of side or back left/right, back center
+        // also, allow Dolby Surrounbd output if the input is already Dolby
+        case HB_AMIXDOWN_DOLBY:
+        case HB_AMIXDOWN_DOLBYPLII:
+            return ((layout & AV_CH_LAYOUT_2_1) == AV_CH_LAYOUT_2_1 ||
+                    (layout & AV_CH_LAYOUT_2_2) == AV_CH_LAYOUT_2_2 ||
+                    (layout & AV_CH_LAYOUT_QUAD) == AV_CH_LAYOUT_QUAD ||
+                    (layout == AV_CH_LAYOUT_STEREO_DOWNMIX &&
+                     mixdown == HB_AMIXDOWN_DOLBY));
+
+        // more than 1 channel
+        case HB_AMIXDOWN_STEREO:
+            return (av_get_channel_layout_nb_channels(layout) > 1);
+
+        // regular stereo (not Dolby)
+        case HB_AMIXDOWN_LEFT:
+        case HB_AMIXDOWN_RIGHT:
+            return (layout == AV_CH_LAYOUT_STEREO);
+
+        // mono remix always supported
+        // HB_AMIXDOWN_NONE always supported (for Passthru)
+        case HB_AMIXDOWN_MONO:
+        case HB_AMIXDOWN_NONE:
+            return 1;
+
+        // unknown mixdown, should never happen
+        default:
+            return 0;
+    }
+}
+
+int hb_mixdown_get_discrete_channel_count(int amixdown)
+{
+    switch (amixdown)
+    {
+        case HB_AMIXDOWN_5_2_LFE:
+        case HB_AMIXDOWN_7POINT1:
+            return 8;
+
+        case HB_AMIXDOWN_6POINT1:
+            return 7;
+
+        case HB_AMIXDOWN_5POINT1:
+            return 6;
+
+        case HB_AMIXDOWN_MONO:
+        case HB_AMIXDOWN_LEFT:
+        case HB_AMIXDOWN_RIGHT:
+            return 1;
+
+        case HB_AMIXDOWN_NONE:
+            return 0;
+
+        default:
+            return 2;
+    }
+}
+
+int hb_mixdown_get_low_freq_channel_count(int amixdown)
+{
+    switch (amixdown)
+    {
+        case HB_AMIXDOWN_5POINT1:
+        case HB_AMIXDOWN_6POINT1:
+        case HB_AMIXDOWN_7POINT1:
+        case HB_AMIXDOWN_5_2_LFE:
+            return 1;
+
+        default:
+            return 0;
+    }
+}
+
+int hb_mixdown_get_best(uint32_t codec, uint64_t layout, int mixdown)
+{
+    // Passthru, only "None" mixdown is supported
+    if (codec & HB_ACODEC_PASS_FLAG)
+        return HB_AMIXDOWN_NONE;
+
+    // caller requested the best available mixdown
+    if (mixdown == HB_INVALID_AMIXDOWN)
+        mixdown  = hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown;
+
+    // test all mixdowns until an authorized, supported mixdown is found
+    // stop before we reach the "worst" non-None mixdown (index == 1)
+    int i;
+    for (i = hb_audio_mixdowns_count - 1; i > 1; i--)
+        if (hb_audio_mixdowns[i].amixdown <= mixdown &&
+            hb_mixdown_is_supported(hb_audio_mixdowns[i].amixdown, codec, layout))
+            break;
+    return hb_audio_mixdowns[i].amixdown;
+}
+
+int hb_mixdown_get_default(uint32_t codec, uint64_t layout)
+{
+    int mixdown;
+    switch (codec)
+    {
+        // the FLAC encoder defaults to the best mixdown up to 7.1
+        case HB_ACODEC_FFFLAC:
+        case HB_ACODEC_FFFLAC24:
+            mixdown = HB_AMIXDOWN_7POINT1;
+            break;
+
+        // the AC3 encoder defaults to the best mixdown up to 5.1
+        case HB_ACODEC_AC3:
+            mixdown = HB_AMIXDOWN_5POINT1;
+            break;
+
+        // other encoders default to the best mixdown up to DPLII
+        default:
+            mixdown = HB_AMIXDOWN_DOLBYPLII;
+            break;
+    }
+
+    // return the best available mixdown up to the selected default
+    return hb_mixdown_get_best(codec, layout, mixdown);
+}
+
+int hb_mixdown_get_from_name(const char *name)
+{
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    // TODO: implement something more flexible
+    if (!strcasecmp(name, "AC3 Passthru") ||
+        !strcasecmp(name, "DTS Passthru") ||
+        !strcasecmp(name, "DTS-HD Passthru"))
+    {
+        return HB_AMIXDOWN_NONE;
+    }
+    if (!strcasecmp(name, "6-channel discrete"))
+    {
+        return HB_AMIXDOWN_5POINT1;
+    }
+
+    int i;
+    for (i = 0; i < hb_audio_mixdowns_count; i++)
+    {
+        if (!strcasecmp(hb_audio_mixdowns[i].name,       name) ||
+            !strcasecmp(hb_audio_mixdowns[i].short_name, name))
+        {
+            return hb_audio_mixdowns[i].amixdown;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+const char* hb_mixdown_get_name(int mixdown)
+{
+    if (mixdown < hb_audio_mixdowns[0].amixdown ||
+        mixdown > hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown)
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_audio_mixdowns_count; i++)
+    {
+        if (hb_audio_mixdowns[i].amixdown == mixdown)
+        {
+            return hb_audio_mixdowns[i].name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_mixdown_get_short_name(int mixdown)
+{
+    if (mixdown < hb_audio_mixdowns[0].amixdown ||
+        mixdown > hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown)
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_audio_mixdowns_count; i++)
+    {
+        if (hb_audio_mixdowns[i].amixdown == mixdown)
+        {
+            return hb_audio_mixdowns[i].short_name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_mixdown_sanitize_name(const char *name)
+{
+    return hb_mixdown_get_name(hb_mixdown_get_from_name(name));
+}
+
+const hb_mixdown_t* hb_mixdown_get_next(const hb_mixdown_t *last)
+{
+    if (last == NULL)
+    {
+        return  &hb_audio_mixdowns[0];
+    }
+    if (last <  &hb_audio_mixdowns[0] ||
+        last >= &hb_audio_mixdowns[hb_audio_mixdowns_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
+}
+
+int hb_video_encoder_get_default(int muxer)
+{
+    if (!(muxer & HB_MUX_MASK))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_video_encoders_count; i++)
+    {
+        if (hb_video_encoders[i].muxers & muxer)
+        {
+            return hb_video_encoders[i].codec;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+int hb_video_encoder_get_from_name(const char *name)
+{
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    // TODO: implement something more flexible
+    if (!strcasecmp(name, "XviD") ||
+        !strcasecmp(name, "FFmpeg"))
+    {
+        return HB_VCODEC_FFMPEG_MPEG4;
+    }
+
+    int i;
+    for (i = 0; i < hb_video_encoders_count; i++)
+    {
+        if (!strcasecmp(hb_video_encoders[i].name,       name) ||
+            !strcasecmp(hb_video_encoders[i].short_name, name))
+        {
+            return hb_video_encoders[i].codec;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+const char* hb_video_encoder_get_name(int encoder)
+{
+    if (!(encoder & HB_VCODEC_MASK))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_video_encoders_count; i++)
+    {
+        if (hb_video_encoders[i].codec == encoder)
+        {
+            return hb_video_encoders[i].name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_video_encoder_get_short_name(int encoder)
+{
+    if (!(encoder & HB_VCODEC_MASK))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_video_encoders_count; i++)
+    {
+        if (hb_video_encoders[i].codec == encoder)
+        {
+            return hb_video_encoders[i].short_name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_video_encoder_sanitize_name(const char *name)
+{
+    return hb_video_encoder_get_name(hb_video_encoder_get_from_name(name));
+}
+
+const hb_encoder_t* hb_video_encoder_get_next(const hb_encoder_t *last)
+{
+    if (last == NULL)
+    {
+        return  &hb_video_encoders[0];
+    }
+    if (last <  &hb_video_encoders[0] ||
+        last >= &hb_video_encoders[hb_video_encoders_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
+}
+
+// for a valid passthru, return the matching encoder for that codec (if any),
+// else return -1 (i.e. drop the track)
+int hb_audio_encoder_get_fallback_for_passthru(int passthru)
+{
+    // TODO: implement something more flexible
+    switch (passthru)
+    {
+        case HB_ACODEC_AAC_PASS:
+#ifdef __APPLE__
+            return HB_ACODEC_CA_AAC;
+#else
+            return HB_ACODEC_FAAC;
+#endif
+
+        case HB_ACODEC_AC3_PASS:
+            return HB_ACODEC_AC3;
+
+        case HB_ACODEC_MP3_PASS:
+            return HB_ACODEC_LAME;
+
+            // passthru tracks are often the second audio from the same source track
+            // if we don't have an encoder matching the passthru codec, return -1
+            // dropping the track, as well as ensuring that there is at least one
+            // audio track in the output is then up to the UIs
+        default:
+            return -1;
+    }
+}
+
+int hb_audio_encoder_get_default(int muxer)
+{
+    if (!(muxer & HB_MUX_MASK))
+        goto fail;
+
+#ifndef __APPLE__
+    if (muxer == HB_MUX_MKV)
+    {
+        return HB_ACODEC_LAME;
+    }
+#endif
+
+    int i;
+    for (i = 0; i < hb_audio_encoders_count; i++)
+    {
+        // default encoder should not be passthru
+        if ((hb_audio_encoders[i].muxers & muxer) &&
+            (hb_audio_encoders[i].codec  & HB_ACODEC_PASS_FLAG) == 0)
+        {
+            return hb_audio_encoders[i].codec;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+int hb_audio_encoder_get_from_name(const char *name)
+{
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    // TODO: implement something more flexible
+    if (!strcasecmp(name, "AC3"))
+    {
+        return HB_ACODEC_AC3;
+    }
+    // libfdk fallback, use Core Audio if available, else FAAC
+#ifndef USE_FDK_AAC
+#ifdef __APPLE__
+#define  AAC_ENC HB_ACODEC_CA_AAC
+#define HAAC_ENC HB_ACODEC_CA_HAAC
+#else
+#define  AAC_ENC HB_ACODEC_FAAC
+#define HAAC_ENC HB_ACODEC_FAAC
+#endif
+    if (!strcasecmp(name, "AAC (FDK)")    || !strcasecmp(name, "fdk_aac"))
+    {
+        return AAC_ENC;
+    }
+    if (!strcasecmp(name, "HE-AAC (FDK)") || !strcasecmp(name, "fdk_haac"))
+    {
+        return HAAC_ENC;
+    }
+#undef  AAC_ENC
+#undef HAAC_ENC
+#endif
+
+    int i;
+    for (i = 0; i < hb_audio_encoders_count; i++)
+    {
+        if (!strcasecmp(hb_audio_encoders[i].name,       name) ||
+            !strcasecmp(hb_audio_encoders[i].short_name, name))
+        {
+            return hb_audio_encoders[i].codec;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+const char* hb_audio_encoder_get_name(int encoder)
+{
+    if (!(encoder & HB_ACODEC_ANY))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_audio_encoders_count; i++)
+    {
+        if (hb_audio_encoders[i].codec == encoder)
+        {
+            return hb_audio_encoders[i].name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_audio_encoder_get_short_name(int encoder)
+{
+    if (!(encoder & HB_ACODEC_ANY))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_audio_encoders_count; i++)
+    {
+        if (hb_audio_encoders[i].codec == encoder)
+        {
+            return hb_audio_encoders[i].short_name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_audio_encoder_sanitize_name(const char *name)
+{
+    return hb_audio_encoder_get_name(hb_audio_encoder_get_from_name(name));
+}
+
+const hb_encoder_t* hb_audio_encoder_get_next(const hb_encoder_t *last)
+{
+    if (last == NULL)
+    {
+        return  &hb_audio_encoders[0];
+    }
+    if (last <  &hb_audio_encoders[0] ||
+        last >= &hb_audio_encoders[hb_audio_encoders_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
+}
+
+void hb_autopassthru_apply_settings(hb_job_t *job)
+{
+    hb_audio_t *audio;
+    int i, already_printed;
+    for (i = already_printed = 0; i < hb_list_count(job->list_audio);)
+    {
+        audio = hb_list_item(job->list_audio, i);
+        if (audio->config.out.codec == HB_ACODEC_AUTO_PASS)
+        {
+            if (!already_printed)
+                hb_autopassthru_print_settings(job);
+            already_printed = 1;
+            audio->config.out.codec = hb_autopassthru_get_encoder(audio->config.in.codec,
+                                                                  job->acodec_copy_mask,
+                                                                  job->acodec_fallback,
+                                                                  job->mux);
+            if (!(audio->config.out.codec & HB_ACODEC_PASS_FLAG) &&
+                !(audio->config.out.codec & HB_ACODEC_MASK))
+            {
+                hb_log("Auto Passthru: passthru not possible and no valid fallback specified, dropping track %d",
+                       audio->config.out.track );
+                hb_list_rem(job->list_audio, audio);
+                hb_audio_close(&audio);
+                continue;
+            }
+            audio->config.out.samplerate = audio->config.in.samplerate;
+            if (!(audio->config.out.codec & HB_ACODEC_PASS_FLAG))
+            {
+                if (audio->config.out.codec == job->acodec_fallback)
+                {
+                    hb_log("Auto Passthru: passthru not possible for track %d, using fallback",
+                           audio->config.out.track);
+                }
+    else
+    {
+                    hb_log("Auto Passthru: passthru and fallback not possible for track %d, using default encoder",
+                           audio->config.out.track);
+                }
+                audio->config.out.mixdown =
+                    hb_mixdown_get_default(audio->config.out.codec,
+                                           audio->config.in.channel_layout);
+                audio->config.out.bitrate =
+                    hb_audio_bitrate_get_default(audio->config.out.codec,
+                                                 audio->config.out.samplerate,
+                                                 audio->config.out.mixdown );
+                audio->config.out.compression_level =
+                    hb_audio_compression_get_default(audio->config.out.codec);
+            }
+            else
+        {
+                const hb_encoder_t *audio_encoder = NULL;
+                while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
+                {
+                    if (audio_encoder->codec == audio->config.out.codec)
+                    {
+                        hb_log("Auto Passthru: using %s for track %d",
+                               audio_encoder->name,
+                               audio->config.out.track);
+                break;
+                    }
+                }
+            }
+        }
+        /* Adjust output track number, in case we removed one.
+         * Output tracks sadly still need to be in sequential order.
+         * Note: out.track starts at 1, i starts at 0 */
+        audio->config.out.track = ++i;
+    }
+}
+
+void hb_autopassthru_print_settings(hb_job_t *job)
+            {
+    char *mask = NULL, *tmp;
+    const char *fallback = NULL;
+    const hb_encoder_t *audio_encoder = NULL;
+    while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
+    {
+        if ((audio_encoder->codec &  HB_ACODEC_PASS_FLAG) &&
+            (audio_encoder->codec != HB_ACODEC_AUTO_PASS) &&
+            (audio_encoder->codec & job->acodec_copy_mask))
+        {
+            if (mask != NULL)
+            {
+                tmp = hb_strncat_dup(mask, ", ", 2);
+                if (tmp != NULL)
+                {
+                    free(mask);
+                    mask = tmp;
+                }
+            }
+            // passthru name without " Passthru"
+            tmp = hb_strncat_dup(mask,  audio_encoder->name,
+                                 strlen(audio_encoder->name) - 9);
+            if (tmp != NULL)
+            {
+                free(mask);
+                mask = tmp;
+            }
+        }
+        else if ((audio_encoder->codec & HB_ACODEC_PASS_FLAG) == 0 &&
+                 (audio_encoder->codec == job->acodec_fallback))
+        {
+            fallback = audio_encoder->name;
+        }
+    }
+    if (mask == NULL)
+        hb_log("Auto Passthru: no codecs allowed");
+    else
+        hb_log("Auto Passthru: allowed codecs are %s", mask);
+    if (fallback == NULL)
+        hb_log("Auto Passthru: no valid fallback specified");
+    else
+        hb_log("Auto Passthru: fallback is %s", fallback);
+}
+
+int hb_autopassthru_get_encoder(int in_codec, int copy_mask, int fallback,
+                                int muxer)
+{
+    int i = 0;
+    const hb_encoder_t *audio_encoder = NULL;
+    int out_codec = (copy_mask & in_codec) | HB_ACODEC_PASS_FLAG;
+    // sanitize fallback encoder and selected passthru
+    // note: invalid fallbacks are caught in hb_autopassthru_apply_settings
+    while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
+    {
+        if (audio_encoder->codec == out_codec)
+        {
+            i++;
+            if (!(audio_encoder->muxers & muxer))
+                out_codec = 0;
+        }
+        else if (audio_encoder->codec == fallback)
+        {
+            i++;
+            if (!(audio_encoder->muxers & muxer))
+                fallback = hb_audio_encoder_get_default(muxer);
+        }
+        if (i > 1)
+        {
+                break;
+            }
+        }
+    return (out_codec & HB_ACODEC_PASS_MASK) ? out_codec : fallback;
+    }
+
+int hb_container_get_from_name(const char *name)
+    {
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    // TODO: implement something more flexible
+    if (!strcasecmp(name, "m4v"))
+    {
+        // old CLI alternate short name for "mp4"
+        return HB_MUX_MP4;
+    }
+    if (!strcasecmp(name, "MP4 file"))
+    {
+        return HB_MUX_MP4;
+}
+    if (!strcasecmp(name, "MKV file"))
+    {
+        return HB_MUX_MKV;
+    }
+
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (!strcasecmp(hb_containers[i].name,              name) ||
+            !strcasecmp(hb_containers[i].short_name,        name) ||
+            !strcasecmp(hb_containers[i].default_extension, name))
+        {
+            return hb_containers[i].format;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+int hb_container_get_from_extension(const char *extension)
+{
+    if (extension == NULL || *extension == '\0')
+        goto fail;
+
+    // TODO: implement something more flexible
+    if (!strcasecmp(extension, "m4v"))
+    {
+        return HB_MUX_MP4;
+    }
+
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (!strcasecmp(hb_containers[i].default_extension, extension))
+        {
+            return hb_containers[i].format;
+        }
+    }
+
+fail:
+    return -1;
+}
+
+const char* hb_container_get_name(int format)
+{
+    if (!(format & HB_MUX_MASK))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (hb_containers[i].format == format)
+        {
+            return hb_containers[i].name;
+        }
+
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_container_get_short_name(int format)
+{
+    if (!(format & HB_MUX_MASK))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (hb_containers[i].format == format)
+        {
+            return hb_containers[i].short_name;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_container_get_default_extension(int format)
+{
+    if (!(format & HB_MUX_MASK))
+        goto fail;
+
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (hb_containers[i].format == format)
+        {
+            return hb_containers[i].default_extension;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const char* hb_container_sanitize_name(const char *name)
+{
+    return hb_container_get_name(hb_container_get_from_name(name));
+}
+
+const hb_container_t* hb_container_get_next(const hb_container_t *last)
+{
+    if (last == NULL)
+    {
+        return  &hb_containers[0];
+    }
+    if (last <  &hb_containers[0] ||
+        last >= &hb_containers[hb_containers_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
 }
 
 /**********************************************************************
@@ -2351,7 +2959,7 @@ void hb_audio_config_init(hb_audio_config_t * audiocfg)
 
     /* Initalize some sensible defaults */
     audiocfg->in.track = audiocfg->out.track = 0;
-    audiocfg->out.codec = hb_audio_encoders[0].encoder;
+    audiocfg->out.codec = hb_audio_encoders[0].codec;
     audiocfg->out.samplerate = -1;
     audiocfg->out.samples_per_frame = -1;
     audiocfg->out.bitrate = -1;
index c8b7818d3214ead4a684cde48f2c4a07633300f0..21167155d89196f5d6272077eaa413bb45e2b12e 100644 (file)
@@ -73,6 +73,7 @@ typedef struct hb_rate_s hb_rate_t;
 typedef struct hb_dither_s hb_dither_t;
 typedef struct hb_mixdown_s hb_mixdown_t;
 typedef struct hb_encoder_s hb_encoder_t;
+typedef struct hb_container_s hb_container_t;
 typedef struct hb_job_s  hb_job_t;
 typedef struct hb_title_set_s hb_title_set_t;
 typedef struct hb_title_s hb_title_t;
@@ -187,7 +188,7 @@ void hb_chapter_set_title(hb_chapter_t *chapter, const char *title);
 
 struct hb_rate_s
 {
-    const char *string;
+    const char *name;
     int         rate;
 };
 
@@ -200,7 +201,7 @@ struct hb_dither_s
 
 struct hb_mixdown_s
 {
-    const char *human_readable_name;
+    const char *name;
     const char *internal_name;
     const char *short_name;
     int         amixdown;
@@ -208,10 +209,18 @@ struct hb_mixdown_s
 
 struct hb_encoder_s
 {
-    const char *human_readable_name; // note: used in presets
-    const char *short_name;          // note: used in CLI
-    int         encoder;             // HB_*CODEC_* define
-    int         muxers;              // supported muxers
+    const char *name;       // note: used in presets
+    const char *short_name; // note: used in CLI
+    int         codec;      // HB_*CODEC_* define
+    int         muxers;     // supported muxers
+};
+
+struct hb_container_s
+{
+    const char *name;
+    const char *short_name;
+    const char *default_extension;
+    int         format;
 };
 
 struct hb_subtitle_config_s
@@ -226,77 +235,115 @@ struct hb_subtitle_config_s
     int64_t offset;
 };
 
-#define HB_VIDEO_RATE_BASE   27000000
-
-extern hb_rate_t    hb_video_rates[];
-extern int          hb_video_rates_count;
-extern hb_rate_t    hb_audio_rates[];
-extern int          hb_audio_rates_count;
-extern int          hb_audio_rates_default;
-extern hb_rate_t    hb_audio_bitrates[];
-extern int          hb_audio_bitrates_count;
-extern hb_dither_t  hb_audio_dithers[];
-extern int          hb_audio_dithers_count;
-extern hb_mixdown_t hb_audio_mixdowns[];
-extern int          hb_audio_mixdowns_count;
-extern hb_encoder_t hb_video_encoders[];
-extern int          hb_video_encoders_count;
-extern hb_encoder_t hb_audio_encoders[];
-extern int          hb_audio_encoders_count;
-
-/* Expose values for PInvoke */
-hb_rate_t*    hb_get_video_rates();
-int           hb_get_video_rates_count();
-hb_rate_t*    hb_get_audio_rates();
-int           hb_get_audio_rates_count();
-int           hb_get_audio_rates_default();
-hb_rate_t*    hb_get_audio_bitrates();
-int           hb_get_audio_bitrates_count();
-hb_dither_t*  hb_get_audio_dithers();
-int           hb_get_audio_dithers_count();
-hb_mixdown_t* hb_get_audio_mixdowns();
-int           hb_get_audio_mixdowns_count();
-hb_encoder_t* hb_get_video_encoders();
-int           hb_get_video_encoders_count();
-hb_encoder_t* hb_get_audio_encoders();
-int           hb_get_audio_encoders_count();
-
-int         hb_audio_dither_get_default();
-int         hb_audio_dither_get_default_method();
-int         hb_audio_dither_is_supported(uint32_t codec);
-const char* hb_audio_dither_get_description(int method);
-
-int         hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout);
-int         hb_mixdown_has_codec_support(int mixdown, uint32_t codec);
-int         hb_mixdown_has_remix_support(int mixdown, uint64_t layout);
-int         hb_mixdown_get_discrete_channel_count(int amixdown);
-int         hb_mixdown_get_low_freq_channel_count(int amixdown);
-int         hb_mixdown_get_mixdown_from_short_name(const char *short_name);
-const char* hb_mixdown_get_short_name_from_mixdown(int amixdown);
+/*******************************************************************************
+ * Lists of rates, mixdowns, encoders etc.
+ *******************************************************************************
+ *
+ * Use hb_*_get_next() to get the next list item (use NULL to get the first).
+ *
+ * Use hb_*_get_from_name() to get the value corresponding to a name.
+ * The name can be either the short or full name.
+ * Legacy names are sanitized to currently-supported values whenever possible.
+ * Returns -1 if no value could be found.
+ *
+ * Use hb_*_get_name() and hb_*_get_short_name() to get the corresponding value.
+ * Returns NULL if the value is invalid.
+ *
+ * hb_*_sanitize_name() are convenience functions for use when dealing
+ * with full names (e.g. to translate legacy values while loading a preset).
+ *
+ * Names are case-insensitive; libhb will ensure that the lists do not contain
+ * more than one entry with the same name.
+ *
+ * Use hb_*_get_limits() to get the minimum/maximum for lists with numerically
+ * ordered values.
+ *
+ * Use hb_*_get_best() to sanitize a value based on other relevant parameters.
+ *
+ * Use hb_*_get_default() to get the default based on other relevant parameters.
+ *
+ */
+
+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);
+const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *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);
+const hb_rate_t* hb_audio_samplerate_get_next(const hb_rate_t *last);
+
+int              hb_audio_bitrate_get_best(uint32_t codec, int bitrate, int samplerate, int mixdown);
+int              hb_audio_bitrate_get_default(uint32_t codec, int samplerate, int mixdown);
+void             hb_audio_bitrate_get_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high);
+const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last);
+
+void  hb_audio_quality_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
+float hb_audio_quality_get_best(uint32_t codec, float quality);
+float hb_audio_quality_get_default(uint32_t codec);
+
+void  hb_audio_compression_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
+float hb_audio_compression_get_best(uint32_t codec, float compression);
+float hb_audio_compression_get_default(uint32_t 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);
+
+int                 hb_mixdown_is_supported(int mixdown, uint32_t codec, uint64_t layout);
+int                 hb_mixdown_has_codec_support(int mixdown, uint32_t codec);
+int                 hb_mixdown_has_remix_support(int mixdown, uint64_t layout);
+int                 hb_mixdown_get_discrete_channel_count(int mixdown);
+int                 hb_mixdown_get_low_freq_channel_count(int mixdown);
+int                 hb_mixdown_get_best(uint32_t codec, uint64_t layout, int mixdown);
+int                 hb_mixdown_get_default(uint32_t codec, uint64_t layout);
+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);
+const hb_mixdown_t* hb_mixdown_get_next(const hb_mixdown_t *last);
+
+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);
+const hb_encoder_t* hb_video_encoder_get_next(const hb_encoder_t *last);
+
+/*
+ * 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);
+const hb_encoder_t* hb_audio_encoder_get_next(const hb_encoder_t *last);
 
+/*
+ * Not typically used by the UIs
+ * (set hb_job_t.acodec_copy_mask, hb_job_t.acodec_fallback instead).
+ */
 void hb_autopassthru_apply_settings(hb_job_t *job);
 void hb_autopassthru_print_settings(hb_job_t *job);
 int  hb_autopassthru_get_encoder(int in_codec, int copy_mask, int fallback, int muxer);
 
-int hb_get_default_audio_encoder(int muxer);
-
-int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown);
-int hb_get_default_mixdown(uint32_t codec, uint64_t layout);
-
-int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift);
-
-int  hb_find_closest_audio_bitrate(int bitrate);
-void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high);
-int  hb_get_best_audio_bitrate(uint32_t codec, int bitrate, int samplerate, int mixdown);
-int  hb_get_default_audio_bitrate(uint32_t codec, int samplerate, int mixdown);
-
-void  hb_get_audio_quality_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
-float hb_get_best_audio_quality(uint32_t codec, float quality);
-float hb_get_default_audio_quality(uint32_t codec);
-
-void  hb_get_audio_compression_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
-float hb_get_best_audio_compression(uint32_t codec, float compression);
-float hb_get_default_audio_compression(uint32_t codec);
+int                   hb_container_get_from_name(const char *name);
+int                   hb_container_get_from_extension(const char *extension); // not really a container name
+const char*           hb_container_get_name(int format);
+const char*           hb_container_get_short_name(int format);
+const char*           hb_container_get_default_extension(int format);
+const char*           hb_container_sanitize_name(const char *name);
+const hb_container_t* hb_container_get_next(const hb_container_t *last);
 
 struct hb_title_set_s
 {
@@ -381,8 +428,6 @@ struct hb_job_s
     int             vcodec;
     float           vquality;
     int             vbitrate;
-    int             pfr_vrate;
-    int             pfr_vrate_base;
     int             vrate;
     int             vrate_base;
     int             cfr;
@@ -428,12 +473,19 @@ struct hb_job_s
 
     hb_metadata_t * metadata;
 
-    /* Muxer settings
-         mux:  output file format
-         file: file path */
-#define HB_MUX_MASK 0xFF0000
-#define HB_MUX_MP4  0x010000
-#define HB_MUX_MKV  0x200000
+    /*
+     * Muxer settings
+     *     mux:  output file format
+     *     file: file path
+     */
+#define HB_MUX_MASK     0xFF0000
+#define HB_MUX_MP4V2    0x010000
+#define HB_MUX_MASK_MP4 0x0F0000
+#define HB_MUX_LIBMKV   0x100000
+#define HB_MUX_MASK_MKV 0xF00000
+// default MP4 and MKV muxers
+#define HB_MUX_MP4      HB_MUX_MP4V2
+#define HB_MUX_MKV      HB_MUX_LIBMKV
 
     int             mux;
     char          * file;
@@ -993,8 +1045,6 @@ typedef struct hb_filter_init_s
     int           crop[4];
     int           vrate_base;
     int           vrate;
-    int           pfr_vrate_base;
-    int           pfr_vrate;
     int           cfr;
 } hb_filter_init_t;
 
index 426f84634fd1470b577da6732db8dfc57732c92e..d217393d14eaa3a8f5018eac2f6a418f2cdc86f0 100644 (file)
@@ -56,8 +56,8 @@ static int hb_crop_scale_init( hb_filter_object_t * filter,
     pv->pix_fmt_out = init->pix_fmt;
     pv->width_in = init->width;
     pv->height_in = init->height;
-    pv->width_out = init->width;
-    pv->height_out = init->height;
+    pv->width_out = init->width - (init->crop[2] + init->crop[3]);
+    pv->height_out = init->height - (init->crop[0] + init->crop[1]);
     memcpy( pv->crop, init->crop, sizeof( int[4] ) );
     if( filter->settings )
     {
index b232dae815e81c38b609b7cce816545508e77977..dcb19da34562c7026626eaa222eba74e223bf4ae 100644 (file)
@@ -117,12 +117,12 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
     // to fps.den.
     if (fps.num == 27000000)
     {
-        int ii;
-        for (ii = 0; ii < hb_video_rates_count; ii++)
+        const hb_rate_t *video_framerate = NULL;
+        while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
         {
-            if (abs(fps.den - hb_video_rates[ii].rate) < 10)
+            if (abs(fps.den - video_framerate->rate) < 10)
             {
-                fps.den = hb_video_rates[ii].rate;
+                fps.den = video_framerate->rate;
                 break;
             }
         }
index c83326d4d0658785fe2e410cbef4a66454493ca4..0d7dde7ffaad8bb85a5168ac327ba04c5188a2fa 100644 (file)
@@ -820,11 +820,12 @@ skip_preview:
             // if the frame rate is very close to one of our "common" framerates,
             // assume it actually is said frame rate; e.g. some 24000/1001 sources
             // may have a rate_base of 1126124 (instead of 1126125)
-            for( i = 0; i < hb_video_rates_count; i++ )
+            const hb_rate_t *video_framerate = NULL;
+            while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL)
             {
-                if( is_close_to( vid_info.rate_base, hb_video_rates[i].rate, 100 ) )
+                if (is_close_to(vid_info.rate_base, video_framerate->rate, 100))
                 {
-                    vid_info.rate_base = hb_video_rates[i].rate;
+                    vid_info.rate_base = video_framerate->rate;
                     break;
                 }
             }
index 844beef80296cf3c5c5b4ea5a94b0cc9ef3f2abc..009f88c4358765c1a04b1ad5a43aa2ffc9bfd53f 100644 (file)
@@ -301,20 +301,19 @@ static void adjust_frame_rate( hb_filter_private_t *pv, hb_buffer_t **buf_out )
     }
 }
 
-static int hb_vfr_init( hb_filter_object_t * filter,
-                        hb_filter_init_t * init )
+static int hb_vfr_init(hb_filter_object_t *filter, hb_filter_init_t *init)
 {
-    filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
-    hb_filter_private_t * pv = filter->private_data;
+    filter->private_data    = calloc(1, sizeof(struct hb_filter_private_s));
+    hb_filter_private_t *pv = filter->private_data;
+    build_gamma_lut(pv);
 
-    build_gamma_lut( pv );
-    pv->cfr = init->cfr;
+    pv->cfr              = init->cfr;
     pv->input_vrate = pv->vrate = init->vrate;
     pv->input_vrate_base = pv->vrate_base = init->vrate_base;
-    if( filter->settings )
+    if (filter->settings != NULL)
     {
-        sscanf( filter->settings, "%d:%d:%d",
-                &pv->cfr, &pv->vrate, &pv->vrate_base );
+        sscanf(filter->settings, "%d:%d:%d",
+               &pv->cfr, &pv->vrate, &pv->vrate_base);
     }
 
     pv->job = init->job;
@@ -336,36 +335,27 @@ static int hb_vfr_init( hb_filter_object_t * filter,
     pv->lost_time[0] = 0; pv->lost_time[1] = 0; pv->lost_time[2] = 0; pv->lost_time[3] = 0;
     pv->frame_metric = 1000; // Force first frame
 
-    if ( pv->cfr == 0 )
-    {
-        /* Ensure we're using "Same as source" FPS */
-        pv->vrate_base = init->vrate_base;
-        pv->vrate = init->vrate;
-    }
-    else if ( pv->cfr == 2 )
+    if (pv->cfr == 2)
     {
-        // For PFR, we want the framerate based on the source's actual 
-        // framerate, unless it's higher than the specified peak framerate. 
+        // For PFR, we want the framerate based on the source's actual
+        // framerate, unless it's higher than the specified peak framerate.
         double source_fps = (double)init->vrate / init->vrate_base;
         double peak_fps = (double)pv->vrate / pv->vrate_base;
-        if ( source_fps > peak_fps )
+        if (source_fps > peak_fps)
         {
-            // peak framerate is lower than source framerate. so signal
-            // that the nominal framerate will be changed.
+            // peak framerate is lower than the source framerate.
+            // so signal that the framerate will be the peak fps.
             init->vrate = pv->vrate;
             init->vrate_base = pv->vrate_base;
         }
-        init->pfr_vrate = pv->vrate;
-        init->pfr_vrate_base = pv->vrate_base;
     }
     else
     {
-        // Constant framerate. Signal the framerate we are using.
         init->vrate = pv->vrate;
         init->vrate_base = pv->vrate_base;
     }
-    init->cfr = pv->cfr;
-    pv->frame_rate = (double)pv->vrate_base * 90000. / pv->vrate;
+    pv->frame_rate        = (double)pv->vrate_base * 90000. / pv->vrate;
+    init->cfr             = pv->cfr;
 
     return 0;
 }
@@ -379,8 +369,27 @@ static int hb_vfr_info( hb_filter_object_t * filter,
         return 1;
 
     memset( info, 0, sizeof( hb_filter_info_t ) );
-    info->out.vrate_base = pv->vrate_base;
-    info->out.vrate = pv->vrate;
+    info->out.vrate_base = pv->input_vrate_base;
+    info->out.vrate      = pv->input_vrate;
+    if (pv->cfr == 2)
+    {
+        // For PFR, we want the framerate based on the source's actual
+        // framerate, unless it's higher than the specified peak framerate.
+        double source_fps = (double)pv->input_vrate / pv->input_vrate_base;
+        double peak_fps = (double)pv->vrate / pv->vrate_base;
+        if (source_fps > peak_fps)
+        {
+            // peak framerate is lower than the source framerate.
+            // so signal that the framerate will be the peak fps.
+            info->out.vrate = pv->vrate;
+            info->out.vrate_base = pv->vrate_base;
+        }
+    }
+    else
+    {
+        info->out.vrate = pv->vrate;
+        info->out.vrate_base = pv->vrate_base;
+    }
     info->out.cfr = pv->cfr;
     if ( pv->cfr == 0 )
     {
index 3d770a5a1bf6035cf5582ffeca868596214c761b..21dc59fce4c1e6d0462d2a22f7019dfa67496904 100644 (file)
@@ -153,12 +153,12 @@ hb_work_object_t* hb_codec_encoder(int codec)
  * Displays job parameters in the debug log.
  * @param job Handle work hb_job_t.
  */
-void hb_display_job_info( hb_job_t * job )
+void hb_display_job_info(hb_job_t *job)
 {
-    hb_title_t * title = job->title;
-    hb_audio_t   * audio;
-    hb_subtitle_t * subtitle;
-    int             i, j;
+    int i;
+    hb_title_t *title = job->title;
+    hb_audio_t *audio;
+    hb_subtitle_t *subtitle;
 
     hb_log("job configuration:");
     hb_log( " * source");
@@ -183,9 +183,10 @@ void hb_display_job_info( hb_job_t * job )
         sec_stop = (float)stop / 90000.0 - min_stop * 60;
         min_stop %= 60;
 
-        hb_log( "   + title %d, start %d:%d:%.2f stop %d:%d:%.2f", title->index,
-                hr_start, min_start, sec_start,
-                hr_stop, min_stop, sec_stop);
+        hb_log("   + title %d, start %02d:%02d:%02.2f stop %02d:%02d:%02.2f",
+               title->index,
+               hr_start, min_start, sec_start,
+               hr_stop,  min_stop,  sec_stop);
     }
     else if( job->frame_to_start || job->frame_to_stop )
     {
@@ -210,26 +211,19 @@ void hb_display_job_info( hb_job_t * job )
 
     hb_log( "   + %s", job->file );
 
-    switch( job->mux )
+    hb_log("   + container: %s", hb_container_get_name(job->mux));
+    switch (job->mux)
     {
-        case HB_MUX_MP4:
-            hb_log("   + container: MPEG-4 (.mp4 and .m4v)");
-
-            if( job->ipod_atom )
-                hb_log( "     + compatibility atom for iPod 5G");
-
-            if( job->largeFileSize )
-                hb_log( "     + 64-bit formatting");
-
-            if( job->mp4_optimize )
-                hb_log( "     + optimized for progressive web downloads");
-
-            if( job->color_matrix_code )
-                hb_log( "     + custom color matrix: %s", job->color_matrix_code == 1 ? "ITU Bt.601 (SD)" : job->color_matrix_code == 2 ? "ITU Bt.709 (HD)" : "Custom" );
+        case HB_MUX_MP4V2:
+            if (job->largeFileSize)
+                hb_log("     + 64-bit chunk offsets");
+            if (job->mp4_optimize)
+                hb_log("     + optimized for HTTP streaming (fast start)");
+            if (job->ipod_atom)
+                hb_log("     + compatibility atom for iPod 5G");
             break;
 
-        case HB_MUX_MKV:
-            hb_log("   + container: Matroska (.mkv)");
+        default:
             break;
     }
 
@@ -247,24 +241,6 @@ void hb_display_job_info( hb_job_t * job )
         hb_log( "     + bitrate %d kbps", title->video_bitrate / 1000 );
     }
 
-    if( job->cfr == 0 )
-    {
-        hb_log( "   + frame rate: same as source (around %.3f fps)",
-            (float) title->rate / (float) title->rate_base );
-    }
-    else if( job->cfr == 1 )
-    {
-        hb_log( "   + frame rate: %.3f fps -> constant %.3f fps",
-            (float) title->rate / (float) title->rate_base,
-            (float) job->vrate / (float) job->vrate_base );
-    }
-    else if( job->cfr == 2 )
-    {
-        hb_log( "   + frame rate: %.3f fps -> peak rate limited to %.3f fps",
-            (float) title->rate / (float) title->rate_base,
-            (float) job->pfr_vrate / (float) job->pfr_vrate_base );
-    }
-
     // Filters can modify dimensions.  So show them first.
     if( hb_list_count( job->list_filter ) )
     {
@@ -317,14 +293,7 @@ void hb_display_job_info( hb_job_t * job )
     if( !job->indepth_scan )
     {
         /* Video encoder */
-        for( i = 0; i < hb_video_encoders_count; i++ )
-        {
-            if( hb_video_encoders[i].encoder == job->vcodec )
-            {
-                hb_log( "   + encoder: %s", hb_video_encoders[i].human_readable_name );
-                break;
-            }
-        }
+        hb_log("   + encoder: %s", hb_video_encoder_get_name(job->vcodec));
 
         if( job->x264_preset && *job->x264_preset &&
             job->vcodec == HB_VCODEC_X264 )
@@ -368,6 +337,18 @@ void hb_display_job_info( hb_job_t * job )
                 hb_log( "                subq=2 (if originally greater than 2, else subq unchanged)" );
             }
         }
+
+        if (job->color_matrix_code && (job->vcodec == HB_VCODEC_X264 ||
+                                       job->mux    == HB_MUX_MP4V2))
+        {
+            // color matrix is set:
+            // 1) at the stream    level (x264  only),
+            // 2) at the container level (mp4v2 only)
+            hb_log("     + custom color matrix: %s",
+                   job->color_matrix_code == 1 ? "ITU Bt.601 (NTSC)" :
+                   job->color_matrix_code == 2 ? "ITU Bt.601 (PAL)"  :
+                   job->color_matrix_code == 3 ? "ITU Bt.709 (HD)"   : "Custom");
+        }
     }
 
     if( job->indepth_scan )
@@ -435,25 +416,13 @@ void hb_display_job_info( hb_job_t * job )
 
             if( audio->config.out.codec & HB_ACODEC_PASS_FLAG )
             {
-                for( j = 0; j < hb_audio_encoders_count; j++ )
-                {
-                    if( hb_audio_encoders[j].encoder == audio->config.out.codec )
-                    {
-                        hb_log( "   + %s", hb_audio_encoders[j].human_readable_name );
-                        break;
-                    }
-                }
+                hb_log("   + %s",
+                       hb_audio_encoder_get_name(audio->config.out.codec));
             }
             else
             {
-                for( j = 0; j < hb_audio_mixdowns_count; j++ )
-                {
-                    if( hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown )
-                    {
-                        hb_log( "   + mixdown: %s", hb_audio_mixdowns[j].human_readable_name );
-                        break;
-                    }
-                }
+                hb_log("   + mixdown: %s",
+                       hb_mixdown_get_name(audio->config.out.mixdown));
                 if( audio->config.out.normalize_mix_level != 0 )
                 {
                     hb_log( "   + normalized mixing levels" );
@@ -471,22 +440,27 @@ void hb_display_job_info( hb_job_t * job )
                     hb_log("   + dither: %s",
                            hb_audio_dither_get_description(audio->config.out.dither_method));
                 }
-                for( j = 0; j < hb_audio_encoders_count; j++ )
+                hb_log("   + encoder: %s",
+                       hb_audio_encoder_get_name(audio->config.out.codec));
+                if (audio->config.out.bitrate > 0)
                 {
-                    if( hb_audio_encoders[j].encoder == audio->config.out.codec )
-                    {
-                        hb_log( "   + encoder: %s", hb_audio_encoders[j].human_readable_name );
-                        if( audio->config.out.bitrate > 0 )
-                            hb_log( "     + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate );
-                        else if( audio->config.out.quality != HB_INVALID_AUDIO_QUALITY )
-                            hb_log( "     + quality: %.2f, samplerate: %d Hz", audio->config.out.quality, audio->config.out.samplerate );
-                        else if( audio->config.out.samplerate > 0 )
-                            hb_log( "     + samplerate: %d Hz", audio->config.out.samplerate );
-                        if( audio->config.out.compression_level >= 0 )
-                            hb_log( "     + compression level: %.2f",
-                                    audio->config.out.compression_level );
-                        break;
-                    }
+                    hb_log("     + bitrate: %d kbps, samplerate: %d Hz",
+                           audio->config.out.bitrate, audio->config.out.samplerate);
+                }
+                else if (audio->config.out.quality != HB_INVALID_AUDIO_QUALITY)
+                {
+                    hb_log("     + quality: %.2f, samplerate: %d Hz",
+                           audio->config.out.quality, audio->config.out.samplerate);
+                }
+                else if (audio->config.out.samplerate > 0)
+                {
+                    hb_log("     + samplerate: %d Hz",
+                           audio->config.out.samplerate);
+                }
+                if (audio->config.out.compression_level >= 0)
+                {
+                    hb_log("     + compression level: %.2f",
+                           audio->config.out.compression_level);
                 }
             }
         }
@@ -516,24 +490,24 @@ void correct_framerate( hb_job_t * job )
  * Closes threads and frees fifos.
  * @param job Handle work hb_job_t.
  */
-static void do_job( hb_job_t * job )
+static void do_job(hb_job_t *job)
 {
-    hb_title_t    * title;
-    int             i, j;
-    hb_work_object_t * w;
-    hb_work_object_t * sync;
-    hb_work_object_t * muxer;
+    int i;
+    hb_title_t *title;
+    hb_interjob_t *interjob;
+    hb_work_object_t *w;
+    hb_work_object_t *sync;
+    hb_work_object_t *muxer;
     hb_work_object_t *reader = hb_get_work(WORK_READER);
-    hb_interjob_t * interjob;
-
-    hb_audio_t   * audio;
-    hb_subtitle_t * subtitle;
-    unsigned int subtitle_highest = 0;
-    unsigned int subtitle_lowest = 0;
-    unsigned int subtitle_lowest_id = 0;
-    unsigned int subtitle_forced_id = 0;
+
+    hb_audio_t *audio;
+    hb_subtitle_t *subtitle;
+    unsigned int subtitle_highest     = 0;
+    unsigned int subtitle_lowest      = 0;
+    unsigned int subtitle_lowest_id   = 0;
+    unsigned int subtitle_forced_id   = 0;
     unsigned int subtitle_forced_hits = 0;
-    unsigned int subtitle_hit = 0;
+    unsigned int subtitle_hit         = 0;
 
     title = job->title;
     interjob = hb_interjob_get( job->h );
@@ -699,11 +673,9 @@ static void do_job( hb_job_t * job )
         init.height = title->height;
         init.par_width = job->anamorphic.par_width;
         init.par_height = job->anamorphic.par_height;
-        memcpy(init.crop, job->crop, sizeof(int[4]));
-        init.vrate_base = job->vrate_base;
-        init.vrate = job->vrate;
-        init.pfr_vrate_base = job->pfr_vrate_base;
-        init.pfr_vrate = job->pfr_vrate;
+        memcpy(init.crop, title->crop, sizeof(int[4]));
+        init.vrate_base = title->rate_base;
+        init.vrate = title->rate;
         init.cfr = 0;
 
         int is_vpp_interlace = 0;
@@ -827,8 +799,6 @@ static void do_job( hb_job_t * job )
         memcpy(job->crop, init.crop, sizeof(int[4]));
         job->vrate_base = init.vrate_base;
         job->vrate = init.vrate;
-        job->pfr_vrate_base = init.pfr_vrate_base;
-        job->pfr_vrate = init.pfr_vrate;
         job->cfr = init.cfr;
     }
 
@@ -934,21 +904,14 @@ static void do_job( hb_job_t * job )
                 audio->config.out.samplerate = audio->config.in.samplerate;
             }
             best_samplerate =
-                hb_get_best_samplerate(audio->config.out.codec,
-                                       audio->config.out.samplerate, NULL);
+                hb_audio_samplerate_get_best(audio->config.out.codec,
+                                             audio->config.out.samplerate,
+                                             NULL);
             if (best_samplerate != audio->config.out.samplerate)
             {
-                int ii;
-                for (ii = 0; ii < hb_audio_rates_count; ii++)
-                {
-                    if (best_samplerate == hb_audio_rates[ii].rate)
-                    {
-                        hb_log("work: sanitizing track %d unsupported samplerate %d Hz to %s kHz",
-                               audio->config.out.track, audio->config.out.samplerate,
-                               hb_audio_rates[ii].string);
-                        break;
-                    }
-                }
+                hb_log("work: sanitizing track %d unsupported samplerate %d Hz to %s kHz",
+                       audio->config.out.track, audio->config.out.samplerate,
+                       hb_audio_samplerate_get_name(best_samplerate));
                 audio->config.out.samplerate = best_samplerate;
             }
 
@@ -957,44 +920,25 @@ static void do_job( hb_job_t * job )
             {
                 /* Mixdown not specified, set the default mixdown */
                 audio->config.out.mixdown =
-                    hb_get_default_mixdown(audio->config.out.codec,
+                    hb_mixdown_get_default(audio->config.out.codec,
                                            audio->config.in.channel_layout);
-                for (j = 0; j < hb_audio_mixdowns_count; j++)
-                {
-                    if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown)
-                    {
-                        hb_log("work: mixdown not specified, track %d setting mixdown %s",
-                               audio->config.out.track,
-                               hb_audio_mixdowns[j].human_readable_name);
-                        break;
-                    }
-                }
+                hb_log("work: mixdown not specified, track %d setting mixdown %s",
+                       audio->config.out.track,
+                       hb_mixdown_get_name(audio->config.out.mixdown));
             }
             else
             {
                 best_mixdown =
-                    hb_get_best_mixdown(audio->config.out.codec,
+                    hb_mixdown_get_best(audio->config.out.codec,
                                         audio->config.in.channel_layout,
                                         audio->config.out.mixdown);
                 if (audio->config.out.mixdown != best_mixdown)
                 {
-                    int prev_mix_idx = 0, best_mix_idx = 0;
-                    for (j = 0; j < hb_audio_mixdowns_count; j++)
-                    {
-                        if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown)
-                        {
-                            prev_mix_idx = j;
-                        }
-                        else if (hb_audio_mixdowns[j].amixdown == best_mixdown)
-                        {
-                            best_mix_idx = j;
-                        }
-                    }
                     /* log the output mixdown */
                     hb_log("work: sanitizing track %d mixdown %s to %s",
                            audio->config.out.track,
-                           hb_audio_mixdowns[prev_mix_idx].human_readable_name,
-                           hb_audio_mixdowns[best_mix_idx].human_readable_name);
+                           hb_mixdown_get_name(audio->config.out.mixdown),
+                           hb_mixdown_get_name(best_mixdown));
                     audio->config.out.mixdown = best_mixdown;
                 }
             }
@@ -1003,7 +947,7 @@ static void do_job( hb_job_t * job )
             if (audio->config.out.compression_level < 0)
             {
                 audio->config.out.compression_level =
-                    hb_get_default_audio_compression(audio->config.out.codec);
+                    hb_audio_compression_get_default(audio->config.out.codec);
                 if (audio->config.out.compression_level >= 0)
                 {
                     hb_log("work: compression level not specified, track %d setting compression level %.2f",
@@ -1014,7 +958,7 @@ static void do_job( hb_job_t * job )
             else
             {
                 float best_compression =
-                    hb_get_best_audio_compression(audio->config.out.codec,
+                    hb_audio_compression_get_best(audio->config.out.codec,
                                                   audio->config.out.compression_level);
                 if (best_compression != audio->config.out.compression_level)
                 {
@@ -1038,7 +982,7 @@ static void do_job( hb_job_t * job )
             if (audio->config.out.quality != HB_INVALID_AUDIO_QUALITY)
             {
                 float best_quality =
-                    hb_get_best_audio_quality(audio->config.out.codec,
+                    hb_audio_quality_get_best(audio->config.out.codec,
                                               audio->config.out.quality);
                 if (best_quality != audio->config.out.quality)
                 {
@@ -1064,7 +1008,7 @@ static void do_job( hb_job_t * job )
                 {
                     /* Bitrate not specified, set the default bitrate */
                     audio->config.out.bitrate =
-                        hb_get_default_audio_bitrate(audio->config.out.codec,
+                        hb_audio_bitrate_get_default(audio->config.out.codec,
                                                      audio->config.out.samplerate,
                                                      audio->config.out.mixdown);
                     if (audio->config.out.bitrate > 0)
@@ -1077,7 +1021,7 @@ static void do_job( hb_job_t * job )
                 else
                 {
                     best_bitrate =
-                        hb_get_best_audio_bitrate(audio->config.out.codec,
+                        hb_audio_bitrate_get_best(audio->config.out.codec,
                                                   audio->config.out.bitrate,
                                                   audio->config.out.samplerate,
                                                   audio->config.out.mixdown);
index a71eb67cc5ae58bbf286e6458cf7baad215436cb..e92f7393a84b49ed094dc786b43a1fb18ec9c9e4 100644 (file)
@@ -656,29 +656,33 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     /* Destination box*/
     NSMenuItem *menuItem;
     [fDstFormatPopUp removeAllItems];
-    // MP4 file
-    menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MP4 file" action: NULL keyEquivalent: @""];
-    [menuItem setTag: HB_MUX_MP4];
-       // MKV file
-    menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""];
-    [menuItem setTag: HB_MUX_MKV];
-    
-    [fDstFormatPopUp selectItemAtIndex: 0];
-    
+    for (const hb_container_t *container = hb_container_get_next(NULL);
+         container != NULL;
+         container  = hb_container_get_next(container))
+    {
+        menuItem = [[fDstFormatPopUp menu] addItemWithTitle:[NSString stringWithUTF8String:container->name]
+                                                     action:nil
+                                              keyEquivalent:@""];
+        [menuItem setTag:container->format];
+    }
+    // select the first container
+    [fDstFormatPopUp selectItemAtIndex:0];
     [self formatPopUpChanged:nil];
+
+    // enable/disable chapter markers as necessary
+    if ([fCreateChapterMarkers isEnabled] &&
+        [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"])
+    {
+        [fCreateChapterMarkers setState:NSOnState];
+    }
+    else
+    {
+        [fCreateChapterMarkers setState:NSOffState];
+    }
     
-       /* We enable the create chapters checkbox here since we are .mp4 */
-       [fCreateChapterMarkers setEnabled: YES];
-       if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
-       {
-               [fCreateChapterMarkers setState: NSOnState];
-       }
-    
-    
-    
-    
-    [fDstFile2Field setStringValue: [NSString stringWithFormat:
-                                     @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
+    [fDstFile2Field setStringValue:[NSString
+                                    stringWithFormat:@"%@/Desktop/Movie.mp4",
+                                    NSHomeDirectory()]];
     
     /* Video encoder */
     [fVidEncoderPopUp removeAllItems];
@@ -694,31 +698,37 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
     
     /* Video framerate */
     [fVidRatePopUp removeAllItems];
-       [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )];
-    for( int i = 0; i < hb_video_rates_count; i++ )
+    menuItem = [[fVidRatePopUp menu] addItemWithTitle:@"Same as source"
+                                               action:nil
+                                        keyEquivalent:@""];
+    [menuItem setTag:-1]; // hb_video_framerate_get_from_name(NULL)
+    for (const hb_rate_t *video_framerate = hb_video_framerate_get_next(NULL);
+         video_framerate != NULL;
+         video_framerate  = hb_video_framerate_get_next(video_framerate))
     {
-        if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]])
-               {
-                       [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
-                                             [NSString stringWithUTF8String: hb_video_rates[i].string], @" (NTSC Film)"]];
-               }
-               else if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]])
-               {
-                       [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
-                                             [NSString stringWithUTF8String: hb_video_rates[i].string], @" (PAL Film/Video)"]];
-               }
-               else if ([[NSString stringWithUTF8String: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]])
-               {
-                       [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
-                                             [NSString stringWithUTF8String: hb_video_rates[i].string], @" (NTSC Video)"]];
-               }
-               else
-               {
-                       [fVidRatePopUp addItemWithTitle:
-             [NSString stringWithUTF8String: hb_video_rates[i].string]];
-               }
+        NSString *itemTitle;
+        if (!strcmp(video_framerate->name, "23.976"))
+        {
+            itemTitle = @"23.976 (NTSC Film)";
+        }
+        else if (!strcmp(video_framerate->name, "25"))
+        {
+            itemTitle = @"25 (PAL Film/Video)";
+        }
+        else if (!strcmp(video_framerate->name, "29.97"))
+        {
+            itemTitle = @"29.97 (NTSC Video)";
+        }
+        else
+        {
+            itemTitle = [NSString stringWithUTF8String:video_framerate->name];
+        }
+        menuItem = [[fVidRatePopUp menu] addItemWithTitle:itemTitle
+                                                   action:nil
+                                            keyEquivalent:@""];
+        [menuItem setTag:video_framerate->rate];
     }
-    [fVidRatePopUp selectItemAtIndex: 0];
+    [fVidRatePopUp selectItemAtIndex:0];
        
        /* Set Auto Crop to On at launch */
     [fPictureController setAutoCrop:YES];
@@ -2114,12 +2124,8 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
                 [fSrcDVD2Field setStringValue:browsedSourceDisplayName];
                 
                 // use the correct extension based on the container
-                int format = [fDstFormatPopUp indexOfSelectedItem];
-                char *ext = "mp4";
-                if (format == 1)
-                {
-                    ext = "mkv";
-                }
+                int videoContainer = [[fDstFormatPopUp selectedItem] tag];
+                const char *ext    = hb_container_get_default_extension(videoContainer);
                 
                 /* If its a queue rescan for edit, get the queue item output path */
                 /* if not, its a new source scan. */
@@ -2140,9 +2146,9 @@ static NSString *        ChooseSourceIdentifier             = @"Choose Source It
                 }
                 
                 // set m4v extension if necessary - do not override user-specified .mp4 extension
-                if (format == 0 && applyQueueToScan != YES)
+                if ((videoContainer & HB_MUX_MASK_MP4) && (applyQueueToScan != YES))
                 {
-                    [self autoSetM4vExtension: sender];
+                    [self autoSetM4vExtension:sender];
                 }
                 
                 /* See if this is the main feature according to libhb */
@@ -2720,8 +2726,8 @@ fWorkingCount = 0;
        
     /* Framerate */
     [queueFileJob setObject:[NSNumber numberWithInt:[fVidRatePopUp indexOfSelectedItem]] forKey:@"JobIndexVideoFramerate"];
-    [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"];
-    [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"];
+    [queueFileJob setObject:[NSNumber numberWithInt:title->rate]                         forKey:@"JobVrate"];
+    [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base]                    forKey:@"JobVrateBase"];
        
     /* Picture Sizing */
        /* Use Max Picture settings for whatever the dvd is.*/
@@ -3379,37 +3385,37 @@ fWorkingCount = 0;
     }
 
     /* Video settings */
-    
+    int fps_mode, fps_num, fps_den;
     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
     {
         /* a specific framerate has been chosen */
-        job->vrate      = 27000000;
-        job->vrate_base = hb_video_rates[[fVidRatePopUp indexOfSelectedItem]-1].rate;
+        fps_num = 27000000;
+        fps_den = [[fVidRatePopUp selectedItem] tag];
         if ([fFramerateMatrix selectedRow] == 1)
         {
             // CFR
-            job->cfr = 1;
+            fps_mode = 1;
         }
         else
         {
             // PFR
-            job->cfr = 2;
+            fps_mode = 2;
         }
     }
     else
     {
         /* same as source */
-        job->vrate      = title->rate;
-        job->vrate_base = title->rate_base;
+        fps_num = title->rate;
+        fps_den = title->rate_base;
         if ([fFramerateMatrix selectedRow] == 1)
         {
             // CFR
-            job->cfr = 1;
+            fps_mode = 1;
         }
         else
         {
             // VFR
-            job->cfr = 0;
+            fps_mode = 0;
         }
     }
 
@@ -3721,9 +3727,9 @@ bool one_burned = FALSE;
                                   job->crop[2], job->crop[3]] UTF8String] );
 
     /* Add framerate shaping filter */
-    filter = hb_filter_init( HB_FILTER_VFR );
-    hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
-                                  job->cfr, job->vrate, job->vrate_base] UTF8String] );
+    filter = hb_filter_init(HB_FILTER_VFR);
+    hb_add_filter(job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
+                                 fps_mode, fps_num, fps_den] UTF8String]);
 }
 
 
@@ -3934,37 +3940,37 @@ bool one_burned = FALSE;
     
     /* Video settings */
     /* Framerate */
-    
-    if( [[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0 )
+    int fps_mode, fps_num, fps_den;
+    if ([[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0)
     {
         /* a specific framerate has been chosen */
-        job->vrate      = 27000000;
-        job->vrate_base = hb_video_rates[[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]-1].rate;
+        fps_num = 27000000;
+        fps_den = [[fVidRatePopUp itemAtIndex:[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]] tag];
         if ([[queueToApply objectForKey:@"VideoFramerateMode"] isEqualToString:@"cfr"])
         {
             // CFR
-            job->cfr = 1;
+            fps_mode = 1;
         }
         else
         {
             // PFR
-            job->cfr = 2;
+            fps_mode = 2;
         }
     }
     else
     {
         /* same as source */
-        job->vrate      = [[queueToApply objectForKey:@"JobVrate"] intValue];
-        job->vrate_base = [[queueToApply objectForKey:@"JobVrateBase"] intValue];
+        fps_num = [[queueToApply objectForKey:@"JobVrate"]     intValue];
+        fps_den = [[queueToApply objectForKey:@"JobVrateBase"] intValue];
         if ([[queueToApply objectForKey:@"VideoFramerateMode"] isEqualToString:@"cfr"])
         {
             // CFR
-            job->cfr = 1;
+            fps_mode = 1;
         }
         else
         {
             // VFR
-            job->cfr = 0;
+            fps_mode = 0;
         }
     }
     
@@ -4155,7 +4161,7 @@ bool one_burned = FALSE;
             /* We go ahead and assign values to our audio->out.<properties> */
             audio->out.track                     = audio->in.track;
             audio->out.codec                     = [[queueToApply objectForKey:[jobPrefix stringByAppendingString:@"Encoder"]]           intValue];
-            audio->out.compression_level         = hb_get_default_audio_compression(audio->out.codec);
+            audio->out.compression_level         = hb_audio_compression_get_default(audio->out.codec);
             audio->out.mixdown                   = [[queueToApply objectForKey:[jobPrefix stringByAppendingString:@"Mixdown"]]           intValue];
             audio->out.normalize_mix_level       = 0;
             audio->out.bitrate                   = [[queueToApply objectForKey:[jobPrefix stringByAppendingString:@"Bitrate"]]           intValue];
@@ -4280,9 +4286,9 @@ bool one_burned = FALSE;
                                   job->crop[2], job->crop[3]] UTF8String] );
 
     /* Add framerate shaping filter */
-    filter = hb_filter_init( HB_FILTER_VFR );
-    hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
-                                  job->cfr, job->vrate, job->vrate_base] UTF8String] );
+    filter = hb_filter_init(HB_FILTER_VFR);
+    hb_add_filter(job, filter, [[NSString stringWithFormat:@"%d:%d:%d",
+                                 fps_mode, fps_num, fps_den] UTF8String]);
 
 [self writeToActivityLog: "prepareJob exiting"];    
 }
@@ -4918,31 +4924,31 @@ bool one_burned = FALSE;
 
 - (IBAction) formatPopUpChanged: (id) sender
 {
-    NSString * string = [fDstFile2Field stringValue];
-    int format = [fDstFormatPopUp indexOfSelectedItem];
-    char * ext = NULL;
+    NSString *string   = [fDstFile2Field stringValue];
+    int videoContainer = [[fDstFormatPopUp selectedItem] tag];
+    const char *ext    = NULL;
     NSMenuItem *menuItem;
-    int i;
-       /* Initially set the large file (64 bit formatting) output checkbox to hidden */
-    [fDstMp4LargeFileCheck setHidden: YES];
-    [fDstMp4HttpOptFileCheck setHidden: YES];
-    [fDstMp4iPodFileCheck setHidden: YES];
+    /* Initially set the large file (64 bit formatting) output checkbox to hidden */
+    [fDstMp4LargeFileCheck   setHidden:YES];
+    [fDstMp4HttpOptFileCheck setHidden:YES];
+    [fDstMp4iPodFileCheck    setHidden:YES];
     
     /* Update the Video Codec Popup */
     /* lets get the tag of the currently selected item first so we might reset it later */
-    int selectedVidEncoderTag;
-    selectedVidEncoderTag = [[fVidEncoderPopUp selectedItem] tag];
+    int selectedVidEncoderTag = [[fVidEncoderPopUp selectedItem] tag];
     
     /* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */
     [fVidEncoderPopUp removeAllItems];
-    for( i = 0; i < hb_video_encoders_count; i++ )
+    for (const hb_encoder_t *video_encoder = hb_video_encoder_get_next(NULL);
+         video_encoder != NULL;
+         video_encoder  = hb_video_encoder_get_next(video_encoder))
     {
-        if( ( ( format == 0 ) && ( hb_video_encoders[i].muxers & HB_MUX_MP4 ) ) ||
-            ( ( format == 1 ) && ( hb_video_encoders[i].muxers & HB_MUX_MKV ) ) )
+        if (video_encoder->muxers & videoContainer)
         {
-            menuItem = [[fVidEncoderPopUp menu] addItemWithTitle: [NSString stringWithUTF8String: hb_video_encoders[i].human_readable_name]
-                                                          action: NULL keyEquivalent: @""];
-            [menuItem setTag: hb_video_encoders[i].encoder];
+             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:[NSString stringWithUTF8String:video_encoder->name]
+                                                           action:nil
+                                                    keyEquivalent:@""];
+            [menuItem setTag:video_encoder->codec];
         }
     }
     
@@ -4961,70 +4967,72 @@ bool one_burned = FALSE;
     
     /* Update the Auto Passtgru Fallback Codec Popup */
     /* lets get the tag of the currently selected item first so we might reset it later */
-    int selectedAutoPassthruFallbackEncoderTag;
-    selectedAutoPassthruFallbackEncoderTag = [[fAudioFallbackPopUp selectedItem] tag];
+    int selectedAutoPassthruFallbackEncoderTag = [[fAudioFallbackPopUp selectedItem] tag];
     
     [fAudioFallbackPopUp removeAllItems];
-    for( i = 0; i < hb_audio_encoders_count; i++ )
+    for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL);
+         audio_encoder != NULL;
+         audio_encoder  = hb_audio_encoder_get_next(audio_encoder))
     {
-        if( !( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
-             ( ( ( format == 0 ) && ( hb_audio_encoders[i].muxers & HB_MUX_MP4 ) ) ||
-               ( ( format == 1 ) && ( hb_audio_encoders[i].muxers & HB_MUX_MKV ) ) ) )
+        if ((audio_encoder->codec  & HB_ACODEC_PASS_FLAG) == 0 &&
+            (audio_encoder->muxers & videoContainer))
         {
-            menuItem = [[fAudioFallbackPopUp menu] addItemWithTitle: [NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name]
-                                                             action: NULL keyEquivalent: @""];
-            [menuItem setTag: hb_audio_encoders[i].encoder];
+            menuItem = [[fAudioFallbackPopUp menu] addItemWithTitle:[NSString stringWithUTF8String:audio_encoder->name]
+                                                             action:nil
+                                                      keyEquivalent:@""];
+            [menuItem setTag:audio_encoder->codec];
         }
     }
     
     /* if we have a previously selected auto passthru fallback encoder tag, then try to select it */
     if (selectedAutoPassthruFallbackEncoderTag)
     {
-        selectedAutoPassthruFallbackEncoderTag = [fAudioFallbackPopUp selectItemWithTag: selectedAutoPassthruFallbackEncoderTag];
+        selectedAutoPassthruFallbackEncoderTag = [fAudioFallbackPopUp selectItemWithTag:selectedAutoPassthruFallbackEncoderTag];
     }
     /* if we had no previous fallback selected OR if selection failed
      * select the default fallback encoder (AC3) */
     if (!selectedAutoPassthruFallbackEncoderTag)
     {
-        [fAudioFallbackPopUp selectItemWithTag: HB_ACODEC_AC3];
+        [fAudioFallbackPopUp selectItemWithTag:HB_ACODEC_AC3];
     }
     
-    switch( format )
+    // enable chapter markers and hide muxer-specific options
+    [fCreateChapterMarkers  setEnabled:YES];
+    [fDstMp4LargeFileCheck   setHidden:YES];
+    [fDstMp4HttpOptFileCheck setHidden:YES];
+    [fDstMp4iPodFileCheck    setHidden:YES];
+    switch (videoContainer)
     {
-        case 0:
-                       [self autoSetM4vExtension: nil];
-            /* We show the mp4 option checkboxes here since we are mp4 */
-            [fCreateChapterMarkers setEnabled: YES];
-                       [fDstMp4LargeFileCheck setHidden: NO];
-                       [fDstMp4HttpOptFileCheck setHidden: NO];
-            [fDstMp4iPodFileCheck setHidden: NO];
+        case HB_MUX_MP4V2:
+            [fDstMp4LargeFileCheck   setHidden:NO];
+            [fDstMp4HttpOptFileCheck setHidden:NO];
+            [fDstMp4iPodFileCheck    setHidden:NO];
             break;
-            
-        case 1:
-            ext = "mkv";
-            /* We enable the create chapters checkbox here */
-                       [fCreateChapterMarkers setEnabled: YES];
-                       break;
-            
 
+        default:
+            break;
+    }
+    // set the file extension
+    ext = hb_container_get_default_extension(videoContainer);
+    [fDstFile2Field setStringValue:[NSString stringWithFormat:@"%@.%s",
+                                    [string stringByDeletingPathExtension],
+                                    ext]];
+    if (videoContainer & HB_MUX_MASK_MP4)
+    {
+        [self autoSetM4vExtension:sender];
     }
-    /* tell fSubtitlesDelegate we have a new video container */
     
-    [fSubtitlesDelegate containerChanged:[[fDstFormatPopUp selectedItem] tag]];
+    /* tell fSubtitlesDelegate we have a new video container */
+    [fSubtitlesDelegate containerChanged:videoContainer];
     [fSubtitlesTable reloadData];
        
-       /* post a notification for any interested observers to indicate that our video container has changed */
-       [[NSNotificationCenter defaultCenter] postNotification:
-        [NSNotification notificationWithName: HBContainerChangedNotification
-                                                                  object: self
-                                                                userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
-                                                                                       [NSNumber numberWithInt: [[fDstFormatPopUp selectedItem] tag]], keyContainerTag,
-                                                                                       nil]]];
-
-    if( format == 0 )
-        [self autoSetM4vExtension: sender];
-    else
-        [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%s", [string stringByDeletingPathExtension], ext]];
+    /* post a notification for any interested observers to indicate that our video container has changed */
+    [[NSNotificationCenter defaultCenter] postNotification:
+     [NSNotification notificationWithName:HBContainerChangedNotification
+                                   object:self
+                                 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+                                           [NSNumber numberWithInt:videoContainer], keyContainerTag,
+                                           nil]]];
 
     if (SuccessfulScan)
     {
@@ -5086,6 +5094,12 @@ the user is using "Custom" settings by determining the sender*/
 
 - (IBAction) videoEncoderPopUpChanged: (id) sender
 {
+    /* if no valid encoder is selected, use the first one */
+    if ([fVidEncoderPopUp selectedItem] == nil)
+    {
+        [fVidEncoderPopUp selectItemAtIndex:0];
+    }
+    
     int videoEncoder = [[fVidEncoderPopUp selectedItem] tag];
     
     [fAdvancedOptions setHidden:YES];
@@ -5166,6 +5180,12 @@ the user is using "Custom" settings by determining the sender*/
 
 - (IBAction ) videoFrameRateChanged: (id) sender
 {
+    /* if no valid framerate is selected, use "Same as source" */
+    if ([fVidRatePopUp selectedItem] == nil)
+    {
+        [fVidRatePopUp selectItemAtIndex:0];
+    }
+    
     /* Hide and set the PFR Checkbox to OFF if we are set to Same as Source */
     /* Depending on whether or not Same as source is selected modify the title for
      * fFramerateVfrPfrCell*/
@@ -5894,21 +5914,23 @@ the user is using "Custom" settings by determining the sender*/
 - (NSString*) muxerOptionsSummary
 {
     NSMutableString *summary = [NSMutableString stringWithString:@""];
-    if (([fDstFormatPopUp selectedItem]) &&
-        [[fDstFormatPopUp selectedItem] tag] == HB_MUX_MP4)
+    if ([fDstMp4LargeFileCheck  isHidden] == NO  &&
+        [fDstMp4LargeFileCheck isEnabled] == YES &&
+        [fDstMp4LargeFileCheck     state] == NSOnState)
     {
-        if ([fDstMp4LargeFileCheck state])
-        {
-            [summary appendString:@" - Large file size"];
-        }
-        if ([fDstMp4HttpOptFileCheck state])
-        {
-            [summary appendString:@" - Web optimized"];
-        }
-        if ([fDstMp4iPodFileCheck state])
-        {
-            [summary appendString:@" - iPod 5G support"];
-        }
+        [summary appendString:@" - Large file size"];
+    }
+    if ([fDstMp4HttpOptFileCheck  isHidden] == NO  &&
+        [fDstMp4HttpOptFileCheck isEnabled] == YES &&
+        [fDstMp4HttpOptFileCheck     state] == NSOnState)
+    {
+        [summary appendString:@" - Web optimized"];
+    }
+    if ([fDstMp4iPodFileCheck  isHidden] == NO  &&
+        [fDstMp4iPodFileCheck isEnabled] == YES &&
+        [fDstMp4iPodFileCheck     state] == NSOnState)
+    {
+        [summary appendString:@" - iPod 5G support"];
     }
     if ([summary hasPrefix:@" - "])
     {
@@ -6393,9 +6415,11 @@ return YES;
 
 - (IBAction)selectPreset:(id)sender
 {
-
     if (YES == [self hasValidPresetSelected])
     {
+        // for mapping names via libhb
+        int         intValue;
+        const char *strValue;
         chosenPreset = [self selectedPreset];
         [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
 
@@ -6409,7 +6433,9 @@ return YES;
         }
         
         /* File Format */
-        [fDstFormatPopUp selectItemWithTitle:[chosenPreset objectForKey:@"FileFormat"]];
+        /* map legacy container names via libhb */
+        strValue = hb_container_sanitize_name([[chosenPreset objectForKey:@"FileFormat"] UTF8String]);
+        [fDstFormatPopUp selectItemWithTitle:[NSString stringWithFormat:@"%s", strValue]];
         [self formatPopUpChanged:nil];
         
         /* Chapter Markers*/
@@ -6423,10 +6449,12 @@ return YES;
         [fDstMp4HttpOptFileCheck setState:[[chosenPreset objectForKey:@"Mp4HttpOptimize"] intValue]];
         
         /* Video encoder */
-        [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]];
+        /* map legacy encoder names via libhb */
+        strValue = hb_video_encoder_sanitize_name([[chosenPreset objectForKey:@"VideoEncoder"] UTF8String]);
+        [fVidEncoderPopUp selectItemWithTitle:[NSString stringWithFormat:@"%s", strValue]];
         [self videoEncoderPopUpChanged:nil];
         
-        if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"H.264 (x264)"])
+        if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264)
         {
             if (![chosenPreset objectForKey:@"x264UseAdvancedOptions"] ||
                 [[chosenPreset objectForKey:@"x264UseAdvancedOptions"] intValue])
@@ -6545,7 +6573,9 @@ return YES;
                 [fFramerateMatrix selectCellAtRow:1 column:0]; // we want cfr
             }
         }
-        [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]];
+        /* map legacy names via libhb */
+        intValue = hb_video_framerate_get_from_name([[chosenPreset objectForKey:@"VideoFramerate"] UTF8String]);
+        [fVidRatePopUp selectItemWithTag:intValue];
         [self videoFrameRateChanged:nil];
         
         /* 2 Pass Encoding */
@@ -6600,11 +6630,13 @@ return YES;
         }
         if ((tempObject = [chosenPreset objectForKey:@"AudioEncoderFallback"]) != nil)
         {
-            [fAudioFallbackPopUp selectItemWithTitle:tempObject];
+            /* map legacy encoder names via libhb */
+            strValue = hb_audio_encoder_sanitize_name([tempObject UTF8String]);
+            [fAudioFallbackPopUp selectItemWithTitle:[NSString stringWithFormat:@"%s", strValue]];
         }
         else
         {
-            [fAudioFallbackPopUp selectItemWithTitle:@"AC3 (ffmpeg)"];
+            [fAudioFallbackPopUp selectItemWithTag:HB_ACODEC_AC3];
         }
         
         /* Audio */
@@ -7127,13 +7159,11 @@ return YES;
         [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
         [preset setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"];
         
-        /* Video framerate */
-        /* Set the Video Frame Rate Mode */
+        /* Video framerate and framerate mode */
         if ([fFramerateMatrix selectedRow] == 1)
         {
             [preset setObject:@"cfr" forKey:@"VideoFramerateMode"];
         }
-        /* Set the actual framerate from popup overriding the cfr setting as needed */
         if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected
         {
             [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
@@ -7143,9 +7173,11 @@ return YES;
                 [preset setObject:@"vfr" forKey:@"VideoFramerateMode"];
             }
         }
-        else // we can record the actual titleOfSelectedItem
+        else // translate the rate (selected item's tag) to the official libhb name
         {
-            [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
+            [preset setObject:[NSString stringWithFormat:@"%s",
+                               hb_video_framerate_get_name([[fVidRatePopUp selectedItem] tag])]
+                       forKey:@"VideoFramerate"];
             
             if ([fFramerateMatrix selectedRow] == 0)
             {
index fdd7b546296f724ecbfdf2aa5b6ff2d669a7d588..999aa94346b90ab65a9f923c75368d3bb087aad7 100644 (file)
@@ -10,8 +10,7 @@
 #import "hb.h"
 
 NSString *keyAudioCodecName = @"keyAudioCodecName";
-NSString *keyAudioMP4 = @"keyAudioMP4";
-NSString *keyAudioMKV = @"keyAudioMKV";
+NSString *keyAudioSupportedMuxers = @"keyAudioSupportedMuxers";
 NSString *keyAudioSampleRateName = @"keyAudioSampleRateName";
 NSString *keyAudioBitrateName = @"keyAudioBitrateName";
 NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack";
@@ -70,83 +69,70 @@ static NSMutableArray *masterBitRateArray = nil;
 {
     if ([HBAudio class] == self)
     {
-        int i, audioMustMatch;
-        BOOL muxMKV, muxMP4;
-        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-        NSDictionary *dict;
-
         masterCodecArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        for (i = 0; i < hb_audio_encoders_count; i++)
+        for (const hb_encoder_t *audio_encoder = hb_audio_encoder_get_next(NULL);
+             audio_encoder != NULL;
+             audio_encoder  = hb_audio_encoder_get_next(audio_encoder))
         {
-            if ((hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG) &&
-                (hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS))
+            id audioMustMatchTrack;
+            if ((audio_encoder->codec &  HB_ACODEC_PASS_FLAG) &&
+                (audio_encoder->codec != HB_ACODEC_AUTO_PASS))
             {
-                audioMustMatch = (hb_audio_encoders[i].encoder & ~HB_ACODEC_PASS_FLAG);
+                audioMustMatchTrack = [NSNumber
+                                       numberWithInt:(audio_encoder->codec &
+                                                      ~HB_ACODEC_PASS_FLAG)];
             }
             else
             {
-                audioMustMatch = 0;
-            }
-            muxMKV = (hb_audio_encoders[i].muxers & HB_MUX_MKV) ? YES : NO;
-            muxMP4 = (hb_audio_encoders[i].muxers & HB_MUX_MP4) ? YES : NO;
-            if (audioMustMatch)
-            {
-                [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
-                                              [NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name], keyAudioCodecName,
-                                              [NSNumber numberWithInt: hb_audio_encoders[i].encoder], keyAudioCodec,
-                                              [NSNumber numberWithBool: muxMP4], keyAudioMP4,
-                                              [NSNumber numberWithBool: muxMKV], keyAudioMKV,
-                                              [NSNumber numberWithInt: audioMustMatch], keyAudioMustMatchTrack,
-                                              nil]];
-            }
-            else
-            {
-                [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
-                                              [NSString stringWithUTF8String: hb_audio_encoders[i].human_readable_name], keyAudioCodecName,
-                                              [NSNumber numberWithInt: hb_audio_encoders[i].encoder], keyAudioCodec,
-                                              [NSNumber numberWithBool: muxMP4], keyAudioMP4,
-                                              [NSNumber numberWithBool: muxMKV], keyAudioMKV,
-                                              [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
-                                              nil]];
+                audioMustMatchTrack = [NSNumber numberWithBool:NO];
             }
+            [masterCodecArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                         [NSString stringWithUTF8String:audio_encoder->name], keyAudioCodecName,
+                                         [NSNumber numberWithInt:audio_encoder->codec],       keyAudioCodec,
+                                         [NSNumber numberWithInt:audio_encoder->muxers],      keyAudioSupportedMuxers,
+                                         audioMustMatchTrack,                                 keyAudioMustMatchTrack,
+                                         nil]];
         }
 
         masterMixdownArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        for (i = 0; i < hb_audio_mixdowns_count; i++)
+        for (const hb_mixdown_t *mixdown = hb_mixdown_get_next(NULL);
+             mixdown != NULL;
+             mixdown  = hb_mixdown_get_next(mixdown))
         {
-            [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
-                                            [NSString stringWithUTF8String: hb_audio_mixdowns[i].human_readable_name], keyAudioMixdownName,
-                                            [NSNumber numberWithInt: hb_audio_mixdowns[i].amixdown], keyAudioMixdown,
-                                            nil]];
+            [masterMixdownArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                           [NSString stringWithUTF8String:mixdown->name], keyAudioMixdownName,
+                                           [NSNumber numberWithInt:mixdown->amixdown],    keyAudioMixdown,
+                                           nil]];
         }
 
         // Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's
         // input sample rate when it finds this 0 value as the selected sample rate.  We do this because the input
         // sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here.
         masterSampleRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
-                                           NSLocalizedString(@"Auto", @"Auto"), keyAudioSampleRateName,
-                                           [NSNumber numberWithInt: 0], keyAudioSamplerate,
-                                           nil]];
-        for (i = 0; i < hb_audio_rates_count; i++)
+        [masterSampleRateArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                          [NSString stringWithString:@"Auto"], keyAudioSampleRateName,
+                                          [NSNumber numberWithInt:0],          keyAudioSamplerate,
+                                          nil]];
+        for (const hb_rate_t *audio_samplerate = hb_audio_samplerate_get_next(NULL);
+             audio_samplerate != NULL;
+             audio_samplerate  = hb_audio_samplerate_get_next(audio_samplerate))
         {
-            [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
-                                               [NSString stringWithUTF8String: hb_audio_rates[i].string], keyAudioSampleRateName,
-                                               [NSNumber numberWithInt: hb_audio_rates[i].rate], keyAudioSamplerate,
-                                               nil]];
+            [masterSampleRateArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                              [NSString stringWithUTF8String:audio_samplerate->name], keyAudioSampleRateName,
+                                              [NSNumber numberWithInt:audio_samplerate->rate],        keyAudioSamplerate,
+                                              nil]];
         }
 
         masterBitRateArray = [[NSMutableArray alloc] init]; // knowingly leaked
-        for (i = 0; i < hb_audio_bitrates_count; i++)
+        for (const hb_rate_t *audio_bitrate = hb_audio_bitrate_get_next(NULL);
+             audio_bitrate != NULL;
+             audio_bitrate  = hb_audio_bitrate_get_next(audio_bitrate))
         {
-            dict = [NSDictionary dictionaryWithObjectsAndKeys:
-                    [NSString stringWithUTF8String: hb_audio_bitrates[i].string], keyAudioBitrateName,
-                    [NSNumber numberWithInt: hb_audio_bitrates[i].rate], keyAudioBitrate,
-                    nil];
-            [masterBitRateArray addObject: dict];
+            [masterBitRateArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                           [NSString stringWithUTF8String:audio_bitrate->name], keyAudioBitrateName,
+                                           [NSNumber numberWithInt:audio_bitrate->rate],        keyAudioBitrate,
+                                           nil]];
         }
-
-        [pool release];
     }
 }
 
@@ -158,21 +144,6 @@ static NSMutableArray *masterBitRateArray = nil;
     NSMutableArray *permittedCodecs = [NSMutableArray array];
     unsigned int count = [masterCodecArray count];
     NSDictionary *dict;
-    NSString *keyThatAllows = nil;
-
-    // Determine which key we use to see which codecs are permitted
-    switch ([videoContainerTag intValue])
-    {
-        case HB_MUX_MP4:
-            keyThatAllows = keyAudioMP4;
-            break;
-        case HB_MUX_MKV:
-            keyThatAllows = keyAudioMKV;
-            break;
-        default:
-            keyThatAllows = @"error condition";
-            break;
-    }
 
     // First get a list of the permitted codecs based on the internal rules
     if (nil != track && [self enabled])
@@ -184,7 +155,8 @@ static NSMutableArray *masterBitRateArray = nil;
             dict = [masterCodecArray objectAtIndex: i];
 
             // First make sure only codecs permitted by the container are here
-            goodToAdd = [[dict objectForKey: keyThatAllows] boolValue];
+            goodToAdd = !!([[dict objectForKey:keyAudioSupportedMuxers] intValue] &
+                           [videoContainerTag                           intValue]);
 
             // Now we make sure if DTS or AC3 is not available in the track it is not put in the codec list, but in a general way
             if ([[dict objectForKey: keyAudioMustMatchTrack] boolValue])
@@ -227,9 +199,9 @@ static NSMutableArray *masterBitRateArray = nil;
     int currentMixdown;
 
     unsigned long long channelLayout = [[track objectForKey: keyAudioInputChannelLayout] unsignedLongLongValue];
-    unsigned int count = [masterMixdownArray count];
-    int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
-    int theDefaultMixdown = hb_get_default_mixdown(codecCodec, channelLayout);
+    unsigned int count               = [masterMixdownArray count];
+    int codecCodec                   = [[codec objectForKey: keyAudioCodec] intValue];
+    int theDefaultMixdown            = hb_mixdown_get_default(codecCodec, channelLayout);
 
     for (unsigned int i = 0; i < count; i++)
     {
@@ -282,10 +254,10 @@ static NSMutableArray *masterBitRateArray = nil;
         theSampleRate = [[[self track] objectForKey: keyAudioInputSampleRate] intValue];
     }
 
-    int ourCodec = [[codec objectForKey: keyAudioCodec] intValue];
-    int ourMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
-    hb_get_audio_bitrate_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
-    int theDefaultBitRate = hb_get_default_audio_bitrate(ourCodec, theSampleRate, ourMixdown);
+    int ourCodec          = [[codec objectForKey:keyAudioCodec] intValue];
+    int ourMixdown        = [[[self mixdown] objectForKey:keyAudioMixdown] intValue];
+    int theDefaultBitRate = hb_audio_bitrate_get_default(ourCodec, theSampleRate, ourMixdown);
+    hb_audio_bitrate_get_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
 
     BOOL codecIsPassthru = ([[codec objectForKey: keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG) ? YES : NO;
     BOOL codecIsLossless = (theDefaultBitRate == -1) ? YES : NO;
@@ -582,8 +554,8 @@ static NSMutableArray *masterBitRateArray = nil;
 
     if (retval)
     {
-        int myCodecCodec = [[[self codec] objectForKey: keyAudioCodec] intValue];
-        int myCodecDefaultBitrate = hb_get_default_audio_bitrate(myCodecCodec, 0, 0);
+        int myCodecCodec          = [[[self codec] objectForKey:keyAudioCodec] intValue];
+        int myCodecDefaultBitrate = hb_audio_bitrate_get_default(myCodecCodec, 0, 0);
         if (myCodecDefaultBitrate < 0)
         {
             retval = NO;
index 353e24f162da8bde412cdbebad5bb3cbb42f2cab..52cc8284b7aef6075f28b1c57310a1392b5a501c 100644 (file)
@@ -163,7 +163,7 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification";
             /* We go ahead and assign values to our audio->out.<properties> */
             audio->out.track                     = audio->in.track;
             audio->out.codec                     = [[[anAudio codec]   objectForKey:keyAudioCodec]   intValue];
-            audio->out.compression_level         = hb_get_default_audio_compression(audio->out.codec);
+            audio->out.compression_level         = hb_audio_compression_get_default(audio->out.codec);
             audio->out.mixdown                   = [[[anAudio mixdown] objectForKey:keyAudioMixdown] intValue];
             audio->out.normalize_mix_level       = 0;
             audio->out.bitrate                   = [[[anAudio bitRate] objectForKey:keyAudioBitrate] intValue];
@@ -295,46 +295,38 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification";
             [newAudio setVideoContainerTag: [self videoContainerTag]];
             [newAudio setTrackFromIndex: trackIndex];
 
-            key = [dict objectForKey: @"AudioEncoder"];
-
             // map faac to ca_aac for built-in presets (can be disabled in preferences)
             if (0 == aType &&
-                [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] &&
-                [key isEqualToString: @"AAC (faac)"])
+                [[NSUserDefaults standardUserDefaults] boolForKey:@"UseCoreAudio"] &&
+                [[dict objectForKey:@"AudioEncoder"] isEqualToString:@"AAC (faac)"])
             {
-                [dict setObject: @"AAC (CoreAudio)" forKey: @"AudioEncoder"];
+                key = @"AAC (CoreAudio)";
             }
-
-            // passthru fallbacks
-            if ([key isEqualToString: @"AAC Passthru"])
+            else
             {
-                if (![newAudio setCodecFromName: key])
-                {
-                    [dict setObject: @"AAC (CoreAudio)" forKey: @"AudioEncoder"];
-                    fallenBack = YES;
-                }
+                key = [dict objectForKey:@"AudioEncoder"];
             }
-            else if ([key isEqualToString: @"AC3 Passthru"])
+
+            // map legacy encoder names via libhb
+            if (key != nil)
             {
-                if (![newAudio setCodecFromName: key])
+                const char *name;
+                // passthru fallbacks
+                if ([key hasSuffix:@"Passthru"] &&
+                    ![newAudio setCodecFromName:key])
                 {
-                    [dict setObject: @"AC3 (ffmpeg)" forKey: @"AudioEncoder"];
+                    int passthru, fallback;
                     fallenBack = YES;
+                    passthru   = hb_audio_encoder_get_from_name([key UTF8String]);
+                    fallback   = hb_audio_encoder_get_fallback_for_passthru(passthru);
+                    name       = hb_audio_encoder_get_name(fallback);
                 }
-            }
-            else if ([key isEqualToString: @"MP3 Passthru"])
-            {
-                if (![newAudio setCodecFromName: key])
+                else
                 {
-                    [dict setObject: @"MP3 (lame)" forKey: @"AudioEncoder"];
-                    fallenBack = YES;
+                    name = hb_audio_encoder_sanitize_name([key UTF8String]);
                 }
-            }
-
-            // map legacy encoder names
-            if ([key isEqualToString: @"AC3"])
-            {
-                [dict setObject: @"AC3 (ffmpeg)" forKey: @"AudioEncoder"];
+                [dict setObject:[NSString stringWithFormat:@"%s", name]
+                         forKey:@"AudioEncoder"];
             }
 
             // If our preset does not contain a drc or gain value set it to a default of 0.0
@@ -347,17 +339,13 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification";
                 [dict setObject:[NSNumber numberWithFloat:0.0] forKey:@"AudioTrackGainSlider"];
             }
 
-            // map legacy mixdowns
+            // map legacy mixdowns via libhb
             key = [dict objectForKey: @"AudioMixdown"];
-            if ([key isEqualToString: @"AC3 Passthru"] ||
-                [key isEqualToString: @"DTS Passthru"] ||
-                [key isEqualToString: @"DTS-HD Passthru"])
-            {
-                [dict setObject: @"None" forKey: @"AudioMixdown"];
-            }
-            else if ([key isEqualToString: @"6-channel discrete"])
+            if (key != nil)
             {
-                [dict setObject: @"5.1 Channels" forKey: @"AudioMixdown"];
+                [dict setObject:[NSString stringWithFormat:@"%s",
+                                 hb_mixdown_sanitize_name([key UTF8String])]
+                         forKey:@"AudioMixdown"];
             }
 
             // If our preset wants us to support a codec that the track does not support, instead
index aaf6ec36c27d097f1515aba3190f5b2fd19b0287..5d132a12ef33282488799ae5c22de53972ededce 100644 (file)
     }
     /* Destination file. We set this to our preview directory
      * changing the extension appropriately.*/
-    if (fTitle->job->mux == HB_MUX_MP4) // MP4 file
+    if (fTitle->job->mux & HB_MUX_MASK_MP4) // MP4 file
     {
         /* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */
         fPreviewMoviePath = [PreviewDirectory stringByAppendingString:@"/preview_temp.m4v"];
     }
-    else if (fTitle->job->mux == HB_MUX_MKV) // MKV file
+    else if (fTitle->job->mux & HB_MUX_MASK_MKV) // MKV file
     {
         fPreviewMoviePath = [PreviewDirectory stringByAppendingString:@"/preview_temp.mkv"];
     }
index d8b4b6989f436e73af54b6a33b92933fb074c3b8..989374e37c62d20a50b1a1af5c457663f22eb06a 100644 (file)
          * by default to avoid massive confusion and anarchy. However we also want to guard against multiple burned in subtitle tracks
          * as libhb would ignore all but the first one anyway. Plus it would probably be stupid. 
          */
-        if (container == HB_MUX_MP4 && [anObject intValue] != 0)
+        if ((container & HB_MUX_MASK_MP4) && ([anObject intValue] != 0))
         {
             if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue] == VOBSUB)
             {
index 16524364d1074b5e0d3381ce620250a16b48f0fe..a990b662bba8b88bb336abe1da9090036633e8bf 100644 (file)
@@ -79,7 +79,6 @@ pkg.push.src.deb:: $(PKG.src.deb.stamp)
        (cd $(STAGE.out.src/)raring && dput handbrake-snapshots handbrake_$(HB.version)ppa1~raring1_source.changes )
        (cd $(STAGE.out.src/)quantal && dput handbrake-snapshots handbrake_$(HB.version)ppa1~quantal1_source.changes )
        (cd $(STAGE.out.src/)precise && dput handbrake-snapshots handbrake_$(HB.version)ppa1~precise1_source.changes )
-       (cd $(STAGE.out.src/)oneiric && dput handbrake-snapshots handbrake_$(HB.version)ppa1~oneiric1_source.changes )
 
 $(PKG.src.deb.stamp): GNUmakefile
        -$(RM.exe) -rf $(STAGE.out.src/)
@@ -120,15 +119,3 @@ $(PKG.src.deb.stamp): GNUmakefile
        echo " -- John Stebbins <jstebbins.hb@gmail.com>  Sun, 11 Apr 2010 9:51:07 -0800" >> $(STAGE.out.src/)precise/$(PKG.deb.basename)/debian/changelog
        $(TAR.exe) czf $(STAGE.out.src/)precise/$(PKG.src.deb.tar) -C $(STAGE.out.src/)precise $(PKG.deb.basename)
        (cd $(STAGE.out.src/)precise/$(PKG.deb.basename) && debuild -S -kjstebbins.hb)
-       svn co -r$(HB.repo.rev) $(HB.repo.url) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)
-       $(CP.exe) -a $(SRC/)download $(STAGE.out.src/)oneiric/$(PKG.deb.basename)
-       cp -a $(PWD)/$(PKG.debian) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)
-       $(CP.exe) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/control.oneiric $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/control
-       $(CP.exe) $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/rules.oneiric $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/rules
-       echo "handbrake ($(HB.version)ppa1~oneiric1) oneiric; urgency=low" > $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
-       echo "  * Snapshot" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
-       echo "    - See timeline at http://trac.handbrake.fr/timeline" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
-       echo "" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
-       echo " -- John Stebbins <jstebbins.hb@gmail.com>  Sun, 11 Apr 2010 9:51:07 -0800" >> $(STAGE.out.src/)oneiric/$(PKG.deb.basename)/debian/changelog
-       $(TAR.exe) czf $(STAGE.out.src/)oneiric/$(PKG.src.deb.tar) -C $(STAGE.out.src/)oneiric $(PKG.deb.basename)
-       (cd $(STAGE.out.src/)oneiric/$(PKG.deb.basename) && debuild -S -kjstebbins.hb)
index 9e83750bf6228235fbb8de6bf33369ec46e2318d..c6d2cdc3f236738a55fc8505bca655d9aecae39a 100755 (executable)
@@ -273,9 +273,9 @@ class Display
     
     #Filename suffix
     case hash["FileFormat"]
-    when /MP4/
+    when /MPEG-4/, /MP4/
       commandString << "mp4 "
-    when /MKV/
+    when /Matroska/, /MKV/
       commandString << "mkv "
     end
     
@@ -477,8 +477,12 @@ class Display
     #Container
     commandString << " -f "
     case hash["FileFormat"]
+    when "MPEG-4 (mp4v2)"
+      commandString << "mp4v2"
     when /MP4/
       commandString << "mp4"
+    when "Matroska (libmkv)"
+      commandString << "libmkv"
     when /MKV/
       commandString << "mkv"
     end
@@ -861,8 +865,12 @@ class Display
     #Container
     commandString << " -f "
     case hash["FileFormat"]
+    when "MPEG-4 (mp4v2)"
+      commandString << "mp4v2"
     when /MP4/
       commandString << "mp4"
+    when "Matroska (libmkv)"
+      commandString << "libmkv"
     when /MKV/
       commandString << "mkv"
     end
@@ -1020,13 +1028,17 @@ class Display
     
     commandString = "if (!strcasecmp(preset_name, \"" << hash["PresetName"] << "\"))\n{\n    "
     
-    #Filename suffix
+    #Container
     commandString << "if( !mux )\n    "
     commandString << "{\n    "
 
     case hash["FileFormat"]
+    when "MPEG-4 (mp4v2)"
+      commandString << "    mux = " << "HB_MUX_MP4V2;\n    "
     when /MP4/
       commandString << "    mux = " << "HB_MUX_MP4;\n    "
+    when "Matroska (libmkv)"
+      commandString << "    mux = " << "HB_MUX_LIBMKV;\n    "
     when /MKV/
       commandString << "    mux = " << "HB_MUX_MKV;\n    "
     end
@@ -1073,23 +1085,23 @@ class Display
     #FPS
     if hash["VideoFramerate"] != "Same as source"
       if hash["VideoFramerate"] == "23.976 (NTSC Film)"
-        commandString << "job->vrate_base = " << "1126125;\n    "
+        commandString << "filter_vrate_base = " << "1126125;\n    "
       elsif hash["VideoFramerate"] == "29.97 (NTSC Video)"
-        commandString << "job->vrate_base = " << "900900;\n    "
+        commandString << "filter_vrate_base = " << "900900;\n    "
       elsif hash["VideoFramerate"] == "25 (PAL Film/Video)"
-        commandString << "job->vrate_base = " << "1080000;\n    "
+        commandString << "filter_vrate_base = " << "1080000;\n    "
       else
-        commandString << "job->vrate_base = " << (27000000 / hash["VideoFramerate"].to_i).to_s << ";\n    "
+        commandString << "filter_vrate_base = " << (27000000 / hash["VideoFramerate"].to_i).to_s << ";\n    "
       end
       # not same as source: pfr, else default (cfr)
       if hash["VideoFramerateMode"] == "pfr"
-        commandString << "job->cfr = 2;\n    "
+        commandString << "filter_cfr = 2;\n    "
       else
-        commandString << "job->cfr = 1;\n    "
+        commandString << "filter_cfr = 1;\n    "
       end
     # same as source: cfr, else default (vfr)
     elsif hash["VideoFramerateMode"] == "cfr"
-      commandString << "job->cfr = 1;\n    "
+      commandString << "filter_cfr = 1;\n    "
     end
     
     #Audio tracks
@@ -1693,8 +1705,12 @@ class Display
     #Container
     commandString << " -f "
     case hash["FileFormat"]
+    when "MPEG-4 (mp4v2)"
+      commandString << "mp4v2"
     when /MP4/
       commandString << "mp4"
+    when "Matroska (libmkv)"
+      commandString << "libmkv"
     when /MKV/
       commandString << "mkv"
     end
index f26b6505030a9e51e2019a2d8bb7d62a26f232fe..e8d14197c42e20a4422734eb87a86f044f3063b2 100644 (file)
@@ -157,11 +157,6 @@ static int  ParseOptions( int argc, char ** argv );
 static int  CheckOptions( int argc, char ** argv );
 static int  HandleEvents( hb_handle_t * h );
 
-static       int   get_dither_for_string(const char *dither);
-static       int   get_acodec_for_string(const char *codec);
-static const char* get_string_for_acodec(int acodec);
-
-static int is_sample_rate_valid(int rate);
 static void str_vfree( char **strv );
 static char** str_split( char *str, char delem );
 
@@ -582,6 +577,7 @@ static int HandleEvents( hb_handle_t * h )
 {
     hb_state_t s;
     int tmp_num_audio_tracks;
+    int filter_cfr, filter_vrate, filter_vrate_base;
 
     hb_get_state( h, &s );
     switch( s.state )
@@ -727,7 +723,10 @@ static int HandleEvents( hb_handle_t * h )
             PrintTitleInfo( title, title_set->feature );
 
             /* Set job settings */
-            job = hb_job_init( title );
+            job = hb_job_init(title);
+            filter_cfr        = job->cfr;
+            filter_vrate      = job->vrate;
+            filter_vrate_base = job->vrate_base;
 
 
             if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame )
@@ -757,8 +756,8 @@ static int HandleEvents( hb_handle_t * h )
                     }
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 20.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1,1");
@@ -827,8 +826,8 @@ static int HandleEvents( hb_handle_t * h )
                     job->ipod_atom = 1;
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 22.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1");
@@ -893,8 +892,8 @@ static int HandleEvents( hb_handle_t * h )
                     job->largeFileSize = 1;
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 22.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1");
@@ -963,8 +962,8 @@ static int HandleEvents( hb_handle_t * h )
                     job->largeFileSize = 1;
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 20.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1");
@@ -1033,8 +1032,8 @@ static int HandleEvents( hb_handle_t * h )
                     job->largeFileSize = 1;
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 20.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1,1");
@@ -1107,8 +1106,8 @@ static int HandleEvents( hb_handle_t * h )
                     job->largeFileSize = 1;
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 20.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1,1");
@@ -1177,8 +1176,8 @@ static int HandleEvents( hb_handle_t * h )
                     job->largeFileSize = 1;
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 20.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1,1");
@@ -1248,8 +1247,8 @@ static int HandleEvents( hb_handle_t * h )
                     }
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 22.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1");
@@ -1316,8 +1315,8 @@ static int HandleEvents( hb_handle_t * h )
                     }
                     vcodec = HB_VCODEC_X264;
                     job->vquality = 22.0;
-                    job->vrate_base = 900000;
-                    job->cfr = 2;
+                    filter_vrate_base = 900000;
+                    filter_cfr = 2;
                     if( !atracks )
                     {
                         atracks = strdup("1");
@@ -1814,25 +1813,25 @@ static int HandleEvents( hb_handle_t * h )
 
 
             // Add framerate shaping filter
-            if( vrate )
+            if (vrate)
             {
-                job->cfr = cfr;
-                job->vrate = 27000000;
-                job->vrate_base = vrate;
+                filter_cfr        = cfr;
+                filter_vrate      = 27000000;
+                filter_vrate_base = vrate;
             }
-            else if ( cfr )
+            else if (cfr)
             {
                 // cfr or pfr flag with no rate specified implies
                 // use the title rate.
-                job->cfr = cfr;
-                job->vrate = title->rate;
-                job->vrate_base = title->rate_base;
+                filter_cfr        = cfr;
+                filter_vrate      = title->rate;
+                filter_vrate_base = title->rate_base;
             }
-            filter_str = hb_strdup_printf("%d:%d:%d",
-                job->cfr, job->vrate, job->vrate_base );
-            filter = hb_filter_init( HB_FILTER_VFR );
-            hb_add_filter( job, filter, filter_str );
-            free( filter_str );
+            filter     = hb_filter_init(HB_FILTER_VFR);
+            filter_str = hb_strdup_printf("%d:%d:%d", filter_cfr, filter_vrate,
+                                          filter_vrate_base);
+            hb_add_filter(job, filter, filter_str);
+            free(filter_str);
 
             if(vcodec == HB_VCODEC_QSV_H264)
             {
@@ -2034,10 +2033,10 @@ static int HandleEvents( hb_handle_t * h )
                     token = acodecs;
                 while ( token != NULL )
                 {
-                    if ((acodec = get_acodec_for_string(token)) == -1)
+                    if ((acodec = hb_audio_encoder_get_from_name(token)) == -1)
                     {
                         fprintf(stderr, "Invalid codec %s, using default for container.\n", token);
-                        acodec = hb_get_default_audio_encoder(job->mux);
+                        acodec = hb_audio_encoder_get_default(job->mux);
                     }
                     if( i < num_audio_tracks )
                     {
@@ -2075,7 +2074,7 @@ static int HandleEvents( hb_handle_t * h )
                  * then use that codec instead.
                  */
                 if (i != 1)
-                    acodec = hb_get_default_audio_encoder(job->mux);
+                    acodec = hb_audio_encoder_get_default(job->mux);
                 for ( ; i < num_audio_tracks; i++)
                 {
                     audio = hb_list_audio_config_item(job->list_audio, i);
@@ -2094,18 +2093,7 @@ static int HandleEvents( hb_handle_t * h )
                     token = arates;
                 while ( token != NULL )
                 {
-                    arate = atoi(token);
                     audio = hb_list_audio_config_item(job->list_audio, i);
-                    int j;
-
-                    for( j = 0; j < hb_audio_rates_count; j++ )
-                    {
-                        if( !strcmp( token, hb_audio_rates[j].string ) )
-                        {
-                            arate = hb_audio_rates[j].rate;
-                            break;
-                        }
-                    }
 
                     if( audio != NULL )
                     {
@@ -2114,9 +2102,15 @@ static int HandleEvents( hb_handle_t * h )
                             arate = audio->in.samplerate;
                             auto_sample_rate = 1;
                         }
-                        if (!is_sample_rate_valid(arate))
+                        else
+                        {
+                            arate = hb_audio_samplerate_get_from_name(token);
+                        }
+                        if (arate == -1)
                         {
-                            fprintf(stderr, "Invalid sample rate %d, using input rate %d\n", arate, audio->in.samplerate);
+                            fprintf(stderr,
+                                    "Invalid sample rate %s, using input rate %d\n",
+                                    token, audio->in.samplerate);
                             arate = audio->in.samplerate;
                         }
 
@@ -2159,8 +2153,8 @@ static int HandleEvents( hb_handle_t * h )
                     token = mixdowns;
                 while ( token != NULL )
                 {
-                    mixdown = hb_mixdown_get_mixdown_from_short_name(token);
-                    audio = hb_list_audio_config_item(job->list_audio, i);
+                    mixdown = hb_mixdown_get_from_name(token);
+                    audio   = hb_list_audio_config_item(job->list_audio, i);
                     if( audio != NULL )
                     {
                         audio->out.mixdown = mixdown;
@@ -2367,8 +2361,8 @@ static int HandleEvents( hb_handle_t * h )
                 int dither_method = hb_audio_dither_get_default();
                 for (i = 0; audio_dither[i] != NULL; i++)
                 {
-                    dither_method = get_dither_for_string(audio_dither[i]);
-                    audio = hb_list_audio_config_item(job->list_audio, i);
+                    dither_method = hb_audio_dither_get_from_name(audio_dither[i]);
+                    audio         = hb_list_audio_config_item(job->list_audio, i);
                     if (audio != NULL)
                     {
                         if (hb_audio_dither_is_supported(audio->out.codec))
@@ -2490,45 +2484,41 @@ static int HandleEvents( hb_handle_t * h )
                 {
                     // Auto Passthru
                     job->acodec_copy_mask = allowed_audio_copy == -1 ? HB_ACODEC_PASS_MASK : allowed_audio_copy;
-                    job->acodec_fallback = acodec_fallback ? get_acodec_for_string( acodec_fallback ) : 0;
+                    job->acodec_fallback  = hb_audio_encoder_get_from_name(acodec_fallback);
                     // sanitize the fallback; -1 isn't a valid HB_ACODEC_* value
-                    if( job->acodec_fallback == -1 )
-                        job->acodec_fallback = 0;
+                    if (job->acodec_fallback == -1)
+                        job->acodec_fallback  =  0;
                 }
                 else if( ( audio->out.codec & HB_ACODEC_PASS_FLAG ) &&
                         !( audio->out.codec & audio->in.codec & HB_ACODEC_PASS_MASK ) )
                 {
-                    if( audio->out.codec == HB_ACODEC_AAC_PASS )
-                    {
-                        fprintf( stderr, "AAC Passthru requested and input codec is not AAC for track %d, using AAC encoder\n",
-                                 audio->out.track );
-                        audio->out.codec = hb_audio_encoders[0].encoder;
-                    }
-                    else if( audio->out.codec == HB_ACODEC_AC3_PASS )
-                    {
-                        fprintf( stderr, "AC3 Passthru requested and input codec is not AC3 for track %d, using AC3 encoder\n",
-                                 audio->out.track );
-                        audio->out.codec = HB_ACODEC_AC3;
-                    }
-                    else if( audio->out.codec == HB_ACODEC_MP3_PASS )
-                    {
-                        fprintf( stderr, "MP3 Passthru requested and input codec is not MP3 for track %d, using MP3 encoder\n",
-                                 audio->out.track );
-                        audio->out.codec = HB_ACODEC_LAME;
-                    }
-                    else
+                    // passthru fallbacks
+                    int requested_passthru = audio->out.codec;
+                    audio->out.codec       =
+                        hb_audio_encoder_get_fallback_for_passthru(requested_passthru);
+                    if (!(audio->out.codec & HB_ACODEC_MASK))
                     {
                         // Passthru not possible, drop audio.
-                        fprintf( stderr, "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n",
-                                 audio->out.track );
-                        hb_audio_t * item = hb_list_item( job->list_audio, i );
-                        hb_list_rem( job->list_audio, item );
+                        fprintf(stderr,
+                                "Passthru requested and input codec is not the same as output codec for track %d, dropping track\n",
+                                audio->out.track);
+                        hb_audio_t *item = hb_list_item(job->list_audio, i);
+                        hb_list_rem(job->list_audio, item);
+                        hb_audio_close(&item);
                         continue;
                     }
+                    fprintf(stderr,
+                            "%s requested and input codec is not compatible for track %d, using %s encoder\n",
+                            hb_audio_encoder_get_name(requested_passthru), audio->out.track,
+                            hb_audio_encoder_get_name(audio->out.codec));
                     // we didn't drop the track, set the mixdown and bitrate from libhb defaults
-                    audio->out.mixdown = hb_get_default_mixdown( audio->out.codec, audio->in.channel_layout );
-                    audio->out.bitrate = hb_get_default_audio_bitrate( audio->out.codec, audio->out.samplerate,
-                                                                       audio->out.mixdown );
+                    audio->out.mixdown =
+                        hb_mixdown_get_default(audio->out.codec,
+                                               audio->in.channel_layout);
+                    audio->out.bitrate =
+                        hb_audio_bitrate_get_default(audio->out.codec,
+                                                     audio->out.samplerate,
+                                                     audio->out.mixdown);
                 }
                 // we didn't drop the track
                 i++;
@@ -2959,7 +2949,13 @@ void SigHandler( int i_signal )
  ****************************************************************************/
 static void ShowHelp()
 {
-    int i, j, len;
+    int i, len;
+    const char *name;
+    const hb_rate_t *rate;
+    const hb_dither_t *dither;
+    const hb_mixdown_t *mixdown;
+    const hb_encoder_t *encoder;
+    const hb_container_t *container;
     FILE* const out = stdout;
     const char * const *x264_opts;
     char tmp[80];
@@ -3002,8 +2998,22 @@ static void ShowHelp()
 
     "### Destination Options------------------------------------------------------\n\n"
     "    -o, --output <string>   Set output file name\n"
-    "    -f, --format <string>   Set output format (mp4/mkv, default:\n"
-    "                            autodetected from file name)\n"
+    "    -f, --format <string>   Set output container format (");
+    container = NULL;
+    while ((container = hb_container_get_next(container)) != NULL)
+    {
+        fprintf(out, "%s", container->short_name);
+        if (hb_container_get_next(container) != NULL)
+        {
+            fprintf(out, "/");
+        }
+        else
+        {
+            fprintf(out, ")\n");
+        }
+    }
+    fprintf(out,
+    "                            (default: autodetected from file name)\n"
     "    -m, --markers           Add chapter markers\n"
     "    -4, --large-file        Create 64-bit mp4 files that can hold more than 4 GB\n"
     "                            of data. Note: breaks pre-iOS iPod compatibility.\n"
@@ -3015,24 +3025,24 @@ static void ShowHelp()
     "### Video Options------------------------------------------------------------\n\n"
     "    -e, --encoder <string>  Set video library encoder\n"
     "                            Options: " );
-    for( i = 0; i < hb_video_encoders_count; i++ )
+    encoder = NULL;
+    while ((encoder = hb_video_encoder_get_next(encoder)) != NULL)
     {
-        fprintf( out, "%s", hb_video_encoders[i].short_name );
-
-        if( i != hb_video_encoders_count - 1 )
-            fprintf( out, "/" );
+        fprintf(out, "%s", encoder->short_name);
+        if (hb_video_encoder_get_next(encoder) != NULL)
+        {
+            fprintf(out, "/");
+        }
         else
-            fprintf( out, "\n" );
-    }
-    for( i = 0; i < hb_video_encoders_count; i++ )
-    {
-        if( hb_video_encoders[i].encoder == vcodec )
         {
-            fprintf( out, "                            (default: %s)\n",
-                     hb_video_encoders[i].short_name );
-            break;
+            fprintf(out, "\n");
+        }
+        if (encoder->codec == vcodec)
+        {
+            name = encoder->short_name;
         }
     }
+    fprintf(out, "                            (default: %s)\n", name);
     fprintf( out,
     "        --x264-preset       When using x264, selects the x264 preset:\n"
     "          <string>          ");
@@ -3133,11 +3143,14 @@ static void ShowHelp()
     "    -T, --turbo             When using 2-pass use \"turbo\" options on the\n"
     "                            1st pass to improve speed (only works with x264)\n"
     "    -r, --rate              Set video framerate (" );
-    for( i = 0; i < hb_video_rates_count; i++ )
+    rate = NULL;
+    while ((rate = hb_video_framerate_get_next(rate)) != NULL)
     {
-        fprintf( out, "%s", hb_video_rates[i].string );
-        if( i != hb_video_rates_count - 1 )
-            fprintf( out, "/" );
+        fprintf(out, "%s", rate->name);
+        if (hb_video_framerate_get_next(rate) != NULL)
+        {
+            fprintf(out, "/");
+        }
     }
     fprintf( out, ")\n"
     "                            Be aware that not specifying a framerate lets\n"
@@ -3161,33 +3174,44 @@ static void ShowHelp()
     "                             tracks, default: first one).\n"
     "                            Multiple output tracks can be used for one input.\n"
     "    -E, --aencoder <string> Audio encoder(s):\n" );
-    for (i = 0; i < hb_audio_encoders_count; i++)
+    encoder = NULL;
+    while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
     {
         fprintf(out, "                               %s\n",
-                hb_audio_encoders[i].short_name);
+                encoder->short_name);
     }
     fprintf(out,
     "                            copy:* will passthrough the corresponding\n"
     "                            audio unmodified to the muxer if it is a\n"
     "                            supported passthrough audio type.\n"
     "                            Separated by commas for more than one audio track.\n"
-    "                            (default: %s for mp4, %s for mkv)\n",
-            get_string_for_acodec(hb_get_default_audio_encoder(HB_MUX_MP4)),
-            get_string_for_acodec(hb_get_default_audio_encoder(HB_MUX_MKV)));
+    "                            Defaults:\n");
+    container = NULL;
+    while ((container = hb_container_get_next(container)) != NULL)
+    {
+        int audio_encoder = hb_audio_encoder_get_default(container->format);
+        fprintf(out, "                               %-8s %s\n",
+                container->short_name,
+                hb_audio_encoder_get_short_name(audio_encoder));
+    }
     fprintf(out,
     "        --audio-copy-mask   Set audio codecs that are permitted when the\n"
     "                <string>    \"copy\" audio encoder option is specified\n"
     "                            (" );
-    for (i = j = 0; i < hb_audio_encoders_count; i++)
+    i       = 0;
+    encoder = NULL;
+    while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
     {
-        if ((hb_audio_encoders[i].encoder &  HB_ACODEC_PASS_FLAG) &&
-            (hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS))
+        if ((encoder->codec &  HB_ACODEC_PASS_FLAG) &&
+            (encoder->codec != HB_ACODEC_AUTO_PASS))
         {
-            if (j)
+            if (i)
+            {
                 fprintf(out, "/");
+            }
+            i = 1;
             // skip "copy:"
-            fprintf(out, "%s", hb_audio_encoders[i].short_name + 5);
-            j = 1;
+            fprintf(out, "%s", encoder->short_name + 5);
         }
     }
     fprintf(out, ", default: all).\n"
@@ -3205,25 +3229,25 @@ static void ShowHelp()
     "                            Separated by commas for more than one audio track.\n"
     "    -6, --mixdown <string>  Format(s) for audio downmixing/upmixing:\n");
     // skip HB_AMIXDOWN_NONE
-    for (i = 1; i < hb_audio_mixdowns_count; i++)
+    mixdown = hb_mixdown_get_next(NULL);
+    while((mixdown = hb_mixdown_get_next(mixdown)) != NULL)
     {
         fprintf(out, "                               %s\n",
-                hb_audio_mixdowns[i].short_name);
+                mixdown->short_name);
     }
     fprintf(out,
     "                            Separated by commas for more than one audio track.\n"
     "                            Defaults:\n");
-    for (i = 0; i < hb_audio_encoders_count; i++)
+    encoder = NULL;
+    while((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
     {
-        if (!(hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG))
+        if (!(encoder->codec & HB_ACODEC_PASS_FLAG))
         {
             // layout: UINT64_MAX (all channels) should work with any mixdown
-            int mixdown = hb_get_default_mixdown(hb_audio_encoders[i].encoder,
-                                                 UINT64_MAX);
+            int mixdown = hb_mixdown_get_default(encoder->codec, UINT64_MAX);
             // assumes that the encoder short name is <= 16 characters long
             fprintf(out, "                               %-16s up to %s\n",
-                    hb_audio_encoders[i].short_name,
-                    hb_mixdown_get_short_name_from_mixdown(mixdown));
+                    encoder->short_name, hb_mixdown_get_short_name(mixdown));
         }
     }
     fprintf(out,
@@ -3232,11 +3256,14 @@ static void ShowHelp()
     "                            0 = Disable Normalization (default)\n"
     "                            1 = Enable Normalization\n"
     "    -R, --arate             Set audio samplerate(s) (" );
-    for( i = 0; i < hb_audio_rates_count; i++ )
+    rate = NULL;
+    while ((rate = hb_audio_samplerate_get_next(rate)) != NULL)
     {
-        fprintf( out, "%s", hb_audio_rates[i].string );
-        if( i != hb_audio_rates_count - 1 )
-            fprintf( out, "/" );
+        fprintf(out, "%s", rate->name);
+        if (hb_audio_samplerate_get_next(rate) != NULL)
+        {
+            fprintf(out, "/");
+        }
     }
     fprintf( out, " kHz)\n"
     "                            Separated by commas for more than one audio track.\n"
@@ -3251,30 +3278,35 @@ static void ShowHelp()
     "        --adither <string>  Apply dithering to the audio before encoding.\n"
     "                            Separated by commas for more than one audio track.\n"
     "                            Only supported by some encoders (");
-    for (i = j = 0; i < hb_audio_encoders_count; i++)
+    i       = 0;
+    encoder = NULL;
+    while ((encoder = hb_audio_encoder_get_next(encoder)) != NULL)
     {
-        if (hb_audio_dither_is_supported(hb_audio_encoders[i].encoder))
+        if (hb_audio_dither_is_supported(encoder->codec))
         {
-            if (j)
+            if (i)
+            {
                 fprintf(out, "/");
-            fprintf(out, "%s", hb_audio_encoders[i].short_name);
-            j = 1;
+            }
+            i = 1;
+            fprintf(out, "%s", encoder->short_name);
         }
     }
     fprintf(out, ").\n");
     fprintf(out,
     "                            Options:\n");
-    for (i = 0; i < hb_audio_dithers_count; i++)
+    dither = NULL;
+    while ((dither = hb_audio_dither_get_next(dither)) != NULL)
     {
-        if (hb_audio_dithers[i].method == hb_audio_dither_get_default())
+        if (dither->method == hb_audio_dither_get_default())
         {
             fprintf(out, "                               %s (default)\n",
-                    hb_audio_dithers[i].short_name);
+                    dither->short_name);
         }
         else
         {
             fprintf(out, "                               %s\n",
-                    hb_audio_dithers[i].short_name);
+                    dither->short_name);
         }
     }
     fprintf(out,
@@ -3993,18 +4025,10 @@ static int ParseOptions( int argc, char ** argv )
                 break;
             case 'e':
             {
-                int i;
-                for( i = 0, vcodec = 0; i < hb_video_encoders_count; i++ )
+                vcodec = hb_video_encoder_get_from_name(optarg);
+                if (vcodec <= 0)
                 {
-                    if( !strcasecmp( hb_video_encoders[i].short_name, optarg ) )
-                    {
-                        vcodec = hb_video_encoders[i].encoder;
-                        break;
-                    }
-                }
-                if( !vcodec )
-                {
-                    fprintf( stderr, "invalid codec (%s)\n", optarg );
+                    fprintf(stderr, "invalid codec (%s)\n", optarg);
                     return -1;
                 }
                 break;
@@ -4039,21 +4063,13 @@ static int ParseOptions( int argc, char ** argv )
                 break;
             case 'r':
             {
-                int i;
-                vrate = 0;
-                for( i = 0; i < hb_video_rates_count; i++ )
+                vrate = hb_video_framerate_get_from_name(optarg);
+                if (vrate <= 0)
                 {
-                    if( !strcmp( optarg, hb_video_rates[i].string ) )
-                    {
-                        vrate = hb_video_rates[i].rate;
-                        break;
-                    }
+                    vrate = 0;
+                    fprintf(stderr, "invalid framerate %s\n", optarg);
                 }
-                if( !vrate )
-                {
-                    fprintf( stderr, "invalid framerate %s\n", optarg );
-                }
-                else if ( cfr == 0 )
+                else if (!cfr)
                 {
                     cfr = 1;
                 }
@@ -4166,28 +4182,33 @@ static int ParseOptions( int argc, char ** argv )
             }
             case ALLOWED_AUDIO_COPY:
             {
-                int i, j;
-                char **allowed = str_split( optarg, ',' );
+                allowed_audio_copy                = 0;
+                const hb_encoder_t *audio_encoder = NULL;
+                char **allowed                    = str_split(optarg, ',');
 
-                allowed_audio_copy = 0;
-                for( i = 0; allowed[i]; i++ )
+                while ((audio_encoder = hb_audio_encoder_get_next(audio_encoder)) != NULL)
                 {
-                    for( j = 0; j < hb_audio_encoders_count; j++ )
+                    if ((audio_encoder->codec &  HB_ACODEC_PASS_FLAG) &&
+                        (audio_encoder->codec != HB_ACODEC_AUTO_PASS))
                     {
-                        const char *encoder = hb_audio_encoders[j].short_name;
-                        // skip "copy:"
-                        if( strlen( encoder ) > 5 )
-                            encoder += 5;
-                        if( !strcmp( allowed[i], encoder ) )
+                        int i = -1;
+                        while(allowed[++i] != NULL)
                         {
-                            allowed_audio_copy |= hb_audio_encoders[j].encoder;
-                            break;
+                            // skip "copy:"
+                            if (!strcasecmp(allowed[i],
+                                            audio_encoder->short_name + 5))
+                            {
+                                allowed_audio_copy |= audio_encoder->codec;
+                                break;
+                            }
                         }
                     }
                 }
+
                 allowed_audio_copy &= HB_ACODEC_PASS_MASK;
-                str_vfree( allowed );
-            } break;
+                str_vfree(allowed);
+                break;
+            }
             case AUDIO_FALLBACK:
                 acodec_fallback = strdup( optarg );
                 break;
@@ -4238,94 +4259,50 @@ static int CheckOptions( int argc, char ** argv )
             return 1;
         }
 
-        if( !format )
+        if (format == NULL)
         {
-            char * p = strrchr( output, '.' );
-
             /* autodetect */
-            if( p && ( !strcasecmp( p, ".mp4" )  ||
-                       !strcasecmp( p, ".m4v" ) ) )
-            {
-                mux = HB_MUX_MP4;
-            }
-            else if( p && !strcasecmp(p, ".mkv" ) )
+            const char *extension = strrchr(output, '.');
+            if (extension != NULL)
             {
-                mux = HB_MUX_MKV;
+                // skip '.'
+                mux = hb_container_get_from_extension(extension + 1);
             }
-            else
+            if (mux <= 0)
             {
-                fprintf( stderr, "Output format couldn't be guessed "
-                         "from file name, using default.\n" );
+                fprintf(stderr,
+                        "Output format can't be guessed from file name (%s), "
+                        "using default.\n", output);
+                // reset the muxer (use default)
+                mux  = 0;
                 return 0;
             }
         }
-        else if( !strcasecmp( format, "mp4" ) ||
-                 !strcasecmp( format, "m4v" ) )
-        {
-            mux = HB_MUX_MP4;
-        }
-        else if( !strcasecmp( format, "mkv" ) )
-        {
-            mux = HB_MUX_MKV;
-        }
         else
         {
-            fprintf( stderr, "Invalid output format (%s). Possible "
-                     "choices are mp4, m4v and mkv\n.", format );
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-static int get_dither_for_string(const char *dither)
-{
-    int i;
-    for (i = 0; i < hb_audio_dithers_count; i++)
-    {
-        if (!strcasecmp(hb_audio_dithers[i].short_name, dither))
-        {
-            return hb_audio_dithers[i].method;
-        }
-    }
-    return hb_audio_dither_get_default();
-}
-
-static int get_acodec_for_string(const char *codec)
-{
-    int i;
-    for (i = 0; i < hb_audio_encoders_count; i++)
-    {
-        if (!strcasecmp(hb_audio_encoders[i].short_name, codec))
-        {
-            return hb_audio_encoders[i].encoder;
-        }
-    }
-    return -1;
-}
-
-static const char* get_string_for_acodec(int acodec)
-{
-    int i;
-    for (i = 0; i < hb_audio_encoders_count; i++)
-    {
-        if (hb_audio_encoders[i].encoder == acodec)
-        {
-            return hb_audio_encoders[i].short_name;
+            mux = hb_container_get_from_name(format);
+            if (mux <= 0)
+            {
+                fprintf(stderr, "Invalid output format (%s).", format);
+                fprintf(stderr, "Possible choices are: ");
+                const hb_container_t *container = NULL;
+                while ((container = hb_container_get_next(container)) != NULL)
+                {
+                    fprintf(stderr, "%s", container->short_name);
+                    if (hb_container_get_next(container) != NULL)
+                    {
+                        fprintf(stderr, ", ");
+                    }
+                    else
+                    {
+                        fprintf(stderr, "\n");
+                    }
+                }
+                return 1;
+            }
         }
     }
-    return NULL;
-}
 
-static int is_sample_rate_valid(int rate)
-{
-    int i;
-    for( i = 0; i < hb_audio_rates_count; i++ )
-    {
-            if (rate == hb_audio_rates[i].rate)
-                return 1;
-    }
     return 0;
 }
 
index 7e3ee4583e47aa9b1c28f28febd79cdd066b07d9..78f5b18abd363509e64db922fc26270623bf9248 100644 (file)
@@ -19,21 +19,11 @@ namespace HandBrake.ApplicationServices
         /// </summary>\r
         public const string Verbosity = "Verbosity";\r
 \r
-        /// <summary>\r
-        /// When Complete Action\r
-        /// </summary>\r
-        public const string WhenCompleteAction = "WhenCompleteAction";\r
-\r
         /// <summary>\r
         /// Process Priority\r
         /// </summary>\r
         public const string ProcessPriority = "ProcessPriority";\r
 \r
-        /// <summary>\r
-        /// Prevent Sleep\r
-        /// </summary>\r
-        public const string PreventSleep = "PreventSleep";\r
-\r
         /// <summary>\r
         /// Save Log Directory\r
         /// </summary>\r
@@ -59,21 +49,6 @@ namespace HandBrake.ApplicationServices
         /// </summary>\r
         public const string DisableLibDvdNav = "DisableLibDvdNav";\r
 \r
-        /// <summary>\r
-        /// Send file enabled.\r
-        /// </summary>\r
-        public const string SendFile = "SendFile";\r
-\r
-        /// <summary>\r
-        /// Send file to application path\r
-        /// </summary>\r
-        public const string SendFileTo = "SendFileTo";\r
-\r
-        /// <summary>\r
-        /// Send file to arguments\r
-        /// </summary>\r
-        public const string SendFileToArgs = "SendFileToArgs";\r
-\r
         /// <summary>\r
         /// Min Title Scan Duration\r
         /// </summary>\r
index 44a66cac74c28bf93c726a6028cfa6a8c71f67f7..2bbb7ab976fa8b9e9d9bbe61defbb4590f55dbb8 100644 (file)
@@ -12,6 +12,8 @@ namespace HandBrake.ApplicationServices.EventArgs
     using System;\r
     using System.Runtime.Serialization;\r
 \r
+    using HandBrake.ApplicationServices.Model;\r
+\r
     /// <summary>\r
     /// Encode Progress Event Args\r
     /// </summary>\r
@@ -30,13 +32,23 @@ namespace HandBrake.ApplicationServices.EventArgs
         /// <param name="errorInformation">\r
         /// The error information.\r
         /// </param>\r
-        public EncodeCompletedEventArgs(bool sucessful, Exception exception, string errorInformation)\r
+        /// <param name="filename">\r
+        /// The filename.\r
+        /// </param>\r
+        public EncodeCompletedEventArgs(bool sucessful, Exception exception, string errorInformation, string filename)\r
         {\r
             this.Successful = sucessful;\r
             this.Exception = exception;\r
             this.ErrorInformation = errorInformation;\r
+            this.FileName = filename;\r
         }\r
 \r
+        /// <summary>\r
+        /// Gets or sets the file name.\r
+        /// </summary>\r
+        [DataMember]\r
+        public string FileName { get; set; }\r
+\r
         /// <summary>\r
         /// Gets or sets a value indicating whether Successful.\r
         /// </summary>\r
index 07d4e13b4d62ee6fc98654df8e1a071c3e55f8df..a90e260c4ee7b622d99ea67f6e4b427bba2183e2 100644 (file)
@@ -133,9 +133,12 @@ namespace HandBrake.ApplicationServices.Model
             this.H264Level = task.H264Level;\r
             this.FastDecode = task.FastDecode;\r
             this.ExtraAdvancedArguments = task.ExtraAdvancedArguments;\r
+            \r
 \r
             this.PreviewStartAt = task.PreviewStartAt;\r
             this.PreviewDuration = task.PreviewDuration;\r
+\r
+            this.ShowAdvancedTab = task.ShowAdvancedTab;\r
         }\r
 \r
         #region Source\r
index e670ccb7e17eee88216b2c3b64d8ba7364bc0b71..9c7d684ca406216c51a1b0939761d3779e436084 100644 (file)
@@ -20,7 +20,7 @@ namespace HandBrake.ApplicationServices.Model
         None = 0,\r
         [Display(Name = "Custom")]\r
         Custom = 1,\r
-        [Display(Name = "Source Maximum")]\r
+        [Display(Name = "Current Source Max Size")]\r
         SourceMaximum = 2,\r
     }\r
 }
\ No newline at end of file
index 34a919908b0f71fb5351dde960b46d07cc3cb139..0a68476f4ff190730b2d4a23d7517ec39d674228 100644 (file)
@@ -68,6 +68,22 @@ namespace HandBrake.ApplicationServices.Parsing
         /// </summary>\r
         public string LanguageCode { get; set; }\r
 \r
+        /// <summary>\r
+        /// Gets the language code clean.\r
+        /// TODO Remove this after fixing language code.\r
+        /// </summary>\r
+        public string LanguageCodeClean\r
+        {\r
+            get\r
+            {\r
+                if (this.LanguageCode != null)\r
+                {\r
+                    return this.LanguageCode.Replace("iso639-2: ", string.Empty).Trim();\r
+                }\r
+                return string.Empty;\r
+            }\r
+        }\r
+\r
         /// <summary>\r
         /// Gets or sets the Subtitle Type\r
         /// </summary>\r
index b4f57252158e390be3cf545b4948775c8e7d23c0..4779d353ebe01598954175da213d881c1b07a8b4 100644 (file)
@@ -14,9 +14,8 @@ namespace HandBrake.ApplicationServices.Services
     using System.IO;\r
     using System.Windows.Forms;\r
 \r
-    using Caliburn.Micro;\r
-\r
     using HandBrake.ApplicationServices.EventArgs;\r
+    using HandBrake.ApplicationServices.Exceptions;\r
     using HandBrake.ApplicationServices.Model;\r
     using HandBrake.ApplicationServices.Services.Base;\r
     using HandBrake.ApplicationServices.Services.Interfaces;\r
@@ -95,11 +94,10 @@ namespace HandBrake.ApplicationServices.Services
             {\r
                 if (this.IsEncoding)\r
                 {\r
-                    throw new Exception("HandBrake is already encodeing.");\r
+                    throw new GeneralApplicationException("HandBrake is already encodeing.", "Please try again in a minute", null);\r
                 }\r
 \r
                 this.IsEncoding = true;\r
-\r
                 this.currentTask = encodeQueueTask;\r
 \r
                 if (enableLogging)\r
@@ -115,11 +113,6 @@ namespace HandBrake.ApplicationServices.Services
                     }\r
                 }\r
 \r
-                if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep))\r
-                {\r
-                    Win32.PreventSleep();\r
-                }\r
-\r
                 // Make sure the path exists, attempt to create it if it doesn't\r
                 this.VerifyEncodeDestinationPath(currentTask);\r
 \r
@@ -200,9 +193,10 @@ namespace HandBrake.ApplicationServices.Services
             catch (Exception exc)\r
             {\r
                 encodeQueueTask.Status = QueueItemStatus.Error;\r
+                this.IsEncoding = false;\r
                 this.InvokeEncodeCompleted(\r
                     new EncodeCompletedEventArgs(\r
-                        false, null, "An Error occured when trying to encode this source. "));\r
+                        false, exc, "An Error occured when trying to encode this source. ", this.currentTask.Task.Destination));\r
                 throw;\r
             }\r
         }\r
@@ -261,17 +255,9 @@ namespace HandBrake.ApplicationServices.Services
                 // This exception doesn't warrent user interaction, but it should be logged (TODO)\r
             }\r
 \r
-            Execute.OnUIThread(() =>\r
-            {\r
-                if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep))\r
-                {\r
-                    Win32.AllowSleep();\r
-                }\r
-            });\r
-\r
             this.currentTask.Status = QueueItemStatus.Completed;\r
             this.IsEncoding = false;\r
-            this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(true, null, string.Empty));\r
+            this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(true, null, string.Empty, this.currentTask.Task.Destination));\r
         }\r
 \r
         /// <summary>\r
index 33453dad877d6e4f9b6cbc541632a42fa49bd78a..f7247f6cf2e48223d1ec4bf12f3598a3b9c7f2e3 100644 (file)
@@ -11,7 +11,6 @@ namespace HandBrake.ApplicationServices.Services
 {\r
     using System;\r
     using System.Diagnostics;\r
-    using System.Globalization;\r
 \r
     using HandBrake.ApplicationServices.Model;\r
     using HandBrake.ApplicationServices.Services.Base;\r
@@ -57,6 +56,11 @@ namespace HandBrake.ApplicationServices.Services
         /// </summary>\r
         private bool loggingEnabled;\r
 \r
+        /// <summary>\r
+        /// The Current Task\r
+        /// </summary>\r
+        private QueueTask currentTask;\r
+\r
         #endregion\r
 \r
         /// <summary>\r
@@ -95,6 +99,7 @@ namespace HandBrake.ApplicationServices.Services
         {\r
             this.startTime = DateTime.Now;\r
             this.loggingEnabled = enableLogging;\r
+            this.currentTask = job;\r
 \r
             try\r
             {\r
@@ -123,12 +128,6 @@ namespace HandBrake.ApplicationServices.Services
                     }\r
                 }\r
 \r
-                // Prvent the system from sleeping if the user asks\r
-                if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep) )\r
-                {\r
-                    Win32.PreventSleep();\r
-                }\r
-\r
                 // Verify the Destination Path Exists, and if not, create it.\r
                 this.VerifyEncodeDestinationPath(job);\r
 \r
@@ -163,7 +162,7 @@ namespace HandBrake.ApplicationServices.Services
             }\r
             catch (Exception exc)\r
             {\r
-                this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(false, exc, "An Error has occured."));\r
+                this.InvokeEncodeCompleted(new EncodeCompletedEventArgs(false, exc, "An Error has occured.", this.currentTask.Task.Destination));\r
             }\r
         }\r
 \r
@@ -271,13 +270,8 @@ namespace HandBrake.ApplicationServices.Services
 \r
             this.InvokeEncodeCompleted(\r
                 e.Error\r
-                    ? new EncodeCompletedEventArgs(false, null, string.Empty)\r
-                    : new EncodeCompletedEventArgs(true, null, string.Empty));\r
-\r
-            if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep))\r
-            {\r
-                Win32.AllowSleep();\r
-            }\r
+                    ? new EncodeCompletedEventArgs(false, null, string.Empty, this.currentTask.Task.Destination)\r
+                    : new EncodeCompletedEventArgs(true, null, string.Empty, this.currentTask.Task.Destination));\r
 \r
             this.ShutdownFileWriter();\r
         }\r
index 75fd00554adb67df6c6b54b9de9046d9d27d1f77..6ef83f068f8ead5cd57ee513f63c325ea355c953 100644 (file)
@@ -314,6 +314,11 @@ namespace HandBrake.ApplicationServices.Services
                                     Task = QueryParserUtility.Parse(presetName[2])\r
                                 };\r
 \r
+                            if (newPreset.Name == "iPod")\r
+                            {\r
+                                newPreset.Task.KeepDisplayAspect = true;\r
+                            }\r
+\r
                             newPreset.Task.AllowedPassthruOptions = new AllowedPassthru(true); // We don't want to override the built-in preset\r
                             \r
                             if (newPreset.Name == "Normal")\r
index 79b348ae42a2c7d2ad52a1e772da076fc174e8a1..a8cb55f582e9d2ff0e399cc997e930bb1aed64bc 100644 (file)
@@ -12,10 +12,8 @@ namespace HandBrake.ApplicationServices.Services
     using System;\r
     using System.Collections.Generic;\r
     using System.ComponentModel;\r
-    using System.Diagnostics;\r
     using System.IO;\r
     using System.Linq;\r
-    using System.Windows.Forms;\r
     using System.Xml.Serialization;\r
 \r
     using Caliburn.Micro;\r
@@ -53,6 +51,11 @@ namespace HandBrake.ApplicationServices.Services
         /// </summary>\r
         private string queueFile;\r
 \r
+        /// <summary>\r
+        /// The is paused.\r
+        /// </summary>\r
+        private bool isPaused;\r
+\r
         #endregion\r
 \r
         #region Constructors and Destructors\r
@@ -238,15 +241,15 @@ namespace HandBrake.ApplicationServices.Services
         {\r
             Execute.OnUIThread(\r
                 () =>\r
+                {\r
+                    List<QueueTask> deleteList =\r
+                        this.queue.Where(task => task.Status == QueueItemStatus.Completed).ToList();\r
+                    foreach (QueueTask item in deleteList)\r
                     {\r
-                        List<QueueTask> deleteList =\r
-                            this.queue.Where(task => task.Status == QueueItemStatus.Completed).ToList();\r
-                        foreach (QueueTask item in deleteList)\r
-                        {\r
-                            this.queue.Remove(item);\r
-                        }\r
-                        this.InvokeQueueChanged(EventArgs.Empty);\r
-                    });\r
+                        this.queue.Remove(item);\r
+                    }\r
+                    this.InvokeQueueChanged(EventArgs.Empty);\r
+                });\r
         }\r
 \r
         /// <summary>\r
@@ -381,8 +384,8 @@ namespace HandBrake.ApplicationServices.Services
                         catch (Exception exc)\r
                         {\r
                             throw new GeneralApplicationException(\r
-                                "Unable to restore queue file.", \r
-                                "The file may be corrupted or from an older incompatible version of HandBrake", \r
+                                "Unable to restore queue file.",\r
+                                "The file may be corrupted or from an older incompatible version of HandBrake",\r
                                 exc);\r
                         }\r
 \r
@@ -421,6 +424,7 @@ namespace HandBrake.ApplicationServices.Services
         {\r
             this.InvokeQueuePaused(EventArgs.Empty);\r
             this.IsProcessing = false;\r
+            this.isPaused = true;\r
         }\r
 \r
         /// <summary>\r
@@ -434,9 +438,16 @@ namespace HandBrake.ApplicationServices.Services
                 throw new Exception("Already Processing the Queue");\r
             }\r
 \r
-            this.IsProcessing = true;\r
+            this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;\r
             this.EncodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted;\r
-            this.ProcessNextJob();\r
+\r
+            if (!this.EncodeService.IsEncoding)\r
+            {\r
+                this.ProcessNextJob();\r
+            }\r
+\r
+            this.IsProcessing = true;\r
+            this.isPaused = false;\r
         }\r
 \r
         #endregion\r
@@ -471,12 +482,6 @@ namespace HandBrake.ApplicationServices.Services
             // Handling Log Data \r
             this.EncodeService.ProcessLogs(this.LastProcessedJob.Task.Destination);\r
 \r
-            // Post-Processing\r
-            if (e.Successful)\r
-            {\r
-                this.SendToApplication(this.LastProcessedJob.Task.Destination);\r
-            }\r
-\r
             // Move onto the next job.\r
             if (this.IsProcessing)\r
             {\r
@@ -490,35 +495,6 @@ namespace HandBrake.ApplicationServices.Services
             }\r
         }\r
 \r
-        /// <summary>\r
-        /// Perform an action after an encode. e.g a shutdown, standby, restart etc.\r
-        /// </summary>\r
-        private void Finish()\r
-        {\r
-            // Do something whent he encode ends.\r
-            switch (this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.WhenCompleteAction))\r
-            {\r
-                case "Shutdown":\r
-                    Process.Start("Shutdown", "-s -t 60");\r
-                    break;\r
-                case "Log off":\r
-                    Win32.ExitWindowsEx(0, 0);\r
-                    break;\r
-                case "Suspend":\r
-                    Application.SetSuspendState(PowerState.Suspend, true, true);\r
-                    break;\r
-                case "Hibernate":\r
-                    Application.SetSuspendState(PowerState.Hibernate, true, true);\r
-                    break;\r
-                case "Lock System":\r
-                    Win32.LockWorkStation();\r
-                    break;\r
-                case "Quit HandBrake":\r
-                    Execute.OnUIThread(Application.Exit);\r
-                    break;\r
-            }\r
-        }\r
-\r
         /// <summary>\r
         /// Invoke the JobProcessingStarted event\r
         /// </summary>\r
@@ -608,31 +584,6 @@ namespace HandBrake.ApplicationServices.Services
 \r
                 // Fire the event to tell connected services.\r
                 this.InvokeQueueCompleted(EventArgs.Empty);\r
-\r
-                // Run the After encode completeion work\r
-                this.Finish();\r
-            }\r
-        }\r
-\r
-        /// <summary>\r
-        /// Send a file to a 3rd party application after encoding has completed.\r
-        /// </summary>\r
-        /// <param name="file">\r
-        /// The file path\r
-        /// </param>\r
-        private void SendToApplication(string file)\r
-        {\r
-            if (this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.SendFile) &&\r
-                !string.IsNullOrEmpty(this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo)))\r
-            {\r
-                string args = string.Format(\r
-                    "{0} \"{1}\"", \r
-                    this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileToArgs), \r
-                    file);\r
-                var vlc =\r
-                    new ProcessStartInfo(\r
-                        this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo), args);\r
-                Process.Start(vlc);\r
             }\r
         }\r
 \r
index 96a12524875e47ed12cb3b62611d4c15be8937eb..c69320e1f738e98958012ba1319bc8906920bcce 100644 (file)
@@ -185,7 +185,9 @@ namespace HandBrake.ApplicationServices.Utilities
                 case "ffaac":\r
                     return "AAC (ffmpeg)";\r
                 case "ffflac":\r
-                    return "Flac (ffmpeg)";\r
+                    return "FLAC (ffmpeg)";\r
+                case "ffflac24":\r
+                    return "FLAC (24-bit)";\r
                 case "copy":\r
                     return "Auto Passthru";\r
                 default:\r
@@ -214,6 +216,8 @@ namespace HandBrake.ApplicationServices.Utilities
                     return AudioEncoder.Ac3;\r
                 case "ffflac":\r
                     return AudioEncoder.ffflac;\r
+                case "ffflac24":\r
+                    return AudioEncoder.ffflac24;\r
                 case "copy:ac3":\r
                     return AudioEncoder.Ac3Passthrough;\r
                 case "copy:dts":\r
@@ -262,8 +266,10 @@ namespace HandBrake.ApplicationServices.Utilities
                     return AudioEncoder.AacPassthru;\r
                 case "MP3 Passthru":\r
                     return AudioEncoder.Mp3Passthru;\r
-                case "Flac (ffmpeg)":\r
+                case "FLAC (ffmpeg)":\r
                     return AudioEncoder.ffflac;\r
+                case "FLAC (24-bit)":\r
+                    return AudioEncoder.ffflac24;\r
                 case "Auto Passthru":\r
                     return AudioEncoder.Passthrough;\r
                 default:\r
@@ -288,6 +294,7 @@ namespace HandBrake.ApplicationServices.Utilities
                     return "faac";\r
                 case AudioEncoder.ffaac:\r
                     return "ffaac";\r
+\r
                 case AudioEncoder.Lame:\r
                     return "lame";\r
                 case AudioEncoder.Vorbis:\r
@@ -308,6 +315,8 @@ namespace HandBrake.ApplicationServices.Utilities
                     return "copy";\r
                 case AudioEncoder.ffflac:\r
                     return "ffflac";\r
+                case AudioEncoder.ffflac24:\r
+                    return "ffflac24";\r
                 default:\r
                     return "faac";\r
             }\r
index 826ddd03a7cd63c246a2cc9186b82969bda91c10..42f075508049085525087d25e5bd72450a6cfc57 100644 (file)
@@ -67,13 +67,20 @@ namespace HandBrake.ApplicationServices.Utilities
                 // Delete old and excessivly large files (> ~50MB).\r
                 foreach (FileInfo file in logFiles)\r
                 {\r
-                    if (file.LastWriteTime < DateTime.Now.AddDays(-daysToKeep))\r
+                    try\r
                     {\r
-                        File.Delete(file.FullName);\r
+                        if (file.LastWriteTime < DateTime.Now.AddDays(-daysToKeep))\r
+                        {\r
+                            File.Delete(file.FullName);\r
+                        }\r
+                        else if (file.Length > 50000000)\r
+                        {\r
+                            File.Delete(file.FullName);\r
+                        }\r
                     }\r
-                    else if (file.Length > 50000000)\r
+                    catch (Exception)\r
                     {\r
-                        File.Delete(file.FullName);\r
+                        // Silently ignore files we can't delete. They are probably being used by the app right now.\r
                     }\r
                 }\r
             }\r
index 833c6d98940209ffd2226d58622751720e571586..bbfe8f62c36ec871dddaca570e8b809674f5334d 100644 (file)
 namespace HandBrake.ApplicationServices.Utilities\r
 {\r
     using System.Collections.Generic;\r
+    using System.Collections.Specialized;\r
 \r
     /// <summary>\r
     /// Language Utilities\r
     /// </summary>\r
     public class LanguageUtilities\r
     {\r
+        /// <summary>\r
+        /// The language map.\r
+        /// </summary>\r
+        private static IDictionary<string, string> languageMap;\r
+\r
         /// <summary>\r
         /// Map languages and their iso639_2 value into a IDictionary\r
         /// </summary>\r
         /// <returns>A Dictionary containing the language and iso code</returns>\r
         public static IDictionary<string, string> MapLanguages()\r
         {\r
-            IDictionary<string, string> languageMap = new Dictionary<string, string>\r
+            if (languageMap != null)\r
+            {\r
+                return languageMap;\r
+            }\r
+\r
+            languageMap = new Dictionary<string, string>\r
                                                           {\r
                                                               {"(Any)", "und"}, \r
                                                               {"Afar", "aar"}, \r
@@ -213,5 +224,30 @@ namespace HandBrake.ApplicationServices.Utilities
                                                           };\r
             return languageMap;\r
         }\r
+\r
+        /// <summary>\r
+        /// The get language codes.\r
+        /// </summary>\r
+        /// <param name="userLanguages">\r
+        /// The user languages.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="IList"/>.\r
+        /// </returns>\r
+        public static List<string> GetLanguageCodes(StringCollection userLanguages)\r
+        {\r
+            // Translate to Iso Codes\r
+            List<string> iso6392Codes = new List<string>();\r
+            foreach (var item in userLanguages)\r
+            {\r
+                string isoCode;\r
+                if (LanguageUtilities.MapLanguages().TryGetValue(item, out isoCode))\r
+                {\r
+                    iso6392Codes.Add(isoCode);\r
+                }\r
+            }\r
+\r
+            return iso6392Codes;\r
+        } \r
     }\r
 }\r
index 4ddcda7f927132e01a2895d4ecb396252279c202..a6a91cce7bec10b1e9fd31bd9a753c0c6b3474ac 100644 (file)
@@ -279,6 +279,8 @@ namespace HandBrake.ApplicationServices.Utilities
                 tune = tune == "none" ? "fastdecode" : tune + ",fastdecode";\r
             }\r
             AddEncodeElement(xmlWriter, "x264Tune", "string", tune);\r
+            AddEncodeElement(xmlWriter, "x264UseAdvancedOptions", "integer", parsed.ShowAdvancedTab ? "1" : "0");\r
+            \r
 \r
             int videoQualityType = 0;\r
             if (parsed.VideoBitrate != null) videoQualityType = 1;\r
index c8877e6d644d078dfe0bf15bbbfd5ffd5a24d9f1..8fb242ac60d608956c396c25f50bbdd6e4d21071 100644 (file)
@@ -49,7 +49,10 @@ namespace HandBrake.Interop.Model.Encoding
         [Display(Name = "Vorbis (vorbis)")]\r
         Vorbis,\r
 \r
-        [Display(Name = "Flac (ffmpeg)")]\r
+        [Display(Name = "FLAC (ffmpeg)")]\r
         ffflac,\r
+\r
+        [Display(Name = "FLAC (24-bit)")]\r
+        ffflac24,\r
     }\r
 }\r
index b6fc92736621447796cd201618c39d09f7f3daf9..d5c21ac0cd0498de86727e6b6093426104b468d6 100644 (file)
@@ -1,6 +1,5 @@
 ï»¿namespace HandBrake.Server\r
 {\r
-    using System;\r
     using System.Linq;\r
 \r
     using HandBrake.ApplicationServices.Services;\r
@@ -21,9 +20,6 @@
         {\r
             if (args.Count() != 1)\r
             {\r
-                //Console.WriteLine("Invalid Arguments");\r
-                //Console.ReadLine();\r
-\r
                 IServerService server = new ServerService();\r
                 server.Start("8001");\r
             }\r
diff --git a/win/CS/HandBrakeWPF/AttachedProperties/DriveMenu.cs b/win/CS/HandBrakeWPF/AttachedProperties/DriveMenu.cs
new file mode 100644 (file)
index 0000000..1149b57
--- /dev/null
@@ -0,0 +1,127 @@
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="DriveMenu.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   The drive menu.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.AttachedProperties\r
+{\r
+    using System;\r
+    using System.Collections.Generic;\r
+    using System.Linq;\r
+    using System.Windows;\r
+    using System.Windows.Controls;\r
+    using System.Windows.Media.Imaging;\r
+\r
+    using HandBrake.ApplicationServices.Utilities;\r
+\r
+    using HandBrakeWPF.Commands;\r
+    using HandBrakeWPF.Model;\r
+    using HandBrakeWPF.ViewModels;\r
+\r
+    /// <summary>\r
+    /// The drive menu.\r
+    /// </summary>\r
+    public class DriveMenu\r
+    {\r
+        /// <summary>\r
+        /// The show available drives property.\r
+        /// </summary>\r
+        public static readonly DependencyProperty ShowAvailableDrivesProperty = DependencyProperty.RegisterAttached(\r
+            "ShowAvailableDrives",\r
+            typeof(Boolean),\r
+            typeof(DriveMenu),\r
+            new PropertyMetadata(false, OnShowAvailableDrivesChanged));\r
+\r
+        /// <summary>\r
+        /// The get show available drives.\r
+        /// </summary>\r
+        /// <param name="element">\r
+        /// The element.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="bool"/>.\r
+        /// </returns>\r
+        public static Boolean GetShowAvailableDrives(MenuItem element)\r
+        {\r
+            bool result;\r
+            return bool.TryParse(element.GetValue(ShowAvailableDrivesProperty).ToString(), out result) && result;\r
+        }\r
+\r
+        /// <summary>\r
+        /// The set show available drives.\r
+        /// </summary>\r
+        /// <param name="element">\r
+        /// The element.\r
+        /// </param>\r
+        /// <param name="value">\r
+        /// The value.\r
+        /// </param>\r
+        public static void SetShowAvailableDrives(MenuItem element, Boolean value)\r
+        {\r
+            element.SetValue(ShowAvailableDrivesProperty, value);\r
+        }\r
+\r
+        /// <summary>\r
+        /// The on show available drives changed.\r
+        /// </summary>\r
+        /// <param name="d">\r
+        /// The d.\r
+        /// </param>\r
+        /// <param name="e">\r
+        /// The e.\r
+        /// </param>\r
+        private static void OnShowAvailableDrivesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\r
+        {\r
+            Menu menu = d as Menu;\r
+            if (menu != null)\r
+            {\r
+                menu.PreviewMouseDown -= MenuMouseDown;\r
+                menu.PreviewMouseDown += MenuMouseDown;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// The menu_ mouse down.\r
+        /// </summary>\r
+        /// <param name="sender">\r
+        /// The sender.\r
+        /// </param>\r
+        /// <param name="e">\r
+        /// The e.\r
+        /// </param>\r
+        private static void MenuMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)\r
+        {\r
+            Menu menu = sender as Menu;\r
+            if (menu != null)\r
+            {\r
+                MainViewModel mvm = menu.DataContext as MainViewModel;\r
+                if (mvm != null)\r
+                {\r
+                    List<SourceMenuItem> remove = mvm.SourceMenu.Where(s => s.IsDrive).ToList();\r
+                    foreach (var item in remove)\r
+                    {\r
+                        mvm.SourceMenu.Remove(item);\r
+                    }\r
+\r
+                    foreach (SourceMenuItem menuItem in from item in GeneralUtilities.GetDrives()\r
+                                                        let driveInformation = item\r
+                                                        select new SourceMenuItem\r
+                                                                   {\r
+                                                                       Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/disc_small.png")), Width = 16, Height = 16 },\r
+                                                                       Text = string.Format("{0} ({1})", item.RootDirectory, item.VolumeLabel),\r
+                                                                       Command = new SourceMenuCommand(() => mvm.ProcessDrive(driveInformation)),\r
+                                                                       Tag = item,\r
+                                                                       IsDrive = true\r
+                                                                   })\r
+                    {\r
+                        mvm.SourceMenu.Add(menuItem);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
index 862f08011794a67b602556a7c6da0a801124e129..1d279427af984c298d3f331b0ff0ecfb54e450fb 100644 (file)
@@ -23,5 +23,20 @@ namespace HandBrakeWPF
         /// The appcast 32.\r
         /// </summary>\r
         public const string Appcast32 = "http://handbrake.fr/appcast.i386.xml";\r
+\r
+        /// <summary>\r
+        /// The any.\r
+        /// </summary>\r
+        public const string Any = "(Any)";\r
+\r
+        /// <summary>\r
+        /// The chapters.\r
+        /// </summary>\r
+        public const string Chapters = "{chapters}";\r
+\r
+        /// <summary>\r
+        /// The title.\r
+        /// </summary>\r
+        public const string Title = "{title}";\r
     }\r
 }\r
diff --git a/win/CS/HandBrakeWPF/Controls/DropButton/DropButton.cs b/win/CS/HandBrakeWPF/Controls/DropButton/DropButton.cs
new file mode 100644 (file)
index 0000000..22383b8
--- /dev/null
@@ -0,0 +1,65 @@
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="DropButton.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   Defines the DropDownButton type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Controls.DropButton\r
+{\r
+    using System.Windows;\r
+    using System.Windows.Controls;\r
+    using System.Windows.Controls.Primitives;\r
+    using System.Windows.Data;\r
+\r
+    /// <summary>\r
+    /// The drop down button.\r
+    /// </summary>\r
+    public class DropButton : ToggleButton\r
+    {\r
+        /// <summary>\r
+        /// The drop down property.\r
+        /// </summary>\r
+        public static readonly DependencyProperty DropDownProperty =\r
+          DependencyProperty.Register("DropDown",\r
+                                      typeof(ContextMenu),\r
+                                      typeof(DropButton),\r
+                                      new UIPropertyMetadata(null));\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the <see cref="DropButton"/> class.\r
+        /// </summary>\r
+        public DropButton()\r
+        {\r
+            // Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property \r
+            Binding binding = new Binding("DropDown.IsOpen") { Source = this };\r
+            this.SetBinding(IsCheckedProperty, binding);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets or sets the drop down.\r
+        /// </summary>\r
+        public ContextMenu DropDown\r
+        {\r
+            get { return (ContextMenu)this.GetValue(DropDownProperty); }\r
+            set { this.SetValue(DropDownProperty, value); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Handle the users click on the button.\r
+        /// </summary>\r
+        protected override void OnClick()\r
+        {\r
+            if (this.DropDown != null)\r
+            {\r
+                // If there is a drop-down assigned to this button, then position and display it \r
+\r
+                this.DropDown.PlacementTarget = this;\r
+                this.DropDown.Placement = PlacementMode.Bottom;\r
+                this.DropDown.IsOpen = true;\r
+            }\r
+        }\r
+    }\r
+}\r
index 061dbd6e8641c18cc8f16c31bb6cba25e458368d..1db7a7c0a3411b5e1a04ff597721e0c232f662ab 100644 (file)
@@ -55,6 +55,7 @@ namespace HandBrakeWPF.Converters.Audio
                 {\r
                     encoders.Remove(AudioEncoder.Vorbis);\r
                     encoders.Remove(AudioEncoder.ffflac);\r
+                    encoders.Remove(AudioEncoder.ffflac24);\r
                 }\r
 \r
                 if (parameter != null && parameter.ToString() == "True")\r
index d7c81d8611010f96799ef70bd7467a7cb1125eee..85ee06fb78d8e98772f756e45202cbd93cc25fed 100644 (file)
       <Generator>MSBuild:Compile</Generator>\r
       <SubType>Designer</SubType>\r
     </ApplicationDefinition>\r
+    <Compile Include="AttachedProperties\DriveMenu.cs" />\r
     <Compile Include="AttachedProperties\MenuItemExtensions.cs" />\r
     <Compile Include="Commands\CancelScanCommand.cs" />\r
     <Compile Include="Commands\Interfaces\IAdvancedEncoderOptionsCommand.cs" />\r
     <Compile Include="Commands\SourceMenuCommand.cs" />\r
     <Compile Include="Commands\AdvancedEncoderOptionsCommand.cs" />\r
     <Compile Include="Constants.cs" />\r
+    <Compile Include="Controls\DropButton\DropButton.cs" />\r
     <Compile Include="Controls\TimeSpanBox.xaml.cs">\r
       <DependentUpon>TimeSpanBox.xaml</DependentUpon>\r
     </Compile>\r
     <Compile Include="Helpers\GrowlCommunicator.cs" />\r
     <Compile Include="Model\OptionsTab.cs" />\r
     <Compile Include="Model\SelectionTitle.cs" />\r
-    <Compile Include="Services\DriveDetectService.cs" />\r
     <Compile Include="Services\EncodeServiceWrapper.cs" />\r
-    <Compile Include="Services\Interfaces\IDriveDetectService.cs" />\r
     <Compile Include="Model\ShellWindow.cs" />\r
     <Compile Include="Model\SourceMenuItem.cs" />\r
     <Compile Include="Model\UpdateCheckInformation.cs" />\r
     <Compile Include="Model\DownloadStatus.cs" />\r
     <Compile Include="Services\Interfaces\INotificationService.cs" />\r
     <Compile Include="Services\Interfaces\IUpdateService.cs" />\r
+    <Compile Include="Services\Interfaces\IPrePostActionService.cs" />\r
     <Compile Include="Services\NotificationService.cs" />\r
     <Compile Include="Services\ScanServiceWrapper.cs" />\r
     <Compile Include="Services\UpdateService.cs" />\r
+    <Compile Include="Services\PrePostActionService.cs" />\r
     <Compile Include="ViewModels\AdvancedViewModel.cs" />\r
     <Compile Include="ViewModels\EncoderOptionsViewModel.cs" />\r
     <Compile Include="ViewModels\Interfaces\IEncoderOptionsViewModel.cs" />\r
     <EmbeddedResource Include="Properties\Resources.resx">\r
       <Generator>PublicResXFileCodeGenerator</Generator>\r
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>\r
+      <SubType>Designer</SubType>\r
     </EmbeddedResource>\r
     <None Include="app.config" />\r
     <None Include="Installer\Installer.nsi" />\r
index 5c4e83cb1ecc6cfe07692289373cecc34240210b..2298eb4aba307119399023b9208967febb238fcf 100644 (file)
@@ -79,8 +79,8 @@ namespace HandBrakeWPF.Helpers
                 {\r
                     destinationFilename = userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat);\r
                     destinationFilename = destinationFilename.Replace("{source}", sourceName)\r
-                                                             .Replace("{title}", dvdTitle)\r
-                                                             .Replace("{chapters}", combinedChapterTag)\r
+                                                             .Replace(Constants.Title, dvdTitle)\r
+                                                             .Replace(Constants.Chapters, combinedChapterTag)\r
                                                              .Replace("{date}", DateTime.Now.Date.ToShortDateString().Replace('/', '-'));\r
                 }\r
                 else\r
index 2e69eacecc6dacd5761ff61c7c47fc8ea1f876ef..0060b1d157a132d17e35faca694648f9c1805131 100644 (file)
@@ -14,6 +14,7 @@ namespace HandBrakeWPF.Helpers
     using System.IO;\r
     using System.Security.Cryptography;\r
     using System.Text.RegularExpressions;\r
+    using System.Windows.Forms;\r
 \r
     using Caliburn.Micro;\r
 \r
@@ -43,7 +44,7 @@ namespace HandBrakeWPF.Helpers
 \r
             // Get the SHA1 Hash of HandBrakeCLI\r
             byte[] hash;\r
-            using (Stream stream = File.OpenRead("HandBrakeCLI.exe"))\r
+            using (Stream stream = File.OpenRead(Path.Combine(Application.StartupPath, "HandBrakeCLI.exe")))\r
             {\r
                 hash = SHA1.Create().ComputeHash(stream);\r
             }\r
@@ -58,7 +59,7 @@ namespace HandBrakeWPF.Helpers
 \r
             // It's not the same, so start the CLI to get it's version data.\r
             Process cliProcess = new Process();\r
-            ProcessStartInfo handBrakeCli = new ProcessStartInfo("HandBrakeCLI.exe", " -u -v0")\r
+            ProcessStartInfo handBrakeCli = new ProcessStartInfo(Path.Combine(Application.StartupPath, "HandBrakeCLI.exe"), " -u -v0")\r
                 {\r
                     UseShellExecute = false,\r
                     RedirectStandardError = true,\r
index fd1b72b5b13e55f1de319545b7555e9e316c2684..c22572b2456aa9bf5971a729ce5dc96be918b7d4 100644 (file)
@@ -8,8 +8,8 @@
 \r
 ; HM NIS Edit Wizard helper defines\r
 !define PRODUCT_NAME "HandBrake"\r
-!define PRODUCT_VERSION "0.9.9"\r
-!define PRODUCT_VERSION_NUMBER "0.9.9"\r
+!define PRODUCT_VERSION "0.9.9.1"\r
+!define PRODUCT_VERSION_NUMBER "0.9.9.1"\r
 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Handbrake.exe"\r
 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"\r
 !define PRODUCT_UNINST_ROOT_KEY "HKLM"\r
index 6840fb270d2d61d98f76d6be74e6744778f2c2b0..609585c7713d7750ea190cdab30fbe393de33bee 100644 (file)
@@ -8,8 +8,8 @@
 \r
 ; HM NIS Edit Wizard helper defines\r
 !define PRODUCT_NAME "HandBrake"\r
-!define PRODUCT_VERSION "0.9.9"\r
-!define PRODUCT_VERSION_NUMBER "0.9.9"\r
+!define PRODUCT_VERSION "0.9.9.1"\r
+!define PRODUCT_VERSION_NUMBER "0.9.9.1"\r
 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Handbrake.exe"\r
 !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"\r
 !define PRODUCT_UNINST_ROOT_KEY "HKLM"\r
index b0c4a9766e51e15387c66c14469c9b242f56ac10..f0b80984961a0f9ab0f5820d1be2e4fa967eddb3 100644 (file)
@@ -46,6 +46,11 @@ namespace HandBrakeWPF.Model
         /// </summary>\r
         public ObservableCollection<SourceMenuItem> Children { get; set; }\r
 \r
+        /// <summary>\r
+        /// Gets or sets a value indicating whether is drive.\r
+        /// </summary>\r
+        public bool IsDrive { get; set; }\r
+\r
         /// <summary>\r
         /// Gets or sets the tag.\r
         /// </summary>\r
index 7db59a4d0639a75c164312902fc060b9f29cb3ec..bef7d703005f53253dc4e46fcc94220e48eb7529 100644 (file)
@@ -1,7 +1,7 @@
 ï»¿//------------------------------------------------------------------------------\r
 // <auto-generated>\r
 //     This code was generated by a tool.\r
-//     Runtime Version:4.0.30319.296\r
+//     Runtime Version:4.0.30319.18047\r
 //\r
 //     Changes to this file may cause incorrect behavior and will be lost if\r
 //     the code is regenerated.\r
@@ -80,13 +80,13 @@ namespace HandBrakeWPF.Properties {
         }\r
         \r
         /// <summary>\r
-        ///   Looks up a localized string similar to You can optionally store a maximum resolution for encodes that use this preset. There are 3 modes:\r
+        ///   Looks up a localized string similar to You can optionally store a maximum resolution for encodes that use this preset. There are 4 modes:\r
         ///\r
-        ///None:  There is no maximum resolution for encodes using this preset. They will always use the source resolution minus any cropping that may be applied.\r
+        ///None:  There is no maximum resolution for encodes using this preset. When the preset is loaded, the current width, height and aspect ratio that you currently have set will be reloaded.\r
         ///\r
-        ///Custom: You can optionally set a Maximum width and height. When doing this an encode will be less than or equal to these values.\r
+        ///Custom: You can optionally set a Maximum width and Height. When doing this an encode will be less than or equal to these values. Keep Aspect Ratio will be automatically turned on.\r
         ///\r
-        ///Source Maximum:  Similar to custom, but the resolution of your current source is used as the Max width and Height values in [rest of string was truncated]&quot;;.\r
+        ///Source Maximum:  Similar to custom, but [rest of string was truncated]&quot;;.\r
         /// </summary>\r
         public static string AddPreset_PictureSizeMode {\r
             get {\r
@@ -337,6 +337,9 @@ namespace HandBrakeWPF.Properties {
             }\r
         }\r
         \r
+        /// <summary>\r
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.\r
+        /// </summary>\r
         public static System.Drawing.Bitmap logo64 {\r
             get {\r
                 object obj = ResourceManager.GetObject("logo64", resourceCulture);\r
@@ -344,6 +347,24 @@ namespace HandBrakeWPF.Properties {
             }\r
         }\r
         \r
+        /// <summary>\r
+        ///   Looks up a localized string similar to WARNING: You do not have automatic file naming turned on. Please enable this in options..\r
+        /// </summary>\r
+        public static string QueueSelection_AutoNameWarning {\r
+            get {\r
+                return ResourceManager.GetString("QueueSelection_AutoNameWarning", resourceCulture);\r
+            }\r
+        }\r
+        \r
+        /// <summary>\r
+        ///   Looks up a localized string similar to WARNING: You do not currently have automatic audio and subtitle track selection setup. You can setup the default track selection behaviour in options..\r
+        /// </summary>\r
+        public static string QueueSelection_AutoTrackSelectionWarning {\r
+            get {\r
+                return ResourceManager.GetString("QueueSelection_AutoTrackSelectionWarning", resourceCulture);\r
+            }\r
+        }\r
+        \r
         /// <summary>\r
         ///   Looks up a localized string similar to Warning: RF 0 is Lossless!.\r
         /// </summary>\r
index fed5d3923cd5dcc4a5600abd3e2da05fb7ea347f..180d0abc56cb7bb71640ad1bee87926a09623674 100644 (file)
@@ -292,13 +292,15 @@ So small increases in value will result in progressively larger increases in the
 Suggested values are: 18 to 20 for Standard Definition and 20 to 23 for High Definition.</value>\r
   </data>\r
   <data name="AddPreset_PictureSizeMode" xml:space="preserve">\r
-    <value>You can optionally store a maximum resolution for encodes that use this preset. There are 3 modes:\r
+    <value>You can optionally store a maximum resolution for encodes that use this preset. There are 4 modes:\r
 \r
-None:  There is no maximum resolution for encodes using this preset. They will always use the source resolution minus any cropping that may be applied.\r
+None:  There is no maximum resolution for encodes using this preset. When the preset is loaded, the current width, height and aspect ratio that you currently have set will be reloaded.\r
 \r
-Custom: You can optionally set a Maximum width and height. When doing this an encode will be less than or equal to these values.\r
+Custom: You can optionally set a Maximum width and Height. When doing this an encode will be less than or equal to these values. Keep Aspect Ratio will be automatically turned on.\r
 \r
-Source Maximum:  Similar to custom, but the resolution of your current source is used as the Max width and Height values instead.</value>\r
+Source Maximum:  Similar to custom, but the resolution of your current source is used as the Max width and Height values instead. Keep Aspect Ratio will be automatically turned on.\r
+\r
+No Limit: Always use the full source resolution for all sources keeping aspect ratio. This is the default behaviour.</value>\r
   </data>\r
   <data name="Advanced_EncoderOptions" xml:space="preserve">\r
     <value>The options passed to the x264 encoder. \r
@@ -329,4 +331,10 @@ To enable this tab, check the "Use Advanced Tab instead" option on the Video Tab
 \r
 If you do not use this tab, it can be hidden from: Tools Menu &gt; Options &gt; Advanced.</value>\r
   </data>\r
+  <data name="QueueSelection_AutoNameWarning" xml:space="preserve">\r
+    <value>WARNING: You do not have automatic file naming turned on. Please enable this in options.</value>\r
+  </data>\r
+  <data name="QueueSelection_AutoTrackSelectionWarning" xml:space="preserve">\r
+    <value>WARNING: You do not currently have automatic audio and subtitle track selection setup. You can setup the default track selection behaviour in options.</value>\r
+  </data>\r
 </root>
\ No newline at end of file
diff --git a/win/CS/HandBrakeWPF/Services/DriveDetectService.cs b/win/CS/HandBrakeWPF/Services/DriveDetectService.cs
deleted file mode 100644 (file)
index 3a4ef51..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------\r
-// <copyright file="DriveDetectService.cs" company="HandBrake Project (http://handbrake.fr)">\r
-//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
-// </copyright>\r
-// <summary>\r
-//   Drive Detection Helper.\r
-// </summary>\r
-// --------------------------------------------------------------------------------------------------------------------\r
-\r
-namespace HandBrakeWPF.Services\r
-{\r
-    using System;\r
-    using System.Management;\r
-    using System.Threading;\r
-\r
-    using HandBrakeWPF.Services.Interfaces;\r
-\r
-    /// <summary>\r
-    /// Drive Detection Helper.\r
-    /// </summary>\r
-    public class DriveDetectService : IDriveDetectService\r
-    {\r
-        /// <summary>\r
-        /// The watcher.\r
-        /// </summary>\r
-        private ManagementEventWatcher watcher;\r
-\r
-        /// <summary>\r
-        /// The detection action.\r
-        /// </summary>\r
-        private Action detectionAction;\r
-\r
-        /// <summary>\r
-        /// The start detection.\r
-        /// </summary>\r
-        /// <param name="action">\r
-        /// The detection Action.\r
-        /// </param>\r
-        public void StartDetection(Action action)\r
-        {\r
-            ThreadPool.QueueUserWorkItem(\r
-                delegate\r
-                {\r
-                    this.detectionAction = action;\r
-\r
-                    var options = new ConnectionOptions { EnablePrivileges = true };\r
-                    var scope = new ManagementScope(@"root\CIMV2", options);\r
-\r
-                    try\r
-                    {\r
-                        var query = new WqlEventQuery\r
-                        {\r
-                            EventClassName = "__InstanceModificationEvent",\r
-                            WithinInterval = TimeSpan.FromSeconds(1),\r
-                            Condition = @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5" // DriveType - 5: CDROM\r
-                        };\r
-\r
-                        this.watcher = new ManagementEventWatcher(scope, query);\r
-                        this.watcher.EventArrived += this.WatcherEventArrived;\r
-                        this.watcher.Start();\r
-                    }\r
-                    catch (Exception e)\r
-                    {\r
-                        Console.WriteLine(e.Message);\r
-                    }\r
-                });\r
-        }\r
-\r
-        /// <summary>\r
-        /// The close.\r
-        /// </summary>\r
-        public void Close()\r
-        {\r
-            if (watcher != null)\r
-            {\r
-                this.watcher.Stop();\r
-            }\r
-        }\r
-\r
-        /// <summary>\r
-        /// The watcher_ event arrived.\r
-        /// </summary>\r
-        /// <param name="sender">\r
-        /// The sender.\r
-        /// </param>\r
-        /// <param name="e">\r
-        /// The EventArrivedEventArgs.\r
-        /// </param>\r
-        private void WatcherEventArrived(object sender, EventArrivedEventArgs e)\r
-        {\r
-            if (this.detectionAction != null)\r
-            {\r
-                this.detectionAction();\r
-            }\r
-        }\r
-    }\r
-}\r
diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/IDriveDetectService.cs b/win/CS/HandBrakeWPF/Services/Interfaces/IDriveDetectService.cs
deleted file mode 100644 (file)
index 16ef42a..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------\r
-// <copyright file="IDriveDetectService.cs" company="HandBrake Project (http://handbrake.fr)">\r
-//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
-// </copyright>\r
-// <summary>\r
-//   Defines the IDriveDetectService type.\r
-// </summary>\r
-// --------------------------------------------------------------------------------------------------------------------\r
-\r
-namespace HandBrakeWPF.Services.Interfaces\r
-{\r
-    using System;\r
-\r
-    /// <summary>\r
-    /// The DriveDetectService interface.\r
-    /// </summary>\r
-    public interface IDriveDetectService\r
-    {\r
-        /// <summary>\r
-        /// The start detection.\r
-        /// </summary>\r
-        /// <param name="action">\r
-        /// The detection Action.\r
-        /// </param>\r
-        void StartDetection(Action action);\r
-\r
-        /// <summary>\r
-        /// Stop the watcher. Must be done before the app shuts down.\r
-        /// </summary>\r
-        void Close();\r
-    }\r
-}
\ No newline at end of file
index d955bb55c7387532e33d40b03b6b962bdfc86475..8a20c274eace3082f25376d6059512c5475a7d1e 100644 (file)
@@ -1,5 +1,17 @@
-namespace HandBrakeWPF.Services.Interfaces\r
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="INotificationService.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   Defines the INotificationService type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Services.Interfaces\r
 {\r
+    /// <summary>\r
+    /// The NotificationService interface.\r
+    /// </summary>\r
     public interface INotificationService\r
     {\r
     }\r
diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/IPrePostActionService.cs b/win/CS/HandBrakeWPF/Services/Interfaces/IPrePostActionService.cs
new file mode 100644 (file)
index 0000000..fcd164a
--- /dev/null
@@ -0,0 +1,18 @@
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="IPrePostActionService.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   Defines the IPrePostActionService type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Services.Interfaces\r
+{\r
+    /// <summary>\r
+    /// The WhenDoneService interface.\r
+    /// </summary>\r
+    public interface IPrePostActionService\r
+    {\r
+    }\r
+}\r
diff --git a/win/CS/HandBrakeWPF/Services/PrePostActionService.cs b/win/CS/HandBrakeWPF/Services/PrePostActionService.cs
new file mode 100644 (file)
index 0000000..ce4eee4
--- /dev/null
@@ -0,0 +1,159 @@
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="WhenDoneService.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   Defines the WhenDoneService type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Services\r
+{\r
+    using System.Diagnostics;\r
+    using System.Windows.Forms;\r
+\r
+    using Caliburn.Micro;\r
+\r
+    using HandBrake.ApplicationServices.Services.Interfaces;\r
+    using HandBrake.ApplicationServices.Utilities;\r
+\r
+    using HandBrakeWPF.Services.Interfaces;\r
+\r
+    using Application = System.Windows.Application;\r
+\r
+    /// <summary>\r
+    /// The when done service.\r
+    /// </summary>\r
+    public class PrePostActionService : IPrePostActionService\r
+    {\r
+        /// <summary>\r
+        /// The queue processor.\r
+        /// </summary>\r
+        private readonly IQueueProcessor queueProcessor;\r
+\r
+        /// <summary>\r
+        /// The user setting service.\r
+        /// </summary>\r
+        private readonly IUserSettingService userSettingService;\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the <see cref="PrePostActionService"/> class.\r
+        /// </summary>\r
+        /// <param name="queueProcessor">\r
+        /// The queue processor.\r
+        /// </param>\r
+        /// <param name="userSettingService">\r
+        /// The user Setting Service.\r
+        /// </param>\r
+        public PrePostActionService(IQueueProcessor queueProcessor, IUserSettingService userSettingService)\r
+        {\r
+            this.queueProcessor = queueProcessor;\r
+            this.userSettingService = userSettingService;\r
+\r
+            this.queueProcessor.QueueCompleted += QueueProcessorQueueCompleted;\r
+            this.queueProcessor.EncodeService.EncodeCompleted += EncodeService_EncodeCompleted;\r
+            this.queueProcessor.EncodeService.EncodeStarted += EncodeService_EncodeStarted;\r
+        }\r
+\r
+        /// <summary>\r
+        /// The encode service_ encode started.\r
+        /// </summary>\r
+        /// <param name="sender">\r
+        /// The sender.\r
+        /// </param>\r
+        /// <param name="e">\r
+        /// The e.\r
+        /// </param>\r
+        private void EncodeService_EncodeStarted(object sender, System.EventArgs e)\r
+        {\r
+            if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))\r
+            {\r
+                Win32.PreventSleep();\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// The encode service_ encode completed.\r
+        /// </summary>\r
+        /// <param name="sender">\r
+        /// The sender.\r
+        /// </param>\r
+        /// <param name="e">\r
+        /// The EncodeCompletedEventArgs.\r
+        /// </param>\r
+        private void EncodeService_EncodeCompleted(object sender, HandBrake.ApplicationServices.EventArgs.EncodeCompletedEventArgs e)\r
+        {\r
+            // Send the file to the users requested applicaiton\r
+            if (e.Successful)\r
+            {\r
+                this.SendToApplication(e.FileName);\r
+            }\r
+\r
+            // Allow the system to sleep again.\r
+            Execute.OnUIThread(() =>\r
+            {\r
+                if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))\r
+                {\r
+                    Win32.AllowSleep();\r
+                }\r
+            });\r
+        }\r
+\r
+        /// <summary>\r
+        /// The queue processor queue completed event handler.\r
+        /// </summary>\r
+        /// <param name="sender">\r
+        /// The sender.\r
+        /// </param>\r
+        /// <param name="e">\r
+        /// The e.\r
+        /// </param>\r
+        private void QueueProcessorQueueCompleted(object sender, System.EventArgs e)\r
+        {\r
+            // Do something whent he encode ends.\r
+            switch (this.userSettingService.GetUserSetting<string>(UserSettingConstants.WhenCompleteAction))\r
+            {\r
+                case "Shutdown":\r
+                    Process.Start("Shutdown", "-s -t 60");\r
+                    break;\r
+                case "Log off":\r
+                    Win32.ExitWindowsEx(0, 0);\r
+                    break;\r
+                case "Suspend":\r
+                    System.Windows.Forms.Application.SetSuspendState(PowerState.Suspend, true, true);\r
+                    break;\r
+                case "Hibernate":\r
+                    System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, true, true);\r
+                    break;\r
+                case "Lock System":\r
+                    Win32.LockWorkStation();\r
+                    break;\r
+                case "Quit HandBrake":\r
+                    Execute.OnUIThread(() => Application.Current.Shutdown());\r
+                    break;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Send a file to a 3rd party application after encoding has completed.\r
+        /// </summary>\r
+        /// <param name="file">\r
+        /// The file path\r
+        /// </param>\r
+        private void SendToApplication(string file)\r
+        {\r
+            if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.SendFile) &&\r
+                !string.IsNullOrEmpty(this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo)))\r
+            {\r
+                string args = string.Format(\r
+                    "{0} \"{1}\"",\r
+                    this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileToArgs),\r
+                    file);\r
+                var vlc =\r
+                    new ProcessStartInfo(\r
+                        this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo), args);\r
+                Process.Start(vlc);\r
+            }\r
+        }\r
+    }\r
+}\r
index 6f3428de35cd8413399b0fe2cf8092ca7772f8a8..87a92824a9d5d3d92dc512b637956eb71f6d4718 100644 (file)
@@ -57,10 +57,10 @@ namespace HandBrakeWPF.Startup
 \r
             // Services\r
             this.windsorContainer.Register(Component.For<IUpdateService>().ImplementedBy<UpdateService>().LifeStyle.Is(LifestyleType.Singleton));\r
-            this.windsorContainer.Register(Component.For<IDriveDetectService>().ImplementedBy<DriveDetectService>().LifeStyle.Is(LifestyleType.Singleton));\r
             this.windsorContainer.Register(Component.For<IScanServiceWrapper>().ImplementedBy<ScanServiceWrapper>().LifeStyle.Is(LifestyleType.Singleton));\r
             this.windsorContainer.Register(Component.For<IEncodeServiceWrapper>().ImplementedBy<EncodeServiceWrapper>().LifeStyle.Is(LifestyleType.Singleton));\r
             this.windsorContainer.Register(Component.For<INotificationService>().ImplementedBy<NotificationService>().LifeStyle.Is(LifestyleType.Singleton));\r
+            this.windsorContainer.Register(Component.For<IPrePostActionService>().ImplementedBy<PrePostActionService>().LifeStyle.Is(LifestyleType.Singleton));\r
 \r
             // Commands\r
             this.windsorContainer.Register(Component.For<IAdvancedEncoderOptionsCommand>().ImplementedBy<AdvancedEncoderOptionsCommand>().LifeStyle.Is(LifestyleType.Singleton));\r
index 1f4c02fce386474cade09d6e1741b240d689aec7..b70d8865485e3cfa440b9e9921853085fc08ab5f 100644 (file)
@@ -200,6 +200,31 @@ namespace HandBrakeWPF
         /// Disable LibHb Features\r
         /// </summary>\r
         public const string DisableLibHbFeatures = "DisableLibHbFeatures";\r
+    \r
+        /// <summary>\r
+        /// When Complete Action\r
+        /// </summary>\r
+        public const string WhenCompleteAction = "WhenCompleteAction";\r
+\r
+        /// <summary>\r
+        /// Send file enabled.\r
+        /// </summary>\r
+        public const string SendFile = "SendFile";\r
+\r
+        /// <summary>\r
+        /// Send file to application path\r
+        /// </summary>\r
+        public const string SendFileTo = "SendFileTo";\r
+\r
+        /// <summary>\r
+        /// Send file to arguments\r
+        /// </summary>\r
+        public const string SendFileToArgs = "SendFileToArgs";\r
+\r
+        /// <summary>\r
+        /// Prevent Sleep\r
+        /// </summary>\r
+        public const string PreventSleep = "PreventSleep";\r
 \r
         #endregion\r
     }\r
index f4f496fcb24cc0112b2b6dc90518a3853bf2793c..488f58d74749609435ed0a32e71585fe5daa2dba 100644 (file)
@@ -13,6 +13,7 @@ namespace HandBrakeWPF.ViewModels
     using System.Windows;\r
 \r
     using HandBrake.ApplicationServices.Model;\r
+    using HandBrake.ApplicationServices.Parsing;\r
     using HandBrake.ApplicationServices.Services;\r
     using HandBrake.ApplicationServices.Services.Interfaces;\r
     using HandBrake.ApplicationServices.Utilities;\r
@@ -25,8 +26,6 @@ namespace HandBrakeWPF.ViewModels
     /// </summary>\r
     public class AddPresetViewModel : ViewModelBase, IAddPresetViewModel\r
     {\r
-        /* TODO this window is up for redesign. Quite a few nippy edge cases that can cause odd behaviour with importing presets. */\r
-\r
         /// <summary>\r
         /// Backing field for the Preset Service\r
         /// </summary>\r
@@ -47,6 +46,11 @@ namespace HandBrakeWPF.ViewModels
         /// </summary>\r
         private bool showCustomInputs;\r
 \r
+        /// <summary>\r
+        /// The source.\r
+        /// </summary>\r
+        private Title selectedTitle;\r
+\r
         /// <summary>\r
         /// Initializes a new instance of the <see cref="AddPresetViewModel"/> class.\r
         /// </summary>\r
@@ -123,9 +127,10 @@ namespace HandBrakeWPF.ViewModels
         /// <param name="task">\r
         /// The Encode Task.\r
         /// </param>\r
-        public void Setup(EncodeTask task)\r
+        public void Setup(EncodeTask task, Title title)\r
         {\r
             this.Preset.Task = new EncodeTask(task);\r
+            this.selectedTitle = title;\r
         }\r
 \r
         /// <summary>\r
@@ -148,7 +153,7 @@ namespace HandBrakeWPF.ViewModels
                }\r
             }\r
 \r
-            if (this.SelectedPictureSettingMode == PresetPictureSettingsMode.SourceMaximum && (this.Preset.Task.Width == null || this.Preset.Task.Width == 0))\r
+            if (this.SelectedPictureSettingMode == PresetPictureSettingsMode.SourceMaximum && this.selectedTitle == null)\r
             {\r
                 this.errorService.ShowMessageBox("You must first scan a source to use the 'Source Maximum' Option.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);\r
                 return;\r
@@ -174,8 +179,8 @@ namespace HandBrakeWPF.ViewModels
 \r
             if (this.SelectedPictureSettingMode == PresetPictureSettingsMode.SourceMaximum)\r
             {\r
-                this.Preset.Task.MaxWidth = this.Preset.Task.Width;\r
-                this.Preset.Task.MaxHeight = this.Preset.Task.Height;\r
+                this.Preset.Task.MaxWidth = selectedTitle.Resolution.Width;\r
+                this.Preset.Task.MaxHeight = selectedTitle.Resolution.Height;\r
             }\r
 \r
             // Add the Preset\r
index 2146b1c6ccaafdc597a92a745b5780b131711ad4..ee9b09f31dc429506798e89d92584830ea9aaa78 100644 (file)
@@ -38,6 +38,9 @@ namespace HandBrakeWPF.ViewModels
         /// </summary>\r
         private IEnumerable<Audio> sourceTracks;\r
 \r
+        /// <summary>\r
+        /// The current preset.\r
+        /// </summary>\r
         private Preset currentPreset;\r
 \r
         #region Constructors and Destructors\r
@@ -414,9 +417,15 @@ namespace HandBrakeWPF.ViewModels
         private IEnumerable<Audio> GetSelectedLanguagesTracks()\r
         {\r
             List<Audio> trackList = new List<Audio>();\r
-            foreach (string language in this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages))\r
+\r
+\r
+            List<string> isoCodes =\r
+                LanguageUtilities.GetLanguageCodes(\r
+                    this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages));\r
+\r
+            foreach (string code in isoCodes)\r
             {\r
-                trackList.AddRange(this.SourceTracks.Where(source => source.Language.Trim() == language));\r
+                trackList.AddRange(this.SourceTracks.Where(source => source.LanguageCode.Trim() == code));\r
             }\r
 \r
             return trackList;\r
index 1d5342e0156ab4e16fcd8ba0c8fe7978a761ab93..ac0ec160fc7a0910d9473d3af05e49e6119dd9e8 100644 (file)
@@ -10,6 +10,7 @@
 namespace HandBrakeWPF.ViewModels.Interfaces\r
 {\r
     using HandBrake.ApplicationServices.Model;\r
+    using HandBrake.ApplicationServices.Parsing;\r
 \r
     /// <summary>\r
     /// The Add Preset View Model\r
@@ -22,6 +23,9 @@ namespace HandBrakeWPF.ViewModels.Interfaces
         /// <param name="task">\r
         /// The Encode Task.\r
         /// </param>\r
-        void Setup(EncodeTask task);\r
+        /// <param name="title">\r
+        /// The title.\r
+        /// </param>\r
+        void Setup(EncodeTask task, Title title);\r
     }\r
 }\r
index 36a64846ad8adeeb02395a3560894eaebc838af8..c9c0e38bdae281eb8ed41f93158f1142bd28f6b7 100644 (file)
@@ -9,6 +9,7 @@
 \r
 namespace HandBrakeWPF.ViewModels.Interfaces\r
 {\r
+    using System;\r
     using System.Collections.Generic;\r
     using System.ComponentModel;\r
 \r
@@ -35,6 +36,9 @@ namespace HandBrakeWPF.ViewModels.Interfaces
         /// <param name="sourceName">\r
         /// The source Name.\r
         /// </param>\r
-        void Setup(Source scannedSource, string sourceName);\r
+        /// <param name="addAction">\r
+        /// The add To Queue action\r
+        /// </param>\r
+        void Setup(Source scannedSource, string sourceName, Action<IEnumerable<SelectionTitle>> addAction);\r
     }\r
 }\r
index fd465d480d3998b397dd197d94b53e9a25863417..fd896f197998972fc4ffa84294f310eb0a367514 100644 (file)
@@ -11,6 +11,7 @@ namespace HandBrakeWPF.ViewModels
 {\r
     using System;\r
     using System.Collections.Generic;\r
+    using System.ComponentModel;\r
     using System.Diagnostics;\r
     using System.Globalization;\r
     using System.IO;\r
@@ -74,11 +75,6 @@ namespace HandBrakeWPF.ViewModels
         /// </summary>\r
         private readonly IUpdateService updateService;\r
 \r
-        /// <summary>\r
-        /// The drive detect service.\r
-        /// </summary>\r
-        private readonly IDriveDetectService driveDetectService;\r
-\r
         /// <summary>\r
         /// Backing field for the user setting service.\r
         /// </summary>\r
@@ -167,7 +163,7 @@ namespace HandBrakeWPF.ViewModels
         /// <summary>\r
         /// The Source Menu Backing Field\r
         /// </summary>\r
-        private IEnumerable<SourceMenuItem> sourceMenu;\r
+        private BindingList<SourceMenuItem> sourceMenu;\r
 \r
         /// <summary>\r
         /// The last percentage complete value.\r
@@ -200,15 +196,17 @@ namespace HandBrakeWPF.ViewModels
         /// <param name="updateService">\r
         /// The update Service.\r
         /// </param>\r
-        /// <param name="driveDetectService">\r
-        /// The drive Detect Service.\r
-        /// </param>\r
         /// <param name="notificationService">\r
         /// The notification Service.\r
-        /// *** Leave in Constructor. ***  TODO find out why?\r
+        /// *** Leave in Constructor. *** \r
+        /// </param>\r
+        /// <param name="whenDoneService">\r
+        /// The when Done Service.\r
+        /// *** Leave in Constructor. *** \r
         /// </param>\r
         public MainViewModel(IUserSettingService userSettingService, IScanServiceWrapper scanService, IEncodeServiceWrapper encodeService, IPresetService presetService,\r
-            IErrorService errorService, IShellViewModel shellViewModel, IUpdateService updateService, IDriveDetectService driveDetectService, INotificationService notificationService)\r
+            IErrorService errorService, IShellViewModel shellViewModel, IUpdateService updateService, INotificationService notificationService,\r
+            IPrePostActionService whenDoneService)\r
         {\r
             this.scanService = scanService;\r
             this.encodeService = encodeService;\r
@@ -216,7 +214,6 @@ namespace HandBrakeWPF.ViewModels
             this.errorService = errorService;\r
             this.shellViewModel = shellViewModel;\r
             this.updateService = updateService;\r
-            this.driveDetectService = driveDetectService;\r
             this.userSettingService = userSettingService;\r
             this.queueProcessor = IoC.Get<IQueueProcessor>();\r
 \r
@@ -343,7 +340,7 @@ namespace HandBrakeWPF.ViewModels
         /// <summary>\r
         /// Gets or sets the source menu.\r
         /// </summary>\r
-        public IEnumerable<SourceMenuItem> SourceMenu\r
+        public BindingList<SourceMenuItem> SourceMenu\r
         {\r
             get\r
             {\r
@@ -695,7 +692,10 @@ namespace HandBrakeWPF.ViewModels
 \r
                     if (this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming))\r
                     {\r
-                        this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+                        if (this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null )\r
+                        {\r
+                            this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+                        }\r
                     }\r
                     this.NotifyOfPropertyChange(() => this.CurrentTask);\r
 \r
@@ -746,7 +746,16 @@ namespace HandBrakeWPF.ViewModels
 \r
                 if (this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming) && this.ScannedSource.ScanPath != null)\r
                 {\r
-                    this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+                    if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null &&\r
+                        this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters))\r
+                    {\r
+                        this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
+                    }\r
+                }\r
+\r
+                if (this.SelectedStartPoint > this.SelectedEndPoint)\r
+                {\r
+                    this.SelectedEndPoint = this.SelectedStartPoint;\r
                 }\r
             }\r
         }\r
@@ -766,10 +775,16 @@ namespace HandBrakeWPF.ViewModels
                 this.NotifyOfPropertyChange(() => this.SelectedEndPoint);\r
                 this.Duration = this.DurationCalculation();\r
 \r
-                if (this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming) && this.ScannedSource.ScanPath != null)\r
+                if (this.SelectedPointToPoint == PointToPointMode.Chapters && this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat) != null &&\r
+                    this.userSettingService.GetUserSetting<string>(UserSettingConstants.AutoNameFormat).Contains(Constants.Chapters))\r
                 {\r
                     this.Destination = AutoNameHelper.AutoName(this.CurrentTask, this.SourceName);\r
                 }\r
+\r
+                if (this.SelectedStartPoint > this.SelectedEndPoint && this.SelectedPointToPoint == PointToPointMode.Chapters)\r
+                {\r
+                    this.SelectedStartPoint = this.SelectedEndPoint;\r
+                }\r
             }\r
         }\r
 \r
@@ -797,8 +812,8 @@ namespace HandBrakeWPF.ViewModels
 \r
 \r
                     this.SelectedStartPoint = 1;\r
-                    this.SelectedEndPoint = selectedTitle.Chapters.Last().ChapterNumber;\r
-                } \r
+                    this.SelectedEndPoint = selectedTitle.Chapters != null && selectedTitle.Chapters.Count > 0 ? selectedTitle.Chapters.Last().ChapterNumber : 1;\r
+                }\r
                 else if (value == PointToPointMode.Seconds)\r
                 {\r
                     if (this.selectedTitle == null)\r
@@ -892,7 +907,8 @@ namespace HandBrakeWPF.ViewModels
             // Setup the presets.\r
             if (this.presetService.CheckIfPresetsAreOutOfDate())\r
                 if (!this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PresetNotification))\r
-                    this.errorService.ShowMessageBox("HandBrake has determined your built-in presets are out of date... These presets will now be updated.",\r
+                    this.errorService.ShowMessageBox("HandBrake has determined your built-in presets are out of date... These presets will now be updated." + Environment.NewLine +\r
+             "Your custom presets have not been updated so you may have to re-create these by deleting and re-adding them.",\r
                                     "Preset Update", MessageBoxButton.OK, MessageBoxImage.Information);\r
 \r
             // Queue Recovery\r
@@ -901,9 +917,7 @@ namespace HandBrakeWPF.ViewModels
             this.SelectedPreset = this.presetService.DefaultPreset;\r
 \r
             // Populate the Source menu with drives.\r
-            this.SourceMenu = this.GenerateSourceMenu();\r
-\r
-            this.driveDetectService.StartDetection(this.DriveTrayChanged);\r
+            this.SourceMenu = new BindingList<SourceMenuItem>(this.GenerateSourceMenu());\r
 \r
             // Log Cleaning\r
             if (userSettingService.GetUserSetting<bool>(UserSettingConstants.ClearOldLogs))\r
@@ -919,8 +933,6 @@ namespace HandBrakeWPF.ViewModels
         public void Shutdown()\r
         {\r
             // Shutdown Service\r
-            this.driveDetectService.Close();\r
-\r
             this.scanService.Shutdown();\r
             this.encodeService.Shutdown();\r
 \r
@@ -1108,7 +1120,14 @@ namespace HandBrakeWPF.ViewModels
             Window window = Application.Current.Windows.Cast<Window>().FirstOrDefault(x => x.GetType() == typeof(QueueSelectionViewModel));\r
             IQueueSelectionViewModel viewModel = IoC.Get<IQueueSelectionViewModel>();\r
 \r
-            viewModel.Setup(this.ScannedSource, this.SourceName);\r
+            viewModel.Setup(this.ScannedSource, this.SourceName, (tasks) =>\r
+                {\r
+                    foreach (SelectionTitle title in tasks)\r
+                    {\r
+                        this.SelectedTitle = title.Title;\r
+                        this.AddToQueue();\r
+                    }\r
+                });\r
 \r
             if (window != null)\r
             {\r
@@ -1389,7 +1408,7 @@ namespace HandBrakeWPF.ViewModels
         public void PresetAdd()\r
         {\r
             IAddPresetViewModel presetViewModel = IoC.Get<IAddPresetViewModel>();\r
-            presetViewModel.Setup(this.CurrentTask);\r
+            presetViewModel.Setup(this.CurrentTask, this.SelectedTitle);\r
             this.WindowManager.ShowWindow(presetViewModel);\r
         }\r
 \r
@@ -1778,7 +1797,7 @@ namespace HandBrakeWPF.ViewModels
                     }\r
                     else\r
                     {\r
-                        this.SourceLabel = "Scan Failed... See Activity Log for details.";                        this.StatusLabel = "Scan Failed... See Activity Log for details.";\r
+                        this.SourceLabel = "Scan Failed... See Activity Log for details."; this.StatusLabel = "Scan Failed... See Activity Log for details.";\r
                     }\r
                 });\r
         }\r
@@ -1822,7 +1841,7 @@ namespace HandBrakeWPF.ViewModels
             Execute.OnUIThread(\r
                 () =>\r
                 {\r
-                    if (this.IsEncoding)\r
+                    if (this.queueProcessor.EncodeService.IsEncoding)\r
                     {\r
                         this.ProgramStatusLabel =\r
                             string.Format(\r
@@ -1841,6 +1860,16 @@ namespace HandBrakeWPF.ViewModels
 \r
                         lastEncodePercentage = percent;\r
                     }\r
+                    else\r
+                    {\r
+                        this.ProgramStatusLabel = "Queue Finished";\r
+                        this.IsEncoding = false;\r
+\r
+                        if (this.windowsSeven.IsWindowsSeven)\r
+                        {\r
+                            this.windowsSeven.SetTaskBarProgressToNoProgress();\r
+                        }\r
+                    }\r
                 });\r
         }\r
 \r
@@ -1913,7 +1942,7 @@ namespace HandBrakeWPF.ViewModels
         /// <param name="item">\r
         /// The item.\r
         /// </param>\r
-        private void ProcessDrive(object item)\r
+        public void ProcessDrive(object item)\r
         {\r
             if (item != null)\r
             {\r
@@ -1927,7 +1956,7 @@ namespace HandBrakeWPF.ViewModels
         /// <returns>\r
         /// The System.Collections.Generic.IEnumerable`1[T -&gt; HandBrakeWPF.Model.SourceMenuItem].\r
         /// </returns>\r
-        private IEnumerable<SourceMenuItem> GenerateSourceMenu()\r
+        private IList<SourceMenuItem> GenerateSourceMenu()\r
         {\r
             List<SourceMenuItem> menuItems = new List<SourceMenuItem>();\r
 \r
@@ -1935,13 +1964,15 @@ namespace HandBrakeWPF.ViewModels
             {\r
                 Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/folder.png")), Width = 16, Height = 16 },\r
                 Text = "Open Folder",\r
-                Command = new SourceMenuCommand(this.FolderScan)\r
+                Command = new SourceMenuCommand(this.FolderScan),\r
+                IsDrive = false\r
             };\r
             SourceMenuItem fileScan = new SourceMenuItem\r
             {\r
                 Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/Movies.png")), Width = 16, Height = 16 },\r
                 Text = "Open File",\r
-                Command = new SourceMenuCommand(this.FileScan)\r
+                Command = new SourceMenuCommand(this.FileScan),\r
+                IsDrive = false\r
             };\r
 \r
             SourceMenuItem titleSpecific = new SourceMenuItem { Text = "Title Specific Scan" };\r
@@ -1949,13 +1980,15 @@ namespace HandBrakeWPF.ViewModels
             {\r
                 Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/folder.png")), Width = 16, Height = 16 },\r
                 Text = "Open Folder",\r
-                Command = new SourceMenuCommand(this.FolderScanTitleSpecific)\r
+                Command = new SourceMenuCommand(this.FolderScanTitleSpecific),\r
+                IsDrive = false\r
             };\r
             SourceMenuItem fileScanTitle = new SourceMenuItem\r
             {\r
                 Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/Movies.png")), Width = 16, Height = 16 },\r
                 Text = "Open File",\r
-                Command = new SourceMenuCommand(this.FileScanTitleSpecific)\r
+                Command = new SourceMenuCommand(this.FileScanTitleSpecific),\r
+                IsDrive = false\r
             };\r
             titleSpecific.Children.Add(folderScanTitle);\r
             titleSpecific.Children.Add(fileScanTitle);\r
@@ -1974,20 +2007,13 @@ namespace HandBrakeWPF.ViewModels
                             Image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/HandBrake;component/Views/Images/disc_small.png")), Width = 16, Height = 16 },\r
                             Text = string.Format("{0} ({1})", item.RootDirectory, item.VolumeLabel),\r
                             Command = new SourceMenuCommand(() => this.ProcessDrive(driveInformation)),\r
-                            Tag = item\r
+                            Tag = item,\r
+                            IsDrive = true\r
                         });\r
 \r
             return menuItems;\r
         }\r
 \r
-        /// <summary>\r
-        /// The drive tray changed.\r
-        /// </summary>\r
-        private void DriveTrayChanged()\r
-        {\r
-            Caliburn.Micro.Execute.OnUIThread(() => this.SourceMenu = this.GenerateSourceMenu());\r
-        }\r
-\r
         /// <summary>\r
         /// Allows the main window to respond to setting changes.\r
         /// </summary>\r
@@ -2017,10 +2043,10 @@ namespace HandBrakeWPF.ViewModels
         /// </param>\r
         private void CurrentTask_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)\r
         {\r
-           if (e.PropertyName == UserSettingConstants.ShowAdvancedTab)\r
-           {\r
-               this.NotifyOfPropertyChange(() => this.ShowAdvancedTab);\r
-           }\r
+            if (e.PropertyName == UserSettingConstants.ShowAdvancedTab)\r
+            {\r
+                this.NotifyOfPropertyChange(() => this.ShowAdvancedTab);\r
+            }\r
         }\r
 \r
         #endregion\r
index bde7bc38c9bb9b57ca9908642a0feddad21238a3..ad012db4fe6b6e7d1ffe848c1e5342ae525b3505 100644 (file)
@@ -19,6 +19,8 @@ namespace HandBrakeWPF.ViewModels
     using System.Linq;\r
     using System.Windows;\r
 \r
+    using Caliburn.Micro;\r
+\r
     using HandBrake.ApplicationServices;\r
     using HandBrake.ApplicationServices.Services.Interfaces;\r
     using HandBrake.ApplicationServices.Utilities;\r
@@ -367,7 +369,7 @@ namespace HandBrakeWPF.ViewModels
         /// <param name="updateService">\r
         /// The update Service.\r
         /// </param>\r
-        public OptionsViewModel(IUserSettingService userSettingService, IShellViewModel shellViewModel, IUpdateService updateService )\r
+        public OptionsViewModel(IUserSettingService userSettingService, IShellViewModel shellViewModel, IUpdateService updateService)\r
         {\r
             this.Title = "Options";\r
             this.userSettingService = userSettingService;\r
@@ -1482,15 +1484,15 @@ namespace HandBrakeWPF.ViewModels
             this.whenDoneOptions.Add("Hibernate");\r
             this.whenDoneOptions.Add("Lock System");\r
             this.whenDoneOptions.Add("Log off");\r
-           // this.whenDoneOptions.Add("Quit HandBrake");\r
+            this.whenDoneOptions.Add("Quit HandBrake");\r
             this.WhenDone = userSettingService.GetUserSetting<string>("WhenCompleteAction");\r
 \r
             this.GrowlAfterEncode = userSettingService.GetUserSetting<bool>(UserSettingConstants.GrowlEncode);\r
             this.GrowlAfterQueue = userSettingService.GetUserSetting<bool>(UserSettingConstants.GrowlQueue);\r
-            this.SendFileAfterEncode = this.userSettingService.GetUserSetting<bool>(ASUserSettingConstants.SendFile);\r
-            this.SendFileTo = Path.GetFileNameWithoutExtension(this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo)) ?? string.Empty;\r
-            this.SendFileToPath = this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileTo) ?? string.Empty;\r
-            this.Arguments = this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.SendFileToArgs) ?? string.Empty;\r
+            this.SendFileAfterEncode = this.userSettingService.GetUserSetting<bool>(UserSettingConstants.SendFile);\r
+            this.SendFileTo = Path.GetFileNameWithoutExtension(this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo)) ?? string.Empty;\r
+            this.SendFileToPath = this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileTo) ?? string.Empty;\r
+            this.Arguments = this.userSettingService.GetUserSetting<string>(UserSettingConstants.SendFileToArgs) ?? string.Empty;\r
 \r
             // #############################\r
             // Output Settings\r
@@ -1554,7 +1556,7 @@ namespace HandBrakeWPF.ViewModels
                 this.preferredLanguages.Add(item);\r
 \r
                 // In the available languages should be no "Any" and no selected language.\r
-                if ((item != "(Any)") && (!this.userSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages).Contains(item)))\r
+                if ((item != Constants.Any) && (!this.userSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages).Contains(item)))\r
                 {\r
                     this.availableLanguages.Add(item);\r
                 }\r
@@ -1597,7 +1599,7 @@ namespace HandBrakeWPF.ViewModels
             this.priorityLevelOptions.Add("Low");\r
             this.SelectedPriority = userSettingService.GetUserSetting<string>(ASUserSettingConstants.ProcessPriority);\r
 \r
-            this.PreventSleep = userSettingService.GetUserSetting<bool>(ASUserSettingConstants.PreventSleep);\r
+            this.PreventSleep = userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep);\r
 \r
             // Log Verbosity Level\r
             this.logVerbosityOptions.Clear();\r
@@ -1820,12 +1822,12 @@ namespace HandBrakeWPF.ViewModels
             /* General */\r
             this.userSettingService.SetUserSetting(UserSettingConstants.UpdateStatus, this.CheckForUpdates);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.DaysBetweenUpdateCheck, this.CheckForUpdatesFrequency);\r
-            this.userSettingService.SetUserSetting(ASUserSettingConstants.WhenCompleteAction, this.WhenDone);\r
+            this.userSettingService.SetUserSetting(UserSettingConstants.WhenCompleteAction, this.WhenDone);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.GrowlQueue, this.GrowlAfterQueue);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.GrowlEncode, this.GrowlAfterEncode);\r
-            this.userSettingService.SetUserSetting(ASUserSettingConstants.SendFileTo, this.SendFileToPath);\r
-            this.userSettingService.SetUserSetting(ASUserSettingConstants.SendFile, this.SendFileAfterEncode);\r
-            this.userSettingService.SetUserSetting(ASUserSettingConstants.SendFileToArgs, this.Arguments);\r
+            this.userSettingService.SetUserSetting(UserSettingConstants.SendFileTo, this.SendFileToPath);\r
+            this.userSettingService.SetUserSetting(UserSettingConstants.SendFile, this.SendFileAfterEncode);\r
+            this.userSettingService.SetUserSetting(UserSettingConstants.SendFileToArgs, this.Arguments);\r
 \r
             /* Output Files */\r
             this.userSettingService.SetUserSetting(UserSettingConstants.AutoNaming, this.AutomaticallyNameFiles);\r
@@ -1852,7 +1854,7 @@ namespace HandBrakeWPF.ViewModels
 \r
             /* System and Logging */\r
             userSettingService.SetUserSetting(ASUserSettingConstants.ProcessPriority, this.SelectedPriority);\r
-            userSettingService.SetUserSetting(ASUserSettingConstants.PreventSleep, this.PreventSleep);\r
+            userSettingService.SetUserSetting(UserSettingConstants.PreventSleep, this.PreventSleep);\r
             userSettingService.SetUserSetting(ASUserSettingConstants.Verbosity, this.SelectedVerbosity);\r
             userSettingService.SetUserSetting(ASUserSettingConstants.SaveLogWithVideo, this.CopyLogToEncodeDirectory);\r
             userSettingService.SetUserSetting(ASUserSettingConstants.SaveLogToCopyDirectory, this.CopyLogToSepcficedLocation);\r
@@ -1879,6 +1881,7 @@ namespace HandBrakeWPF.ViewModels
             userSettingService.SetUserSetting(UserSettingConstants.ServerPort, this.ServerPort.ToString());\r
             userSettingService.SetUserSetting(UserSettingConstants.EnableDebugFeatures, this.EnableDebugFeatures);\r
             userSettingService.SetUserSetting(UserSettingConstants.DisableLibHbFeatures, this.DisableLibHbFeatures);\r
+            userSettingService.SetUserSetting(UserSettingConstants.EnableLibHb, this.EnableLibHb);\r
         }\r
 \r
         /// <summary>\r
@@ -1894,7 +1897,7 @@ namespace HandBrakeWPF.ViewModels
             {\r
                 this.UpdateMessage = "A New Update is Available!";\r
                 this.UpdateAvailable = true;\r
-            } \r
+            }\r
             else\r
             {\r
                 this.UpdateMessage = "There are no new updates at this time.";\r
@@ -1935,7 +1938,7 @@ namespace HandBrakeWPF.ViewModels
             this.UpdateMessage = info.WasSuccessful ? "Update Downloaded" : "Update Failed. You can try downloading the update from http://handbrake.fr";\r
 \r
             Process.Start(Path.Combine(Path.GetTempPath(), "handbrake-setup.exe"));\r
-            Application.Current.Shutdown();\r
+            Execute.OnUIThread(() => Application.Current.Shutdown());\r
         }\r
 \r
         /// <summary>\r
index 1a6c90538505b1d54d938864f1655142be85c093..972af2910b4e93b9d38de00c910251c1faf34db2 100644 (file)
@@ -601,59 +601,53 @@ namespace HandBrakeWPF.ViewModels
         {\r
             this.Task = task;\r
 \r
-            // TODO: These all need to be handled correctly.\r
-            this.SelectedAnamorphicMode = preset.Task.Anamorphic;\r
-\r
-            // Set the limits on the UI Controls.\r
-            this.MaxWidth = preset.Task.MaxWidth ?? this.sourceResolution.Width;\r
-            this.MaxHeight = preset.Task.MaxHeight ?? this.sourceResolution.Height;\r
-            this.Task.MaxWidth = preset.Task.MaxWidth;\r
-            this.Task.MaxHeight = preset.Task.MaxHeight;\r
-\r
-            // Setup the Width\r
-            if (preset.Task.MaxWidth.HasValue)\r
+            // Handle built-in presets.\r
+            if (preset.IsBuildIn)\r
             {\r
-                if (this.Width > preset.Task.MaxWidth)\r
-                {\r
-                    // Limit the Width to the Max Width\r
-                    this.Width = preset.Task.MaxWidth.Value; \r
-                }\r
-                else\r
-                {\r
-                    // Figure out the best width based on the preset and source\r
-                    this.Width = preset.Task.Width ?? this.GetModulusValue(this.getRes((this.sourceResolution.Width - this.CropLeft - this.CropRight), preset.Task.MaxWidth.Value));\r
-                }\r
+                preset.PictureSettingsMode = PresetPictureSettingsMode.Custom;\r
             }\r
-            else\r
+\r
+            // Setup the Picture Sizes\r
+            switch (preset.PictureSettingsMode)\r
             {\r
-                this.Width = preset.Task.Width ?? this.GetModulusValue((this.sourceResolution.Width - this.CropLeft - this.CropRight));\r
-            }\r
+                default:\r
+                case PresetPictureSettingsMode.Custom:\r
+                case PresetPictureSettingsMode.SourceMaximum:\r
 \r
-            // Set the Maintain Aspect ratio. This will calculate Height for us now.\r
-            this.MaintainAspectRatio = preset.Task.Anamorphic == Anamorphic.None || preset.Task.KeepDisplayAspect;\r
+                    // Anamorphic Mode\r
+                    this.SelectedAnamorphicMode = preset.Task.Anamorphic;\r
 \r
-            // Set Height, but only if necessary.\r
-            if (preset.Task.MaxHeight.HasValue)\r
-            {\r
-                if (this.Height > preset.Task.MaxHeight)\r
-                {\r
-                    // Limit the Height to the Max Height of the preset. Setting this will recalculate the width.\r
-                    this.Height = preset.Task.MaxHeight.Value;\r
-                }\r
-                else\r
-                {\r
-                    // Only calculate height if Maintain Aspect ratio is off.\r
-                    if (!this.MaintainAspectRatio)\r
+                    // Modulus\r
+                    if (preset.Task.Modulus.HasValue)\r
                     {\r
-                        this.Height = preset.Task.Height ??\r
-                                      this.getRes(\r
-                                          (this.sourceResolution.Height - this.CropTop - this.CropBottom),\r
-                                          preset.Task.MaxHeight.Value);\r
+                        this.SelectedModulus = preset.Task.Modulus;\r
                     }\r
-                }\r
+\r
+                    // Set the Maintain Aspect ratio.\r
+                    this.MaintainAspectRatio = preset.Task.KeepDisplayAspect;\r
+\r
+                    // Set the width, then check the height doesn't breach the max height and correct if necessary.\r
+                    int width = this.GetModulusValue(this.getRes((this.sourceResolution.Width - this.CropLeft - this.CropRight), preset.Task.MaxWidth));\r
+                    this.Width = width;\r
+\r
+                    // If we have a max height, make sure we havn't breached it.\r
+                    int height = this.GetModulusValue(this.getRes((this.sourceResolution.Height - this.CropTop - this.CropBottom), preset.Task.MaxHeight));\r
+                    if (preset.Task.MaxHeight.HasValue && this.Height > preset.Task.MaxHeight.Value)\r
+                    {\r
+                        this.Height = height;\r
+                    }\r
+\r
+                    this.MaxWidth = width;\r
+                    this.MaxHeight = height;\r
+                    break;\r
+                case PresetPictureSettingsMode.None:\r
+                    // Do Nothing except reset the Max Width/Height\r
+                    this.MaxWidth = this.sourceResolution.Width;\r
+                    this.MaxHeight = this.sourceResolution.Height;\r
+                    break;\r
             }\r
 \r
-            // Anamorphic\r
+            // Custom Anamorphic\r
             if (preset.Task.Anamorphic == Anamorphic.Custom)\r
             {\r
                 this.DisplayWidth = preset.Task.DisplayWidth != null ? int.Parse(preset.Task.DisplayWidth.ToString()) : 0;\r
@@ -661,12 +655,6 @@ namespace HandBrakeWPF.ViewModels
                 this.ParHeight = preset.Task.PixelAspectY;\r
             }\r
 \r
-            // Modulus\r
-            if (preset.Task.Modulus.HasValue)\r
-            {\r
-                this.SelectedModulus = preset.Task.Modulus;\r
-            }\r
-\r
             // Cropping\r
             if (preset.Task.HasCropping)\r
             {\r
@@ -721,23 +709,64 @@ namespace HandBrakeWPF.ViewModels
                 this.sourceParValues = title.ParVal;\r
                 this.sourceResolution = title.Resolution;\r
 \r
-                // Set the Max Width / Height available to the user controls\r
-                if (this.sourceResolution.Width < this.MaxWidth)\r
+                if (preset.PictureSettingsMode == PresetPictureSettingsMode.None)\r
                 {\r
-                    this.MaxWidth = this.sourceResolution.Width;\r
+                    // We have no instructions, so simply set it to the source.\r
+                    this.Width = this.GetModulusValue(this.sourceResolution.Width - this.CropLeft - this.CropRight);\r
+                    this.MaintainAspectRatio = true;\r
                 }\r
-                else if (this.sourceResolution.Width > this.MaxWidth)\r
+                else\r
                 {\r
-                    this.MaxWidth = preset.Task.MaxWidth ?? this.sourceResolution.Width;\r
-                }\r
+                    // Set the Max Width / Height available to the user controls\r
+                    if (this.sourceResolution.Width < this.MaxWidth)\r
+                    {\r
+                        this.MaxWidth = this.sourceResolution.Width;\r
+                    }\r
+                    else if (this.sourceResolution.Width > this.MaxWidth)\r
+                    {\r
+                        this.MaxWidth = preset.Task.MaxWidth ?? this.sourceResolution.Width;\r
+                    }\r
 \r
-                if (this.sourceResolution.Height < this.MaxHeight)\r
-                {\r
-                    this.MaxHeight = this.sourceResolution.Height;\r
-                }\r
-                else if (this.sourceResolution.Height > this.MaxHeight)\r
-                {\r
-                    this.MaxHeight = preset.Task.MaxHeight ?? this.sourceResolution.Height;\r
+                    if (this.sourceResolution.Height < this.MaxHeight)\r
+                    {\r
+                        this.MaxHeight = this.sourceResolution.Height;\r
+                    }\r
+                    else if (this.sourceResolution.Height > this.MaxHeight)\r
+                    {\r
+                        this.MaxHeight = preset.Task.MaxHeight ?? this.sourceResolution.Height;\r
+                    }\r
+\r
+                    // Update the cropping values, preffering those in the presets.\r
+                    if (!preset.Task.HasCropping)\r
+                    {\r
+                        this.CropTop = title.AutoCropDimensions.Top;\r
+                        this.CropBottom = title.AutoCropDimensions.Bottom;\r
+                        this.CropLeft = title.AutoCropDimensions.Left;\r
+                        this.CropRight = title.AutoCropDimensions.Right;\r
+                        this.IsCustomCrop = false;\r
+                    }\r
+                    else\r
+                    {\r
+                        this.CropLeft = preset.Task.Cropping.Left;\r
+                        this.CropRight = preset.Task.Cropping.Right;\r
+                        this.CropTop = preset.Task.Cropping.Top;\r
+                        this.CropBottom = preset.Task.Cropping.Bottom;\r
+                        this.IsCustomCrop = true;\r
+                    }\r
+\r
+                    // Set the Width, and Maintain Aspect ratio. That should calc the Height for us.\r
+                    this.Width = preset.Task.Width ?? this.MaxWidth;  // Note: This will be auto-corrected in the property if it's too large.\r
+\r
+                    // If our height is too large, let it downscale the width for us by setting the height to the lower value.\r
+                    if (!this.MaintainAspectRatio && this.Height > this.MaxHeight)\r
+                    {\r
+                        this.Height = this.MaxHeight;\r
+                    }\r
+\r
+                    if (this.SelectedAnamorphicMode == Anamorphic.Custom)\r
+                    {\r
+                        this.AnamorphicAdjust(); // Refresh the values\r
+                    }\r
                 }\r
 \r
                 // Set Screen Controls\r
@@ -746,38 +775,6 @@ namespace HandBrakeWPF.ViewModels
                     title.Resolution.Width,\r
                     title.Resolution.Height,\r
                     title.AspectRatio);\r
-\r
-                if (!preset.Task.HasCropping)\r
-                {\r
-                    this.CropTop = title.AutoCropDimensions.Top;\r
-                    this.CropBottom = title.AutoCropDimensions.Bottom;\r
-                    this.CropLeft = title.AutoCropDimensions.Left;\r
-                    this.CropRight = title.AutoCropDimensions.Right;\r
-                    this.IsCustomCrop = false;\r
-                }\r
-                else\r
-                {\r
-                    this.CropLeft = preset.Task.Cropping.Left;\r
-                    this.CropRight = preset.Task.Cropping.Right;\r
-                    this.CropTop = preset.Task.Cropping.Top;\r
-                    this.CropBottom = preset.Task.Cropping.Bottom;\r
-                    this.IsCustomCrop = true;\r
-                }\r
-\r
-                // Set the Width, and Maintain Aspect ratio. That should calc the Height for us.\r
-                this.Width = this.MaxWidth;\r
-                this.MaintainAspectRatio = true;\r
-\r
-                // If our height is too large, let it downscale the width for us by setting the height to the lower value.\r
-                if (this.Height > this.MaxHeight)\r
-                {\r
-                    this.Height = this.MaxHeight;\r
-                }\r
-       \r
-                if (this.SelectedAnamorphicMode == Anamorphic.Custom)\r
-                {\r
-                    this.AnamorphicAdjust(); // Refresh the values\r
-                }\r
             }\r
 \r
             this.NotifyOfPropertyChange(() => this.Task);\r
@@ -813,7 +810,16 @@ namespace HandBrakeWPF.ViewModels
                     this.ShowDisplaySize = false;\r
                     this.ShowKeepAR = true;\r
                     this.SelectedModulus = 16; // Reset\r
-                    this.Width = this.sourceResolution.Width;\r
+                    if (this.Width == 0)\r
+                    {\r
+                        this.Width = this.GetModulusValue(this.sourceResolution.Width - this.CropLeft - this.CropRight);\r
+                    }\r
+\r
+                    if (!this.MaintainAspectRatio && this.Height == 0)\r
+                    {\r
+                        this.Height = this.GetModulusValue(this.sourceResolution.Height - this.CropTop - this.CropBottom);\r
+                    }\r
+\r
                     this.SetDisplaySize();\r
                     break;\r
                 case Anamorphic.Strict:\r
@@ -834,7 +840,10 @@ namespace HandBrakeWPF.ViewModels
                     this.HeightControlEnabled = false;\r
                     this.ShowCustomAnamorphicControls = false;\r
                     this.ShowModulus = true;\r
-                    this.Width = this.sourceResolution.Width;\r
+                    if (this.Width == 0)\r
+                    {\r
+                        this.Width = this.sourceResolution.Width;\r
+                    }\r
                     this.Height = 0;\r
                     this.ShowKeepAR = false;\r
 \r
@@ -1145,9 +1154,9 @@ namespace HandBrakeWPF.ViewModels
         /// <returns>\r
         /// An Int\r
         /// </returns>\r
-        private int getRes(int value, int max)\r
+        private int getRes(int value, int? max)\r
         {\r
-            return value > max ? max : value;\r
+            return max.HasValue ? (value > max.Value ? max.Value : value) : value;\r
         }\r
 \r
         #endregion\r
index c5b6072cce316a953b7a5ab8c1bca48b21e15fff..3cbe56feb2a53333a42eea88373b97ce83ebf298 100644 (file)
@@ -40,6 +40,11 @@ namespace HandBrakeWPF.ViewModels
         /// </summary>\r
         private bool orderedByTitle;\r
 \r
+        /// <summary>\r
+        /// The add to queue.\r
+        /// </summary>\r
+        private Action<IEnumerable<SelectionTitle>> addToQueue;\r
+\r
         /// <summary>\r
         /// Initializes a new instance of the <see cref="QueueSelectionViewModel"/> class. \r
         /// </summary>\r
@@ -98,6 +103,36 @@ namespace HandBrakeWPF.ViewModels
             }\r
         }\r
 \r
+        /// <summary>\r
+        /// Gets a value indicating whether is auto naming enabled.\r
+        /// </summary>\r
+        public bool IsAutoNamingEnabled\r
+        {\r
+            get\r
+            {\r
+                return this.UserSettingService.GetUserSetting<bool>(UserSettingConstants.AutoNaming);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether is automatic track selection enabled.\r
+        /// </summary>\r
+        public bool IsAutomaticTrackSelectionEnabled\r
+        {\r
+            get\r
+            {\r
+                // TODO decide what is the minimal requirement to hide the warning message.\r
+                if (this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguage) != Constants.Any ||\r
+                    this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguageForSubtitles) !=\r
+                    Constants.Any)\r
+                {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            }\r
+        }\r
+\r
         /// <summary>\r
         /// The order by title.\r
         /// </summary>\r
@@ -147,6 +182,7 @@ namespace HandBrakeWPF.ViewModels
         /// </summary>\r
         public void Add()\r
         {\r
+            this.addToQueue(this.TitleList.Where(c => c.IsSelected));\r
             this.Close();\r
         }\r
 \r
@@ -176,23 +212,29 @@ namespace HandBrakeWPF.ViewModels
         /// <param name="srcName">\r
         /// The src Name.\r
         /// </param>\r
-        public void Setup(Source scannedSource, string srcName)\r
+        /// <param name="addAction">\r
+        /// The add Action.\r
+        /// </param>\r
+        public void Setup(Source scannedSource, string srcName, Action<IEnumerable<SelectionTitle>> addAction)\r
         {\r
             this.TitleList.Clear();\r
+            this.addToQueue = addAction;\r
 \r
             if (scannedSource != null)\r
             {\r
-\r
                 IEnumerable<Title> titles = orderedByTitle\r
                                          ? scannedSource.Titles\r
                                          : scannedSource.Titles.OrderByDescending(o => o.Duration).ToList();\r
 \r
                 foreach (Title item in titles)\r
                 {\r
-                    SelectionTitle title = new SelectionTitle(item, srcName);\r
+                    SelectionTitle title = new SelectionTitle(item, srcName) { IsSelected = true };\r
                     TitleList.Add(title);\r
                 }\r
             }\r
+\r
+            this.NotifyOfPropertyChange(() => this.IsAutoNamingEnabled);\r
+            this.NotifyOfPropertyChange(() => this.IsAutomaticTrackSelectionEnabled);\r
         }\r
     }\r
 }\r
index 3b5bf33e8ec38470870723fadcea4d4fba247e66..65f67c43addc49e2f009af6ac9606dda6557259e 100644 (file)
 namespace HandBrakeWPF.ViewModels\r
 {\r
     using System;\r
-    using System.Collections.ObjectModel;\r
     using System.ComponentModel;\r
     using System.Windows;\r
 \r
     using Caliburn.Micro;\r
 \r
-    using HandBrake.ApplicationServices;\r
     using HandBrake.ApplicationServices.EventArgs;\r
     using HandBrake.ApplicationServices.Model;\r
     using HandBrake.ApplicationServices.Services.Interfaces;\r
@@ -31,13 +29,6 @@ namespace HandBrakeWPF.ViewModels
     /// </summary>\r
     public class QueueViewModel : ViewModelBase, IQueueViewModel\r
     {\r
-        /*\r
-         \r
-         * TODO FIX THE DRAP/DROP ADORNER!\r
-         */\r
-\r
-\r
-\r
         #region Constants and Fields\r
 \r
         /// <summary>\r
@@ -82,9 +73,6 @@ namespace HandBrakeWPF.ViewModels
         /// <summary>\r
         /// Initializes a new instance of the <see cref="QueueViewModel"/> class.\r
         /// </summary>\r
-        /// <param name="windowManager">\r
-        /// The window manager.\r
-        /// </param>\r
         /// <param name="userSettingService">\r
         /// The user Setting Service.\r
         /// </param>\r
@@ -94,7 +82,7 @@ namespace HandBrakeWPF.ViewModels
         /// <param name="errorService">\r
         /// The Error Service \r
         /// </param>\r
-        public QueueViewModel(IWindowManager windowManager, IUserSettingService userSettingService, IQueueProcessor queueProcessor, IErrorService errorService)\r
+        public QueueViewModel(IUserSettingService userSettingService, IQueueProcessor queueProcessor, IErrorService errorService)\r
         {\r
             this.userSettingService = userSettingService;\r
             this.queueProcessor = queueProcessor;\r
@@ -199,7 +187,7 @@ namespace HandBrakeWPF.ViewModels
         public void WhenDone(string action)\r
         {\r
             this.WhenDoneAction = action;\r
-            this.userSettingService.SetUserSetting(ASUserSettingConstants.WhenCompleteAction, action);\r
+            this.userSettingService.SetUserSetting(UserSettingConstants.WhenCompleteAction, action);\r
         }\r
 \r
         /// <summary>\r
@@ -249,6 +237,13 @@ namespace HandBrakeWPF.ViewModels
         public void PauseEncode()\r
         {\r
             this.queueProcessor.Pause();\r
+\r
+            this.JobStatus = "Queue Paused";\r
+            this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+            this.IsEncoding = false;\r
+\r
+            MessageBox.Show("The Queue has been pasued. The currently running job will run to completion and no further jobs will start.", "Queue",\r
+                MessageBoxButton.OK, MessageBoxImage.Information);\r
         }\r
 \r
         /// <summary>\r
@@ -305,6 +300,10 @@ namespace HandBrakeWPF.ViewModels
                 return;\r
             }\r
 \r
+            this.JobStatus = "Queue Started";\r
+            this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+            this.IsEncoding = true;\r
+\r
             this.queueProcessor.Start();\r
         }\r
 \r
@@ -374,13 +373,16 @@ namespace HandBrakeWPF.ViewModels
         {\r
             this.Load();\r
 \r
-            this.WhenDoneAction = this.userSettingService.GetUserSetting<string>(ASUserSettingConstants.WhenCompleteAction);\r
+            this.WhenDoneAction = this.userSettingService.GetUserSetting<string>(UserSettingConstants.WhenCompleteAction);\r
 \r
-            this.queueProcessor.JobProcessingStarted += this.queueProcessor_JobProcessingStarted;\r
             this.queueProcessor.QueueCompleted += this.queueProcessor_QueueCompleted;\r
-            this.queueProcessor.QueuePaused += this.queueProcessor_QueuePaused;\r
             this.queueProcessor.QueueChanged += this.QueueManager_QueueChanged;\r
             this.queueProcessor.EncodeService.EncodeStatusChanged += this.EncodeService_EncodeStatusChanged;\r
+            this.queueProcessor.EncodeService.EncodeCompleted += EncodeService_EncodeCompleted;\r
+            this.queueProcessor.JobProcessingStarted += this.QueueProcessorJobProcessingStarted;\r
+\r
+            this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+            this.JobStatus = "Queue Ready";\r
 \r
             base.OnActivate();\r
         }\r
@@ -393,11 +395,11 @@ namespace HandBrakeWPF.ViewModels
         /// </param>\r
         protected override void OnDeactivate(bool close)\r
         {\r
-            this.queueProcessor.JobProcessingStarted -= this.queueProcessor_JobProcessingStarted;\r
             this.queueProcessor.QueueCompleted -= this.queueProcessor_QueueCompleted;\r
-            this.queueProcessor.QueuePaused -= this.queueProcessor_QueuePaused;\r
             this.queueProcessor.QueueChanged -= this.QueueManager_QueueChanged;\r
             this.queueProcessor.EncodeService.EncodeStatusChanged -= this.EncodeService_EncodeStatusChanged;\r
+            this.queueProcessor.EncodeService.EncodeCompleted -= EncodeService_EncodeCompleted;\r
+            this.queueProcessor.JobProcessingStarted -= this.QueueProcessorJobProcessingStarted;\r
 \r
             base.OnDeactivate(close);\r
         }\r
@@ -416,20 +418,18 @@ namespace HandBrakeWPF.ViewModels
         {\r
             Caliburn.Micro.Execute.OnUIThread(() =>\r
             {\r
-                if (this.IsEncoding)\r
-                {\r
-                    this.JobStatus =\r
-                        string.Format(\r
-                            "Encoding: Pass {0} of {1},  {2:00.00}%, FPS: {3:000.0},  Avg FPS: {4:000.0},  Time Remaining: {5},  Elapsed: {6:hh\\:mm\\:ss}",\r
-                            e.Task,\r
-                            e.TaskCount,\r
-                            e.PercentComplete,\r
-                            e.CurrentFrameRate,\r
-                            e.AverageFrameRate,\r
-                            e.EstimatedTimeLeft,\r
-                            e.ElapsedTime);\r
-                }\r
 \r
+\r
+                this.JobStatus =\r
+                    string.Format(\r
+                        "Encoding: Pass {0} of {1},  {2:00.00}%, FPS: {3:000.0},  Avg FPS: {4:000.0},  Time Remaining: {5},  Elapsed: {6:hh\\:mm\\:ss}",\r
+                        e.Task,\r
+                        e.TaskCount,\r
+                        e.PercentComplete,\r
+                        e.CurrentFrameRate,\r
+                        e.AverageFrameRate,\r
+                        e.EstimatedTimeLeft,\r
+                        e.ElapsedTime);\r
             });\r
         }\r
 \r
@@ -445,55 +445,60 @@ namespace HandBrakeWPF.ViewModels
         private void QueueManager_QueueChanged(object sender, EventArgs e)\r
         {\r
             this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
+\r
+            if (!queueProcessor.IsProcessing)\r
+            {\r
+                this.JobStatus = "Queue Not Running";\r
+            }\r
         }\r
 \r
         /// <summary>\r
-        /// Handle teh Job Processing Started Event\r
+        /// Handle the Queue Completed Event\r
         /// </summary>\r
         /// <param name="sender">\r
         /// The sender.\r
         /// </param>\r
         /// <param name="e">\r
-        /// The QueueProgressEventArgs.\r
+        /// The EventArgs.\r
         /// </param>\r
-        private void queueProcessor_JobProcessingStarted(\r
-            object sender, QueueProgressEventArgs e)\r
+        private void queueProcessor_QueueCompleted(object sender, EventArgs e)\r
         {\r
-            this.JobStatus = "Queue Started";\r
+            this.JobStatus = "Queue Completed";\r
             this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
-            this.IsEncoding = true;\r
+            this.IsEncoding = false;\r
         }\r
 \r
         /// <summary>\r
-        /// Handle the Queue Completed Event\r
+        /// The encode service_ encode completed.\r
         /// </summary>\r
         /// <param name="sender">\r
         /// The sender.\r
         /// </param>\r
         /// <param name="e">\r
-        /// The EventArgs.\r
+        /// The e.\r
         /// </param>\r
-        private void queueProcessor_QueueCompleted(object sender, EventArgs e)\r
+        private void EncodeService_EncodeCompleted(object sender, EncodeCompletedEventArgs e)\r
         {\r
-            this.JobStatus = "Queue Completed";\r
-            this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
-            this.IsEncoding = false;\r
+            if (!this.queueProcessor.IsProcessing)\r
+            {\r
+                this.JobStatus = "Last Queued Job Finished";\r
+            }\r
         }\r
 \r
         /// <summary>\r
-        /// Handle the Queue Paused Event\r
+        /// The queue processor job processing started.\r
         /// </summary>\r
         /// <param name="sender">\r
         /// The sender.\r
         /// </param>\r
         /// <param name="e">\r
-        /// The EventArgs.\r
+        /// The QueueProgressEventArgs.\r
         /// </param>\r
-        private void queueProcessor_QueuePaused(object sender, EventArgs e)\r
+        private void QueueProcessorJobProcessingStarted(object sender, QueueProgressEventArgs e)\r
         {\r
-            this.JobStatus = "Queue Paused";\r
+            this.JobStatus = "Queue Started";\r
             this.JobsPending = string.Format("{0} jobs pending", this.queueProcessor.Count);\r
-            this.IsEncoding = false;\r
+            this.IsEncoding = true;\r
         }\r
 \r
         #endregion\r
index 90dae495fe2d190d1c5bc878a920b11ff899e65d..feabc08f3e6cef36c25d0d4caff5b3f45cfb9ef8 100644 (file)
@@ -113,7 +113,6 @@ namespace HandBrakeWPF.ViewModels
         /// </summary>\r
         public void AddAllClosedCaptions()\r
         {\r
-\r
             foreach (Subtitle subtitle in this.SourceTitlesSubset(null).Where(s => s.SubtitleType == SubtitleType.CC))\r
             {\r
                 this.Add(subtitle);\r
@@ -137,12 +136,14 @@ namespace HandBrakeWPF.ViewModels
         public void AddAllRemainingForSelectedLanguages()\r
         {\r
             // Get a list of subtitle tracks that match the users lanaguages\r
-            StringCollection userSelectedLanguages =\r
-                this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages);\r
-            userSelectedLanguages.Add(\r
-                this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguageForSubtitles));\r
+            StringCollection userSelectedLanguages = this.UserSettingService.GetUserSetting<StringCollection>(UserSettingConstants.SelectedLanguages);\r
+            userSelectedLanguages.Add(this.UserSettingService.GetUserSetting<string>(UserSettingConstants.NativeLanguageForSubtitles));\r
+\r
+            // Translate to Iso Codes\r
+            List<string> iso6392Codes = LanguageUtilities.GetLanguageCodes(userSelectedLanguages);\r
+\r
             List<Subtitle> availableTracks =\r
-                this.SourceTracks.Where(subtitle => userSelectedLanguages.Contains(subtitle.Language)).ToList();\r
+                this.SourceTracks.Where(subtitle => iso6392Codes.Contains(subtitle.LanguageCodeClean)).ToList();\r
 \r
             foreach (Subtitle subtitle in this.SourceTitlesSubset(availableTracks))\r
             {\r
index 6355bd9457ef06729547fd494e218cd984cae60b..160706af8e3ade778a24da3c08176d4cb8c7bdd8 100644 (file)
@@ -316,7 +316,7 @@ namespace HandBrakeWPF.ViewModels
         {\r
             get\r
             {\r
-                return 51.Equals(this.RF) && this.SelectedVideoEncoder == VideoEncoder.X264;\r
+                return 0.0.Equals(this.DisplayRF) && this.SelectedVideoEncoder == VideoEncoder.X264;\r
             }\r
         }\r
 \r
index 3e7a3fd7b335ba8d0fa1ab518d106c3feae5d741..b49b439a685891ed13380a01e461604949cfac11 100644 (file)
@@ -88,7 +88,7 @@
                        Grid.Column="0"\r
                        Style="{StaticResource LongToolTipHolder}"\r
                        ToolTip="{x:Static Properties:Resources.AddPreset_PictureSizeMode}"\r
-                       Text="Picture Size:" />\r
+                       Text="Max Picture Size:" />\r
             <ComboBox Grid.Row="2"\r
                       Grid.Column="1"\r
                       Width="125"\r
index 3cb8423a2c403f7add2515af1cf0b860d6137cdb..28d17d776e1f9ecd629080bf7c2783ec94984158 100644 (file)
@@ -9,7 +9,7 @@
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"\r
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
              xmlns:NumericUpDown="clr-namespace:EagleBoost.Wpf.Presentation.Controls.NumericUpDown;assembly=EagleBoost.Wpf.Presentation"\r
-             xmlns:controls="clr-namespace:HandBrakeWPF.Controls"\r
+             xmlns:dropButton="clr-namespace:HandBrakeWPF.Controls.DropButton"\r
              d:DesignHeight="170"\r
              d:DesignWidth="616"\r
              mc:Ignorable="d">\r
                 <ColumnDefinition Width="*" />\r
                 <ColumnDefinition Width="Auto" />\r
             </Grid.ColumnDefinitions>\r
-            <Button Grid.Column="0"\r
-                    MaxWidth="95"\r
+            \r
+            <StackPanel Orientation="Horizontal" Grid.Row="0">\r
+                <dropButton:DropButton Content="Add Track" FontWeight="Bold" Margin="0,0,10,0" Style="{StaticResource DropButtonStyle}">\r
+                    <dropButton:DropButton.DropDown>\r
+                        <ContextMenu>\r
+                            <MenuItem Header="Add New Track" cal:Message.Attach="[Event Click] = [Action Add]" />\r
+                            <MenuItem Header="Add All Remaining Tracks" cal:Message.Attach="[Event Click] = [Action AddAllRemaining]" />\r
+                            <MenuItem Header="Add All Remaining Selected Languages" cal:Message.Attach="[Event Click] = [Action AddAllRemainingForSelectedLanguages]" />\r
+                        </ContextMenu>\r
+                    </dropButton:DropButton.DropDown>\r
+                </dropButton:DropButton>\r
+                \r
+                <Button MinWidth="65"\r
                     Margin="0,0,10,0"\r
-                    cal:Message.Attach="[Event Click] = [Action Add]"\r
-                    Content="Add Track" />\r
+                    cal:Message.Attach="[Event Click] = [Action Clear]"\r
+                    Content="Clear" />\r
+\r
+\r
+            </StackPanel>\r
 \r
             <StackPanel Grid.Column="2"\r
                         Orientation="Horizontal"\r
index 0d93eea2d3d819bbf95d10b3f8e4234adbab704d..8d7575f547ef43507b0a2de3d5ab48ff68526be2 100644 (file)
@@ -5,7 +5,8 @@
         xmlns:Converters="clr-namespace:HandBrakeWPF.Converters"\r
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"\r
         xmlns:Micro="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"\r
-        AllowDrop="True"\r
+             xmlns:attachedProperties="clr-namespace:HandBrakeWPF.AttachedProperties"\r
+             AllowDrop="True"\r
         Background="#FFF0F0F0"\r
         FontSize="11"\r
         Micro:Message.Attach="[Event Loaded] = [Action Load]"\r
                      ToolBar.OverflowMode="Never"\r
                      ToolBarTray.IsLocked="True"\r
                      >\r
-                <Menu Background="Transparent">\r
+                <Menu Background="Transparent" attachedProperties:DriveMenu.ShowAvailableDrives="true">\r
                     <MenuItem ItemsSource="{Binding SourceMenu}">\r
                         <MenuItem.Header>\r
                             <StackPanel Orientation="Horizontal">\r
                             </StackPanel>\r
                         </MenuItem.Header>\r
                         <MenuItem Header="Add All" Micro:Message.Attach="[Event Click] = [Action AddAllToQueue]" />\r
-                        <!--<MenuItem Header="Add Selection" Micro:Message.Attach="[Event Click] = [Action AddSelectionToQueue]" />-->\r
+                        <MenuItem Header="Add Selection" Micro:Message.Attach="[Event Click] = [Action AddSelectionToQueue]" />\r
                     </MenuItem>\r
                 </Menu>\r
 \r
index b46b07ff5533d6a6d9e8e9860986e19b6717a3de..5e645dc7baf3af0c5464432aa7a11463025bf6f7 100644 (file)
@@ -4,6 +4,8 @@
         xmlns:cal="http://www.caliburnproject.org"\r
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\r
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
+        xmlns:Conveters="clr-namespace:HandBrakeWPF.Converters"\r
+        xmlns:Properties="clr-namespace:HandBrakeWPF.Properties"\r
         Title="{Binding Title}"\r
         Width="450"\r
         MaxHeight="450"\r
@@ -18,6 +20,8 @@
             <Setter Property="ToolTipService.ShowDuration" Value="20000" />\r
             <Setter Property="Margin" Value="0,2,0,2" />\r
         </Style>\r
+        \r
+        <Conveters:BooleanToVisibilityConverter x:Key="boolToVisConverter" />\r
     </Window.Resources>\r
 \r
     <Grid HorizontalAlignment="Stretch"\r
 \r
         <!--  Header  -->\r
         <StackPanel Grid.Row="0"\r
-                    Height="30"\r
+                    Height="36"\r
                     Margin="0,0,0,10"\r
                     Background="White"\r
                     Orientation="Horizontal">\r
-            <Image Width="24"\r
-                   Height="24"\r
+            <Image Width="32"\r
+                   Height="32"\r
                    Margin="10,0,5,0"\r
                    VerticalAlignment="Center"\r
                    Source="Images/AddToQueue_small.png" />\r
             <StackPanel VerticalAlignment="Center" Orientation="Vertical">\r
-                <TextBlock FontWeight="Bold" Text="Queue Multiple Items" />\r
+                <TextBlock FontWeight="Bold" Text="Add to Queue" />\r
+                <TextBlock Text="*** Experimental ***" />\r
             </StackPanel>\r
         </StackPanel>\r
 \r
@@ -70,7 +75,7 @@
             <ListBox.ContextMenu>\r
                 <ContextMenu>\r
                     <MenuItem Header="Select All" cal:Message.Attach="[Event Click] = [Action SelectAll]" />\r
-                    <MenuItem Header="Select All" cal:Message.Attach="[Event Click] = [Action UnSelectAll]" />\r
+                    <MenuItem Header="Deselect All" cal:Message.Attach="[Event Click] = [Action UnSelectAll]" />\r
                     <Separator />\r
                     <MenuItem Header="Order by Title" IsChecked="{Binding OrderedByTitle}" cal:Message.Attach="[Event Click] = [Action OrderByTitle]" />\r
                     <MenuItem Header="Order by Duration" IsChecked="{Binding OrderedByDuration}" cal:Message.Attach="[Event Click] = [Action OrderByDuration]" />\r
 \r
         <!-- Checlist -->\r
         <StackPanel Orientation="Vertical" Grid.Row="3" Margin="10,10,10,0">\r
-            <TextBlock Text="Checklist " />\r
+            <TextBlock Text="{x:Static Properties:Resources.QueueSelection_AutoTrackSelectionWarning}"\r
+                       TextWrapping="Wrap" Visibility="{Binding IsAutomaticTrackSelectionEnabled, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}" \r
+                       Margin="0,0,0,10"/>\r
+\r
+            <TextBlock Text="{x:Static Properties:Resources.QueueSelection_AutoNameWarning}"\r
+                       TextWrapping="Wrap" Visibility="{Binding IsAutoNamingEnabled, Converter={StaticResource boolToVisConverter}, ConverterParameter=true}"/>\r
         </StackPanel>\r
 \r
         <!--  Controls  -->\r
index 394eb35e447d10ae6f05b434790b1094ac189f78..d3df53451a9adc96617685fdb421fd3c7e09b390 100644 (file)
         xmlns:YourNamespace="clr-namespace:HandBrakeWPF.AttachedProperties"\r
         xmlns:Audio="clr-namespace:HandBrakeWPF.Converters.Audio"\r
         xmlns:Subtitles="clr-namespace:HandBrakeWPF.Converters.Subtitles" Title="{Binding Title}"\r
-        Width="600"\r
-        Height="400"\r
-        MinWidth="600"\r
-        MinHeight="400"\r
-        MaxWidth="600"\r
+        Width="700"\r
+        Height="500"\r
+        MinWidth="200"\r
+        MinHeight="200"\r
         Background="#FFF0F0F0"\r
         WindowStartupLocation="CenterScreen"\r
         TextOptions.TextFormattingMode="Display"\r
         <Converters:QueueStatusToVisibilityConverter x:Key="queueStatusVisConverter" />\r
         <Audio:AudioQueueDisplayConverter x:Key="audioTrackDisplayConverter" />\r
         <Subtitles:SubtitlesQueueDisplayConverter x:Key="subtitleTrackDisplayConverter" />\r
+\r
+\r
+        <Style x:Key="LongToolTipHolder" TargetType="FrameworkElement">\r
+            <Setter Property="ToolTipService.ShowDuration" Value="10000" />\r
+        </Style>\r
+\r
     </Window.Resources>\r
 \r
     <Grid>\r
                                   YourNamespace:MenuItemExtensions.GroupName="whenDone" />\r
                         <MenuItem x:Name="lock"\r
                                   cal:Message.Attach="[Event Click] = [Action WhenDone(lock.Header)]"\r
-                                  Header="Lock system"\r
+                                  Header="Lock System"\r
                                   IsCheckable="True"\r
                                   YourNamespace:MenuItemExtensions.GroupName="whenDone" />\r
                         <MenuItem x:Name="logoff"\r
             <TextBlock Text="{Binding JobsPending}" />\r
             <TextBlock Text="{Binding JobStatus}" />\r
         </StackPanel>\r
-        \r
+\r
         <ListBox Grid.Row="2"\r
                  Margin="10,0,10,10"\r
                  Background="LightGray"\r
                     <Setter Property="Margin" Value="0,0,0,1" />\r
                     <Setter Property="ToolTip">\r
                         <Setter.Value>\r
-                            <StackPanel Grid.Column="1"\r
-                                    Margin="0,5,0,5"\r
-                                    HorizontalAlignment="Stretch">\r
-                                <StackPanel Orientation="Horizontal">\r
-                                    <TextBlock FontWeight="Bold" Text="Video" />\r
-                                    <TextBlock Text=": " />\r
-                                    <TextBlock Text="{Binding Task.VideoEncoder, Converter={StaticResource enumComboConverter}}" />\r
-                                    <TextBlock Margin="10,0,0,0" FontWeight="Bold" Text="Audio: " />\r
-                                    <TextBlock Text="{Binding Task.AudioTracks, Converter={StaticResource audioTrackDisplayConverter}}" />\r
-                                </StackPanel>\r
-\r
-                                <StackPanel Orientation="Horizontal">\r
-                                    <TextBlock FontWeight="Bold" Text="Subtitles: " />\r
-                                    <TextBlock Text="{Binding Task.SubtitleTracks, Converter={StaticResource subtitleTrackDisplayConverter}}" />\r
-                                </StackPanel>\r
-\r
-                                <StackPanel Orientation="Horizontal">\r
-                                    <TextBlock FontWeight="Bold" Text="Advanced: " />\r
-                                    <TextBlock Text="{Binding Task.AdvancedEncoderOptions}" />\r
-                                </StackPanel>\r
+                            <Grid MaxWidth="650" Margin="0,5,0,5" Style="{StaticResource LongToolTipHolder}">\r
+                                <Grid.Resources>\r
+                                    <Style TargetType="TextBlock">\r
+                                        <Setter Property="Margin" Value="0,5,0,5" />\r
+                                    </Style>\r
+                                </Grid.Resources>\r
+\r
+                                <Grid.RowDefinitions>\r
+                                    <RowDefinition Height="Auto" />\r
+                                    <RowDefinition Height="Auto" />\r
+                                    <RowDefinition Height="Auto" />\r
+                                    <RowDefinition Height="Auto" />\r
+                                    <RowDefinition Height="Auto" />\r
+                                    <RowDefinition Height="Auto" />\r
+                                </Grid.RowDefinitions>\r
+\r
+                                <Grid.ColumnDefinitions>\r
+                                    <ColumnDefinition Width="90" />\r
+                                    <ColumnDefinition Width="*" />\r
+                                </Grid.ColumnDefinitions>\r
+\r
+                                <TextBlock FontWeight="Bold" Text="Source:" VerticalAlignment="Top" Grid.Row="0" Grid.Column="0" />\r
+                                <TextBlock Text="{Binding Task.Source}" TextWrapping="Wrap" Grid.Row="0" Grid.Column="1" />\r
+\r
+                                <TextBlock FontWeight="Bold" Text="Destination:" VerticalAlignment="Top" Grid.Row="1" Grid.Column="0" />\r
+                                <TextBlock Text="{Binding Task.Destination}" TextWrapping="Wrap" Grid.Row="1" Grid.Column="1" />\r
+\r
+                                <TextBlock FontWeight="Bold" Text="Video:" Grid.Row="2" Grid.Column="0" />\r
+                                <TextBlock Text="{Binding Task.VideoEncoder, Converter={StaticResource enumComboConverter}}"\r
+                                           Grid.Row="2" Grid.Column="1" />\r
+\r
+                                <TextBlock FontWeight="Bold" Text="Audio: "  Grid.Row="3" Grid.Column="0"/>\r
+                                <TextBlock Text="{Binding Task.AudioTracks, Converter={StaticResource audioTrackDisplayConverter}}"\r
+                                           Grid.Row="3" Grid.Column="1"/>\r
+\r
+                                <TextBlock FontWeight="Bold" VerticalAlignment="Top" Text="Subtitles: " Grid.Row="4" Grid.Column="0"  />\r
+                                <TextBlock Text="{Binding Task.SubtitleTracks, Converter={StaticResource subtitleTrackDisplayConverter}}"\r
+                                           Grid.Row="4" Grid.Column="1" />\r
+\r
+\r
+                                <TextBlock FontWeight="Bold" VerticalAlignment="Top" Grid.Row="5" Grid.Column="0"  Text="Advanced: " />\r
+                                <TextBlock Text="{Binding Task.AdvancedEncoderOptions}" Grid.Row="5" Grid.Column="1"  />\r
+                            </Grid>\r
 \r
-                            </StackPanel>\r
                         </Setter.Value>\r
                     </Setter>\r
                 </Style>\r
index 407666234e16fabdae3f2035f6c4053df96c920a..88624c5dfd8c0f3b464b6fdf6cd1ef7a29d3aab4 100644 (file)
@@ -3,7 +3,6 @@
 \r
     <Style x:Key="{x:Type StatusBar}" TargetType="{x:Type StatusBar}">\r
         <Setter Property="SnapsToDevicePixels" Value="True"/>\r
-        <Setter Property="OverridesDefaultStyle" Value="true"/>\r
         <Setter Property="Template">\r
             <Setter.Value>\r
                 <ControlTemplate TargetType="{x:Type StatusBar}">\r
 \r
     <SolidColorBrush x:Key="GlyphBrush" Color="#444"/>\r
 \r
+    <Style x:Key="DropButtonStyle" TargetType="ToggleButton" >\r
+        <Setter Property="Padding" Value="2,2" />\r
+        <Setter Property="ContentTemplate">\r
+            <Setter.Value>\r
+                <DataTemplate>\r
+                    <Grid VerticalAlignment="Stretch">\r
+                        <Grid.ColumnDefinitions>\r
+                            <ColumnDefinition Width="*" />\r
+                            <ColumnDefinition Width="Auto" />\r
+                            <ColumnDefinition Width="Auto" />\r
+                        </Grid.ColumnDefinitions>\r
+\r
+                        <TextBlock Text="{TemplateBinding Content}" Margin="4,0,0,0" Grid.Column="0" />\r
+\r
+                        <!--<Rectangle Grid.Column="1" Width="1" Fill="Black" Opacity="0.4" Margin="6,2,0,2"/>-->\r
+\r
+                        <Path Data="M 0,0 L 8,0 L 4,4 Z" Fill="Black" Grid.Column="2" Margin="4,0,4,0" VerticalAlignment="Center"/>\r
+                    </Grid>\r
+                </DataTemplate>\r
+            </Setter.Value>\r
+        </Setter>\r
+    </Style>\r
+\r
 </ResourceDictionary>
\ No newline at end of file
index cd8529937af897c22ff9203298db1c65551125c1..2eeb5dfdfb3965bb281516e847982368bddd31b4 100644 (file)
@@ -9,6 +9,7 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
              xmlns:NumericUpDown="clr-namespace:EagleBoost.Wpf.Presentation.Controls.NumericUpDown;assembly=EagleBoost.Wpf.Presentation"\r
              xmlns:controls="clr-namespace:HandBrakeWPF.Controls"\r
+             xmlns:dropButton="clr-namespace:HandBrakeWPF.Controls.DropButton"\r
              d:DesignHeight="153"\r
              d:DesignWidth="319"\r
              mc:Ignorable="d">\r
                    FontWeight="Bold"\r
                    Text="Subtitles" />\r
 \r
-        <Grid Grid.Row="1" Margin="10,5,10,0">\r
-            <Grid.ColumnDefinitions>\r
-                <ColumnDefinition Width="Auto" />\r
-                <ColumnDefinition Width="Auto" />\r
-                <ColumnDefinition Width="Auto" />\r
-            </Grid.ColumnDefinitions>\r
-            <Button Name="AddTrack"\r
-                    Grid.Column="0"\r
-                    Width="75"\r
-                    Margin="0,0,10,0"\r
-                    cal:Message.Attach="[Event Click] = [Action Add]"\r
-                    Content="Add" />\r
-            <Button Grid.Column="2"\r
-                    MaxWidth="100"\r
+        <StackPanel Grid.Row="1" Margin="10,5,10,0" Orientation="Horizontal">\r
+            <dropButton:DropButton Content="Add Track" FontWeight="Bold" Margin="0,0,10,0" Style="{StaticResource DropButtonStyle}">\r
+                <dropButton:DropButton.DropDown>\r
+                    <ContextMenu>\r
+                        <MenuItem Header="Add New Track" cal:Message.Attach="[Event Click] = [Action Add]" />\r
+                        <MenuItem Header="Add All Remaining Tracks" cal:Message.Attach="[Event Click] = [Action AddAllRemaining]" />\r
+                        <MenuItem Header="Add All Remaining Closed Captions" cal:Message.Attach="[Event Click] = [Action AddAllClosedCaptions]" />\r
+                        <MenuItem Header="Add All Remaining Selected Languages" cal:Message.Attach="[Event Click] = [Action AddAllRemainingForSelectedLanguages]" />\r
+                    </ContextMenu>\r
+                </dropButton:DropButton.DropDown>\r
+            </dropButton:DropButton>\r
+\r
+            <Button MinWidth="75"\r
                     cal:Message.Attach="[Event Click] = [Action Import]"\r
-                    Content="Import SRT" />\r
-        </Grid>\r
+                    Content="Import SRT"\r
+                    Margin="0,0,10,0"/>\r
+            <Button MinWidth="65"\r
+                    Grid.Column="3"\r
+                    Margin="0,0,10,0"\r
+                    cal:Message.Attach="[Event Click] = [Action Clear]"\r
+                    Content="Clear" />\r
+        </StackPanel>\r
 \r
         <ListBox Grid.Row="2"\r
                  Margin="10,10,10,10"\r
index 0c8fb0c3d1ad79e291d14be3054c45a47c1aad23..4e1d7626307f0812c03054fae5970ee0cf2eb32b 100644 (file)
@@ -95,8 +95,8 @@
 \r
                 <StackPanel Orientation="Horizontal" Margin="0,0,0,10" >\r
                     <RadioButton Content="Constant Quality:" IsChecked="{Binding IsConstantQuantity}"  Margin="0,0,10,0"/>\r
-                    <TextBlock Text="{Binding DisplayRF}" Width="25" />\r
-                    <TextBlock Text="{Binding Rfqp}" FontWeight="Bold" />\r
+                    <TextBlock Text="{Binding DisplayRF}" MinWidth="30" />\r
+                    <TextBlock Text="{Binding Rfqp}" FontWeight="Bold" Margin="5,0,0,0" />\r
 \r
                     <TextBlock Text="{x:Static Properties:Resources.Video_LosslessWarning}" Visibility="{Binding IsLossless, Converter={StaticResource boolToVisConverter}}" \r
                            Margin="10,0,0,0" ToolTip="{x:Static Properties:Resources.Video_LosslessWarningTooltip}" FontWeight="Bold" />\r
index d14f6f7f3981cb78e1fed356e582a42d24f291a4..10480d486ebd2a65e28e2cabc223544b3f554f7d 100644 (file)
       <string>ShowAdvancedTab</string>\r
     </key>\r
     <value>\r
-      <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:boolean" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">true</anyType>\r
+      <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:boolean" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">false</anyType>\r
     </value>\r
   </item>\r
   <item>\r