OSDN Git Service

LinGui: remove target file size option
[handbrake-jp/handbrake-jp-git.git] / gtk / src / hb-backend.c
index 44de3c2..0f7bba1 100644 (file)
@@ -2,7 +2,7 @@
  *            hb-backend.c
  *
  *  Fri Mar 28 10:38:44 2008
- *  Copyright  2008  John Stebbins
+ *  Copyright  2008-2011  John Stebbins
  *  <john at stebbins dot name>
  ****************************************************************************/
 
@@ -86,6 +86,7 @@ static options_map_t d_when_complete_opts[] =
 {
        {"Do Nothing",            "nothing",  0, "0"},
        {"Show Notification",     "notify",   1, "1"},
+       {"Quit Handbrake",        "quit",     4, "4"},
        {"Put Computer To Sleep", "sleep",    2, "2"},
        {"Shutdown Computer",     "shutdown", 3, "3"},
 };
@@ -249,12 +250,13 @@ combo_opts_t vcodec_opts =
 
 static options_map_t d_acodec_opts[] =
 {
-       {"AAC (faac)",      "faac",   HB_ACODEC_FAAC,   "faac"},
-       {"MP3 (lame)",      "lame",   HB_ACODEC_LAME,   "lame"},
-       {"Vorbis",          "vorbis", HB_ACODEC_VORBIS, "vorbis"},
-       {"AC3 (pass-thru)", "ac3",    HB_ACODEC_AC3,    "ac3"},
-       {"DTS (pass-thru)", "dts",    HB_ACODEC_DCA,    "dts"},
-       {"Choose For Me",   "auto",   HB_ACODEC_MASK,   "auto"},
+       {"AAC (faac)",      "faac",    HB_ACODEC_FAAC,     "faac"},
+       {"MP3 (lame)",      "lame",    HB_ACODEC_LAME,     "lame"},
+       {"Vorbis",          "vorbis",  HB_ACODEC_VORBIS,   "vorbis"},
+       {"AC3 (ffmpeg)",    "ac3",     HB_ACODEC_AC3,      "ac3"},
+       {"AC3 (pass-thru)", "ac3pass", HB_ACODEC_AC3_PASS, "ac3pass"},
+       {"DTS (pass-thru)", "dtspass", HB_ACODEC_DCA_PASS, "dtspass"},
+       {"Choose For Me",   "auto",    HB_ACODEC_ANY,      "auto"},
 };
 combo_opts_t acodec_opts =
 {
@@ -287,6 +289,30 @@ combo_opts_t badapt_opts =
        d_badapt_opts
 };
 
+static options_map_t d_bpyramid_opts[] =
+{
+       {"Off",    "none",   0, "none"},
+       {"Strict", "strict", 1, "strict"},
+       {"Normal", "normal", 2, "normal"},
+};
+combo_opts_t bpyramid_opts =
+{
+       sizeof(d_bpyramid_opts)/sizeof(options_map_t),
+       d_bpyramid_opts
+};
+
+static options_map_t d_weightp_opts[] =
+{
+       {"Off",    "0", 0, "0"},
+       {"Simple", "1", 1, "1"},
+       {"Smart",  "2", 2, "2"},
+};
+combo_opts_t weightp_opts =
+{
+       sizeof(d_weightp_opts)/sizeof(options_map_t),
+       d_weightp_opts
+};
+
 static options_map_t d_me_opts[] =
 {
        {"Diamond",              "dia",  0, "dia"},
@@ -303,16 +329,17 @@ combo_opts_t me_opts =
 
 static options_map_t d_subme_opts[] =
 {
-       {"1", "1", 1, "1"},
-       {"2", "2", 2, "2"},
-       {"3", "3", 3, "3"},
-       {"4", "4", 4, "4"},
-       {"5", "5", 5, "5"},
-       {"6", "6", 6, "6"},
-       {"7", "7", 7, "7"},
-       {"8", "8", 8, "8"},
-       {"9", "9", 9, "9"},
-       {"10", "10", 10, "10"},
+       {"0: SAD, no subpel",          "0", 0, "0"},
+       {"1: SAD, qpel",               "1", 1, "1"},
+       {"2: SATD, qpel",              "2", 2, "2"},
+       {"3: SATD: multi-qpel",        "3", 3, "3"},
+       {"4: SATD, qpel on all",       "4", 4, "4"},
+       {"5: SATD, multi-qpel on all", "5", 5, "5"},
+       {"6: RD in I/P-frames",        "6", 6, "6"},
+       {"7: RD in all frames",        "7", 7, "7"},
+       {"8: RD refine in I/P-frames", "8", 8, "8"},
+       {"9: RD refine in all frames", "9", 9, "9"},
+       {"10: QPRD in all frames",     "10", 10, "10"},
 };
 combo_opts_t subme_opts =
 {
@@ -322,10 +349,11 @@ combo_opts_t subme_opts =
 
 static options_map_t d_analyse_opts[] =
 {
-       {"Some", "some", 0, "some"},
+       {"Most", "p8x8,b8x8,i8x8,i4x4", 0, "p8x8,b8x8,i8x8,i4x4"},
        {"None", "none", 1, "none"},
-       {"All",  "all",  2, "all"},
-       {"Custom",  "custom",  3, "all"},
+       {"Some", "i4x4,i8x8", 2, "i4x4,i8x8"},
+       {"All",  "all",  3, "all"},
+       {"Custom",  "custom",  4, "all"},
 };
 combo_opts_t analyse_opts =
 {
@@ -335,9 +363,9 @@ combo_opts_t analyse_opts =
 
 static options_map_t d_trellis_opts[] =
 {
-       {"Disabled",          "0", 0, "0"},
-       {"Final Macro Block", "1", 1, "1"},
-       {"Always",            "2", 2, "2"},
+       {"Off",         "0", 0, "0"},
+       {"Encode only", "1", 1, "1"},
+       {"Always",      "2", 2, "2"},
 };
 combo_opts_t trellis_opts =
 {
@@ -386,8 +414,11 @@ combo_name_map_t combo_name_map[] =
        {"PictureDenoise", &denoise_opts},
        {"VideoEncoder", &vcodec_opts},
        {"AudioEncoder", &acodec_opts},
+       {"AudioEncoderActual", &acodec_opts},
        {"x264_direct", &direct_opts},
        {"x264_b_adapt", &badapt_opts},
+       {"x264_bpyramid", &bpyramid_opts},
+       {"x264_weighted_pframes", &weightp_opts},
        {"x264_me", &me_opts},
        {"x264_subme", &subme_opts},
        {"x264_analyse", &analyse_opts},
@@ -731,23 +762,67 @@ ghb_vquality_range(
        }
 }
 
+gint
+find_combo_entry(combo_opts_t *opts, const GValue *gval)
+{
+       gint ii;
+
+       if (G_VALUE_TYPE(gval) == G_TYPE_STRING)
+       {
+               gchar *str;
+               str = ghb_value_string(gval);
+               for (ii = 0; ii < opts->count; ii++)
+               {
+                       if (strcmp(opts->map[ii].shortOpt, str) == 0)
+                       {
+                               break;
+                       }
+               }
+               g_free(str);
+               return ii;
+       }
+       else if (G_VALUE_TYPE(gval) == G_TYPE_DOUBLE)
+       {
+               gdouble val;
+               val = ghb_value_double(gval);
+               for (ii = 0; ii < opts->count; ii++)
+               {
+                       if (opts->map[ii].ivalue == val)
+                       {
+                               break;
+                       }
+               }
+               return ii;
+       }
+       else if (G_VALUE_TYPE(gval) == G_TYPE_INT ||
+                        G_VALUE_TYPE(gval) == G_TYPE_BOOLEAN ||
+                        G_VALUE_TYPE(gval) == G_TYPE_INT64)
+       {
+               gint64 val;
+               val = ghb_value_int64(gval);
+               for (ii = 0; ii < opts->count; ii++)
+               {
+                       if ((gint64)opts->map[ii].ivalue == val)
+                       {
+                               break;
+                       }
+               }
+               return ii;
+       }
+       return opts->count;
+}
+
 static const gchar*
 lookup_generic_string(combo_opts_t *opts, const GValue *gval)
 {
        gint ii;
-       gchar *str;
        const gchar *result = "";
 
-       str = ghb_value_string(gval);
-       for (ii = 0; ii < opts->count; ii++)
+       ii = find_combo_entry(opts, gval);
+       if (ii < opts->count)
        {
-               if (strcmp(opts->map[ii].shortOpt, str) == 0)
-               {
-                       result = opts->map[ii].svalue;
-                       break;
-               }
+               result = opts->map[ii].svalue;
        }
-       g_free(str);
        return result;
 }
 
@@ -755,19 +830,13 @@ static gint
 lookup_generic_int(combo_opts_t *opts, const GValue *gval)
 {
        gint ii;
-       gchar *str;
        gint result = -1;
 
-       str = ghb_value_string(gval);
-       for (ii = 0; ii < opts->count; ii++)
+       ii = find_combo_entry(opts, gval);
+       if (ii < opts->count)
        {
-               if (strcmp(opts->map[ii].shortOpt, str) == 0)
-               {
-                       result = opts->map[ii].ivalue;
-                       break;
-               }
+               result = opts->map[ii].ivalue;
        }
-       g_free(str);
        return result;
 }
 
@@ -775,19 +844,13 @@ static gdouble
 lookup_generic_double(combo_opts_t *opts, const GValue *gval)
 {
        gint ii;
-       gchar *str;
        gdouble result = -1;
 
-       str = ghb_value_string(gval);
-       for (ii = 0; ii < opts->count; ii++)
+       ii = find_combo_entry(opts, gval);
+       if (ii < opts->count)
        {
-               if (strcmp(opts->map[ii].shortOpt, str) == 0)
-               {
-                       result = opts->map[ii].ivalue;
-                       break;
-               }
+               result = opts->map[ii].ivalue;
        }
-       g_free(str);
        return result;
 }
 
@@ -795,19 +858,13 @@ static const gchar*
 lookup_generic_option(combo_opts_t *opts, const GValue *gval)
 {
        gint ii;
-       gchar *str;
        const gchar *result = "";
 
-       str = ghb_value_string(gval);
-       for (ii = 0; ii < opts->count; ii++)
+       ii = find_combo_entry(opts, gval);
+       if (ii < opts->count)
        {
-               if (strcmp(opts->map[ii].shortOpt, str) == 0)
-               {
-                       result = opts->map[ii].option;
-                       break;
-               }
+               result = opts->map[ii].option;
        }
-       g_free(str);
        return result;
 }
 
@@ -815,20 +872,36 @@ static gint
 lookup_mix_int(const GValue *mix)
 {
        gint ii;
-       gchar *str;
        gint result = 0;
 
 
-       str = ghb_value_string(mix);
-       for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+       if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
        {
-               if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
+               gchar * str = ghb_value_string(mix);
+               for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
                {
-                       result = hb_audio_mixdowns[ii].amixdown;
-                       break;
+                       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;
+                       }
                }
        }
-       g_free(str);
        return result;
 }
 
@@ -836,20 +909,73 @@ static const gchar*
 lookup_mix_option(const GValue *mix)
 {
        gint ii;
-       gchar *str;
        gchar *result = "None";
 
 
-       str = ghb_value_string(mix);
-       for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
+       if (G_VALUE_TYPE(mix) == G_TYPE_STRING)
        {
-               if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
+               gchar *str = ghb_value_string(mix);
+               for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
                {
-                       result = hb_audio_mixdowns[ii].human_readable_name;
-                       break;
+                       if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
+                       {
+                               result = hb_audio_mixdowns[ii].human_readable_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].human_readable_name;
+                               break;
+                       }
+               }
+       }
+       return result;
+}
+
+static const gchar*
+lookup_mix_string(const GValue *mix)
+{
+       gint ii;
+       gchar *result = "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;
+                       }
                }
        }
-       g_free(str);
        return result;
 }
 
@@ -899,21 +1025,37 @@ static gint
 lookup_audio_rate_int(const GValue *rate)
 {
        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);
-       for (ii = 0; ii < hb_audio_rates_count; ii++)
+       if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
        {
-               if (strcmp(hb_audio_rates[ii].string, str) == 0)
+               // 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++)
                {
-                       result = hb_audio_rates[ii].rate;
-                       break;
+                       if (strcmp(hb_audio_rates[ii].string, str) == 0)
+                       {
+                               result = hb_audio_rates[ii].rate;
+                               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].rate;
+                               break;
+                       }
                }
        }
-       g_free(str);
        return result;
 }
 
@@ -921,70 +1063,96 @@ static const gchar*
 lookup_audio_rate_option(const GValue *rate)
 {
        gint ii;
-       gchar *str;
        const gchar *result = "Same as source";
 
-       // 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 < hb_audio_rates_count; ii++)
+       if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
        {
-               if (strcmp(hb_audio_rates[ii].string, str) == 0)
+               // 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++)
                {
-                       result = hb_audio_rates[ii].string;
-                       break;
+                       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;
+                       }
                }
        }
-       g_free(str);
        return result;
 }
 
 gint
-ghb_find_closest_audio_bitrate(gint codec, gint rate)
+ghb_find_closest_audio_rate(gint rate)
 {
        gint ii;
-       gint low = 32;
-       gint high = 768;
        gint result;
 
-       if (codec == HB_ACODEC_FAAC)
-               high = 160;
-
-       result = high;
-       for (ii = 0; ii < hb_audio_bitrates_count; ii++)
+       result = 0;
+       for (ii = 0; ii < hb_audio_rates_count; ii++)
        {
-               if (hb_audio_bitrates[ii].rate < low)
-                       continue;
-               if (hb_audio_bitrates[ii].rate > high)
-                       break;
-               if (rate <= hb_audio_bitrates[ii].rate)
+               if (rate <= hb_audio_rates[ii].rate)
                {
-                       result = hb_audio_bitrates[ii].rate;
+                       result = hb_audio_rates[ii].rate;
                        break;
                }
        }
        return result;
 }
 
+hb_rate_t *ghb_audio_bitrates;
+int ghb_audio_bitrates_count;
+
 static gint
 lookup_audio_bitrate_int(const GValue *rate)
 {
        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);
-       for (ii = 0; ii < hb_audio_bitrates_count; ii++)
+       if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
        {
-               if (strcmp(hb_audio_bitrates[ii].string, str) == 0)
+               // 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++)
                {
-                       result = hb_audio_bitrates[ii].rate;
-                       break;
+                       if (strcmp(ghb_audio_bitrates[ii].string, str) == 0)
+                       {
+                               result = ghb_audio_bitrates[ii].rate;
+                               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)
+       {
+               gint val = ghb_value_int(rate);
+               for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
+               {
+                       if (ghb_audio_bitrates[ii].rate == val)
+                       {
+                               result = ghb_audio_bitrates[ii].rate;
+                               break;
+                       }
                }
        }
-       g_free(str);
        return result;
 }
 
@@ -992,21 +1160,37 @@ static const gchar*
 lookup_audio_bitrate_option(const GValue *rate)
 {
        gint ii;
-       gchar *str;
        const gchar *result = "Same as source";
 
-       // 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 < hb_audio_bitrates_count; ii++)
+       if (G_VALUE_TYPE(rate) == G_TYPE_STRING)
        {
-               if (strcmp(hb_audio_bitrates[ii].string, str) == 0)
+               // 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++)
                {
-                       result = hb_audio_bitrates[ii].string;
-                       break;
+                       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)
+       {
+               gint val = ghb_value_int(rate);
+               for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
+               {
+                       if (ghb_audio_bitrates[ii].rate == val)
+                       {
+                               result = ghb_audio_bitrates[ii].string;
+                               break;
+                       }
                }
        }
-       g_free(str);
        return result;
 }
 
@@ -1068,9 +1252,10 @@ ghb_lookup_acodec_value(gint val)
                if ((int)acodec_opts.map[ii].ivalue == val)
                {
                        value = ghb_string_value_new(acodec_opts.map[ii].shortOpt);
-                       break;
+                       return value;
                }
        }
+       value = ghb_string_value_new("auto");
        return value;
 }
 
@@ -1095,14 +1280,14 @@ get_amix_value(gint val)
 static hb_handle_t * h_scan = NULL;
 static hb_handle_t * h_queue = NULL;
 
-extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]);
+extern void hb_get_temporary_directory(char path[512]);
 
 gchar*
 ghb_get_tmp_dir()
 {
        char dir[512];
 
-       hb_get_tempory_directory(h_scan, dir);
+       hb_get_temporary_directory(dir);
        return g_strdup(dir);
 }
 
@@ -1111,7 +1296,7 @@ ghb_hb_cleanup(gboolean partial)
 {
        char dir[512];
 
-       hb_get_tempory_directory(h_scan, dir);
+       hb_get_temporary_directory(dir);
        del_tree(dir, !partial);
 }
 
@@ -1149,6 +1334,37 @@ ghb_subtitle_track_source(signal_user_data_t *ud, gint track)
 }
 
 const char*
+ghb_subtitle_source_name(gint source)
+{
+       const gchar * name = "Unknown";
+       switch (source)
+       {
+               case VOBSUB:
+                       name = "VOBSUB";
+                       break;
+               case TX3GSUB:
+                       name = "TX3G";
+                       break;
+               case UTF8SUB:
+                       name = "UTF8";
+                       break;
+               case CC708SUB:
+               case CC608SUB:
+                       name = "CC";
+                       break;
+               case SRTSUB:
+                       name = "SRT";
+                       break;
+               case SSASUB:
+                       name = "SSA";
+                       break;
+               default:
+                       break;
+       }
+       return name;
+}
+
+const char*
 ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track)
 {
        gint titleindex;
@@ -1186,21 +1402,7 @@ ghb_subtitle_track_source_name(signal_user_data_t *ud, gint track)
        sub = hb_list_item( title->list_subtitle, track);
        if (sub != NULL)
        {
-               switch (sub->source)
-               {
-                       case VOBSUB:
-                               name = "Bitmap";
-                               break;
-                       case CC708SUB:
-                       case CC608SUB:
-                               name = "Text";
-                               break;
-                       case SRTSUB:
-                               name = "SRT";
-                               break;
-                       default:
-                               break;
-               }
+               name = ghb_subtitle_source_name(sub->source);
        }
 
 done:
@@ -1263,14 +1465,14 @@ ghb_get_title_number(gint titleindex)
 }
 
 static hb_audio_config_t*
-get_hb_audio(gint titleindex, gint track)
+get_hb_audio(hb_handle_t *h, gint titleindex, gint track)
 {
        hb_list_t  * list;
        hb_title_t * title;
     hb_audio_config_t *audio = NULL;
        
-    if (h_scan == NULL) return NULL;
-       list = hb_get_titles( h_scan );
+    if (h == NULL) return NULL;
+       list = hb_get_titles( h );
        if( !hb_list_count( list ) )
        {
                /* No valid title, stop right there */
@@ -1333,7 +1535,7 @@ ghb_grey_combo_options(GtkBuilder *builder)
 {
        GtkWidget *widget;
        gint container, track, titleindex, acodec;
-    hb_audio_config_t *audio = NULL;
+    hb_audio_config_t *aconfig = NULL;
        GValue *gval;
        
        widget = GHB_WIDGET (builder, "title");
@@ -1344,13 +1546,13 @@ ghb_grey_combo_options(GtkBuilder *builder)
        gval = ghb_widget_value(widget);
        track = ghb_lookup_combo_int("AudioTrack", gval);
        ghb_value_free(gval);
-       audio = get_hb_audio(titleindex, track);
+       aconfig = get_hb_audio(h_scan, titleindex, track);
        widget = GHB_WIDGET (builder, "FileFormat");
        gval = ghb_widget_value(widget);
        container = ghb_lookup_combo_int("FileFormat", gval);
        ghb_value_free(gval);
 
-       grey_combo_box_item(builder, "x264_analyse", 3, TRUE);
+       grey_combo_box_item(builder, "x264_analyse", 4, TRUE);
        grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_FAAC, FALSE);
        grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_LAME, FALSE);
        grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, FALSE);
@@ -1358,19 +1560,19 @@ ghb_grey_combo_options(GtkBuilder *builder)
        gboolean allow_dca = TRUE;
        allow_dca = (container != HB_MUX_MP4);
 
-       grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3, FALSE);
+       grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, FALSE);
        if (allow_dca)
-               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA, FALSE);
+               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, FALSE);
        else
-               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA, TRUE);
+               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE);
 
-       if (audio && audio->in.codec != HB_ACODEC_AC3)
+       if (aconfig && aconfig->in.codec != HB_ACODEC_AC3)
        {
-               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3, TRUE);
+               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, TRUE);
        }
-       if (audio && audio->in.codec != HB_ACODEC_DCA)
+       if (aconfig && aconfig->in.codec != HB_ACODEC_DCA)
        {
-               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA, TRUE);
+               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE);
        }
        grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, FALSE);
 
@@ -1378,13 +1580,9 @@ ghb_grey_combo_options(GtkBuilder *builder)
        gval = ghb_widget_value(widget);
        acodec = ghb_lookup_combo_int("AudioEncoder", gval);
        ghb_value_free(gval);
-       if (acodec != HB_ACODEC_AC3)
-       {
-               grey_combo_box_item(builder, "AudioMixdown", 0, TRUE);
-       }
+       grey_combo_box_item(builder, "AudioMixdown", 0, TRUE);
        if (container == HB_MUX_MP4)
        {
-               grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_LAME, TRUE);
                grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE);
                grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE);
        }
@@ -1394,24 +1592,16 @@ ghb_grey_combo_options(GtkBuilder *builder)
        gboolean allow_dolby = TRUE;
        gboolean allow_dpl2 = TRUE;
        gboolean allow_6ch = TRUE;
-       allow_mono = acodec & ~HB_ACODEC_LAME;
+       allow_mono = TRUE;
        allow_6ch = acodec & ~HB_ACODEC_LAME;
-       if (audio)
-       {
-               allow_mono = allow_mono &&
-                       (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA));
-               gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
-               allow_stereo =
-                       ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
-               allow_dolby =
-                       (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
-                       (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
-                       (layout == HB_INPUT_CH_LAYOUT_DOLBY);
-               allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
-               allow_6ch = allow_6ch &&
-                       (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
-                       (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
-                       (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
+       if (aconfig)
+       {
+               gint best = hb_get_best_mixdown(acodec, aconfig->in.channel_layout, 0);
+
+               allow_stereo = best >= HB_AMIXDOWN_STEREO;
+               allow_dolby = best >= HB_AMIXDOWN_DOLBY;
+               allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
+               allow_6ch = best >= HB_AMIXDOWN_6CH;
        }
        grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_MONO, !allow_mono);
        grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_STEREO, !allow_stereo);
@@ -1421,88 +1611,12 @@ ghb_grey_combo_options(GtkBuilder *builder)
 }
 
 gint
-ghb_get_best_audio_bitrate(gint acodec, gint br, gint channels)
+ghb_get_best_mix(hb_audio_config_t *aconfig, gint acodec, gint mix)
 {
-       if (acodec & HB_ACODEC_FAAC)
-       {
-       int maxbr = channels * 80;
-               if (br > maxbr)
-                       br = maxbr;
-       }
-       return br;
-}
-
-gint
-ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix)
-{
-    hb_audio_config_t *audio = NULL;
-       gboolean allow_mono = TRUE;
-       gboolean allow_stereo = TRUE;
-       gboolean allow_dolby = TRUE;
-       gboolean allow_dpl2 = TRUE;
-       gboolean allow_6ch = TRUE;
-       
-       if (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
-       {
-               // Audio codec pass-thru.  No mixdown
-               return 0;
-       }
-       audio = get_hb_audio(titleindex, track);
-       if (audio)
-       {
-               allow_mono =
-                       (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
-                       (acodec & ~HB_ACODEC_LAME);
-               gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
-               allow_stereo =
-                       ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
-               allow_dolby =
-                       (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
-                       (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
-                       (layout == HB_INPUT_CH_LAYOUT_DOLBY);
-               allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
-               allow_6ch =
-                       (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
-                       (acodec & ~HB_ACODEC_LAME) &&
-                       (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
-                       (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
-       }
-       gboolean greater = FALSE;
-       if (mix == 0) 
-       {
-               // If no mix is specified, select the best available.
-               mix = HB_AMIXDOWN_6CH;
-       }
-       if (mix == HB_AMIXDOWN_6CH)
-       {
-               greater = TRUE;
-               if (allow_6ch) return HB_AMIXDOWN_6CH;
-       }
-       if (mix == HB_AMIXDOWN_DOLBYPLII || greater)
-       {
-               greater = TRUE;
-               if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
-       }
-       if (mix == HB_AMIXDOWN_DOLBY || greater)
-       {
-               greater = TRUE;
-               if (allow_dolby) return HB_AMIXDOWN_DOLBY;
-       }
-       if (mix == HB_AMIXDOWN_STEREO || greater)
-       {
-               greater = TRUE;
-               if (allow_stereo) return HB_AMIXDOWN_STEREO;
-       }
-       if (mix == HB_AMIXDOWN_MONO || greater)
-       {
-               greater = TRUE;
-               if (allow_mono) return HB_AMIXDOWN_MONO;
-       }
-       if (allow_stereo) return HB_AMIXDOWN_STEREO;
-       if (allow_dolby) return HB_AMIXDOWN_DOLBY;
-       if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
-       if (allow_6ch) return HB_AMIXDOWN_6CH;
-       return 0;
+       int layout;
+       layout = aconfig ? aconfig->in.channel_layout : 
+                                               HB_INPUT_CH_LAYOUT_3F2R | HB_INPUT_CH_LAYOUT_HAS_LFE;
+       return hb_get_best_mixdown( acodec, layout, mix );
 }
 
 // Set up the model for the combo box
@@ -1776,14 +1890,20 @@ title_opts_set(GtkBuilder *builder, const gchar *name)
                {
                        if (title->duration != 0)
                        {
-                               titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds - %s",
+                char *tmp;
+                               tmp  = g_strdup_printf ("%d - %02dh%02dm%02ds - %s",
                                        title->index, title->hours, title->minutes, title->seconds, 
                                        title->name);
+                titles[ii] = g_markup_escape_text(tmp, -1);
+                g_free(tmp);
                        }
                        else
                        {
-                               titles[ii]  = g_strdup_printf ("%d - %s", 
+                char *tmp;
+                               tmp  = g_strdup_printf ("%d - %s", 
                                                                                title->index, title->name);
+                titles[ii] = g_markup_escape_text(tmp, -1);
+                g_free(tmp);
                        }
                }
                else
@@ -1826,7 +1946,7 @@ find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
                do
                {
                        gtk_tree_model_get(store, iter, 3, &ivalue, -1);
-                       if (value == (int)ivalue)
+                       if (value == (gint)ivalue)
                        {
                                foundit = TRUE;
                                break;
@@ -1966,9 +2086,9 @@ subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
                for (ii = 0; ii < count; ii++)
                {
                        subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
-                       // Skip subtitles that must be burned if there is already
-                       // a burned subtitle in the list
-                       options[ii] = g_strdup_printf("%d - %s", ii+1, subtitle->lang);
+                       options[ii] = g_strdup_printf("%d - %s (%s)", ii+1, 
+                               subtitle->lang, 
+                               ghb_subtitle_source_name(subtitle->source));
                        subtitle_opts.map[ii+1].option = options[ii];
                        subtitle_opts.map[ii+1].shortOpt = index_str[ii];
                        subtitle_opts.map[ii+1].ivalue = ii;
@@ -2019,21 +2139,23 @@ ghb_longest_title()
        hb_title_t * title;
        gint ii;
        gint count = 0;
-       guint64 longest = 0;
        gint titleindex = 0;
+       gint feature;
        
        g_debug("ghb_longest_title ()\n");
        if (h_scan == NULL) return 0;
        list = hb_get_titles( h_scan );
        count = hb_list_count( list );
        if (count > 100) count = 100;
+       if (count < 1) return 0;
+       title = (hb_title_t*)hb_list_item(list, 0);
+       feature = title->job->feature;
        for (ii = 0; ii < count; ii++)
        {
                title = (hb_title_t*)hb_list_item(list, ii);
-               if (title->duration > longest)
+               if (title->index == feature)
                {
-                       titleindex = ii;
-                       longest = title->duration;
+                       return ii;
                }
        }
        return titleindex;
@@ -2097,12 +2219,13 @@ ghb_find_audio_track(
        gint ii;
        gint count = 0;
        gint track = -1;
-       gint max_chan = 0;
-       gboolean *used;
+       gint max_chan;
+       gboolean *used = NULL;
        gboolean *passthru_used;
        gint try_acodec;
        gint passthru_acodec;
        gboolean passthru;
+       gint channels;
        
        g_debug("find_audio_track ()\n");
        if (h_scan == NULL) return -1;
@@ -2115,16 +2238,15 @@ ghb_find_audio_track(
        if (count > 10) count = 10;
        // Try to find an item that matches the preferred language and
        // the passthru codec type
-       passthru = (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA)) != 0;
+       max_chan = 0;
+       passthru = (acodec & HB_ACODEC_PASS_FLAG) != 0;
        if (passthru)
        {
                for (ii = 0; ii < count; ii++)
                {
-                       gint channels;
-
                        audio = (hb_audio_config_t*)hb_list_audio_config_item( 
                                                                                                        title->list_audio, ii );
-                       passthru_acodec = (HB_ACODEC_AC3 | HB_ACODEC_DCA) & audio->in.codec;
+                       passthru_acodec = HB_ACODEC_PASS_MASK & acodec & audio->in.codec;
                        // Is the source track use a passthru capable codec?
                        if (passthru_acodec == 0)
                                continue;
@@ -2160,6 +2282,7 @@ ghb_find_audio_track(
                return track;
        }
        // Try to find an item that matches the preferred language
+       max_chan = 0;
        used = get_track_used(try_acodec, track_indices, count);
        for (ii = 0; ii < count; ii++)
        {
@@ -2168,7 +2291,7 @@ ghb_find_audio_track(
                        continue;
                audio = (hb_audio_config_t*)hb_list_audio_config_item( 
                                                                                                title->list_audio, ii );
-               passthru_acodec = (HB_ACODEC_AC3 | HB_ACODEC_DCA) & audio->in.codec;
+               passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
                if (passthru_acodec && passthru)
                {
                        passthru_used = get_track_used(passthru_acodec, track_indices, count);
@@ -2176,13 +2299,18 @@ ghb_find_audio_track(
                        if (passthru_used[ii])
                                continue;
                }
+               channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
+                                                                                               audio->in.channel_layout);
                // Find a track that is not visually impaired or dirctor's commentary
                if ((audio->lang.type < 2) &&
                        ((strcmp(lang, audio->lang.iso639_2) == 0) ||
                        (strcmp(lang, "und") == 0)))
                {
-                       track = ii;
-                       break;
+                       if (channels > max_chan)
+                       {
+                               track = ii;
+                               max_chan = channels;
+                       }
                }
        }
        if (track > -1)
@@ -2192,15 +2320,14 @@ ghb_find_audio_track(
        }
        // Try to fine an item that does not match the preferred language and
        // matches the passthru codec type
+       max_chan = 0;
        if (passthru)
        {
                for (ii = 0; ii < count; ii++)
                {
-                       gint channels;
-
                        audio = (hb_audio_config_t*)hb_list_audio_config_item( 
                                                                                                        title->list_audio, ii );
-                       passthru_acodec = (HB_ACODEC_AC3 | HB_ACODEC_DCA) & audio->in.codec;
+                       passthru_acodec = HB_ACODEC_PASS_MASK & acodec & audio->in.codec;
                        // Is the source track use a passthru capable codec?
                        if (passthru_acodec == 0)
                                continue;
@@ -2234,6 +2361,7 @@ ghb_find_audio_track(
                return track;
        }
        // Try to fine an item that does not match the preferred language
+       max_chan = 0;
        used = get_track_used(try_acodec, track_indices, count);
        for (ii = 0; ii < count; ii++)
        {
@@ -2242,7 +2370,9 @@ ghb_find_audio_track(
                        continue;
                audio = (hb_audio_config_t*)hb_list_audio_config_item( 
                                                                                                        title->list_audio, ii );
-               passthru_acodec = (HB_ACODEC_AC3 | HB_ACODEC_DCA) & audio->in.codec;
+               passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
+               channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
+                                                                                               audio->in.channel_layout);
                if (passthru_acodec && passthru)
                {
                        passthru_used = get_track_used(passthru_acodec, track_indices, count);
@@ -2253,8 +2383,11 @@ ghb_find_audio_track(
                // Find a track that is not visually impaired or dirctor's commentary
                if (audio->lang.type < 2)
                {
-                       track = ii;
-                       break;
+                       if (channels > max_chan)
+                       {
+                               track = ii;
+                               max_chan = channels;
+                       }
                }
        }
        if (track > -1)
@@ -2267,7 +2400,7 @@ ghb_find_audio_track(
        {
                audio = (hb_audio_config_t*)hb_list_audio_config_item( 
                                                                                                title->list_audio, ii );
-               passthru_acodec = (HB_ACODEC_AC3 | HB_ACODEC_DCA) & audio->in.codec;
+               passthru_acodec = HB_ACODEC_PASS_MASK & audio->in.codec;
                if (passthru_acodec && passthru)
                {
                        passthru_used = get_track_used(passthru_acodec, track_indices, count);
@@ -2330,6 +2463,18 @@ ghb_find_cc_track(gint titleindex)
        return -2;
 }
 
+static gboolean
+canForce(int source)
+{
+       return (source == VOBSUB);
+}
+
+static gboolean
+canBurn(int source)
+{
+       return (source == VOBSUB || source == SSASUB);
+}
+
 gint
 ghb_find_subtitle_track(
        gint          titleindex, 
@@ -2382,7 +2527,8 @@ ghb_find_subtitle_track(
                                continue;
 
                        subtitle = (hb_subtitle_t*)hb_list_item( title->list_subtitle, ii );
-                       if (((burn || force) && (subtitle->source == VOBSUB)) &&
+                       if (((!force || (force && canForce(subtitle->source))) &&
+                                (!burn  || (burn  &&  canBurn(subtitle->source)))) &&
                                ((strcmp(lang, subtitle->iso639_2) == 0) ||
                                 (strcmp(lang, "und") == 0)))
                        {
@@ -2426,7 +2572,7 @@ small_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
        gint ii;
        gchar *str;
        
-       g_debug("generic_opts_set ()\n");
+       g_debug("small_opts_set ()\n");
        if (name == NULL || opts == NULL) return;
        store = get_combo_box_store(builder, name);
        gtk_list_store_clear(store);
@@ -2547,7 +2693,7 @@ ghb_lookup_combo_string(const gchar *name, const GValue *gval)
        else if (strcmp(name, "VideoFramerate") == 0)
                return lookup_video_rate_option(gval);
        else if (strcmp(name, "AudioMixdown") == 0)
-               return lookup_mix_option(gval);
+               return lookup_mix_string(gval);
        else if (strcmp(name, "SrtLanguage") == 0)
                return lookup_audio_lang_option(gval);
        else if (strcmp(name, "PreferredLanguage") == 0)
@@ -2618,12 +2764,14 @@ ghb_update_ui_combo_box(
                generic_opts_set(ud->builder, "PictureDenoise", &denoise_opts);
                generic_opts_set(ud->builder, "VideoEncoder", &vcodec_opts);
                small_opts_set(ud->builder, "AudioEncoder", &acodec_opts);
-               generic_opts_set(ud->builder, "x264_direct", &direct_opts);
-               generic_opts_set(ud->builder, "x264_b_adapt", &badapt_opts);
-               generic_opts_set(ud->builder, "x264_me", &me_opts);
-               generic_opts_set(ud->builder, "x264_subme", &subme_opts);
-               generic_opts_set(ud->builder, "x264_analyse", &analyse_opts);
-               generic_opts_set(ud->builder, "x264_trellis", &trellis_opts);
+               small_opts_set(ud->builder, "x264_direct", &direct_opts);
+               small_opts_set(ud->builder, "x264_b_adapt", &badapt_opts);
+               small_opts_set(ud->builder, "x264_bpyramid", &bpyramid_opts);
+               small_opts_set(ud->builder, "x264_weighted_pframes", &weightp_opts);
+               small_opts_set(ud->builder, "x264_me", &me_opts);
+               small_opts_set(ud->builder, "x264_subme", &subme_opts);
+               small_opts_set(ud->builder, "x264_analyse", &analyse_opts);
+               small_opts_set(ud->builder, "x264_trellis", &trellis_opts);
        }
        else
        {
@@ -2824,6 +2972,15 @@ audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
 
        if (rate < 8) return;
 
+       if (ghb_audio_bitrates[hb_audio_bitrates_count].string)
+       {
+               g_free(ghb_audio_bitrates[hb_audio_bitrates_count].string);
+       }
+       ghb_audio_bitrates[hb_audio_bitrates_count].rate = rate;
+       ghb_audio_bitrates[hb_audio_bitrates_count].string = 
+               g_strdup_printf("%d", rate);
+       ghb_audio_bitrates_count = hb_audio_bitrates_count + 1;
+
        store = get_combo_box_store(builder, name);
        if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
        {
@@ -2832,9 +2989,9 @@ audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
                gtk_list_store_set(store, &iter, 
                                                   0, str, 
                                                   1, TRUE, 
-                                                  2, str
+                                                  2, ghb_audio_bitrates[hb_audio_bitrates_count].string
                                                   3, (gdouble)rate, 
-                                                  4, str
+                                                  4, ghb_audio_bitrates[hb_audio_bitrates_count].string
                                                   -1);
                g_free(str);
        }
@@ -2855,6 +3012,8 @@ audio_bitrate_opts_clean(
        guint last = (guint)last_rate;
        guint first = (guint)first_rate;
        
+       ghb_audio_bitrates_count = hb_audio_bitrates_count;
+
        g_debug("audio_bitrate_opts_clean ()\n");
        store = get_combo_box_store(builder, name);
        if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
@@ -2863,7 +3022,7 @@ audio_bitrate_opts_clean(
                {
                        gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
                        if (search_rates(
-                               hb_audio_bitrates, ivalue, hb_audio_bitrates_count) < 0)
+                               ghb_audio_bitrates, ivalue, ghb_audio_bitrates_count) < 0)
                        {
                                done = !gtk_list_store_remove(store, &iter);
                        }
@@ -2891,20 +3050,28 @@ audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
        gint ii;
        gchar *str;
        
+       ghb_audio_bitrates_count = hb_audio_bitrates_count;
+       ghb_audio_bitrates = calloc(hb_audio_bitrates_count+1, sizeof(hb_rate_t));
+
+       for (ii = 0; ii < hb_audio_bitrates_count; ii++)
+       {
+               ghb_audio_bitrates[ii] = hb_audio_bitrates[ii];
+       }
+
        g_debug("audio_bitrate_opts_set ()\n");
        store = get_combo_box_store(builder, name);
        gtk_list_store_clear(store);
-       for (ii = 0; ii < hb_audio_bitrates_count; ii++)
+       for (ii = 0; ii < ghb_audio_bitrates_count; ii++)
        {
                gtk_list_store_append(store, &iter);
                str = g_strdup_printf ("<small>%s</small>", 
-                       hb_audio_bitrates[ii].string);
+                       ghb_audio_bitrates[ii].string);
                gtk_list_store_set(store, &iter, 
                                                   0, str,
                                                   1, TRUE, 
-                                                  2, hb_audio_bitrates[ii].string, 
-                                                  3, (gdouble)hb_audio_bitrates[ii].rate, 
-                                                  4, hb_audio_bitrates[ii].string, 
+                                                  2, ghb_audio_bitrates[ii].string, 
+                                                  3, (gdouble)ghb_audio_bitrates[ii].rate, 
+                                                  4, ghb_audio_bitrates[ii].string, 
                                                   -1);
                g_free(str);
        }
@@ -2949,6 +3116,7 @@ ghb_backend_close()
 {
        hb_close(&h_queue);
        hb_close(&h_scan);
+       hb_global_close();
 }
 
 void ghb_backend_scan_stop()
@@ -2957,9 +3125,9 @@ void ghb_backend_scan_stop()
 }
 
 void
-ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count)
+ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count, uint64_t min_duration)
 {
-    hb_scan( h_scan, path, titleindex, preview_count, 1 );
+    hb_scan( h_scan, path, titleindex, preview_count, 1, min_duration );
        hb_status.scan.state |= GHB_STATE_SCANNING;
        // initialize count and cur to something that won't cause FPE
        // when computing progress
@@ -2971,7 +3139,7 @@ void
 ghb_backend_queue_scan(const gchar *path, gint titlenum)
 {
        g_debug("ghb_backend_queue_scan()");
-       hb_scan( h_queue, path, titlenum, 10, 0 );
+       hb_scan( h_queue, path, titlenum, 10, 0, 0 );
        hb_status.queue.state |= GHB_STATE_SCANNING;
 }
 
@@ -3166,6 +3334,7 @@ ghb_track_status()
                        hb_status.queue.state &= ~GHB_STATE_MUXING;
                        hb_status.queue.state &= ~GHB_STATE_PAUSED;
                        hb_status.queue.state &= ~GHB_STATE_WORKING;
+                       hb_status.queue.state &= ~GHB_STATE_SEARCHING;
                        switch (p.error)
                        {
                        case HB_ERROR_NONE:
@@ -3218,6 +3387,7 @@ ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
        tinfo->num_chapters = hb_list_count(title->list_chapter);
        tinfo->rate_base = title->rate_base;
        tinfo->rate = title->rate;
+       tinfo->interlaced = title->detected_interlacing;
        hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
                                title->width * title->pixel_aspect_width, 
                                title->height * title->pixel_aspect_height);
@@ -3233,24 +3403,27 @@ ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
        return TRUE;
 }
 
-gboolean
-ghb_get_audio_info(ghb_audio_info_t *ainfo, gint titleindex, gint audioindex)
+hb_audio_config_t*
+ghb_get_scan_audio_info(gint titleindex, gint audioindex)
 {
-    hb_audio_config_t *audio;
+    hb_audio_config_t *aconfig;
        
-       audio = get_hb_audio(titleindex, audioindex);
-       if (audio == NULL) return FALSE; // Bad audioindex
-       ainfo->codec = audio->in.codec;
-       ainfo->bitrate = audio->in.bitrate;
-       ainfo->samplerate = audio->in.samplerate;
-       return TRUE;
+       aconfig = get_hb_audio(h_scan, titleindex, audioindex);
+       return aconfig;
 }
 
 gboolean
 ghb_audio_is_passthru(gint acodec)
 {
        g_debug("ghb_audio_is_passthru () \n");
-       return (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA));
+       return (acodec & HB_ACODEC_PASS_FLAG) != 0;
+}
+
+gboolean
+ghb_audio_can_passthru(gint acodec)
+{
+       g_debug("ghb_audio_can_passthru () \n");
+       return (acodec & HB_ACODEC_PASS_MASK) != 0;
 }
 
 gint
@@ -3330,7 +3503,6 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
        gint mod;
        gint max_width = 0;
        gint max_height = 0;
-       static gboolean busy = FALSE;
        
        g_debug("ghb_set_scale ()\n");
        picture_settings_deps(ud);
@@ -3344,19 +3516,13 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
        gint titleindex;
 
        titleindex = ghb_settings_combo_int(ud->settings, "title");
-    title = hb_list_item( list, titleindex );
+       title = hb_list_item( list, titleindex );
        if (title == NULL) return;
        job   = title->job;
        if (job == NULL) return;
 
-       if (busy) return;
-       busy = TRUE;
-
-       if (!ud->dont_clear_presets && (keep_width || keep_height))
-       {
-               ghb_settings_set_int(ud->settings, "PictureWidth", 0);
-               ghb_settings_set_int(ud->settings, "PictureHeight", 0);
-       }
+       if (ud->scale_busy) return;
+       ud->scale_busy = TRUE;
 
        // First configure widgets
        mod = ghb_settings_combo_int(ud->settings, "PictureModulus");
@@ -3460,10 +3626,13 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
        {
                width = ghb_settings_get_int(ud->settings, "scale_width");
                height = ghb_settings_get_int(ud->settings, "scale_height");
-               max_width = MOD_DOWN(
-                       ghb_settings_get_int(ud->settings, "PictureWidth"), mod);
-               max_height = MOD_DOWN(
-                       ghb_settings_get_int(ud->settings, "PictureHeight"), mod);
+               if (mode & GHB_PIC_USE_MAX)
+               {
+                       max_width = MOD_DOWN(
+                               ghb_settings_get_int(ud->settings, "PictureWidth"), mod);
+                       max_height = MOD_DOWN(
+                               ghb_settings_get_int(ud->settings, "PictureHeight"), mod);
+               }
        }
        g_debug("max_width %d, max_height %d\n", max_width, max_height);
 
@@ -3475,25 +3644,19 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
        width = MOD_ROUND(width, mod);
        height = MOD_ROUND(height, mod);
 
-       // Adjust dims according to max values
-       if (max_height)
-               height = MIN(height, max_height);
-       if (max_width)
-               width = MIN(width, max_width);
-
+       job->anamorphic.mode = pic_par;
        if (pic_par)
        {
-               job->anamorphic.mode = pic_par;
                // The scaler crashes if the dimensions are not divisible by 2
                // Align mod 2.  And so does something in x264_encoder_headers()
-               job->anamorphic.modulus = mod;
+               job->modulus = mod;
                job->anamorphic.par_width = title->pixel_aspect_width;
                job->anamorphic.par_height = title->pixel_aspect_height;
                job->anamorphic.dar_width = 0;
                job->anamorphic.dar_height = 0;
 
                if (keep_height && pic_par == 2)
-                       width = ((double)height * crop_width / crop_height) + mod / 2;
+                       width = ((double)height * crop_width / crop_height);
                job->width = width;
                job->height = height;
                job->maxWidth = max_width;
@@ -3522,6 +3685,9 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
                {
                        job->anamorphic.keep_display_aspect = 1;
                }
+               // hb_set_anamorphic_size will adjust par, dar, and width/height
+               // to conform to job parameters that have been set, including 
+               // maxWidth and maxHeight
                hb_set_anamorphic_size( job, &width, &height, 
                                                                &par_width, &par_height );
                if (job->anamorphic.mode == 3 && !keep_aspect && 
@@ -3538,7 +3704,12 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
        }
        else 
        {
-               job->anamorphic.mode = pic_par;
+               // Adjust dims according to max values
+               if (max_height)
+                       height = MIN(height, max_height);
+               if (max_width)
+                       width = MIN(width, max_width);
+
                if (keep_aspect)
                {
                        gdouble par;
@@ -3617,7 +3788,7 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
        ghb_ui_update(ud, "PicturePARHeight", ghb_int64_value(par_height));
        ghb_ui_update(ud, "PictureDisplayWidth", ghb_int64_value(disp_width));
        ghb_ui_update(ud, "PictureDisplayHeight", ghb_int64_value(height));
-       busy = FALSE;
+       ud->scale_busy = FALSE;
 }
 
 static void
@@ -3629,7 +3800,7 @@ set_preview_job_settings(hb_job_t *job, GValue *settings)
        job->crop[3] = ghb_settings_get_int(settings, "PictureRightCrop");
 
        job->anamorphic.mode = ghb_settings_combo_int(settings, "PicturePAR");
-       job->anamorphic.modulus = 
+       job->modulus = 
                ghb_settings_combo_int(settings, "PictureModulus");
        job->width = ghb_settings_get_int(settings, "scale_width");
        job->height = ghb_settings_get_int(settings, "scale_height");
@@ -3646,7 +3817,7 @@ set_preview_job_settings(hb_job_t *job, GValue *settings)
                job->crop[1] = 0;
                job->crop[2] = 0;
                job->crop[3] = 0;
-               job->anamorphic.modulus = 2;
+               job->modulus = 2;
        }
 
        gboolean decomb_deint = ghb_settings_get_boolean(settings, "PictureDecombDeinterlace");
@@ -3685,24 +3856,6 @@ set_preview_job_settings(hb_job_t *job, GValue *settings)
        }
 }
 
-gint
-ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
-{
-       hb_list_t  * list;
-       hb_title_t * title;
-       hb_job_t   * job;
-       gint size;
-
-       if (h_scan == NULL) return 1500;
-       list = hb_get_titles( h_scan );
-    title = hb_list_item( list, titleindex );
-       if (title == NULL) return 1500;
-       job   = title->job;
-       if (job == NULL) return 1500;
-       size = ghb_settings_get_int(settings, "VideoTargetSize");
-       return hb_calc_bitrate( job, size );
-}
-
 gboolean
 ghb_validate_filter_string(const gchar *str, gint max_fields)
 {
@@ -3858,7 +4011,6 @@ ghb_validate_subtitles(signal_user_data_t *ud)
        titleindex = ghb_settings_combo_int(ud->settings, "title");
     title = hb_list_item( list, titleindex );
        if (title == NULL) return FALSE;
-       gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
 
        const GValue *slist, *settings;
        gint count, ii, source;
@@ -3891,23 +4043,6 @@ ghb_validate_subtitles(signal_user_data_t *ud)
                {
                        one_burned = TRUE;
                }
-               if (!burned && mux == HB_MUX_MP4 && source == VOBSUB)
-               {
-                       // MP4 can only handle burned vobsubs.  make sure there isn't
-                       // already something burned in the list
-                       message = g_strdup_printf(
-                       "Your chosen container does not support soft bitmap subtitles.\n\n"
-                               "You should change your subtitle selections.\n"
-                               "If you continue, some subtitles will be lost.");
-                       if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, 
-                               "Cancel", "Continue"))
-                       {
-                               g_free(message);
-                               return FALSE;
-                       }
-                       g_free(message);
-                       break;
-               }
                if (source == SRTSUB)
                {
                        gchar *filename;
@@ -3934,62 +4069,63 @@ ghb_validate_subtitles(signal_user_data_t *ud)
 }
 
 gint
-ghb_select_audio_codec(signal_user_data_t *ud, gint track)
+ghb_select_audio_codec(GValue *settings, hb_audio_config_t *aconfig, gint acodec)
 {
-       hb_list_t  * list;
-       hb_title_t * title;
-       hb_audio_config_t *audio;
+       gint mux = ghb_settings_combo_int(settings, "FileFormat");
 
-       if (h_scan == NULL) return -1;
-       list = hb_get_titles( h_scan );
-       if( !hb_list_count( list ) )
-       {
-               return -1;
-       }
-
-       gint titleindex;
-
-       titleindex = ghb_settings_combo_int(ud->settings, "title");
-    title = hb_list_item( list, titleindex );
-       if (title == NULL) return -1;
-
-       gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
-
-       if (track < 0 || track >= hb_list_count(title->list_audio))
-               return -1;
-
-       audio = (hb_audio_config_t *) hb_list_audio_config_item(
-                                                                       title->list_audio, track );
+       guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK;
        if (mux == HB_MUX_MP4)
        {
-               if (audio->in.codec == HB_ACODEC_AC3)
-                       return audio->in.codec;
+               if ((acodec & in_codec & HB_ACODEC_AC3))
+               {
+                       return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
+               }
+               else if (acodec & HB_ACODEC_AC3)
+               {
+                       return HB_ACODEC_AC3;
+               }
+               else if (acodec & HB_ACODEC_LAME)
+               {
+                       return HB_ACODEC_LAME;
+               }
+               else if (acodec & HB_ACODEC_FAAC)
+               {
+                       return HB_ACODEC_FAAC;
+               }
                else
+               {
                        return HB_ACODEC_FAAC;
+               }
        }
        else
        {
-               if (audio->in.codec == HB_ACODEC_AC3 || audio->in.codec == HB_ACODEC_DCA)
-                       return audio->in.codec;
+               if ((acodec & in_codec & HB_ACODEC_PASS_MASK))
+               {
+                       return acodec & (in_codec | HB_ACODEC_PASS_FLAG);
+               }
+               else if (acodec & HB_ACODEC_AC3)
+               {
+                       return HB_ACODEC_AC3;
+               }
+               else if (acodec & HB_ACODEC_VORBIS)
+               {
+                       return HB_ACODEC_VORBIS;
+               }
+               else if (acodec & HB_ACODEC_LAME)
+               {
+                       return HB_ACODEC_LAME;
+               }
+               else if (acodec & HB_ACODEC_FAAC)
+               {
+                       return HB_ACODEC_FAAC;
+               }
                else
+               {
                        return HB_ACODEC_LAME;
+               }
        }
 }
 
-const gchar*
-ghb_select_audio_codec_str(signal_user_data_t *ud, gint track)
-{
-       gint acodec, ii;
-
-       acodec = ghb_select_audio_codec(ud, track);
-       for (ii = 0; ii < acodec_opts.count; ii++)
-       {
-               if (acodec_opts.map[ii].ivalue == acodec)
-                       return acodec_opts.map[ii].option;
-       }
-       return "Unknown";
-}
-
 gboolean
 ghb_validate_audio(signal_user_data_t *ud)
 {
@@ -4022,18 +4158,19 @@ ghb_validate_audio(signal_user_data_t *ud)
        for (ii = 0; ii < count; ii++)
        {
                GValue *asettings;
-           hb_audio_config_t *taudio;
+           hb_audio_config_t *aconfig;
 
                asettings = ghb_array_get_nth(audio_list, ii);
                gint track = ghb_settings_combo_int(asettings, "AudioTrack");
                gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
-               if (codec == HB_ACODEC_MASK)
+               if (codec == HB_ACODEC_ANY)
                        continue;
 
-        taudio = (hb_audio_config_t *) hb_list_audio_config_item(
+        aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
                                                                                        title->list_audio, track );
-               if (!(taudio->in.codec & codec) && 
-                       (codec & (HB_ACODEC_AC3 | HB_ACODEC_DCA)))
+               if ( ghb_audio_is_passthru(codec) &&
+                       !(ghb_audio_can_passthru(aconfig->in.codec) && 
+                        (aconfig->in.codec & codec)))
                {
                        // Not supported.  AC3 is passthrough only, so input must be AC3
                        message = g_strdup_printf(
@@ -4046,7 +4183,12 @@ ghb_validate_audio(signal_user_data_t *ud)
                                return FALSE;
                        }
                        g_free(message);
-                       if (mux == HB_MUX_MKV)
+                       if ((codec & HB_ACODEC_AC3) ||
+                               aconfig->in.codec == HB_ACODEC_DCA)
+                       {
+                               codec = HB_ACODEC_AC3;
+                       }
+                       else if (mux == HB_MUX_MKV)
                        {
                                codec = HB_ACODEC_LAME;
                        }
@@ -4062,12 +4204,7 @@ ghb_validate_audio(signal_user_data_t *ud)
                if (mux == HB_MUX_MP4)
                { 
                        mux_s = "MP4";
-                       // mp4/mp3|vorbis combination is not supported.
-                       if (codec == HB_ACODEC_LAME)
-                       {
-                               a_unsup = "MP3";
-                               codec = HB_ACODEC_FAAC;
-                       }
+                       // mp4/vorbis|DTS combination is not supported.
                        if (codec == HB_ACODEC_VORBIS)
                        {
                                a_unsup = "Vorbis";
@@ -4076,7 +4213,7 @@ ghb_validate_audio(signal_user_data_t *ud)
                        if (codec == HB_ACODEC_DCA)
                        {
                                a_unsup = "DTS";
-                               codec = HB_ACODEC_FAAC;
+                               codec = HB_ACODEC_AC3;
                        }
                }
                if (a_unsup)
@@ -4094,28 +4231,21 @@ ghb_validate_audio(signal_user_data_t *ud)
                        value = ghb_lookup_acodec_value(codec);
                        ghb_settings_take_value(asettings, "AudioEncoder", value);
                }
+
                gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
                gboolean allow_mono = TRUE;
                gboolean allow_stereo = TRUE;
                gboolean allow_dolby = TRUE;
                gboolean allow_dpl2 = TRUE;
                gboolean allow_6ch = TRUE;
-               allow_mono =
-                       (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
-                       (codec & ~HB_ACODEC_LAME);
-               gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
-               allow_stereo =
-                       ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
-               allow_dolby =
-                       (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
-                       (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
-                       (layout == HB_INPUT_CH_LAYOUT_DOLBY);
-               allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
-               allow_6ch =
-                       (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
-                       (codec & ~HB_ACODEC_LAME) &&
-                       (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
-                       (taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
+               allow_mono = TRUE;
+
+               gint best = hb_get_best_mixdown(codec, aconfig->in.channel_layout, 0);
+
+               allow_stereo = best >= HB_AMIXDOWN_STEREO;
+               allow_dolby = best >= HB_AMIXDOWN_DOLBY;
+               allow_dpl2 = best >= HB_AMIXDOWN_DOLBYPLII;
+               allow_6ch = best >= HB_AMIXDOWN_6CH;
 
                gchar *mix_unsup = NULL;
                if (mix == HB_AMIXDOWN_MONO && !allow_mono)
@@ -4150,7 +4280,7 @@ ghb_validate_audio(signal_user_data_t *ud)
                                return FALSE;
                        }
                        g_free(message);
-                       mix = ghb_get_best_mix(titleindex, track, codec, mix);
+                       mix = ghb_get_best_mix(aconfig, codec, mix);
                        value = get_amix_value(mix);
                        ghb_settings_take_value(asettings, "AudioMixdown", value);
                }
@@ -4197,11 +4327,28 @@ ghb_validate_vquality(GValue *settings)
                                max = 62;
                        } break;
                }
-               if (vquality < min || vquality > max)
+               if (vcodec == HB_VCODEC_X264 && vquality == 0.0)
+               {
+                       message = g_strdup_printf(
+                                               "Warning: lossless h.264 selected\n\n"
+                                               "Lossless h.264 is not well supported by\n"
+                                               "many players and editors.\n\n"
+                        "It will produce enormous output files.\n\n"
+                                               "Are you sure you wish to use this setting?",
+                                               (gint)vquality, min, max);
+                       if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
+                                                                       "Cancel", "Continue"))
+                       {
+                               g_free(message);
+                               return FALSE;
+                       }
+                       g_free(message);
+               }
+               else if (vquality < min || vquality > max)
                {
                        message = g_strdup_printf(
-                                               "Interesting video quality choise: %d\n\n"
-                                               "Typical values range from %d to %d.\n"
+                                               "Interesting video quality choice: %d\n\n"
+                                               "Typical values range from %d to %d.\n\n"
                                                "Are you sure you wish to use this setting?",
                                                (gint)vquality, min, max);
                        if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
@@ -4273,6 +4420,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                gint start, end;
                gint num_chapters = hb_list_count(title->list_chapter);
                gint duration = title->duration / 90000;
+               job->chapter_markers = FALSE;
                job->chapter_start = 1;
                job->chapter_end = num_chapters;
 
@@ -4286,8 +4434,6 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                }
                if (ghb_settings_combo_int(js, "PtoPType") == 1)
                {
-                       job->chapter_start = 1;
-                       job->chapter_end = num_chapters;
                        start = ghb_settings_get_int(js, "start_point");
                        end = ghb_settings_get_int(js, "end_point");
                        job->pts_to_start = (int64_t)MIN(duration-1, start) * 90000;
@@ -4296,8 +4442,6 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                }
                if (ghb_settings_combo_int(js, "PtoPType") == 2)
                {
-                       job->chapter_start = 1;
-                       job->chapter_end = num_chapters;
                        start = ghb_settings_get_int(js, "start_point");
                        end = ghb_settings_get_int(js, "end_point");
                        gint64 max_frames;
@@ -4306,7 +4450,10 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                        job->frame_to_stop = (int64_t)MAX(start, end-1) - 
                                                                 job->frame_to_start;
                }
-               job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
+               if (job->chapter_start != job->chapter_end)
+               {
+                       job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
+               }
                if (job->chapter_start == job->chapter_end)
                        job->chapter_markers = 0;
                if ( job->chapter_markers )
@@ -4318,22 +4465,19 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
 
                        chapters = ghb_settings_get_value(js, "chapter_list");
                        count = ghb_array_len(chapters);
-                       for(chap = start; chap <= end; chap++)
+                       for(chap = 0; chap < count; chap++)
                        {
                                hb_chapter_t * chapter_s;
                                gchar *name;
 
                                name = NULL;
-                               if (chap-1 < count)
-                               {
-                                       chapter = ghb_array_get_nth(chapters, chap-1);
-                                       name = ghb_value_string(chapter); 
-                               }
+                               chapter = ghb_array_get_nth(chapters, chap);
+                               name = ghb_value_string(chapter); 
                                if (name == NULL)
                                {
-                                       name = g_strdup_printf ("Chapter %2d", chap);
+                                       name = g_strdup_printf ("Chapter %2d", chap+1);
                                }
-                               chapter_s = hb_list_item( job->title->list_chapter, chap - 1);
+                               chapter_s = hb_list_item( job->title->list_chapter, chap);
                                strncpy(chapter_s->title, name, 1023);
                                chapter_s->title[1023] = '\0';
                                g_free(name);
@@ -4358,7 +4502,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
        gboolean keep_aspect;
        keep_aspect = ghb_settings_get_boolean(js, "PictureKeepRatio");
        job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
-       job->anamorphic.modulus = ghb_settings_combo_int(js, "PictureModulus");
+       job->modulus = ghb_settings_combo_int(js, "PictureModulus");
        if (job->anamorphic.mode)
        {
                job->anamorphic.par_width = title->pixel_aspect_width;
@@ -4470,14 +4614,18 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
        {
                job->vrate = title->rate;
                job->vrate_base = title->rate_base;
-               job->cfr = 0;
        }
        else
        {
                job->vrate = 27000000;
                job->vrate_base = vrate;
-               job->cfr = 1;
        }
+       if (ghb_settings_get_boolean(js, "VideoFrameratePFR"))
+               job->cfr = 2;
+       else if (ghb_settings_get_boolean(js, "VideoFramerateCFR"))
+               job->cfr = 1;
+       else
+               job->cfr = 0;
 
        const GValue *audio_list;
        gint count, ii;
@@ -4489,95 +4637,53 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
        {
                GValue *asettings;
            hb_audio_config_t audio;
-           hb_audio_config_t *taudio;
+           hb_audio_config_t *aconfig;
+               gint acodec;
 
                hb_audio_config_init(&audio);
                asettings = ghb_array_get_nth(audio_list, ii);
                audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
                audio.out.track = tcount;
-               audio.out.codec = ghb_settings_combo_int(asettings, "AudioEncoder");
-        taudio = (hb_audio_config_t *) hb_list_audio_config_item(
+
+        aconfig = (hb_audio_config_t *) hb_list_audio_config_item(
                                                                        title->list_audio, audio.in.track );
-               if (audio.out.codec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
-               {
-                       if (!(taudio->in.codec & (HB_ACODEC_AC3 | HB_ACODEC_DCA)))
-                       {
-                               // Not supported.  
-                               // AC3/DTS is passthrough only, so input must be AC3/DTS
-                               if (job->mux == HB_MUX_MKV)
-                               {
-                                       audio.out.codec = HB_ACODEC_LAME;
-                               }
-                               else
-                               {
-                                       audio.out.codec = HB_ACODEC_FAAC;
-                               }
-                       }
-                       else
-                       {
-                               audio.out.codec &= taudio->in.codec;
-                       }
-               }
-               if ((job->mux == HB_MUX_MP4) && 
-                       ((audio.out.codec & HB_ACODEC_LAME) ||
-                       (audio.out.codec & HB_ACODEC_DCA) ||
-                       (audio.out.codec & HB_ACODEC_VORBIS)))
-               {
-                       // mp4/mp3|dts|vorbis combination is not supported.
-                       audio.out.codec = HB_ACODEC_FAAC;
-               }
+
+               acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
+               audio.out.codec = ghb_select_audio_codec(js, aconfig, acodec);
+
         audio.out.dynamic_range_compression = 
                        ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
         if (audio.out.dynamic_range_compression < 1.0)
                audio.out.dynamic_range_compression = 0.0;
 
                // It would be better if this were done in libhb for us, but its not yet.
-               if (audio.out.codec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
+               if (ghb_audio_is_passthru(audio.out.codec))
                {
                        audio.out.mixdown = 0;
                }
                else
                {
-                       int channels;
-
                        audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
-                       if (audio.out.mixdown == HB_AMIXDOWN_MONO)
-                               channels = 1;
-                       else if (audio.out.mixdown == HB_AMIXDOWN_6CH)
-                               channels = 6;
-                       else
-                               channels = 2;
-
                        // Make sure the mixdown is valid and pick a new one if not.
-                       audio.out.mixdown = ghb_get_best_mix(titleindex
-                               audio.in.track, audio.out.codec, audio.out.mixdown);
+                       audio.out.mixdown = ghb_get_best_mix(aconfig, audio.out.codec
+                                                                                                       audio.out.mixdown);
                        audio.out.bitrate = 
                                ghb_settings_combo_int(asettings, "AudioBitrate");
                        gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
                        if (srate == 0) // 0 is same as source
-                               audio.out.samplerate = taudio->in.samplerate;
+                               audio.out.samplerate = aconfig->in.samplerate;
                        else
                                audio.out.samplerate = srate;
 
-                       audio.out.bitrate = ghb_get_best_audio_bitrate(
-                               audio.out.codec, audio.out.bitrate, channels);
+                       audio.out.bitrate = hb_get_best_audio_bitrate(
+                               audio.out.codec, audio.out.bitrate, 
+                               audio.out.samplerate, audio.out.mixdown);
                }
 
                // Add it to the jobs audio list
         hb_audio_add( job, &audio );
                tcount++;
        }
-       // I was tempted to move this up with the reset of the video quality
-       // settings, but I suspect the settings above need to be made
-       // first in order for hb_calc_bitrate to be accurate.
-       if (ghb_settings_get_boolean(js, "vquality_type_target"))
-       {
-               gint size;
-               
-               size = ghb_settings_get_int(js, "VideoTargetSize");
-        job->vbitrate = hb_calc_bitrate( job, size );
-               job->vquality = -1.0;
-       }
 
        dest_str = ghb_settings_get_string(js, "destination");
        job->file = dest_str;
@@ -4614,8 +4720,10 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                        sub_config.offset = ghb_settings_get_int(ssettings, "SrtOffset");
                        lang = ghb_settings_get_string(ssettings, "SrtLanguage");
                        code = ghb_settings_get_string(ssettings, "SrtCodeset");
-                       strncpy(sub_config.src_filename, filename, 128);
-                       strncpy(sub_config.src_codeset, code, 40);
+                       strncpy(sub_config.src_filename, filename, 255);
+                       sub_config.src_filename[255] = 0;
+                       strncpy(sub_config.src_codeset, code, 39);
+                       sub_config.src_codeset[39] = 0;
                        sub_config.force = 0;
                        sub_config.dest = PASSTHRUSUB;
                        sub_config.default_track = def;
@@ -4631,15 +4739,10 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                subtitle = ghb_settings_get_int(ssettings, "SubtitleTrack");
                if (subtitle == -1)
                {
-                       if (!burned && job->mux == HB_MUX_MKV)
+                       if (!burned)
                        {
                                job->select_subtitle_config.dest = PASSTHRUSUB;
                        }
-                       else if (!burned && job->mux == HB_MUX_MP4)
-                       {
-                               // Skip any non-burned vobsubs when output is mp4
-                               continue;
-                       }
                        else if (burned)
                        {
                                // Only allow one subtitle to be burned into the video
@@ -4659,25 +4762,19 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
                hb_subtitle_config_t sub_config;
 
                        subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
-                       sub_config = subt->config;
                        if (subt != NULL)
                        {
-                               if (!burned && job->mux == HB_MUX_MKV && 
-                                       subt->format == PICTURESUB)
+                               sub_config = subt->config;
+                               if (!burned)
                                {
                                        sub_config.dest = PASSTHRUSUB;
                                }
-                               else if (!burned && job->mux == HB_MUX_MP4 && 
-                                       subt->format == PICTURESUB)
-                               {
-                                       // Skip any non-burned vobsubs when output is mp4
-                                       continue;
-                               }
-                               else if ( burned && subt->format == PICTURESUB )
+                               else if ( burned && canBurn(subt->source) )
                                {
                                        // Only allow one subtitle to be burned into the video
                                        if (one_burned)
                                                continue;
+                                       sub_config.dest = RENDERSUB;
                                        one_burned = TRUE;
                                }
                                sub_config.force = force;