diff options
-rw-r--r-- | gtk/src/audiohandler.c | 164 | ||||
-rw-r--r-- | gtk/src/audiohandler.h | 4 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 283 | ||||
-rw-r--r-- | gtk/src/presets.c | 10 | ||||
-rw-r--r-- | libhb/common.c | 150 | ||||
-rw-r--r-- | libhb/common.h | 19 | ||||
-rw-r--r-- | libhb/work.c | 107 | ||||
-rw-r--r-- | macosx/Controller.m | 111 | ||||
-rw-r--r-- | macosx/HBAudio.m | 133 | ||||
-rw-r--r-- | macosx/HBAudioController.m | 8 | ||||
-rw-r--r-- | test/test.c | 351 |
11 files changed, 731 insertions, 609 deletions
diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c index 9729f1b33..90256d6cf 100644 --- a/gtk/src/audiohandler.c +++ b/gtk/src/audiohandler.c @@ -26,127 +26,69 @@ static GValue* get_selected_asettings(signal_user_data_t *ud); static gboolean block_updates = FALSE; gint -ghb_select_audio_codec(int mux, hb_audio_config_t *aconfig, gint acodec, gint fallback) +ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint fallback, gint copy_mask) { guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK; - if (mux == HB_MUX_MP4) + if (acodec == HB_ACODEC_AUTO_PASS) { - if (acodec & HB_ACODEC_PASS_FLAG) - { - if ((acodec & in_codec & HB_ACODEC_PASS_MASK & ~HB_ACODEC_VORBIS)) - { - return acodec & (in_codec | HB_ACODEC_PASS_FLAG); - } - else if (fallback) - { - return fallback; - } - else - { - return HB_ACODEC_FAAC; - } - } - 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 if (acodec & HB_ACODEC_FFAAC) - { - return HB_ACODEC_FFAAC; - } - else if (fallback) - { - return fallback; - } - else - { - return HB_ACODEC_FAAC; - } + return hb_autopassthru_get_encoder(in_codec, copy_mask, fallback, mux); } - else + + gint ii; + // Sanitize fallback + for (ii = 0; ii < hb_audio_encoders_count; ii++) { - if (acodec & HB_ACODEC_PASS_FLAG) + if (hb_audio_encoders[ii].encoder == fallback && + !(hb_audio_encoders[ii].muxers & mux)) { - if ((acodec & in_codec & HB_ACODEC_PASS_MASK)) - { - return acodec & (in_codec | HB_ACODEC_PASS_FLAG); - } - else if (fallback) - { - return fallback; - } + if ( mux == HB_MUX_MKV ) + fallback = HB_ACODEC_LAME; else - { - return HB_ACODEC_FAAC; - } + fallback = HB_ACODEC_FAAC; + break; } - 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_VORBIS) - { - return HB_ACODEC_VORBIS; - } - else if (acodec & HB_ACODEC_FAAC) - { - return HB_ACODEC_FAAC; - } - else if (acodec & HB_ACODEC_FFAAC) - { - return HB_ACODEC_FFAAC; - } - else if (fallback ) + } + if ((acodec & HB_ACODEC_PASS_FLAG) && + !(acodec & in_codec & HB_ACODEC_PASS_MASK)) + { + return fallback; + } + for (ii = 0; ii < hb_audio_encoders_count; ii++) + { + if (hb_audio_encoders[ii].encoder == acodec && + !(hb_audio_encoders[ii].muxers & mux)) { return fallback; } - else - { - return HB_ACODEC_LAME; - } } + return acodec; } -int ghb_allowed_passthru_mask(GValue *settings, int acodec) +int ghb_get_copy_mask(GValue *settings) { - gint ret = acodec; - - if (acodec == HB_ACODEC_ANY) - { - if (!ghb_settings_get_boolean(settings, "AudioAllowMP3Pass")) - { - ret &= ~HB_ACODEC_MP3; - } - if (!ghb_settings_get_boolean(settings, "AudioAllowAACPass")) - { - ret &= ~HB_ACODEC_FFAAC; - } - if (!ghb_settings_get_boolean(settings, "AudioAllowAC3Pass")) - { - ret &= ~HB_ACODEC_AC3; - } - if (!ghb_settings_get_boolean(settings, "AudioAllowDTSPass")) - { - ret &= ~HB_ACODEC_DCA; - } - if (!ghb_settings_get_boolean(settings, "AudioAllowDTSHDPass")) - { - ret &= ~HB_ACODEC_DCA_HD; - } - } - return ret; + gint mask = 0; + + if (ghb_settings_get_boolean(settings, "AudioAllowMP3Pass")) + { + mask |= HB_ACODEC_MP3; + } + if (ghb_settings_get_boolean(settings, "AudioAllowAACPass")) + { + mask |= HB_ACODEC_FFAAC; + } + if (ghb_settings_get_boolean(settings, "AudioAllowAC3Pass")) + { + mask |= HB_ACODEC_AC3; + } + if (ghb_settings_get_boolean(settings, "AudioAllowDTSPass")) + { + mask |= HB_ACODEC_DCA; + } + if (ghb_settings_get_boolean(settings, "AudioAllowDTSHDPass")) + { + mask |= HB_ACODEC_DCA_HD; + } + return mask; } static int ghb_select_fallback( GValue *settings, int mux, int acodec ) @@ -223,8 +165,8 @@ ghb_adjust_audio_rate_combos(signal_user_data_t *ud) sr = aconfig ? aconfig->in.samplerate : 48000; } gint fallback = ghb_select_fallback( ud->settings, mux, acodec ); - select_acodec = ghb_allowed_passthru_mask(ud->settings, acodec); - select_acodec = ghb_select_audio_codec(mux, aconfig, select_acodec, fallback); + gint copy_mask = ghb_get_copy_mask(ud->settings); + select_acodec = ghb_select_audio_codec(mux, aconfig, acodec, fallback, copy_mask); gboolean codec_defined_bitrate = FALSE; if (ghb_audio_is_passthru (select_acodec)) { @@ -339,8 +281,8 @@ ghb_set_pref_audio(gint titleindex, signal_user_data_t *ud) audio = ghb_array_get_nth(pref_audio, ii); acodec = ghb_settings_combo_int(audio, "AudioEncoder"); fallback = ghb_select_fallback( ud->settings, mux, acodec ); - select_acodec = ghb_allowed_passthru_mask(ud->settings, acodec); - select_acodec = ghb_select_audio_codec(mux, NULL, select_acodec, fallback); + gint copy_mask = ghb_get_copy_mask(ud->settings); + select_acodec = ghb_select_audio_codec(mux, NULL, acodec, fallback, copy_mask); bitrate = ghb_settings_combo_int(audio, "AudioBitrate"); rate = ghb_settings_combo_double(audio, "AudioSamplerate"); mix = ghb_settings_combo_int(audio, "AudioMixdown"); @@ -361,7 +303,7 @@ ghb_set_pref_audio(gint titleindex, signal_user_data_t *ud) // HB_ACODEC_* are bit fields. Treat acodec as mask if (!(aconfig->in.codec & select_acodec & HB_ACODEC_PASS_MASK)) { - if (acodec != HB_ACODEC_ANY) + if (acodec != HB_ACODEC_AUTO_PASS) acodec = fallback; // If we can't substitute the passthru with a suitable // encoder and diff --git a/gtk/src/audiohandler.h b/gtk/src/audiohandler.h index 74df87a3d..88ee306ae 100644 --- a/gtk/src/audiohandler.h +++ b/gtk/src/audiohandler.h @@ -34,7 +34,7 @@ void ghb_set_audio(signal_user_data_t *ud, GValue *settings); gchar* ghb_get_user_audio_lang( signal_user_data_t *ud, gint titleindex, gint track); void ghb_audio_list_refresh_selected(signal_user_data_t *ud); -int ghb_allowed_passthru_mask(GValue *settings, int acodec); -gint ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, int fallback_acodec); +gint ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint fallback_acodec, gint copy_mask); +int ghb_get_copy_mask(GValue *settings); #endif // _AUDIOHANDLER_H_ diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 400246f5f..733340784 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -236,53 +236,6 @@ combo_opts_t denoise_opts = d_denoise_opts }; -static options_map_t d_vcodec_opts[] = -{ - {"H.264 (x264)", "x264", HB_VCODEC_X264, ""}, - {"MPEG-4 (FFmpeg)", "ffmpeg", HB_VCODEC_FFMPEG_MPEG4, ""}, - {"MPEG-2 (FFmpeg)", "ffmpeg2",HB_VCODEC_FFMPEG_MPEG2, ""}, - {"VP3 (Theora)", "theora", HB_VCODEC_THEORA, ""}, -}; -combo_opts_t vcodec_opts = -{ - sizeof(d_vcodec_opts)/sizeof(options_map_t), - d_vcodec_opts -}; - -static options_map_t d_acodec_opts[] = -{ - {"AAC (faac)", "faac", HB_ACODEC_FAAC, "faac"}, - {"AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, "ffaac"}, - {"MP3 (lame)", "lame", HB_ACODEC_LAME, "lame"}, - {"Vorbis", "vorbis", HB_ACODEC_VORBIS, "vorbis"}, - {"AC3 (ffmpeg)", "ac3", HB_ACODEC_AC3, "ac3"}, - {"MP3 Passthru", "mp3pass", HB_ACODEC_MP3_PASS, "mp3pass"}, - {"AAC Passthru", "aacpass", HB_ACODEC_AAC_PASS, "aacpass"}, - {"AC3 Passthru", "ac3pass", HB_ACODEC_AC3_PASS, "ac3pass"}, - {"DTS Passthru", "dtspass", HB_ACODEC_DCA_PASS, "dtspass"}, - {"DTS-HD Passthru", "dtshdpass", HB_ACODEC_DCA_HD_PASS, "dtshdpass"}, - {"Auto Passthru", "auto", HB_ACODEC_ANY, "auto"}, -}; -combo_opts_t acodec_opts = -{ - sizeof(d_acodec_opts)/sizeof(options_map_t), - d_acodec_opts -}; - -static options_map_t d_acodec_fallback_opts[] = -{ - {"AAC (faac)", "faac", HB_ACODEC_FAAC, "faac"}, - {"AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, "ffaac"}, - {"MP3 (lame)", "lame", HB_ACODEC_LAME, "lame"}, - {"Vorbis", "vorbis", HB_ACODEC_VORBIS, "vorbis"}, - {"AC3 (ffmpeg)", "ac3", HB_ACODEC_AC3, "ac3"}, -}; -combo_opts_t acodec_fallback_opts = -{ - sizeof(d_acodec_fallback_opts)/sizeof(options_map_t), - d_acodec_fallback_opts -}; - static options_map_t d_direct_opts[] = { {"None", "none", 0, "none"}, @@ -432,10 +385,6 @@ combo_name_map_t combo_name_map[] = {"PictureDecomb", &decomb_opts}, {"PictureDetelecine", &detel_opts}, {"PictureDenoise", &denoise_opts}, - {"VideoEncoder", &vcodec_opts}, - {"AudioEncoder", &acodec_opts}, - {"AudioEncoderActual", &acodec_opts}, - {"AudioEncoderFallback", &acodec_fallback_opts}, {"x264_direct", &direct_opts}, {"x264_b_adapt", &badapt_opts}, {"x264_bpyramid", &bpyramid_opts}, @@ -1229,6 +1178,111 @@ lookup_audio_bitrate_option(const GValue *rate) } static gint +lookup_hb_encoder_int(const GValue *enc, hb_encoder_t *encoders, int len) +{ + gint ii; + + if (G_VALUE_TYPE(enc) == G_TYPE_STRING) + { + gchar *str = ghb_value_string(enc); + for (ii = 0; ii < len; ii++) + { + if (strcmp(encoders[ii].human_readable_name, str) == 0 || + strcmp(encoders[ii].short_name, str) == 0) + { + g_free(str); + return encoders[ii].encoder; + } + } + 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].encoder; + } + } + } + return 0; +} + +static const gchar* +lookup_hb_encoder_option(const GValue *enc, hb_encoder_t *encoders, int len) +{ + gint ii; + + if (G_VALUE_TYPE(enc) == G_TYPE_STRING) + { + gchar *str = ghb_value_string(enc); + for (ii = 0; ii < len; ii++) + { + 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; + } + } + 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; +} + +static const gchar* +lookup_hb_encoder_string(const GValue *enc, hb_encoder_t *encoders, int len) +{ + gint ii; + + if (G_VALUE_TYPE(enc) == G_TYPE_STRING) + { + gchar *str = ghb_value_string(enc); + for (ii = 0; ii < len; ii++) + { + if (strcmp(encoders[ii].human_readable_name, str) == 0 || + strcmp(encoders[ii].short_name, str) == 0) + { + g_free(str); + return encoders[ii].short_name; + } + } + 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].short_name; + } + } + } + return 0; +} + +static gint lookup_audio_lang_int(const GValue *rate) { gint ii; @@ -1281,15 +1335,15 @@ ghb_lookup_acodec_value(gint val) GValue *value = NULL; gint ii; - for (ii = 0; ii < acodec_opts.count; ii++) + for (ii = 0; ii < hb_audio_encoders_count; ii++) { - if ((int)acodec_opts.map[ii].ivalue == val) + if ((int)hb_audio_encoders[ii].encoder == val) { - value = ghb_string_value_new(acodec_opts.map[ii].shortOpt); + value = ghb_string_value_new(hb_audio_encoders[ii].short_name); return value; } } - value = ghb_string_value_new("auto"); + value = ghb_string_value_new("copy"); return value; } @@ -1644,9 +1698,9 @@ ghb_grey_combo_options(signal_user_data_t *ud) allow_6ch = acodec & ~HB_ACODEC_LAME; if (aconfig) { - acodec = ghb_allowed_passthru_mask(ud->settings, acodec); fallback = ghb_settings_combo_int(ud->settings, "AudioEncoderFallback"); - acodec = ghb_select_audio_codec(mux, aconfig, acodec, fallback); + gint copy_mask = ghb_get_copy_mask(ud->settings); + acodec = ghb_select_audio_codec(mux, aconfig, acodec, fallback, copy_mask); gint best = hb_get_best_mixdown(acodec, aconfig->in.channel_layout, 0); allow_stereo = best >= HB_AMIXDOWN_STEREO; @@ -1792,6 +1846,60 @@ video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gi } static void +hb_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"); + store = get_combo_box_store(builder, name); + gtk_list_store_clear(store); + for (ii = 0; ii < len; ii++) + { + if ((mask & encoders[ii].encoder) && + !(neg_mask & encoders[ii].encoder)) + { + gtk_list_store_append(store, &iter); + str = g_strdup_printf("<small>%s</small>", + encoders[ii].human_readable_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, + -1); + g_free(str); + } + } +} + +static void +hb_encoder_opts_set( + GtkBuilder *builder, + const gchar *name, + hb_encoder_t *encoders, + int len) +{ + hb_encoder_opts_set_with_mask(builder, name, encoders, len, ~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); +} + +static void mix_opts_set(GtkBuilder *builder, const gchar *name) { GtkTreeIter iter; @@ -1802,14 +1910,6 @@ mix_opts_set(GtkBuilder *builder, const gchar *name) g_debug("mix_opts_set ()\n"); store = get_combo_box_store(builder, name); gtk_list_store_clear(store); - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, "<small>None</small>", - 1, TRUE, - 2, "none", - 3, 0.0, - 4, "none", - -1); for (ii = 0; ii < hb_audio_mixdowns_count; ii++) { gtk_list_store_append(store, &iter); @@ -2689,6 +2789,14 @@ ghb_lookup_combo_int(const gchar *name, const GValue *gval) 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); + else if (strcmp(name, "AudioEncoder") == 0) + return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderFallback") == 0) + return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderActual") == 0) + return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count); else { return lookup_generic_int(find_combo_table(name), gval); @@ -2714,6 +2822,14 @@ ghb_lookup_combo_double(const gchar *name, const GValue *gval) 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); + else if (strcmp(name, "AudioEncoder") == 0) + return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderFallback") == 0) + return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderActual") == 0) + return lookup_hb_encoder_int(gval, hb_audio_encoders, hb_audio_encoders_count); else { return lookup_generic_double(find_combo_table(name), gval); @@ -2739,6 +2855,14 @@ ghb_lookup_combo_option(const gchar *name, const GValue *gval) 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); + else if (strcmp(name, "AudioEncoder") == 0) + return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderFallback") == 0) + return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderActual") == 0) + return lookup_hb_encoder_option(gval, hb_audio_encoders, hb_audio_encoders_count); else { return lookup_generic_option(find_combo_table(name), gval); @@ -2764,6 +2888,14 @@ ghb_lookup_combo_string(const gchar *name, const GValue *gval) 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); + else if (strcmp(name, "AudioEncoder") == 0) + return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderFallback") == 0) + return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderActual") == 0) + return lookup_hb_encoder_string(gval, hb_audio_encoders, hb_audio_encoders_count); else { return lookup_generic_string(find_combo_table(name), gval); @@ -2809,6 +2941,9 @@ ghb_update_ui_combo_box( 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); 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); + acodec_fallback_opts_set(ud->builder, "AudioEncoderFallback"); language_opts_set(ud->builder, "SrtLanguage"); language_opts_set(ud->builder, "PreferredLanguage"); srt_codeset_opts_set(ud->builder, "SrtCodeset"); @@ -2828,9 +2963,6 @@ ghb_update_ui_combo_box( generic_opts_set(ud->builder, "PictureDetelecine", &detel_opts); generic_opts_set(ud->builder, "PictureDecomb", &decomb_opts); generic_opts_set(ud->builder, "PictureDenoise", &denoise_opts); - generic_opts_set(ud->builder, "VideoEncoder", &vcodec_opts); - small_opts_set(ud->builder, "AudioEncoder", &acodec_opts); - small_opts_set(ud->builder, "AudioEncoderFallback", &acodec_fallback_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); @@ -2850,6 +2982,12 @@ ghb_update_ui_combo_box( video_rate_opts_set(ud->builder, "VideoFramerate", hb_video_rates, hb_video_rates_count); 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); + else if (strcmp(name, "AudioEncoder") == 0) + hb_encoder_opts_set(ud->builder, "AudioEncoder", hb_audio_encoders, hb_audio_encoders_count); + else if (strcmp(name, "AudioEncoderFallback") == 0) + acodec_fallback_opts_set(ud->builder, "AudioEncoderFallback"); else if (strcmp(name, "SrtLanguage") == 0) language_opts_set(ud->builder, "SrtLanguage"); else if (strcmp(name, "PreferredLanguage") == 0) @@ -2885,6 +3023,9 @@ init_ui_combo_boxes(GtkBuilder *builder) init_combo_box(builder, "SrtCodeset"); init_combo_box(builder, "title"); init_combo_box(builder, "AudioTrack"); + init_combo_box(builder, "VideoEncoder"); + init_combo_box(builder, "AudioEncoder"); + init_combo_box(builder, "AudioEncoderFallback"); for (ii = 0; combo_name_map[ii].name != NULL; ii++) { init_combo_box(builder, combo_name_map[ii].name); @@ -4236,7 +4377,7 @@ ghb_validate_audio(signal_user_data_t *ud) 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_ANY) + if (codec == HB_ACODEC_AUTO_PASS) continue; aconfig = (hb_audio_config_t *) hb_list_audio_config_item( @@ -4730,9 +4871,9 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) acodec = ghb_settings_combo_int(asettings, "AudioEncoder"); - acodec = ghb_allowed_passthru_mask(js, acodec); fallback = ghb_settings_combo_int(js, "AudioEncoderFallback"); - audio.out.codec = ghb_select_audio_codec(job->mux, aconfig, acodec, fallback); + gint copy_mask = ghb_get_copy_mask(js); + audio.out.codec = ghb_select_audio_codec(job->mux, aconfig, acodec, fallback, copy_mask); audio.out.gain = ghb_settings_get_double(asettings, "AudioTrackGain"); diff --git a/gtk/src/presets.c b/gtk/src/presets.c index bc87e9a14..8305c4ae3 100644 --- a/gtk/src/presets.c +++ b/gtk/src/presets.c @@ -1989,8 +1989,9 @@ typedef struct static value_map_t vcodec_xlat[] = { {"MPEG-2 (FFmpeg)", "ffmpeg2"}, + {"MPEG-4 (FFmpeg)", "ffmpeg4"}, {"MPEG-4 (FFmpeg)", "ffmpeg"}, - {"MPEG-4 (XviD)", "ffmpeg"}, + {"MPEG-4 (XviD)", "ffmpeg4"}, {"H.264 (x264)", "x264"}, {"VP3 (Theora)", "theora"}, {NULL,NULL} @@ -2002,13 +2003,20 @@ static value_map_t acodec_xlat[] = {"AAC (faac)", "faac"}, {"AAC (CoreAudio)", "faac"}, {"HE-AAC (CoreAudio)", "faac"}, + {"AC3 (ffmpeg)", "ffac3"}, {"AC3 (ffmpeg)", "ac3"}, {"AC3", "ac3"}, // Backwards compatibility with mac ui + {"MP3 Passthru", "copy:mp3"}, {"MP3 Passthru", "mp3pass"}, + {"AAC Passthru", "copy:aac"}, {"AAC Passthru", "aacpass"}, + {"AC3 Passthru", "copy:ac3"}, {"AC3 Passthru", "ac3pass"}, + {"DTS Passthru", "copy:dts"}, {"DTS Passthru", "dtspass"}, + {"DTS-HD Passthru", "copy:dtshd"}, {"DTS-HD Passthru", "dtshdpass"}, + {"Auto Passthru", "copy"}, {"Auto Passthru", "auto"}, {"MP3 (lame)", "lame"}, {"Vorbis (vorbis)", "vorbis"}, diff --git a/libhb/common.c b/libhb/common.c index db2fac551..f320ff2c1 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -41,15 +41,43 @@ int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) / static hb_error_handler_t *error_handler = NULL; hb_mixdown_t hb_audio_mixdowns[] = -{ { "Mono", "HB_AMIXDOWN_MONO", "mono", HB_AMIXDOWN_MONO }, +{ { "None", "HB_AMIXDOWN_NONE", "none", HB_AMIXDOWN_NONE }, + { "Mono", "HB_AMIXDOWN_MONO", "mono", HB_AMIXDOWN_MONO }, { "Stereo", "HB_AMIXDOWN_STEREO", "stereo", HB_AMIXDOWN_STEREO }, { "Dolby Surround", "HB_AMIXDOWN_DOLBY", "dpl1", HB_AMIXDOWN_DOLBY }, { "Dolby Pro Logic II", "HB_AMIXDOWN_DOLBYPLII", "dpl2", HB_AMIXDOWN_DOLBYPLII }, - { "6-channel discrete", "HB_AMIXDOWN_6CH", "6ch", HB_AMIXDOWN_6CH } -}; + { "6-channel discrete", "HB_AMIXDOWN_6CH", "6ch", HB_AMIXDOWN_6CH } }; 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 } }; +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 }, +#endif + { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MP4|HB_MUX_MKV }, + { "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 }, + { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MP4|HB_MUX_MKV } }; +int hb_audio_encoders_count = sizeof( hb_audio_encoders ) / + sizeof( hb_encoder_t ); + int hb_mixdown_get_mixdown_from_short_name( const char * short_name ) { int i; @@ -76,6 +104,106 @@ const char * hb_mixdown_get_short_name_from_mixdown( int amixdown ) return ""; } +void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ) +{ + int i, j; + hb_audio_t * audio; + for( i = 0; i < hb_list_count( title->list_audio ); ) + { + audio = hb_list_item( title->list_audio, i ); + if( audio->config.out.codec == HB_ACODEC_AUTO_PASS ) + { + 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( title->list_audio, audio ); + free( 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 ); + } + 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; + } +} + +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 work.c + 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 +#ifndef __APPLE__ + if( muxer == HB_MUX_MKV ) + // Lame is the default for MKV + fallback = HB_ACODEC_LAME; + else +#endif // Core Audio or faac + fallback = hb_audio_encoders[0].encoder; + break; + } + } + for( i = 0; i < hb_audio_encoders_count; i++ ) + { + if( ( hb_audio_encoders[i].encoder == out_codec ) && + !( hb_audio_encoders[i].muxers & muxer ) ) + { + // selected passthru not possible with current muxer + out_codec = fallback; + break; + } + } + if( !( out_codec & HB_ACODEC_PASS_MASK ) ) + return fallback; + return out_codec; +} + // Given an input bitrate, find closest match in the set of allowed bitrates int hb_find_closest_audio_bitrate(int bitrate) { @@ -338,7 +466,7 @@ int hb_get_best_mixdown( uint32_t codec, int layout, int mixdown ) if (codec & HB_ACODEC_PASS_FLAG) { // Audio pass-thru. No mixdown. - return 0; + return HB_AMIXDOWN_NONE; } switch (layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK) { @@ -1226,24 +1354,24 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg) if( (audiocfg->in.bitrate != -1) && (audiocfg->in.codec != 0xDEADBEEF) ) { /* This most likely means the client didn't call hb_audio_config_init - * so bail. - */ + * so bail. */ return 0; } /* Really shouldn't ignore the passed out track, but there is currently no - * way to handle duplicates or out-of-order track numbers. - */ + * way to handle duplicates or out-of-order track numbers. */ audio->config.out.track = hb_list_count(job->list_audio) + 1; audio->config.out.codec = audiocfg->out.codec; - if( (audiocfg->out.codec & HB_ACODEC_MASK) == (audio->config.in.codec & HB_ACODEC_MASK) && - (audiocfg->out.codec & HB_ACODEC_PASS_FLAG ) ) + if((audiocfg->out.codec & HB_ACODEC_PASS_FLAG) && + ((audiocfg->out.codec == HB_ACODEC_AUTO_PASS) || + (audiocfg->out.codec & audio->config.in.codec & HB_ACODEC_PASS_MASK))) { /* Pass-through, copy from input. */ audio->config.out.samplerate = audio->config.in.samplerate; audio->config.out.bitrate = audio->config.in.bitrate; - audio->config.out.dynamic_range_compression = 0; audio->config.out.mixdown = 0; + audio->config.out.dynamic_range_compression = 0; + audio->config.out.gain = 0; } else { diff --git a/libhb/common.h b/libhb/common.h index d6024aac5..41272b93f 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -56,6 +56,7 @@ typedef struct hb_handle_s hb_handle_t; typedef struct hb_list_s hb_list_t; typedef struct hb_rate_s hb_rate_t; typedef struct hb_mixdown_s hb_mixdown_t; +typedef struct hb_encoder_s hb_encoder_t; typedef struct hb_job_s hb_job_t; typedef struct hb_title_s hb_title_t; typedef struct hb_chapter_s hb_chapter_t; @@ -126,6 +127,14 @@ struct hb_mixdown_s int amixdown; }; +struct hb_encoder_s +{ + char * human_readable_name; // note: used in presets + char * short_name; // note: used in CLI + int encoder; // HB_*CODEC_* define + int muxers; // supported muxers +}; + struct hb_subtitle_config_s { enum subdest { RENDERSUB, PASSTHRUSUB } dest; @@ -149,8 +158,14 @@ extern hb_rate_t hb_audio_bitrates[]; extern int hb_audio_bitrates_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; int hb_mixdown_get_mixdown_from_short_name( const char * short_name ); const char * hb_mixdown_get_short_name_from_mixdown( int amixdown ); +void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ); +int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer ); int hb_get_best_mixdown( uint32_t codec, int layout, int mixdown ); int hb_get_default_mixdown( uint32_t codec, int layout ); int hb_find_closest_audio_bitrate(int bitrate); @@ -250,6 +265,8 @@ struct hb_job_s /* List of audio settings. */ hb_list_t * list_audio; + int acodec_copy_mask; // Auto Passthru allowed codecs + int acodec_fallback; // Auto Passthru fallback encoder /* Subtitles */ hb_list_t * list_subtitle; @@ -328,6 +345,7 @@ struct hb_job_s #define HB_ACODEC_FF_MASK 0x000f0000 #define HB_ACODEC_PASS_FLAG 0x40000000 #define HB_ACODEC_PASS_MASK (HB_ACODEC_MP3 | HB_ACODEC_FFAAC | HB_ACODEC_DCA_HD | HB_ACODEC_AC3 | HB_ACODEC_DCA) +#define HB_ACODEC_AUTO_PASS (HB_ACODEC_PASS_MASK | HB_ACODEC_PASS_FLAG) #define HB_ACODEC_MP3_PASS (HB_ACODEC_MP3 | HB_ACODEC_PASS_FLAG) #define HB_ACODEC_AAC_PASS (HB_ACODEC_FFAAC | HB_ACODEC_PASS_FLAG) #define HB_ACODEC_AC3_PASS (HB_ACODEC_AC3 | HB_ACODEC_PASS_FLAG) @@ -346,6 +364,7 @@ struct hb_job_s #define HB_AMIXDOWN_A52_FORMAT_MASK 0x00000FF0 #define HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK 0x0000000F /* define the HB_AMIXDOWN_XXXX values */ +#define HB_AMIXDOWN_NONE 0x00000000 #define HB_AMIXDOWN_MONO 0x01000001 // DCA_FORMAT of DCA_MONO = 0 = 0x000 // A52_FORMAT of A52_MONO = 1 = 0x01 diff --git a/libhb/work.c b/libhb/work.c index 86f453ef1..c9e5ee205 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -279,28 +279,18 @@ void hb_display_job_info( hb_job_t * job ) if( !job->indepth_scan ) { /* Video encoder */ - switch( job->vcodec ) + for( i = 0; i < hb_video_encoders_count; i++ ) { - case HB_VCODEC_FFMPEG_MPEG4: - hb_log( " + encoder: FFmpeg MPEG-4" ); - break; - - case HB_VCODEC_FFMPEG_MPEG2: - hb_log( " + encoder: FFmpeg MPEG-2" ); - break; - - case HB_VCODEC_X264: - hb_log( " + encoder: x264" ); - break; - - case HB_VCODEC_THEORA: - hb_log( " + encoder: Theora" ); + if( hb_video_encoders[i].encoder == job->vcodec ) + { + hb_log( " + encoder: %s", hb_video_encoders[i].human_readable_name ); break; + } } - if ( job->advanced_opts && *job->advanced_opts && - ( ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) || - job->vcodec == HB_VCODEC_X264 ) ) + if( job->advanced_opts && *job->advanced_opts && + ( ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) || + ( job->vcodec == HB_VCODEC_X264 ) ) ) { hb_log( " + options: %s", job->advanced_opts); } @@ -360,46 +350,44 @@ void hb_display_job_info( hb_job_t * job ) hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.in.bitrate / 1000, audio->config.in.samplerate ); } - if( !(audio->config.out.codec & HB_ACODEC_PASS_FLAG) ) + if( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) { - for (j = 0; j < hb_audio_mixdowns_count; j++) + for( j = 0; j < hb_audio_encoders_count; j++ ) { - if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown) { + if( hb_audio_encoders[j].encoder == audio->config.out.codec ) + { + hb_log( " + %s", hb_audio_encoders[j].human_readable_name ); + break; + } + } + } + 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; } } - if ( audio->config.out.gain != 0.0 ) + if( audio->config.out.gain != 0.0 ) { hb_log( " + gain: %.fdB", audio->config.out.gain ); } - } - - if ( audio->config.out.dynamic_range_compression && (audio->config.in.codec == HB_ACODEC_AC3) && (audio->config.out.codec != HB_ACODEC_AC3_PASS) ) - { - hb_log(" + dynamic range compression: %f", audio->config.out.dynamic_range_compression); - } - - if( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) - { - hb_log( " + %s passthrough", - (audio->config.out.codec == HB_ACODEC_MP3_PASS) ? "MP3" : - (audio->config.out.codec == HB_ACODEC_AAC_PASS) ? "AAC" : - (audio->config.out.codec == HB_ACODEC_AC3_PASS) ? "AC3" : - (audio->config.out.codec == HB_ACODEC_DCA_PASS) ? "DTS" : - "DTS-HD"); - } - else - { - hb_log( " + encoder: %s", - ( audio->config.out.codec == HB_ACODEC_FAAC ) ? "faac" : - ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? "lame" : - ( ( audio->config.out.codec == HB_ACODEC_CA_AAC ) ? "ca_aac" : - ( ( audio->config.out.codec == HB_ACODEC_CA_HAAC ) ? "ca_haac" : - ( ( audio->config.out.codec == HB_ACODEC_FFAAC ) ? "ffaac" : - ( ( audio->config.out.codec == HB_ACODEC_AC3 ) ? "ffac3" : - "vorbis" ) ) ) ) ) ); - hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate ); + if( ( audio->config.out.dynamic_range_compression != 0.0 ) && ( audio->config.in.codec == HB_ACODEC_AC3 ) ) + { + hb_log( " + dynamic range compression: %f", audio->config.out.dynamic_range_compression ); + } + for( j = 0; j < hb_audio_encoders_count; j++ ) + { + if( hb_audio_encoders[j].encoder == audio->config.out.codec ) + { + hb_log( " + encoder: %s", hb_audio_encoders[j].human_readable_name ); + hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate ); + break; + } + } } } } @@ -530,16 +518,23 @@ static void do_job( hb_job_t * job ) */ if( !job->indepth_scan ) { - // if we are doing passthru, and the input codec is not the same as the output - // codec, then remove this audio from the job. If we're not doing passthru and - // the input codec is the 'internal' ffmpeg codec, make sure that only one - // audio references that audio stream since the codec context is specific to - // the audio id & multiple copies of the same stream will garble the audio - // or cause aborts. + // apply Auto Passthru settings + hb_autopassthru_apply_settings( job, title ); + // sanitize audio settings for( i = 0; i < hb_list_count( title->list_audio ); ) { audio = hb_list_item( title->list_audio, i ); - if( ( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) && + if( audio->config.out.codec == HB_ACODEC_AUTO_PASS ) + { + // Auto Passthru should have been handled above + // remove track to avoid a crash + hb_log( "Auto Passthru error, dropping track %d", + audio->config.out.track ); + hb_list_rem( title->list_audio, audio ); + free( audio ); + continue; + } + if( ( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) && !( audio->config.in.codec & audio->config.out.codec & HB_ACODEC_PASS_MASK ) ) { hb_log( "Passthru requested and input codec is not the same as output codec for track %d, dropping track", diff --git a/macosx/Controller.m b/macosx/Controller.m index 865cc7f60..57ea2cc3b 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -2415,12 +2415,25 @@ fWorkingCount = 0; [queueFileJob setObject:[NSString stringWithFormat:@"%d",[fPictureController deblock]] forKey:@"PictureDeblock"]; [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"]; + + /* Auto Passthru */ + /* For the time being, values are hardcoded. */ + [queueFileJob setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowAACPass"]; + [queueFileJob setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowAC3Pass"]; + [queueFileJob setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowDTSHDPass"]; + [queueFileJob setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowDTSPass"]; + [queueFileJob setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowMP3Pass"]; + // just in case we need it for display purposes + [queueFileJob setObject: @"AC3 (ffmpeg)" forKey: @"AudioEncoderFallback"]; + // actual fallback encoder + [queueFileJob setObject: [NSNumber numberWithInt: HB_ACODEC_AC3] forKey: @"JobAudioEncoderFallback"]; + + /* Audio */ [self writeToActivityLog: "createQueueFileItem: Getting Audio from prepareAudioForQueueFileJob ..."]; - /*Audio*/ - [fAudioDelegate prepareAudioForQueueFileJob: queueFileJob]; - [self writeToActivityLog: "createQueueFileItem: Returned getting audio from prepareAudioForQueueFileJob"]; + [fAudioDelegate prepareAudioForQueueFileJob: queueFileJob]; + [self writeToActivityLog: "createQueueFileItem: Returned getting audio from prepareAudioForQueueFileJob"]; - /* Subtitles*/ + /* Subtitles */ NSMutableArray *subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesDelegate getSubtitleArray] copyItems:YES]; [queueFileJob setObject:[NSArray arrayWithArray: subtitlesArray] forKey:@"SubtitleList"]; [subtitlesArray autorelease]; @@ -2815,11 +2828,13 @@ fWorkingCount = 0; /* Turbo 1st pass for 2 Pass Encoding */ [fVidTurboPassCheck setState:[[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue]]; - /*Audio*/ - + /* Auto Passthru */ + /* For the time being, there are no GUI elements for this; + * everything is hardcoded. */ + /* Audio */ /* Now lets add our new tracks to the audio list here */ - [fAudioDelegate addTracksFromQueue: queueToApply]; + [fAudioDelegate addTracksFromQueue: queueToApply]; /*Subtitles*/ /* Crashy crashy right now, working on it */ @@ -3220,8 +3235,13 @@ bool one_burned = FALSE; -[subtitlesArray autorelease]; +[subtitlesArray autorelease]; + + /* Auto Passthru */ + /* For the time being, values are hardcoded. */ + job->acodec_copy_mask = HB_ACODEC_PASS_MASK; + job->acodec_fallback = HB_ACODEC_AC3; /* Audio tracks and mixdowns */ [fAudioDelegate prepareAudioForJob: job]; @@ -3716,11 +3736,34 @@ bool one_burned = FALSE; #pragma mark - - + /* Auto Passthru */ + job->acodec_copy_mask = 0; + if( [[queueToApply objectForKey: @"AudioAllowAACPass"] intValue] == 1 ) + { + job->acodec_copy_mask |= HB_ACODEC_FFAAC; + } + if( [[queueToApply objectForKey: @"AudioAllowAC3Pass"] intValue] == 1 ) + { + job->acodec_copy_mask |= HB_ACODEC_AC3; + } + if( [[queueToApply objectForKey: @"AudioAllowDTSHDPass"] intValue] == 1 ) + { + job->acodec_copy_mask |= HB_ACODEC_DCA_HD; + } + if( [[queueToApply objectForKey: @"AudioAllowDTSPass"] intValue] == 1 ) + { + job->acodec_copy_mask |= HB_ACODEC_DCA; + } + if( [[queueToApply objectForKey: @"AudioAllowMP3Pass"] intValue] == 1 ) + { + job->acodec_copy_mask |= HB_ACODEC_MP3; + } + job->acodec_fallback = [[queueToApply objectForKey: @"JobAudioEncoderFallback"] intValue]; + /* Audio tracks and mixdowns */ - /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/ + /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty */ int audiotrack_count = hb_list_count(job->list_audio); - for( int i = 0; i < audiotrack_count;i++) + for( int i = 0; i < audiotrack_count; i++ ) { hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 ); hb_list_rem(job->list_audio, temp_audio); @@ -4059,8 +4102,8 @@ bool one_burned = FALSE; { /* Let libhb do the job */ hb_start( fQueueEncodeLibhb ); - /*set the fEncodeState State */ - fEncodeState = 1; + /* set the fEncodeState State */ + fEncodeState = 1; } @@ -4500,13 +4543,17 @@ bool one_burned = FALSE; /* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */ [fVidEncoderPopUp removeAllItems]; NSMenuItem *menuItem; - /* These video encoders are available to all of our current muxers, so lets list them once here */ - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (FFmpeg)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_FFMPEG_MPEG4]; - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-2 (FFmpeg)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_FFMPEG_MPEG2]; - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_X264]; + int i; + for( i = 0; i < hb_video_encoders_count; i++ ) + { + if( ( ( format == 0 ) && ( hb_video_encoders[i].muxers & HB_MUX_MP4 ) ) || + ( ( format == 1 ) && ( hb_video_encoders[i].muxers & HB_MUX_MKV ) ) ) + { + menuItem = [[fVidEncoderPopUp menu] addItemWithTitle: [NSString stringWithUTF8String: hb_video_encoders[i].human_readable_name] + action: NULL keyEquivalent: @""]; + [menuItem setTag: hb_video_encoders[i].encoder]; + } + } switch( format ) { @@ -4519,11 +4566,8 @@ bool one_burned = FALSE; [fDstMp4iPodFileCheck setHidden: NO]; break; - case 1: + case 1: ext = "mkv"; - /* Add additional video encoders here */ - menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_VCODEC_THEORA]; /* We enable the create chapters checkbox here */ [fCreateChapterMarkers setEnabled: YES]; break; @@ -5592,8 +5636,12 @@ return YES; /* Turbo 1st pass for 2 Pass Encoding */ [fVidTurboPassCheck setState:[[chosenPreset objectForKey:@"VideoTurboTwoPass"] intValue]]; - /*Audio*/ - [fAudioDelegate addTracksFromPreset: chosenPreset]; + /* Auto Passthru */ + /* For the time being, there are no GUI elements for this; + * everything is hardcoded. */ + + /* Audio */ + [fAudioDelegate addTracksFromPreset: chosenPreset]; /*Subtitles*/ [fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]]; @@ -6112,7 +6160,16 @@ return YES; [preset setObject:[fPictureController decombCustomString] forKey:@"PictureDecombCustom"]; [preset setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"]; - /*Audio*/ + /* Auto Pasthru */ + /* For the time being, values are hardcoded. */ + [preset setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowAACPass"]; + [preset setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowAC3Pass"]; + [preset setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowDTSHDPass"]; + [preset setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowDTSPass"]; + [preset setObject: [NSNumber numberWithInt: 1] forKey: @"AudioAllowMP3Pass"]; + [preset setObject: @"AC3 (ffmpeg)" forKey: @"AudioEncoderFallback"]; + + /* Audio */ NSMutableArray *audioListArray = [[NSMutableArray alloc] init]; [fAudioDelegate prepareAudioForPreset: audioListArray]; diff --git a/macosx/HBAudio.m b/macosx/HBAudio.m index b7fdbcc85..10522b3d3 100644 --- a/macosx/HBAudio.m +++ b/macosx/HBAudio.m @@ -70,104 +70,51 @@ static NSMutableArray *masterBitRateArray = nil; { if ([HBAudio class] == self) { - int i; + int i, audioMustMatch, shouldAdd; + BOOL muxMKV, muxMP4; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSDictionary *dict; masterCodecArray = [[NSMutableArray alloc] init]; // knowingly leaked - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AAC (CoreAudio)", @"AAC (CoreAudio)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_CA_AAC], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; - if (encca_haac_available()) + for( i = 0; i < hb_audio_encoders_count; i++ ) { - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"HE-AAC (CoreAudio)", @"HE-AAC (CoreAudio)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_CA_HAAC], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; + if( ( hb_audio_encoders[i].encoder & HB_ACODEC_PASS_FLAG ) && + ( hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS ) ) + { + audioMustMatch = ( hb_audio_encoders[i].encoder & ~HB_ACODEC_PASS_FLAG ); + } + else + { + audioMustMatch = 0; + } + // Auto Passthru disabled until we have GUI widgets for it + shouldAdd = ( hb_audio_encoders[i].encoder != HB_ACODEC_AUTO_PASS ) && + ( ( hb_audio_encoders[i].encoder != HB_ACODEC_CA_HAAC ) || encca_haac_available() ); + muxMKV = ( hb_audio_encoders[i].muxers & HB_MUX_MKV ) ? YES : NO; + muxMP4 = ( hb_audio_encoders[i].muxers & HB_MUX_MP4 ) ? YES : NO; + if( shouldAdd && 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 if( shouldAdd ) + { + [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]]; + } } - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AAC (ffmpeg)", @"AAC (ffmpeg)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_FFAAC], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AAC (faac)", @"AAC (faac)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_FAAC], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AAC Passthru", @"AAC Passthru"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_AAC_PASS], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithInt: HB_ACODEC_FFAAC], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AC3 (ffmpeg)", @"AC3 (ffmpeg)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithInt: HB_ACODEC_DCA], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"DTS-HD Passthru", @"DTS-HD Passthru"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_DCA_HD_PASS], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithInt: HB_ACODEC_DCA_HD], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"MP3 (lame)", @"MP3 (lame)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_LAME], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"MP3 Passthru", @"MP3 Passthru"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_MP3_PASS], keyAudioCodec, - [NSNumber numberWithBool: YES], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithInt: HB_ACODEC_MP3], keyAudioMustMatchTrack, - nil]]; - [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"Vorbis (vorbis)", @"Vorbis (vorbis)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_VORBIS], keyAudioCodec, - [NSNumber numberWithBool: NO], keyAudioMP4, - [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, - nil]]; masterMixdownArray = [[NSMutableArray alloc] init]; // knowingly leaked - [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"None", @"None"), keyAudioMixdownName, - [NSNumber numberWithInt: 0], keyAudioMixdown, - nil]]; for (i = 0; i < hb_audio_mixdowns_count; i++) { [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: @@ -296,11 +243,11 @@ static NSMutableArray *masterBitRateArray = nil; // Basically with the way the mixdowns are stored, the assumption from the libhb point of view // currently is that all mixdowns from the best down to mono are supported. - if (currentMixdown && currentMixdown <= theBestMixdown) + if ((currentMixdown != HB_AMIXDOWN_NONE) && (currentMixdown <= theBestMixdown)) { shouldAdd = YES; } - else if (0 == currentMixdown && (codecCodec & HB_ACODEC_PASS_FLAG)) + else if ((currentMixdown == HB_AMIXDOWN_NONE) && (codecCodec & HB_ACODEC_PASS_FLAG)) { // "None" mixdown (passthru) shouldAdd = YES; @@ -638,7 +585,7 @@ static NSMutableArray *masterBitRateArray = nil; if (retval) { int myMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue]; - if (0 == myMixdown) + if (myMixdown == HB_AMIXDOWN_NONE) { // "None" mixdown (passthru) retval = NO; diff --git a/macosx/HBAudioController.m b/macosx/HBAudioController.m index 16538c2ff..b275f7a82 100644 --- a/macosx/HBAudioController.m +++ b/macosx/HBAudioController.m @@ -302,14 +302,6 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification"; [dict setObject: @"AAC (CoreAudio)" forKey: @"AudioEncoder"]; } - // Auto Passthru not yet implemented - fallback to AC3 Passthru as it is - // compatible with all source codecs (via the AC3 encoder fallback) - if ([key isEqualToString: @"Auto Passthru"]) - { - [dict setObject: @"AC3 Passthru" forKey: @"AudioEncoder"]; - key = @"AC3 Passthru"; - } - // passthru fallbacks if ([key isEqualToString: @"AAC Passthru"]) { diff --git a/test/test.c b/test/test.c index 9074064cd..ff94c1c5b 100644 --- a/test/test.c +++ b/test/test.c @@ -1969,107 +1969,53 @@ static int HandleEvents( hb_handle_t * h ) for( i = 0; i < hb_list_count( job->list_audio ); ) { audio = hb_list_audio_config_item( job->list_audio, i ); - // check whether we're doing passthru - if( audio->out.codec & HB_ACODEC_PASS_FLAG ) - { - // compute the output passthru codec - // required to make 'copy' work - // doesn't break codec-specific passthru - int out_codec = ( audio->out.codec & ( audio->in.codec | HB_ACODEC_PASS_FLAG ) ); - // check whether passthru is possible or not - if( !( out_codec & audio->in.codec & HB_ACODEC_PASS_MASK ) ) - { - // first, check whether we're doing a codec-specific passthru - // for which we have a corresponding encoder - // note: Auto Passthru with a single codec in the passthru - // mask is assimilated to codec-specific passthru - 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 ); -#ifdef __APPLE_CC__ - audio->out.codec = HB_ACODEC_CA_AAC; -#else - audio->out.codec = HB_ACODEC_FAAC; -#endif - } - 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; - } - // we're doing either DTS, DTS-HD or Auto Passthru - else if( ( audio->out.codec != HB_ACODEC_DCA_PASS ) && - ( audio->out.codec != HB_ACODEC_DCA_HD_PASS ) ) - { - // we're doing Auto Passthru, check if there's a fallback - if( acodec_fallback ) - { - fprintf( stderr, "Auto passthru requested and input codec is not compatible for track %d, using fallback\n", - audio->out.track ); - audio->out.codec = get_acodec_for_string( acodec_fallback ); - } - // we didn't find a suitable fallback - // check whether we have an encoder for - // one of the allowed passthru codecs - else if( audio->out.codec & HB_ACODEC_AAC_PASS ) - { - fprintf( stderr, "Auto passthru requested and input codec is not compatible for track %d, AAC Passthru allowed: using AAC encoder\n", - audio->out.track ); + if( audio->out.codec == HB_ACODEC_AUTO_PASS ) + { + // Auto Passthru + job->acodec_copy_mask = allowed_audio_copy; + job->acodec_fallback = acodec_fallback ? get_acodec_for_string( acodec_fallback ) : 0; + // sanitize the fallback; -1 isn't a valid HB_ACODEC_* value + 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 ); #ifdef __APPLE_CC__ - audio->out.codec = HB_ACODEC_CA_AAC; + audio->out.codec = HB_ACODEC_CA_AAC; #else - audio->out.codec = HB_ACODEC_FAAC; + audio->out.codec = HB_ACODEC_FAAC; #endif - } - else if( audio->out.codec & HB_ACODEC_AC3_PASS ) - { - fprintf( stderr, "Auto passthru requested and input codec is not compatible for track %d, AC3 Passthru allowed: using AC3 encoder\n", - audio->out.track ); - audio->out.codec = HB_ACODEC_AC3; - } - else if( audio->out.codec & HB_ACODEC_MP3_PASS ) - { - fprintf( stderr, "Auto passthru requested and input codec is not compatible for track %d, MP3 Passthru allowed: using MP3 encoder\n", - audio->out.track ); - audio->out.codec = HB_ACODEC_LAME; - } - else - { - // Passthru not possible, drop audio. - fprintf( stderr, "Auto passthru requested, input codec is not compatible for track %d and no valid fallback specified: dropping track\n", - audio->out.track ); - hb_audio_t * item = hb_list_item( job->list_audio, i ); - hb_list_rem( job->list_audio, item ); - continue; - } - } - else - { - // 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 ); - continue; - } - // 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 ); + } + 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 is possible - audio->out.codec = out_codec; + // 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 ); + continue; } + // 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 ); } // we didn't drop the track i++; @@ -2541,7 +2487,7 @@ void SigHandler( int i_signal ) ****************************************************************************/ static void ShowHelp() { - int i; + int i, j; FILE* const out = stdout; fprintf( out, @@ -2595,8 +2541,25 @@ static void ShowHelp() "### Video Options------------------------------------------------------------\n\n" " -e, --encoder <string> Set video library encoder\n" - " Options: ffmpeg4,ffmpeg2,x264,theora\n" - " (default: ffmpeg4)\n" + " Options: " ); + for( i = 0; i < hb_video_encoders_count; i++ ) + { + fprintf( out, "%s", hb_video_encoders[i].short_name ); + if( i != hb_video_encoders_count - 1 ) + 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, " -x, --encopts <string> Specify advanced encoder options in the\n" " same style as mencoder (x264 and ffmpeg only):\n" " option1=value1:option2=value2\n" @@ -2632,58 +2595,42 @@ static void ShowHelp() "\n" "### Audio Options-----------------------------------------------------------\n\n" " -a, --audio <string> Select audio track(s), separated by commas\n" - " More than one output track can be used for one\n" - " input.\n" " (\"none\" for no audio, \"1,2,3\" for multiple\n" - " tracks, default: first one)\n" ); - -#ifdef __APPLE_CC__ + " 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++ ) + { + fprintf( out, " %s\n", + hb_audio_encoders[i].short_name ); + } fprintf( out, - " -E, --aencoder <string> Audio encoder(s)\n" - " ca_aac\n" - " ca_haac\n" - " faac\n" - " lame\n" - " vorbis\n" - " ac3\n" - " copy\n" - " copy:aac\n" - " copy:ac3\n" - " copy:dts\n" - " copy:dtshd\n" - " copy:mp3\n" - " copy* will passthrough the corresponding\n" + " 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: ca_aac)\n" ); +#ifdef __APPLE_CC__ + " (default: ca_aac)\n" #else - fprintf( out, - " -E, --aencoder <string> Audio encoder(s):\n" - " faac\n" - " lame\n" - " vorbis\n" - " ac3\n" - " copy\n" - " copy:aac\n" - " copy:ac3\n" - " copy:dts\n" - " copy:dtshd\n" - " copy:mp3\n" - " 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: faac for mp4, lame for mkv)\n" ); + " (default: faac for mp4, lame for mkv)\n" #endif - fprintf( out, - " --audio-copy-mask Set audio codecs that are permitted when\n" - " <string> \"copy\" audio encoder option is specified.\n" - " Separated by commas for multiple allowed options.\n"); - fprintf( out, + " --audio-copy-mask Set audio codecs that are permitted when the\n" + " <string> \"copy\" audio encoder option is specified\n" + " (" ); + for( i = 0, j = 0; i < hb_audio_encoders_count; i++ ) + { + if( !strncmp( hb_audio_encoders[i].short_name, "copy:", 5 ) ) + { + if( j != 0 ) + fprintf( out, "/" ); + fprintf( out, "%s", hb_audio_encoders[i].short_name + 5 ); + j = 1; + } + } + fprintf( out, ", default: all).\n" + " Separated by commas for multiple allowed options.\n" " --audio-fallback Set audio codec to use when it is not possible\n" - " <string> to copy an audio track without re-encoding.\n"); - fprintf( out, + " <string> to copy an audio track without re-encoding.\n" " -B, --ab <kb/s> Set audio bitrate(s) (default: depends on the\n" " selected codec, mixdown and samplerate)\n" " Separated by commas for more than one audio track.\n" @@ -3357,32 +3304,23 @@ static int ParseOptions( int argc, char ** argv ) } break; case 'e': - if( !strcasecmp( optarg, "ffmpeg" ) ) - { - vcodec = HB_VCODEC_FFMPEG_MPEG4; - } - else if( !strcasecmp( optarg, "ffmpeg4" ) ) - { - vcodec = HB_VCODEC_FFMPEG_MPEG4; - } - else if( !strcasecmp( optarg, "ffmpeg2" ) ) - { - vcodec = HB_VCODEC_FFMPEG_MPEG2; - } - else if( !strcasecmp( optarg, "x264" ) ) - { - vcodec = HB_VCODEC_X264; - } - else if( !strcasecmp( optarg, "theora" ) ) + { + int i; + for( i = 0, vcodec = 0; i < hb_video_encoders_count; i++ ) { - vcodec = HB_VCODEC_THEORA; + if( !strcasecmp( hb_video_encoders[i].short_name, optarg ) ) + { + vcodec = hb_video_encoders[i].encoder; + break; + } } - else + if( !vcodec ) { fprintf( stderr, "invalid codec (%s)\n", optarg ); return -1; } break; + } case 'E': if( optarg != NULL ) { @@ -3514,23 +3452,26 @@ static int ParseOptions( int argc, char ** argv ) break; case ALLOWED_AUDIO_COPY: { - int i; + int i, j; char **allowed = str_split( optarg, ',' ); allowed_audio_copy = 0; - for ( i = 0; allowed[i]; i++ ) - { - if ( !strcmp( allowed[i], "ac3" ) ) - allowed_audio_copy |= HB_ACODEC_AC3; - if ( !strcmp( allowed[i], "dts" ) ) - allowed_audio_copy |= HB_ACODEC_DCA; - if ( !strcmp( allowed[i], "dtshd" ) ) - allowed_audio_copy |= HB_ACODEC_DCA_HD; - if ( !strcmp( allowed[i], "mp3" ) ) - allowed_audio_copy |= HB_ACODEC_MP3; - if ( !strcmp( allowed[i], "aac" ) ) - allowed_audio_copy |= HB_ACODEC_FFAAC; + for( i = 0; allowed[i]; i++ ) + { + for( j = 0; j < hb_audio_encoders_count; j++ ) + { + char * encoder = hb_audio_encoders[j].short_name; + // skip "copy:" + if( strlen( encoder ) > 5 ) + encoder += 5; + if( !strcmp( allowed[i], encoder ) ) + { + allowed_audio_copy |= hb_audio_encoders[j].encoder; + break; + } + } } + allowed_audio_copy &= HB_ACODEC_PASS_MASK; str_vfree( allowed ); } break; case AUDIO_FALLBACK: @@ -3695,64 +3636,16 @@ static int CheckOptions( int argc, char ** argv ) static int get_acodec_for_string( char *codec ) { - if( !strcasecmp( codec, "ac3" ) ) - { - return HB_ACODEC_AC3; - } - else if( !strcasecmp( codec, "copy" ) ) - { - return (HB_ACODEC_PASS_MASK & allowed_audio_copy) | HB_ACODEC_PASS_FLAG; - } - else if( !strcasecmp( codec, "copy:aac" ) ) - { - return HB_ACODEC_AAC_PASS; - } - else if( !strcasecmp( codec, "copy:ac3" ) ) - { - return HB_ACODEC_AC3_PASS; - } - else if( !strcasecmp( codec, "copy:dts" ) || !strcasecmp( codec, "copy:dca" ) ) - { - return HB_ACODEC_DCA_PASS; - } - else if( !strcasecmp( codec, "copy:dtshd" ) ) - { - return HB_ACODEC_DCA_HD_PASS; - } - else if( !strcasecmp( codec, "copy:mp3" ) ) - { - return HB_ACODEC_MP3_PASS; - } - else if( !strcasecmp( codec, "lame" ) ) - { - return HB_ACODEC_LAME; - } - else if( !strcasecmp( codec, "faac" ) ) + int i, acodec; + for( i = 0, acodec = 0; i < hb_audio_encoders_count; i++ ) { - return HB_ACODEC_FAAC; - } - else if( !strcasecmp( codec, "ffaac" ) ) - { - return HB_ACODEC_FFAAC; - } - else if( !strcasecmp( codec, "vorbis") ) - { - return HB_ACODEC_VORBIS; - } -#ifdef __APPLE__ - else if( !strcasecmp( codec, "ca_aac") ) - { - return HB_ACODEC_CA_AAC; - } - else if( !strcasecmp( codec, "ca_haac") ) - { - return HB_ACODEC_CA_HAAC; - } -#endif - else - { - return -1; + if( !strcasecmp( hb_audio_encoders[i].short_name, codec ) ) + { + acodec = hb_audio_encoders[i].encoder; + break; + } } + return acodec ? acodec : -1; } static int is_sample_rate_valid(int rate) |