]> granicus.if.org Git - handbrake/commitdiff
Don't expose rate, mixdown, dither and encoder arrays to the UIs.
authorRodeo <tdskywalker@gmail.com>
Thu, 30 May 2013 13:57:37 +0000 (13:57 +0000)
committerRodeo <tdskywalker@gmail.com>
Thu, 30 May 2013 13:57:37 +0000 (13:57 +0000)
- instead, make these lists available through enumerators:
--> hb_*_get_next(<type> *last);

- this should give us more flexibility to populate the lists at runtime, using the implementation(s) of our choice, whether they use arrays or not, without requiring UI modifications

- use consistent naming for getters
--> hb_get_best_foo() becomes hb_foo_get_best(), and so on

- hb_*_get_from_name() and hb_*_ sanitize_name() sanitize the requested value to a supported one if it's unavailable

- adds an additional, passthru-specific fallback mechanism

- adds a list of video containers

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5526 b64f7644-9d1e-0410-96f1-a4d463321fa5

16 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/encavcodec.c
libhb/scan.c
libhb/work.c
macosx/Controller.m
macosx/HBAudio.m
macosx/HBAudioController.m
macosx/HBPreviewController.m
macosx/HBSubtitles.m
scripts/manicure.rb
test/test.c

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 95c9f921d009abb30349aa827509f486eff3b387..1d02af53647de8d30ff1618935a8b8c64faa2dd6 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,10 +112,10 @@ 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 },
-    { "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 },
+    { "H.264 (x264)",    "x264",    HB_VCODEC_X264,         HB_MUX_MASK_MP4|HB_MUX_MASK_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);
 
@@ -123,566 +123,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; }
-
-int hb_audio_dither_get_default()
+// note: for each container, the muxer nearer the top is the default
+hb_container_t hb_containers[] =
 {
-    // "auto"
-    return hb_audio_dithers[0].method;
-}
+    { "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_method()
+int hb_video_framerate_get_from_name(const char *name)
 {
-    /*
-     * 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;
-}
+    if (name == NULL || *name == '\0')
+        goto fail;
 
-int hb_audio_dither_is_supported(uint32_t codec)
-{
-    // encoder's input sample format must be s16(p)
-    switch (codec)
+    // TODO: implement something more flexible
+    if (!strcasecmp(name, "23.976 (NTSC Film)"))
     {
-        case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FDK_AAC:
-        case HB_ACODEC_FDK_HAAC:
-            return 1;
-        default:
-            return 0;
+        return 1126125;
+    }
+    if (!strcasecmp(name, "25 (PAL Film/Video)"))
+    {
+        return 1080000;
+    }
+    if (!strcasecmp(name, "29.97 (NTSC Video)"))
+    {
+        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);
+        if (hb_video_rates[i].rate == framerate)
+        {
+            return hb_video_rates[i].name;
+        }
+    }
 
-        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));
+fail:
+    return NULL;
+}
 
-        default:
-            return (mixdown <= HB_AMIXDOWN_5POINT1);
-    }
+const char* hb_video_framerate_sanitize_name(const char *name)
+{
+    return hb_video_framerate_get_name(hb_video_framerate_get_from_name(name));
 }
 
-int hb_mixdown_has_remix_support(int mixdown, uint64_t layout)
+const hb_rate_t* hb_video_framerate_get_next(const hb_rate_t *last)
 {
-    switch (mixdown)
+    if (last == NULL)
     {
-        // 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[0];
     }
+    if (last <  &hb_video_rates[0] ||
+        last >= &hb_video_rates[hb_video_rates_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
 }
 
-int hb_mixdown_get_discrete_channel_count(int amixdown)
+int hb_audio_samplerate_get_best(uint32_t codec, int samplerate, int *sr_shift)
 {
-    switch (amixdown)
+    int ii, best_samplerate, samplerate_shift;
+    if ((samplerate < 32000) &&
+        (codec == HB_ACODEC_CA_HAAC || codec == HB_ACODEC_AC3))
     {
-        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;
+        // 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)
+    {
+        // fdk_haac can't do samplerates < 16 kHz
+        best_samplerate  = 16000;
+        samplerate_shift = 1;
+    }
+    else
+    {
+        best_samplerate = samplerate;
+        for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
+        {
+            // valid samplerate
+            if (best_samplerate == hb_audio_rates[ii].rate)
+                break;
 
-        default:
-            return 2;
+            // 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;
+            }
+        }
+        /* 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;
+    }
+    return best_samplerate;
 }
 
-int hb_mixdown_get_low_freq_channel_count(int amixdown)
+int hb_audio_samplerate_get_from_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;
+    if (name == NULL || *name == '\0')
+        goto fail;
 
-        default:
-            return 0;
+    // 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)
+    {
+        return i;
     }
-}
 
-int hb_mixdown_get_mixdown_from_short_name(const char *short_name)
-{
-    int i;
-    for (i = 0; i < hb_audio_mixdowns_count; i++)
+    for (i = 0; i < hb_audio_rates_count; i++)
     {
-        if (!strcmp(hb_audio_mixdowns[i].short_name, short_name))
+        if (!strcasecmp(hb_audio_rates[i].name, name))
         {
-            return hb_audio_mixdowns[i].amixdown;
+            return hb_audio_rates[i].rate;
         }
     }
-    return 0;
+
+fail:
+    return -1;
 }
 
-const char* hb_mixdown_get_short_name_from_mixdown(int amixdown)
+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;
-    for (i = 0; i < hb_audio_mixdowns_count; i++)
+    for (i = 0; i < hb_audio_rates_count; i++)
     {
-        if (hb_audio_mixdowns[i].amixdown == amixdown)
+        if (hb_audio_rates[i].rate == samplerate)
         {
-            return hb_audio_mixdowns[i].short_name;
+            return hb_audio_rates[i].name;
         }
     }
-    return "";
+
+fail:
+    return NULL;
 }
 
-void hb_autopassthru_apply_settings( hb_job_t * job )
+const hb_rate_t* hb_audio_samplerate_get_next(const hb_rate_t *last)
 {
-    int i, j, already_printed;
-    hb_audio_t * audio;
-    for( i = 0, already_printed = 0; i < hb_list_count( job->list_audio ); )
+    if (last == NULL)
     {
-        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_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
-            {
-                for( j = 0; j < hb_audio_encoders_count; j++ )
-                {
-                    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 );
-                        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;
+        return  &hb_audio_rates[0];
+    }
+    if (last <  &hb_audio_rates[0] ||
+        last >= &hb_audio_rates[hb_audio_rates_count - 1])
+    {
+        return NULL;
     }
+    return last + 1;
 }
 
-void hb_autopassthru_print_settings( hb_job_t * job )
+// Given an input bitrate, find closest match in the set of allowed bitrates
+static int hb_audio_bitrate_find_closest(int bitrate)
 {
-    int i, codec_len;
-    char *mask = NULL, *tmp;
-    const char *fallback = NULL;
-    for( i = 0; i < hb_audio_encoders_count; i++ )
-    {
-        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;
-                }
-            }
-            // 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 )
-            {
-                free( mask );
-                mask = tmp;
-            }
-        }
-        else if( !( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) &&
-                  ( hb_audio_encoders[i].encoder == job->acodec_fallback ) )
-        {
-            fallback = hb_audio_encoders[i].human_readable_name;
-        }
-    }
-    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 );
-}
+    // Check if bitrate mode was disabled
+    if (bitrate <= 0)
+        return bitrate;
 
-int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer )
-{
-    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++ )
-    {
-        if( ( hb_audio_encoders[i].encoder == fallback ) &&
-           !( hb_audio_encoders[i].muxers & muxer ) )
-        {
-            // fallback not possible with current muxer
-            // use the default audio encoder instead
-            fallback = hb_get_default_audio_encoder(muxer);
-            break;
-        }
-    }
-    for( i = 0; i < hb_audio_encoders_count; i++ )
+    // result is highest rate if none found during search.
+    // rate returned will always be <= rate asked for.
+    int i, result = hb_audio_bitrates[0].rate;
+    for (i = hb_audio_bitrates_count - 1; i > 0; i--)
     {
-        if( ( hb_audio_encoders[i].encoder == out_codec ) &&
-           !( hb_audio_encoders[i].muxers & muxer ) )
+        if (bitrate >= hb_audio_bitrates[i].rate)
         {
-            // selected passthru not possible with current muxer
-            out_codec = fallback;
+            result = hb_audio_bitrates[i].rate;
             break;
         }
     }
-    if( !( out_codec & HB_ACODEC_PASS_MASK ) )
-        return fallback;
-    return out_codec;
+    return result;
 }
 
-int hb_get_default_audio_encoder(int muxer)
+// 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)
 {
-#ifndef __APPLE__
-    if (muxer == HB_MUX_MKV)
-    {
-        return HB_ACODEC_LAME;
-    }
-#endif
-    return hb_audio_encoders[0].encoder;
+    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);
 }
 
-// Given an input bitrate, find closest match in the set of allowed bitrates
-int hb_find_closest_audio_bitrate(int bitrate)
+// Get the default bitrate for a given codec/samplerate/mixdown triplet.
+int hb_audio_bitrate_get_default(uint32_t codec, int samplerate, int mixdown)
 {
-    // Check if bitrate mode was disabled
-    if (bitrate <= 0)
-        return bitrate;
+    if ((codec & HB_ACODEC_PASS_FLAG) || !(codec & HB_ACODEC_MASK))
+        goto fail;
 
-    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 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)
     {
-        if (bitrate >= hb_audio_bitrates[ii].rate)
-        {
-            result = hb_audio_bitrates[ii].rate;
+        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;
-        }
     }
-    return result;
+    // 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_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown,
+ *
+ * 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)
 {
-    if (codec & HB_ACODEC_PASS_FLAG)
-    {
-        // 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;
-    }
-
     /* 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;
@@ -710,32 +564,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)));
@@ -781,304 +640,1053 @@ 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;
+            *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;
+    if (*high > hb_audio_bitrates[hb_audio_bitrates_count - 1].rate)
+        *high = hb_audio_bitrates[hb_audio_bitrates_count - 1].rate;
+}
+
+const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last)
+{
+    if (last == NULL)
+    {
+        return  &hb_audio_bitrates[0];
+    }
+    if (last <  &hb_audio_bitrates[0] ||
+        last >= &hb_audio_bitrates[hb_audio_bitrates_count - 1])
+    {
+        return NULL;
+    }
+    return last + 1;
+}
+
+// Get limits and hints for the UIs.
+//
+// granularity sets the minimum step increments that should be used
+// (it's ok to round up to some nice multiple if you like)
+//
+// direction says whether 'low' limit is highest or lowest
+// quality (direction 0 == lowest value is worst quality)
+void hb_audio_quality_get_limits(uint32_t codec, float *low, float *high,
+                                 float *granularity, int *direction)
+{
+    switch (codec)
+    {
+        case HB_ACODEC_LAME:
+            *direction   = 1;
+            *granularity = 0.5;
+            *low         = 0.;
+            *high        = 10.;
+            break;
+
+        case HB_ACODEC_VORBIS:
+            *direction   = 0;
+            *granularity = 0.5;
+            *low         = -2.;
+            *high        = 10.;
+            break;
+
+        case HB_ACODEC_CA_AAC:
+            *direction   = 0;
+            *granularity = 9.;
+            *low         = 1.;
+            *high        = 127.;
+            break;
+
+        default:
+            *direction   = 0;
+            *granularity = 1.;
+            *low = *high = HB_INVALID_AUDIO_QUALITY;
+            break;
+    }
+}
+
+float hb_audio_quality_get_best(uint32_t codec, float quality)
+{
+    int direction;
+    float low, high, granularity;
+    hb_audio_quality_get_limits(codec, &low, &high, &granularity, &direction);
+    if (quality > high)
+        quality = high;
+    if (quality < low)
+        quality = low;
+    return quality;
+}
+
+float hb_audio_quality_get_default(uint32_t codec)
+{
+    switch (codec)
+    {
+        case HB_ACODEC_LAME:
+            return 2.;
+
+        case HB_ACODEC_VORBIS:
+            return 5.;
+
+        case HB_ACODEC_CA_AAC:
+            return 91.;
+
+        default:
+            return HB_INVALID_AUDIO_QUALITY;
+    }
+}
+
+// Get limits and hints for the UIs.
+//
+// granularity sets the minimum step increments that should be used
+// (it's ok to round up to some nice multiple if you like)
+//
+// direction says whether 'low' limit is highest or lowest
+// compression level (direction 0 == lowest value is worst compression level)
+void hb_audio_compression_get_limits(uint32_t codec, float *low, float *high,
+                                     float *granularity, int *direction)
+{
+    switch (codec)
+    {
+        case HB_ACODEC_FFFLAC:
+        case HB_ACODEC_FFFLAC24:
+            *direction   = 0;
+            *granularity = 1.;
+            *high        = 12.;
+            *low         = 0.;
             break;
+            
+        case HB_ACODEC_LAME:
+            *direction   = 1;
+            *granularity = 1.;
+            *high        = 9.;
+            *low         = 0.;
+            break;
+            
+        default:
+            *direction   = 0;
+            *granularity = 1.;
+            *low = *high = -1.;
+            break;
+    }
+}
+
+float hb_audio_compression_get_best(uint32_t codec, float compression)
+{
+    int direction;
+    float low, high, granularity;
+    hb_audio_compression_get_limits(codec, &low, &high, &granularity, &direction);
+    if( compression > high )
+        compression = high;
+    if( compression < low )
+        compression = low;
+    return compression;
+}
+
+float hb_audio_compression_get_default(uint32_t codec)
+{
+    switch (codec)
+    {
+        case HB_ACODEC_FFFLAC:
+        case HB_ACODEC_FFFLAC24:
+            return 5.;
+
+        case HB_ACODEC_LAME:
+            return 2.;
+
+        default:
+            return -1.;
+    }
+}
+
+int hb_audio_dither_get_default()
+{
+    // "auto"
+    return hb_audio_dithers[0].method;
+}
+
+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_audio_dither_is_supported(uint32_t codec)
+{
+    // encoder's input sample format must be s16(p)
+    switch (codec)
+    {
+        case HB_ACODEC_FFFLAC:
+        case HB_ACODEC_FDK_AAC:
+        case HB_ACODEC_FDK_HAAC:
+            return 1;
+
+        default:
+            return 0;
+    }
+}
+
+int hb_audio_dither_get_from_name(const char *name)
+{
+    if (name == NULL || *name == '\0')
+        goto fail;
+
+    int i;
+    for ( i = 0; i < hb_audio_dithers_count; i++)
+    {
+        if (!strcasecmp(hb_audio_dithers[i].short_name, name))
+        {
+            return hb_audio_dithers[i].method;
+        }
+    }
+
+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++)
+    {
+        if (hb_audio_dithers[i].method == method)
+        {
+            return hb_audio_dithers[i].description;
+        }
+    }
+
+fail:
+    return NULL;
+}
+
+const hb_dither_t* hb_audio_dither_get_next(const hb_dither_t *last)
+{
+    if (last == NULL)
+    {
+        return  &hb_audio_dithers[0];
+    }
+    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;
     }
-    // sanitize max. bitrate
-    if (*high < hb_audio_bitrates[0].rate)
-        *high = hb_audio_bitrates[0].rate;
-    if (*high > hb_audio_bitrates[hb_audio_bitrates_count-1].rate)
-        *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)
-{
-    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)
+void hb_autopassthru_print_settings(hb_job_t *job)
 {
-    if (codec & HB_ACODEC_PASS_FLAG)
+    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)
     {
-        return -1;
+        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 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)
+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)
     {
-        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;
+        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;
+        }
     }
-    // sample_rate adjustment
-    bitrate >>= sr_shift;
-    return hb_get_best_audio_bitrate(codec, bitrate, samplerate, mixdown);
+    return (out_codec & HB_ACODEC_PASS_MASK) ? out_codec : fallback;
 }
 
-// Get limits and hints for the UIs.
-//
-// granularity sets the minimum step increments that should be used
-// (it's ok to round up to some nice multiple if you like)
-//
-// 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,
-                                 float *granularity, int *direction)
+int hb_container_get_from_name(const char *name)
 {
-    switch (codec)
-    {
-        case HB_ACODEC_LAME:
-            *direction = 1;
-            *granularity = 0.5;
-            *low = 0.;
-            *high = 10.0;
-            break;
+    if (name == NULL || *name == '\0')
+        goto fail;
 
-        case HB_ACODEC_VORBIS:
-            *direction = 0;
-            *granularity = 0.5;
-            *low = -2.0;
-            *high = 10.0;
-            break;
-
-        case HB_ACODEC_CA_AAC:
-            *direction = 0;
-            *granularity = 9;
-            *low = 1.;
-            *high = 127.0;
-            break;
+    // 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;
+    }
 
-        default:
-            *direction = 0;
-            *granularity = 1;
-            *low = *high = HB_INVALID_AUDIO_QUALITY;
-            break;
+    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;
+        }
     }
-}
 
-float hb_get_best_audio_quality(uint32_t codec, float quality)
-{
-    float low, high, granularity;
-    int direction;
-    hb_get_audio_quality_limits(codec, &low, &high, &granularity, &direction);
-    if (quality > high)
-        quality = high;
-    if (quality < low)
-        quality = low;
-    return quality;
+fail:
+    return -1;
 }
 
-float hb_get_default_audio_quality( uint32_t codec )
+int hb_container_get_from_extension(const char *extension)
 {
-    float quality;
-    switch( codec )
-    {
-        case HB_ACODEC_LAME:
-            quality = 2.;
-            break;
-
-        case HB_ACODEC_VORBIS:
-            quality = 5.;
-            break;
+    if (extension == NULL || *extension == '\0')
+        goto fail;
 
-        case HB_ACODEC_CA_AAC:
-            quality = 91.;
-            break;
+    // TODO: implement something more flexible
+    if (!strcasecmp(extension, "m4v"))
+    {
+        return HB_MUX_MP4;
+    }
 
-        default:
-            quality = HB_INVALID_AUDIO_QUALITY;
-            break;
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (!strcasecmp(hb_containers[i].default_extension, extension))
+        {
+            return hb_containers[i].format;
+        }
     }
-    return quality;
+
+fail:
+    return -1;
 }
 
-// Get limits and hints for the UIs.
-//
-// granularity sets the minimum step increments that should be used
-// (it's ok to round up to some nice multiple if you like)
-//
-// 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,
-                                     float *granularity, int *direction)
+const char* hb_container_get_name(int format)
 {
-    switch (codec)
-    {
-        case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FFFLAC24:
-            *direction = 0;
-            *granularity = 1;
-            *high = 12;
-            *low = 0;
-            break;
+    if (!(format & HB_MUX_MASK))
+        goto fail;
 
-        case HB_ACODEC_LAME:
-            *direction = 1;
-            *granularity = 1;
-            *high = 9;
-            *low = 0;
-            break;
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (hb_containers[i].format == format)
+        {
+            return hb_containers[i].name;
+        }
 
-        default:
-            *direction = 0;
-            *granularity = 1;
-            *low = *high = -1;
-            break;
     }
-}
 
-float hb_get_best_audio_compression(uint32_t codec, float compression)
-{
-    float low, high, granularity;
-    int direction;
-    hb_get_audio_compression_limits(codec, &low, &high, &granularity, &direction);
-    if( compression > high )
-        compression = high;
-    if( compression < low )
-        compression = low;
-    return compression;
+fail:
+    return NULL;
 }
 
-float hb_get_default_audio_compression(uint32_t codec)
+const char* hb_container_get_short_name(int format)
 {
-    switch (codec)
-    {
-        case HB_ACODEC_FFFLAC:
-        case HB_ACODEC_FFFLAC24:
-            return 5.;
-
-        case HB_ACODEC_LAME:
-            return 2.;
+    if (!(format & HB_MUX_MASK))
+        goto fail;
 
-        default:
-            return -1.;
+    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;
 }
 
-int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown)
+const char* hb_container_get_default_extension(int format)
 {
-    // Passthru, only "None" mixdown is supported
-    if (codec & HB_ACODEC_PASS_FLAG)
-        return HB_AMIXDOWN_NONE;
+    if (!(format & HB_MUX_MASK))
+        goto fail;
 
-    // caller requested the best available mixdown
-    if (mixdown == HB_INVALID_AMIXDOWN)
-        mixdown  = hb_audio_mixdowns[hb_audio_mixdowns_count - 1].amixdown;
+    int i;
+    for (i = 0; i < hb_containers_count; i++)
+    {
+        if (hb_containers[i].format == format)
+        {
+            return hb_containers[i].default_extension;
+        }
+    }
 
-    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;
+fail:
+    return NULL;
 }
 
-int hb_get_default_mixdown(uint32_t codec, uint64_t layout)
+const char* hb_container_sanitize_name(const char *name)
 {
-    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_get_best_mixdown(codec, layout, mixdown);
+    return hb_container_get_name(hb_container_get_from_name(name));
 }
 
-int hb_get_best_samplerate(uint32_t codec, int samplerate, int *sr_shift)
+const hb_container_t* hb_container_get_next(const hb_container_t *last)
 {
-    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)
-    {
-        // fdk_haac can't do samplerates < 16 kHz
-        best_samplerate  = 16000;
-        samplerate_shift = 1;
-    }
-    else
+    if (last == NULL)
     {
-        best_samplerate = samplerate;
-        for (ii = hb_audio_rates_count - 1; ii >= 0; ii--)
-        {
-            // 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;
-            }
-        }
-        /* 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);
+        return  &hb_containers[0];
     }
-    if (sr_shift != NULL)
+    if (last <  &hb_containers[0] ||
+        last >= &hb_containers[hb_containers_count - 1])
     {
-        *sr_shift = samplerate_shift;
+        return NULL;
     }
-    return best_samplerate;
+    return last + 1;
 }
 
 /**********************************************************************
@@ -2336,7 +2944,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;
@@ -2970,9 +3578,9 @@ void hb_attachment_close( hb_attachment_t **attachment )
  * hb_yuv2rgb
  **********************************************************************
  * Converts a YCrCb pixel to an RGB pixel.
- * 
+ *
  * This conversion is lossy (due to rounding and clamping).
- * 
+ *
  * Algorithm:
  *   http://en.wikipedia.org/w/index.php?title=YCbCr&oldid=361987695#Technical_details
  *********************************************************************/
@@ -3004,9 +3612,9 @@ int hb_yuv2rgb(int yuv)
  * hb_rgb2yuv
  **********************************************************************
  * Converts an RGB pixel to a YCrCb pixel.
- * 
+ *
  * This conversion is lossy (due to rounding and clamping).
- * 
+ *
  * Algorithm:
  *   http://en.wikipedia.org/w/index.php?title=YCbCr&oldid=361987695#Technical_details
  *********************************************************************/
index 2951def5d17a375b641fb2f9fd21d6323b1e00de..58d102c9abd7e6c1f11b722f8ac5edb1c7c809ad 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;
@@ -171,7 +172,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;
 };
 
@@ -184,7 +185,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;
@@ -192,10 +193,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
@@ -210,77 +219,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
 {
@@ -408,12 +455,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;
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 72d758eedc82e8ca2186a7a242b92c702982a5ba..1e05c9db76fb9e29d6d67af53dd2dd270335a7c9 100644 (file)
@@ -149,12 +149,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");
@@ -206,26 +206,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;
     }
 
@@ -295,14 +288,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 )
@@ -346,6 +332,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 )
@@ -413,25 +411,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" );
@@ -449,22 +435,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);
                 }
             }
         }
@@ -494,24 +485,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 );
@@ -797,21 +788,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;
             }
 
@@ -820,44 +804,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;
                 }
             }
@@ -866,7 +831,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",
@@ -877,7 +842,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)
                 {
@@ -901,7 +866,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)
                 {
@@ -927,7 +892,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)
@@ -940,7 +905,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 93c61f8b57790c21cbef6a707319234549e3763c..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.*/
@@ -3313,8 +3319,6 @@ fWorkingCount = 0;
             [fSrcTitlePopUp indexOfSelectedItem] );
     hb_job_t * job = title->job;
     hb_filter_object_t * filter;
-    int vrate, vrate_base;
-
     /* set job->angle for libdvdnav */
     job->angle = [fSrcAnglePopUp indexOfSelectedItem] + 1;
     /* Chapter selection */
@@ -3381,37 +3385,37 @@ fWorkingCount = 0;
     }
 
     /* Video settings */
-    
+    int fps_mode, fps_num, fps_den;
     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
     {
         /* a specific framerate has been chosen */
-        vrate      = 27000000;
-        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 */
-        vrate      = title->rate;
-        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;
         }
     }
 
@@ -3723,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, vrate, 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]);
 }
 
 
@@ -3742,8 +3746,6 @@ bool one_burned = FALSE;
     hb_job_t * job = title->job;
     hb_audio_config_t * audio;
     hb_filter_object_t * filter;
-    int vrate, vrate_base;
-
     /* Title Angle for dvdnav */
     job->angle = [[queueToApply objectForKey:@"TitleAngle"] intValue];
     
@@ -3938,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 */
-        vrate      = 27000000;
-        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 */
-        vrate      = [[queueToApply objectForKey:@"JobVrate"] intValue];
-        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;
         }
     }
     
@@ -4159,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];
@@ -4284,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, vrate, 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"];    
 }
@@ -4922,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];
         }
     }
     
@@ -4965,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)
     {
@@ -5090,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];
@@ -5170,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*/
@@ -5898,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:@" - "])
     {
@@ -6397,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"]];
 
@@ -6413,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*/
@@ -6427,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])
@@ -6549,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 */
@@ -6604,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 */
@@ -7131,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"];
@@ -7147,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 4dc9b8db75ae0c3f108316230d72904f0a36f066..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
@@ -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 efa7ae2271717624fcec3ee82353c0b93ce63931..05b415043d4587d963d9ad72a093c84e0888e2fb 100644 (file)
@@ -153,11 +153,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 );
 
@@ -578,7 +573,7 @@ static int HandleEvents( hb_handle_t * h )
 {
     hb_state_t s;
     int tmp_num_audio_tracks;
-    int filter_vrate, filter_vrate_base, filter_cfr;
+    int filter_cfr, filter_vrate, filter_vrate_base;
 
     hb_get_state( h, &s );
     switch( s.state )
@@ -688,10 +683,10 @@ static int HandleEvents( hb_handle_t * h )
             PrintTitleInfo( title, title_set->feature );
 
             /* Set job settings */
-            job = hb_job_init( title );
-            filter_vrate = job->vrate;
+            job = hb_job_init(title);
+            filter_cfr        = job->cfr;
+            filter_vrate      = job->vrate;
             filter_vrate_base = job->vrate_base;
-            filter_cfr = job->cfr;
 
 
             if( chapter_start && chapter_end && !stop_at_pts && !start_at_preview && !stop_at_frame && !start_at_pts && !start_at_frame )
@@ -1756,25 +1751,25 @@ static int HandleEvents( hb_handle_t * h )
             free( filter_str );
 
             // Add framerate shaping filter
-            if( vrate )
+            if (vrate)
             {
-                filter_cfr = cfr;
-                filter_vrate = 27000000;
+                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.
-                filter_cfr = cfr;
-                filter_vrate = title->rate;
+                filter_cfr        = cfr;
+                filter_vrate      = title->rate;
                 filter_vrate_base = title->rate_base;
             }
-            filter_str = hb_strdup_printf("%d:%d:%d",
-                filter_cfr, filter_vrate, filter_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);
 
             // hb_job_init() will set a default muxer for us
             // only override it if a specific muxer has been set
@@ -1966,10 +1961,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 )
                     {
@@ -2007,7 +2002,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);
@@ -2026,18 +2021,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 )
                     {
@@ -2046,9 +2030,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;
                         }
                         
@@ -2091,8 +2081,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;
@@ -2299,8 +2289,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))
@@ -2422,45 +2412,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++;
@@ -2891,7 +2877,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];
@@ -2934,8 +2926,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"
@@ -2947,23 +2953,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>          ");
@@ -3060,11 +3067,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"
@@ -3088,33 +3098,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"
@@ -3132,25 +3153,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,
@@ -3159,11 +3180,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"
@@ -3178,30 +3202,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,
@@ -3894,18 +3923,10 @@ static int ParseOptions( int argc, char ** argv )
                 break;
             case 'e':
             {
-                int i;
-                for( i = 0, vcodec = 0; i < hb_video_encoders_count; i++ )
-                {
-                    if( !strcasecmp( hb_video_encoders[i].short_name, optarg ) )
-                    {
-                        vcodec = hb_video_encoders[i].encoder;
-                        break;
-                    }
-                }
-                if( !vcodec )
+                vcodec = hb_video_encoder_get_from_name(optarg);
+                if (vcodec <= 0)
                 {
-                    fprintf( stderr, "invalid codec (%s)\n", optarg );
+                    fprintf(stderr, "invalid codec (%s)\n", optarg);
                     return -1;
                 }
                 break;
@@ -3940,21 +3961,13 @@ static int ParseOptions( int argc, char ** argv )
                 break;
             case 'r':
             {
-                int i;
-                vrate = 0;
-                for( i = 0; i < hb_video_rates_count; i++ )
-                {
-                    if( !strcmp( optarg, hb_video_rates[i].string ) )
-                    {
-                        vrate = hb_video_rates[i].rate;
-                        break;
-                    }
-                }
-                if( !vrate )
+                vrate = hb_video_framerate_get_from_name(optarg);
+                if (vrate <= 0)
                 {
-                    fprintf( stderr, "invalid framerate %s\n", optarg );
+                    vrate = 0;
+                    fprintf(stderr, "invalid framerate %s\n", optarg);
                 }
-                else if ( cfr == 0 )
+                else if (!cfr)
                 {
                     cfr = 1;
                 }
@@ -4067,28 +4080,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;
@@ -4139,94 +4157,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;
 }