diff options
-rw-r--r-- | contrib/ffmpeg/A04-dca-frame-size.patch | 12 | ||||
-rw-r--r-- | gtk/src/audiohandler.c | 239 | ||||
-rw-r--r-- | gtk/src/audiohandler.h | 2 | ||||
-rw-r--r-- | gtk/src/callbacks.c | 7 | ||||
-rw-r--r-- | gtk/src/ghb.ui | 144 | ||||
-rw-r--r-- | gtk/src/hb-backend.c | 189 | ||||
-rw-r--r-- | gtk/src/hb-backend.h | 3 | ||||
-rw-r--r-- | gtk/src/internal_defaults.xml | 12 | ||||
-rw-r--r-- | gtk/src/makedeps.py | 19 | ||||
-rw-r--r-- | gtk/src/presets.c | 8 | ||||
-rw-r--r-- | libhb/common.h | 10 | ||||
-rw-r--r-- | libhb/deca52.c | 1 | ||||
-rw-r--r-- | libhb/decavcodec.c | 6 | ||||
-rw-r--r-- | libhb/decdca.c | 1 | ||||
-rw-r--r-- | libhb/declpcm.c | 2 | ||||
-rw-r--r-- | libhb/encavcodecaudio.c | 2 | ||||
-rw-r--r-- | libhb/encfaac.c | 1 | ||||
-rw-r--r-- | libhb/enclame.c | 1 | ||||
-rw-r--r-- | libhb/encvorbis.c | 1 | ||||
-rw-r--r-- | libhb/muxmkv.c | 9 | ||||
-rw-r--r-- | libhb/muxmp4.c | 376 | ||||
-rw-r--r-- | libhb/platform/macosx/encca_aac.c | 2 | ||||
-rw-r--r-- | libhb/scan.c | 1 | ||||
-rw-r--r-- | libhb/stream.c | 18 | ||||
-rw-r--r-- | libhb/sync.c | 174 | ||||
-rw-r--r-- | libhb/work.c | 2 | ||||
-rw-r--r-- | macosx/HBAudio.m | 36 | ||||
-rw-r--r-- | macosx/HBAudioController.m | 7 | ||||
-rw-r--r-- | test/test.c | 46 |
29 files changed, 830 insertions, 501 deletions
diff --git a/contrib/ffmpeg/A04-dca-frame-size.patch b/contrib/ffmpeg/A04-dca-frame-size.patch new file mode 100644 index 000000000..5af1040b2 --- /dev/null +++ b/contrib/ffmpeg/A04-dca-frame-size.patch @@ -0,0 +1,12 @@ +diff --git a/libavcodec/dca.c b/libavcodec/dca.c +index 68731c9..cf62c48 100644 +--- a/libavcodec/dca.c ++++ b/libavcodec/dca.c +@@ -1650,6 +1650,7 @@ static int dca_decode_frame(AVCodecContext * avctx, + //set AVCodec values with parsed data + avctx->sample_rate = s->sample_rate; + avctx->bit_rate = s->bit_rate; ++ avctx->frame_size = s->sample_blocks * 32; + + s->profile = FF_PROFILE_DTS; + diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c index 54cd1a496..ee84a798f 100644 --- a/gtk/src/audiohandler.c +++ b/gtk/src/audiohandler.c @@ -25,6 +25,130 @@ 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) +{ + guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK; + if (mux == HB_MUX_MP4) + { + if (acodec & HB_ACODEC_PASS_FLAG) + { + if ((acodec & in_codec & HB_ACODEC_MASK & ~HB_ACODEC_VORBIS)) + { + return acodec & (in_codec | HB_ACODEC_PASS_FLAG); + } + else if (fallback & (HB_ACODEC_AC3 | HB_ACODEC_LAME | HB_ACODEC_FAAC | HB_ACODEC_FFAAC)) + { + 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 & (HB_ACODEC_AC3 | HB_ACODEC_LAME | HB_ACODEC_FAAC | HB_ACODEC_FFAAC)) + { + return fallback; + } + else + { + return HB_ACODEC_FAAC; + } + } + else + { + if (acodec & HB_ACODEC_PASS_FLAG) + { + if ((acodec & in_codec & HB_ACODEC_PASS_MASK)) + { + 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_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 ) + { + return fallback; + } + else + { + return HB_ACODEC_LAME; + } + } +} + +int ghb_allowed_passthru_mask(GValue *settings, int acodec) +{ + 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; +} + void ghb_adjust_audio_rate_combos(signal_user_data_t *ud) { @@ -32,7 +156,7 @@ ghb_adjust_audio_rate_combos(signal_user_data_t *ud) hb_audio_config_t *aconfig; GtkWidget *widget; GValue *gval; - int mux; + gint mux; gint bitrate; gint sr = 48000; @@ -62,25 +186,15 @@ ghb_adjust_audio_rate_combos(signal_user_data_t *ud) gval = ghb_widget_value(widget); sr = ghb_lookup_combo_int("AudioSamplerate", gval); - select_acodec = acodec; - if (mux == HB_MUX_MP4) - { - select_acodec &= ~HB_ACODEC_DCA; - } - if ((select_acodec & HB_ACODEC_MASK) == 0) - { - // Unsuported codec in this container. - select_acodec |= HB_ACODEC_AC3; - acodec = select_acodec; - } aconfig = ghb_get_scan_audio_info(titleindex, track); if (sr == 0) { sr = aconfig ? aconfig->in.samplerate : 48000; } - if (aconfig) - select_acodec = ghb_select_audio_codec(mux, aconfig, select_acodec); + gint fallback = ghb_settings_combo_int(ud->settings, "AudioEncoderFallback"); + select_acodec = ghb_allowed_passthru_mask(ud->settings, acodec); + select_acodec = ghb_select_audio_codec(mux, aconfig, select_acodec, fallback); gboolean codec_defined_bitrate = FALSE; if (ghb_audio_is_passthru (select_acodec)) { @@ -89,44 +203,33 @@ ghb_adjust_audio_rate_combos(signal_user_data_t *ud) bitrate = aconfig->in.bitrate / 1000; // Set the values for bitrate and samplerate to the input rates - if (aconfig->in.codec & select_acodec & HB_ACODEC_PASS_MASK) - { - ghb_set_passthru_bitrate_opts (ud->builder, bitrate); - ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(0)); - select_acodec &= aconfig->in.codec | HB_ACODEC_PASS_FLAG; - codec_defined_bitrate = TRUE; - } - else - { - gint mux = ghb_settings_get_int(ud->settings, "FileFormat"); - select_acodec = ghb_select_audio_codec(mux, aconfig, acodec); - if (acodec != HB_ACODEC_ANY) - { - ghb_ui_update(ud, "AudioEncoder", ghb_int64_value(select_acodec)); - } - - mix = ghb_get_best_mix( aconfig, select_acodec, mix); - bitrate = hb_get_default_audio_bitrate(select_acodec, sr, mix); - ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix)); - } + ghb_set_passthru_bitrate_opts (ud->builder, bitrate); + mix = 0; + ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix)); + select_acodec &= aconfig->in.codec | HB_ACODEC_PASS_FLAG; + codec_defined_bitrate = TRUE; ghb_ui_update(ud, "AudioSamplerate", ghb_int64_value(0)); } else { ghb_ui_update(ud, "AudioSamplerate", ghb_int64_value(0)); - ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(0)); + mix = 0; + ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix)); bitrate = 448; - mix = ghb_get_best_mix( aconfig, select_acodec, 0); } ghb_ui_update(ud, "AudioTrackDRCSlider", ghb_double_value(0)); } else { + if (mix == 0) + mix = ghb_get_best_mix( aconfig, select_acodec, 0); bitrate = hb_get_best_audio_bitrate(select_acodec, bitrate, sr, mix); + ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix)); } if (!codec_defined_bitrate) { int low, high; + mix = ghb_get_best_mix( aconfig, select_acodec, mix); hb_get_audio_bitrate_limits(select_acodec, sr, mix, &low, &high); ghb_set_default_bitrate_opts (ud->builder, low, high); } @@ -182,14 +285,7 @@ ghb_set_pref_audio(gint titleindex, signal_user_data_t *ud) g_debug("set_pref_audio"); mux = ghb_settings_combo_int(ud->settings, "FileFormat"); - if (mux == HB_MUX_MP4) - { - fallback_acodec = HB_ACODEC_FAAC; - } - else - { - fallback_acodec = HB_ACODEC_LAME; - } + fallback_acodec = ghb_settings_combo_int(ud->settings, "AudioEncoderFallback"); track_indices = g_hash_table_new_full(g_int_hash, g_int_equal, free_audio_hash_key_value, free_audio_hash_key_value); // Clear the audio list @@ -208,24 +304,12 @@ ghb_set_pref_audio(gint titleindex, signal_user_data_t *ud) count = ghb_array_len(pref_audio); for (ii = 0; ii < count; ii++) { - int select_acodec; + gint select_acodec; audio = ghb_array_get_nth(pref_audio, ii); - select_acodec = acodec = ghb_settings_combo_int(audio, "AudioEncoder"); - if (mux == HB_MUX_MP4) - { - select_acodec &= ~HB_ACODEC_DCA; - } - if ((select_acodec & HB_ACODEC_MASK) == 0) - { - // Unsuported codec in this container. - select_acodec |= HB_ACODEC_AC3; - acodec = select_acodec; - } - if ( ghb_audio_can_passthru( select_acodec ) ) - { - fallback_acodec = HB_ACODEC_AC3; - } + acodec = ghb_settings_combo_int(audio, "AudioEncoder"); + select_acodec = ghb_allowed_passthru_mask(ud->settings, acodec); + select_acodec = ghb_select_audio_codec(mux, NULL, select_acodec, fallback_acodec); bitrate = ghb_settings_combo_int(audio, "AudioBitrate"); rate = ghb_settings_combo_double(audio, "AudioSamplerate"); mix = ghb_settings_combo_int(audio, "AudioMixdown"); @@ -260,17 +344,13 @@ ghb_set_pref_audio(gint titleindex, signal_user_data_t *ud) } else { - int channels, min_rate, max_rate; + int channels; select_acodec = fallback_acodec; mix = ghb_get_best_mix(aconfig, select_acodec, mix); channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(mix); bitrate = aconfig->in.bitrate / 1000; - min_rate = channels * 64; - max_rate = channels * 160; - if (bitrate < min_rate) - bitrate = min_rate; - if (bitrate > max_rate) - bitrate = max_rate; + bitrate = hb_get_best_audio_bitrate(select_acodec, bitrate, + aconfig->in.samplerate, mix); rate = 0; } } @@ -417,7 +497,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) if (block_updates) { prev_acodec = acodec_code; - ghb_grey_combo_options (ud->builder); + ghb_grey_combo_options (ud); return; } @@ -469,7 +549,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_ui_update(ud, "AudioMixdown", ghb_int64_value(mix_code)); } ghb_adjust_audio_rate_combos(ud); - ghb_grey_combo_options (ud->builder); + ghb_grey_combo_options (ud); ghb_check_dependency(ud, widget, NULL); prev_acodec = acodec_code; if (asettings != NULL) @@ -488,11 +568,15 @@ audio_track_changed_cb(GtkWidget *widget, signal_user_data_t *ud) GValue *asettings; g_debug("audio_track_changed_cb ()"); - if (block_updates) return; + if (block_updates) + { + ghb_grey_combo_options (ud); + return; + } ghb_adjust_audio_rate_combos(ud); ghb_check_dependency(ud, widget, NULL); - ghb_grey_combo_options(ud->builder); + ghb_grey_combo_options(ud); asettings = get_selected_asettings(ud); if (asettings != NULL) { @@ -544,6 +628,19 @@ audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_live_reset(ud); } +G_MODULE_EXPORT void +global_audio_widget_changed_cb(GtkWidget *widget, signal_user_data_t *ud) +{ + g_debug("global_audio_widget_changed_cb ()"); + if (block_updates) return; + + ghb_check_dependency(ud, widget, NULL); + ghb_widget_to_setting(ud->settings, widget); + ghb_adjust_audio_rate_combos(ud); + ghb_audio_list_refresh_selected(ud); + ghb_live_reset(ud); +} + G_MODULE_EXPORT gchar* format_drc_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud) { diff --git a/gtk/src/audiohandler.h b/gtk/src/audiohandler.h index 87b9612f7..74df87a3d 100644 --- a/gtk/src/audiohandler.h +++ b/gtk/src/audiohandler.h @@ -34,5 +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); #endif // _AUDIOHANDLER_H_ diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index 0fd92a9e6..03d576603 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -1250,7 +1250,8 @@ window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *u static void update_acodec_combo(signal_user_data_t *ud) { - ghb_grey_combo_options (ud->builder); + ghb_adjust_audio_rate_combos(ud); + ghb_grey_combo_options (ud); } G_MODULE_EXPORT void @@ -1507,7 +1508,7 @@ title_changed_cb(GtkWidget *widget, signal_user_data_t *ud) update_chapter_list (ud); ghb_adjust_audio_rate_combos(ud); ghb_set_pref_audio(titleindex, ud); - ghb_grey_combo_options (ud->builder); + ghb_grey_combo_options (ud); ghb_set_pref_subtitle(titleindex, ud); // Unfortunately, there is no way to query how many frames were @@ -1662,7 +1663,7 @@ http_opt_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_clear_presets_selection(ud); ghb_live_reset(ud); // AC3 is not allowed when Web optimized - ghb_grey_combo_options (ud->builder); + ghb_grey_combo_options (ud); } G_MODULE_EXPORT void diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui index 999f3c621..7d037434b 100644 --- a/gtk/src/ghb.ui +++ b/gtk/src/ghb.ui @@ -1716,7 +1716,7 @@ <object class="GtkLabel" id="label46"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Video Codec:</property> + <property name="label" translatable="yes">Video Encoder:</property> <property name="width_chars">11</property> </object> <packing> @@ -2113,9 +2113,10 @@ FFMpeg's and Theora's scale is more linear. These encoders do not have a lossle <object class="GtkTable" id="table14"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="n_rows">2</property> + <property name="n_rows">4</property> <property name="n_columns">5</property> <property name="row_spacing">5</property> + <property name="column_spacing">5</property> <child> <object class="GtkLabel" id="audio_name_label"> <property name="visible">True</property> @@ -2228,7 +2229,7 @@ FFMpeg's and Theora's scale is more linear. These encoders do not have a lossle <child> <object class="GtkHScale" id="AudioTrackGain"> <property name="visible">True</property> - <property name="width-request">200</property> + <property name="width-request">150</property> <property name="orientation">horizontal</property> <property name="adjustment">adjustment35</property> <property name="value_pos">right</property> @@ -2282,6 +2283,141 @@ FFMpeg's and Theora's scale is more linear. These encoders do not have a lossle <property name="x_options">GTK_FILL</property> </packing> </child> + <child> + <object class="GtkHBox" id="hbox40"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">5</property> + <child> + <object class="GtkLabel" id="labela3"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Auto Passthru:</property> + </object> + <packing> + <property name="position">0</property> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="AudioAllowMP3Pass"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Enable this if your playback device supports AAC. This permits AAC passthru to be selected when automatic passthru selection is enabled.</property> + <property name="label" translatable="yes">MP3</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal handler="global_audio_widget_changed_cb" name="toggled"/> + </object> + <packing> + <property name="position">1</property> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="AudioAllowAACPass"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Enable this if your playback device supports AAC. This permits AAC passthru to be selected when automatic passthru selection is enabled.</property> + <property name="label" translatable="yes">AAC</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal handler="global_audio_widget_changed_cb" name="toggled"/> + </object> + <packing> + <property name="position">2</property> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="AudioAllowAC3Pass"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Enable this if your playback device supports AC-3. This permits AC-3 passthru to be selected when automatic passthru selection is enabled.</property> + <property name="label" translatable="yes">AC-3</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal handler="global_audio_widget_changed_cb" name="toggled"/> + </object> + <packing> + <property name="position">3</property> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="AudioAllowDTSPass"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Enable this if your playback device supports DTS. This permits DTS passthru to be selected when automatic passthru selection is enabled.</property> + <property name="label" translatable="yes">DTS</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal handler="global_audio_widget_changed_cb" name="toggled"/> + </object> + <packing> + <property name="position">4</property> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="AudioAllowDTSHDPass"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Enable this if your playback device supports DTS-HD. This permits DTS-HD passthru to be selected when automatic passthru selection is enabled.</property> + <property name="label" translatable="yes">DTS-HD</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal handler="global_audio_widget_changed_cb" name="toggled"/> + </object> + <packing> + <property name="position">5</property> + <property name="expand">False</property> + </packing> + </child> + </object> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="left_attach">0</property> + <property name="right_attach">4</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="labela4"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">Passthru Fallback:</property> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="AudioEncoderFallback"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="tooltip-text" translatable="yes">Set the audio codec to encode with when a suitable track can not be found for audio passthru.</property> + <signal handler="global_audio_widget_changed_cb" name="changed"/> + </object> + <packing> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + </packing> + </child> </object> </child> </object> @@ -2323,7 +2459,7 @@ FFMpeg's and Theora's scale is more linear. These encoders do not have a lossle <object class="GtkLabel" id="label68"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Codec</property> + <property name="label" translatable="yes">Encoder</property> </object> <packing> <property name="top_attach">0</property> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index 8a90d4ece..a3b9e5106 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -57,7 +57,7 @@ static gint index_str_size = 0; static void index_str_init(gint max_index) { - int ii; + gint ii; if (max_index+1 > index_str_size) { @@ -256,10 +256,12 @@ static options_map_t d_acodec_opts[] = {"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"}, - {"DTS-HD (pass-thru)", "dtshdpass", HB_ACODEC_DCA_HD_PASS, "dtshdpass"}, - {"Choose For Me", "auto", HB_ACODEC_ANY, "auto"}, + {"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 = { @@ -267,6 +269,20 @@ combo_opts_t acodec_opts = 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"}, @@ -418,6 +434,7 @@ combo_name_map_t combo_name_map[] = {"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}, @@ -1535,71 +1552,75 @@ grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean } void -ghb_grey_combo_options(GtkBuilder *builder) +ghb_grey_combo_options(signal_user_data_t *ud) { GtkWidget *widget; - gint mux, track, titleindex, acodec; - hb_audio_config_t *aconfig = NULL; + gint mux, track, titleindex, acodec, fallback; + hb_audio_config_t *aconfig = NULL; GValue *gval; - widget = GHB_WIDGET (builder, "title"); + widget = GHB_WIDGET (ud->builder, "title"); gval = ghb_widget_value(widget); titleindex = ghb_lookup_combo_int("title", gval); ghb_value_free(gval); - widget = GHB_WIDGET (builder, "AudioTrack"); + widget = GHB_WIDGET (ud->builder, "AudioTrack"); gval = ghb_widget_value(widget); track = ghb_lookup_combo_int("AudioTrack", gval); ghb_value_free(gval); aconfig = get_hb_audio(h_scan, titleindex, track); - widget = GHB_WIDGET (builder, "FileFormat"); + widget = GHB_WIDGET (ud->builder, "FileFormat"); gval = ghb_widget_value(widget); mux = ghb_lookup_combo_int("FileFormat", gval); ghb_value_free(gval); - grey_combo_box_item(builder, "x264_analyse", 4, TRUE); - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_FFAAC, FALSE); - 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); - - gboolean allow_dca = TRUE; - allow_dca = (mux != HB_MUX_MP4); + grey_combo_box_item(ud->builder, "x264_analyse", 4, TRUE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_FFAAC, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_FAAC, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_LAME, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_VORBIS, FALSE); - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, FALSE); - if (allow_dca) - { - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, FALSE); - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_HD_PASS, FALSE); - } - else - { - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE); - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_HD_PASS, TRUE); - } + grey_combo_box_item(ud->builder, "AudioEncoderFallback", HB_ACODEC_FFAAC, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoderFallback", HB_ACODEC_FAAC, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoderFallback", HB_ACODEC_LAME, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoderFallback", HB_ACODEC_VORBIS, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_MP3_PASS, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_AAC_PASS, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_AC3_PASS, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_DCA_PASS, FALSE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_DCA_HD_PASS, FALSE); + if (aconfig && (aconfig->in.codec & HB_ACODEC_MASK) != HB_ACODEC_MP3) + { + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_MP3_PASS, TRUE); + } + if (aconfig && (aconfig->in.codec & HB_ACODEC_MASK) != HB_ACODEC_FFAAC) + { + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_AAC_PASS, TRUE); + } if (aconfig && (aconfig->in.codec & HB_ACODEC_MASK) != HB_ACODEC_AC3) { - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3_PASS, TRUE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_AC3_PASS, TRUE); } if (aconfig && (aconfig->in.codec & HB_ACODEC_MASK) != HB_ACODEC_DCA) { - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_DCA_PASS, TRUE); } if (aconfig && (aconfig->in.codec & HB_ACODEC_MASK) != HB_ACODEC_DCA_HD) { - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA_HD_PASS, TRUE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_DCA_HD_PASS, TRUE); } - grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, FALSE); + grey_combo_box_item(ud->builder, "VideoEncoder", HB_VCODEC_THEORA, FALSE); - widget = GHB_WIDGET (builder, "AudioEncoder"); + widget = GHB_WIDGET (ud->builder, "AudioEncoder"); gval = ghb_widget_value(widget); acodec = ghb_lookup_combo_int("AudioEncoder", gval); ghb_value_free(gval); - grey_combo_box_item(builder, "AudioMixdown", 0, TRUE); + grey_combo_box_item(ud->builder, "AudioMixdown", 0, TRUE); if (mux == HB_MUX_MP4) { - grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE); - grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE); + grey_combo_box_item(ud->builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE); + grey_combo_box_item(ud->builder, "AudioEncoderFallback", HB_ACODEC_VORBIS, TRUE); + grey_combo_box_item(ud->builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE); } gboolean allow_mono = TRUE; @@ -1610,7 +1631,9 @@ ghb_grey_combo_options(GtkBuilder *builder) allow_6ch = acodec & ~HB_ACODEC_LAME; if (aconfig) { - acodec = ghb_select_audio_codec(mux, aconfig, acodec); + 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 best = hb_get_best_mixdown(acodec, aconfig->in.channel_layout, 0); allow_stereo = best >= HB_AMIXDOWN_STEREO; @@ -1619,17 +1642,17 @@ ghb_grey_combo_options(GtkBuilder *builder) allow_6ch = best >= HB_AMIXDOWN_6CH; allow_mono = best >= HB_AMIXDOWN_MONO; } - grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_MONO, !allow_mono); - grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_STEREO, !allow_stereo); - grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_DOLBY, !allow_dolby); - grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2); - grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_6CH, !allow_6ch); + grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_MONO, !allow_mono); + grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_STEREO, !allow_stereo); + grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_DOLBY, !allow_dolby); + grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2); + grey_combo_box_item(ud->builder, "AudioMixdown", HB_AMIXDOWN_6CH, !allow_6ch); } gint ghb_get_best_mix(hb_audio_config_t *aconfig, gint acodec, gint mix) { - int layout; + gint 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 ); @@ -2780,6 +2803,7 @@ 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); + 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); @@ -4135,70 +4159,6 @@ ghb_validate_subtitles(signal_user_data_t *ud) return TRUE; } -gint -ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec) -{ - guint32 in_codec = aconfig ? aconfig->in.codec : HB_ACODEC_MASK; - if (mux == HB_MUX_MP4) - { - 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 if (acodec & HB_ACODEC_FFAAC) - { - return HB_ACODEC_FFAAC; - } - else - { - return HB_ACODEC_FAAC; - } - } - else - { - 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 if (acodec & HB_ACODEC_FFAAC) - { - return HB_ACODEC_FFAAC; - } - else - { - return HB_ACODEC_LAME; - } - } -} - gboolean ghb_validate_audio(signal_user_data_t *ud) { @@ -4283,11 +4243,6 @@ ghb_validate_audio(signal_user_data_t *ud) a_unsup = "Vorbis"; codec = HB_ACODEC_FAAC; } - if (codec == HB_ACODEC_DCA) - { - a_unsup = "DTS"; - codec = HB_ACODEC_AC3; - } } if (a_unsup) { @@ -4711,7 +4666,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) GValue *asettings; hb_audio_config_t audio; hb_audio_config_t *aconfig; - gint acodec; + gint acodec, fallback; hb_audio_config_init(&audio); asettings = ghb_array_get_nth(audio_list, ii); @@ -4735,7 +4690,9 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) acodec = ghb_settings_combo_int(asettings, "AudioEncoder"); - audio.out.codec = ghb_select_audio_codec(job->mux, aconfig, acodec); + 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); audio.out.gain = ghb_settings_get_double(asettings, "AudioTrackGain"); diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index 6733ad306..f59d821a6 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -137,7 +137,7 @@ hb_audio_config_t* ghb_get_scan_audio_info(gint titleindex, gint audioindex); void ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate); void ghb_set_default_bitrate_opts( GtkBuilder *builder, gint first_rate, gint last_rate); -void ghb_grey_combo_options(GtkBuilder *builder); +void ghb_grey_combo_options(signal_user_data_t *ud); void ghb_update_ui_combo_box( signal_user_data_t *ud, const gchar *name, gint user_data, gboolean all); gchar* ghb_get_source_audio_lang(gint titleindex, gint track); @@ -175,7 +175,6 @@ gdouble ghb_lookup_combo_double(const gchar *name, const GValue *gval); const gchar* ghb_lookup_combo_option(const gchar *name, const GValue *gval); const gchar* ghb_lookup_combo_string(const gchar *name, const GValue *gval); gchar* ghb_get_tmp_dir(); -gint ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec); gint ghb_find_closest_audio_rate(gint rate); GValue* ghb_lookup_acodec_value(gint val); diff --git a/gtk/src/internal_defaults.xml b/gtk/src/internal_defaults.xml index e4a4a72b6..b4d06694d 100644 --- a/gtk/src/internal_defaults.xml +++ b/gtk/src/internal_defaults.xml @@ -295,6 +295,18 @@ <true /> <key>Mp4LargeFile</key> <false /> + <key>AudioAllowMP3Pass</key> + <true /> + <key>AudioAllowAACPass</key> + <true /> + <key>AudioAllowAC3Pass</key> + <true /> + <key>AudioAllowDTSPass</key> + <true /> + <key>AudioAllowDTSHDPass</key> + <true /> + <key>AudioEncoderFallback</key> + <string>ac3</string> <key>AudioList</key> <array> <dict> diff --git a/gtk/src/makedeps.py b/gtk/src/makedeps.py index a16b28ca5..65d398eca 100644 --- a/gtk/src/makedeps.py +++ b/gtk/src/makedeps.py @@ -49,13 +49,18 @@ dep_map = ( DepEntry("VideoEncoder", "x264_tab", "x264", False, True), DepEntry("VideoEncoder", "lavc_mpeg4_tab", "ffmpeg|ffmpeg2", False, True), DepEntry("VideoEncoder", "Mp4iPodCompatible", "x264", False, False), - DepEntry("AudioEncoderActual", "AudioBitrate", "ac3pass|dtspass", True, False), - DepEntry("AudioEncoderActual", "AudioSamplerate", "ac3pass|dtspass", True, False), - DepEntry("AudioEncoderActual", "AudioMixdown", "ac3pass|dtspass", True, False), - DepEntry("AudioEncoderActual", "AudioTrackDRCSlider", "ac3pass|dtspass", True, False), - DepEntry("AudioEncoderActual", "drc_label", "ac3pass|dtspass", True, False), - DepEntry("AudioEncoderActual", "AudioTrackGain", "ac3pass|dtspass", True, False), - DepEntry("AudioEncoderActual", "gain_label", "ac3pass|dtspass", True, False), + DepEntry("AudioEncoderActual", "AudioBitrate", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoderActual", "AudioSamplerate", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoderActual", "AudioMixdown", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoderActual", "AudioTrackDRCSlider", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoderActual", "drc_label", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoderActual", "AudioTrackGain", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoderActual", "gain_label", "mp3pass|aacpass|ac3pass|dtspass|dtshdpass", True, False), + DepEntry("AudioEncoder", "AudioAllowMP3Pass", "auto", False, False), + DepEntry("AudioEncoder", "AudioAllowAACPass", "auto", False, False), + DepEntry("AudioEncoder", "AudioAllowAC3Pass", "auto", False, False), + DepEntry("AudioEncoder", "AudioAllowDTSPass", "auto", False, False), + DepEntry("AudioEncoder", "AudioAllowDTSHDPass", "auto", False, False), DepEntry("x264_bframes", "x264_bpyramid", "<2", True, False), DepEntry("x264_bframes", "x264_direct", "0", True, False), DepEntry("x264_bframes", "x264_b_adapt", "0", True, False), diff --git a/gtk/src/presets.c b/gtk/src/presets.c index 064d27323..0a4d46745 100644 --- a/gtk/src/presets.c +++ b/gtk/src/presets.c @@ -2004,6 +2004,8 @@ static value_map_t acodec_xlat[] = {"HE-AAC (CoreAudio)", "faac"}, {"AC3", "ac3"}, // Backwards compatibility with mac ui {"AC3 (ffmpeg)", "ac3"}, + {"MP3 Passthru", "mp3pass"}, + {"AAC Passthru", "aacpass"}, {"AC3 Passthru", "ac3pass"}, {"DTS Passthru", "dtspass"}, {"DTS-HD Passthru", "dtshdpass"}, @@ -2055,10 +2057,10 @@ value_map_t mix_xlat[] = {"Dolby Surround", "dpl1"}, {"Dolby Pro Logic II", "dpl2"}, {"6-channel discrete", "6ch"}, - {"AC3 Passthru", "none"}, - {"DTS Passthru", "none"}, - {"DTS-HD Passthru", "none"}, {"None", "none"}, + {"AC3 Passthru", "none"}, // Backwards compatibility with mac ui + {"DTS Passthru", "none"}, // Backwards compatibility with mac ui + {"DTS-HD Passthru", "none"}, // Backwards compatibility with mac ui {NULL, NULL} }; diff --git a/libhb/common.h b/libhb/common.h index 48a4812bb..88bb8389d 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -321,9 +321,12 @@ struct hb_job_s #define HB_ACODEC_FFAAC 0x00010000 #define HB_ACODEC_FFMPEG 0x00020000 #define HB_ACODEC_DCA_HD 0x00040000 -#define HB_ACODEC_FF_MASK 0x00060000 +#define HB_ACODEC_MP3 0x00080000 +#define HB_ACODEC_FF_MASK 0x000f0000 #define HB_ACODEC_PASS_FLAG 0x40000000 -#define HB_ACODEC_PASS_MASK (HB_ACODEC_DCA_HD | HB_ACODEC_AC3 | HB_ACODEC_DCA) +#define HB_ACODEC_PASS_MASK (HB_ACODEC_MP3 | HB_ACODEC_FFAAC | HB_ACODEC_DCA_HD | HB_ACODEC_AC3 | HB_ACODEC_DCA) +#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) #define HB_ACODEC_DCA_PASS (HB_ACODEC_DCA | HB_ACODEC_PASS_FLAG) #define HB_ACODEC_DCA_HD_PASS (HB_ACODEC_DCA_HD | HB_ACODEC_PASS_FLAG) @@ -404,6 +407,7 @@ struct hb_audio_config_s * are ignored. */ int samplerate; /* Output sample rate (Hz) */ + int samples_per_frame; /* Number of samples per frame */ int bitrate; /* Output bitrate (kbps) */ int mixdown; /* The mixdown format to be used for this audio track (see HB_AMIXDOWN_*) */ double dynamic_range_compression; /* Amount of DRC that gets applied to this track */ @@ -423,6 +427,7 @@ struct hb_audio_config_s PRIVATE uint32_t version; /* Bitsream version */ PRIVATE uint32_t mode; /* Bitstream mode, codec dependent encoding */ PRIVATE int samplerate; /* Input sample rate (Hz) */ + PRIVATE int samples_per_frame; /* Number of samples per frame */ PRIVATE int bitrate; /* Input bitrate (kbps) */ PRIVATE int channel_layout; /* channel_layout is the channel layout of this audio this is used to * provide a common way of describing the source audio */ @@ -714,6 +719,7 @@ typedef struct hb_work_info_s struct { // info only valid for audio decoders int channel_layout; hb_chan_map_t * channel_map; + int samples_per_frame; }; }; } hb_work_info_t; diff --git a/libhb/deca52.c b/libhb/deca52.c index 2771eda55..a8d537d52 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -414,6 +414,7 @@ static int deca52BSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->flags = flags; info->version = raw >> 3; /* bsid is the first 5 bits */ info->mode = raw & 0x7; /* bsmod is the following 3 bits */ + info->samples_per_frame = 1536; if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY ) { diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index e52021655..f67850d86 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -439,6 +439,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, &out_size, &avp ); if ( len > 0 && context->sample_rate > 0 ) { + int isamp = av_get_bytes_per_sample( context->sample_fmt ); info->bitrate = context->bit_rate; info->rate = context->sample_rate; info->rate_base = 1; @@ -446,6 +447,11 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, hb_ff_layout_xlat(context->channel_layout, context->channels); ret = 1; + if ( context->channels && isamp ) + { + info->samples_per_frame = out_size / + (isamp * context->channels); + } break; } } diff --git a/libhb/decdca.c b/libhb/decdca.c index 138024a6d..4f5ee3929 100644 --- a/libhb/decdca.c +++ b/libhb/decdca.c @@ -311,6 +311,7 @@ static int decdcaBSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->rate_base = 1; info->bitrate = bitrate; info->flags = flags; + info->samples_per_frame = frame_length; if ( ( flags & DCA_CHANNEL_MASK) == DCA_DOLBY ) { diff --git a/libhb/declpcm.c b/libhb/declpcm.c index 3dd1f7366..62eb563e8 100644 --- a/libhb/declpcm.c +++ b/libhb/declpcm.c @@ -259,6 +259,7 @@ static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b, int rate = hdr2samplerate[ ( b->data[4] >> 4 ) & 0x3 ]; int bitrate = rate * sample_size * nchannels; + int64_t duration = b->data[0] * 150; memset( info, 0, sizeof(*info) ); @@ -269,6 +270,7 @@ static int declpcmBSInfo( hb_work_object_t *w, const hb_buffer_t *b, info->flags = ( b->data[3] << 16 ) | ( b->data[4] << 8 ) | b->data[5]; info->channel_layout = hdr2layout[nchannels - 1]; info->channel_map = &hb_qt_chan_map; + info->samples_per_frame = ( duration * rate ) / 90000; return 1; } diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index 9239c519a..ebf2fd8f2 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -103,7 +103,7 @@ static int encavcodecaInit( hb_work_object_t * w, hb_job_t * job ) } pv->context = context; - pv->samples_per_frame = context->frame_size; + audio->config.out.samples_per_frame = pv->samples_per_frame = context->frame_size; pv->input_samples = pv->samples_per_frame * pv->out_discrete_channels; // Set a reasonable maximum output size diff --git a/libhb/encfaac.c b/libhb/encfaac.c index fe1a1f55b..0ab9124c8 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -99,6 +99,7 @@ int encfaacInit( hb_work_object_t * w, hb_job_t * job ) pv->obuf = malloc( pv->output_bytes ); pv->framedur = 90000.0 * pv->input_samples / ( audio->config.out.samplerate * pv->out_discrete_channels ); + audio->config.out.samples_per_frame = pv->input_samples / pv->out_discrete_channels; cfg = faacEncGetCurrentConfiguration( pv->faac ); cfg->mpegVersion = MPEG4; diff --git a/libhb/enclame.c b/libhb/enclame.c index ba05e1fc0..434aa185e 100644 --- a/libhb/enclame.c +++ b/libhb/enclame.c @@ -76,6 +76,7 @@ int enclameInit( hb_work_object_t * w, hb_job_t * job ) pv->input_samples = 1152 * pv->out_discrete_channels; pv->output_bytes = LAME_MAXMP3BUFFER; pv->buf = malloc( pv->input_samples * sizeof( float ) ); + audio->config.out.samples_per_frame = 1152; pv->list = hb_list_init(); pv->pts = -1; diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c index 01bd216e8..fc186e089 100644 --- a/libhb/encvorbis.c +++ b/libhb/encvorbis.c @@ -111,6 +111,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job ) } pv->input_samples = pv->out_discrete_channels * OGGVORBIS_FRAME_SIZE; + audio->config.out.samples_per_frame = OGGVORBIS_FRAME_SIZE; pv->buf = malloc( pv->input_samples * sizeof( float ) ); pv->list = hb_list_init(); diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index f73139b98..2ec32139d 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -187,23 +187,21 @@ static int MKVInit( hb_mux_object_t * m ) mux_data->codec = audio->config.out.codec; - switch (audio->config.out.codec) + switch (audio->config.out.codec & HB_ACODEC_MASK) { case HB_ACODEC_DCA: - case HB_ACODEC_DCA_PASS: case HB_ACODEC_DCA_HD: - case HB_ACODEC_DCA_HD_PASS: track->codecPrivate = NULL; track->codecPrivateSize = 0; track->codecID = MK_ACODEC_DTS; break; case HB_ACODEC_AC3: - case HB_ACODEC_AC3_PASS: track->codecPrivate = NULL; track->codecPrivateSize = 0; track->codecID = MK_ACODEC_AC3; break; case HB_ACODEC_LAME: + case HB_ACODEC_MP3: track->codecPrivate = NULL; track->codecPrivateSize = 0; track->codecID = MK_ACODEC_MP3; @@ -259,8 +257,7 @@ static int MKVInit( hb_mux_object_t * m ) lang = lang_for_code2( audio->config.lang.iso639_2 ); track->language = lang->iso639_2b ? lang->iso639_2b : lang->iso639_2; track->extra.audio.samplingFreq = (float)audio->config.out.samplerate; - if (audio->config.out.codec == HB_ACODEC_AC3_PASS || - audio->config.out.codec == HB_ACODEC_DCA_PASS) + if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) { track->extra.audio.channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout); } diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index b9c7637e8..05bce561a 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -257,228 +257,206 @@ static int MP4Init( hb_mux_object_t * m ) MP4SetTrackFloatProperty(m->file, mux_data->track, "tkhd.width", job->width * (width / height)); } - /* add the audio tracks */ + /* add the audio tracks */ for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { audio = hb_list_item( title->list_audio, i ); mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; - if( audio->config.out.codec == HB_ACODEC_AC3_PASS ) + switch ( audio->config.out.codec & HB_ACODEC_MASK ) { - uint8_t bsid = audio->config.in.version; - uint8_t bsmod = audio->config.in.mode; - uint8_t acmod = audio->config.flags.ac3 & 0x7; - uint8_t lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0; - uint8_t bit_rate_code = 0; - int ii, jj; - int freq = audio->config.in.samplerate; - int bitrate = audio->config.in.bitrate; - int sr_shift, sr_code; - - for (ii = 0; ii < 3; ii++) + case HB_ACODEC_AC3: { - for (jj = 0; jj < 3; jj++) + uint8_t bsid; + uint8_t bsmod; + uint8_t acmod; + uint8_t lfeon; + uint8_t bit_rate_code = 0; + int ii, jj; + int freq; + int bitrate; + int sr_shift, sr_code; + + if ( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) { - if ((ac3_sample_rate_tab[jj] >> ii) == freq) + bsmod = audio->config.in.mode; + acmod = audio->config.flags.ac3 & 0x7; + lfeon = (audio->config.flags.ac3 & A52_LFE) ? 1 : 0; + freq = audio->config.in.samplerate; + bitrate = audio->config.in.bitrate; + } + else + { + bsmod = 0; + freq = audio->config.out.samplerate; + bitrate = audio->config.out.bitrate * 1000; + switch( audio->config.out.mixdown ) { - goto rate_found1; + case HB_AMIXDOWN_MONO: + acmod = 1; + lfeon = 0; + break; + + case HB_AMIXDOWN_STEREO: + case HB_AMIXDOWN_DOLBY: + case HB_AMIXDOWN_DOLBYPLII: + acmod = 2; + lfeon = 0; + break; + + case HB_AMIXDOWN_6CH: + acmod = 7; + lfeon = 1; + break; + + default: + hb_log(" MP4Init: bad mixdown" ); + acmod = 2; + lfeon = 0; + break; } } - } - hb_error("Unknown AC3 samplerate"); - ii = jj = 0; -rate_found1: - sr_shift = ii; - sr_code = jj; - for (ii = 0; ii < 19; ii++) - { - if ((ac3_bitrate_tab[ii] >> sr_shift)*1000 == bitrate) - break; - } - if ( ii >= 19 ) - { - hb_error("Unknown AC3 bitrate"); - ii = 0; - } - bit_rate_code = ii; - - mux_data->track = MP4AddAC3AudioTrack( - m->file, - audio->config.in.samplerate, - sr_code, - bsid, - bsmod, - acmod, - lfeon, - bit_rate_code); - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - - if (audio->config.out.name == NULL) { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)"Surround", strlen("Surround")); - } - else { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)(audio->config.out.name), - strlen(audio->config.out.name)); - } - } - else if( audio->config.out.codec == HB_ACODEC_AC3 ) - { - uint8_t bsid = 8; - uint8_t bsmod = 0; - uint8_t acmod = 2; - uint8_t lfeon = 0; - uint8_t bit_rate_code = 0; - int ii, jj; - int freq = audio->config.out.samplerate; - int bitrate = audio->config.out.bitrate; - int sr_shift, sr_code; - - for (ii = 0; ii < 3; ii++) - { - for (jj = 0; jj < 3; jj++) + for (ii = 0; ii < 3; ii++) { - if ((ac3_sample_rate_tab[jj] >> ii) == freq) + for (jj = 0; jj < 3; jj++) { - goto rate_found2; + if ((ac3_sample_rate_tab[jj] >> ii) == freq) + { + goto rate_found1; + } } } - } - hb_error("Unknown AC3 samplerate"); - ii = jj = 0; -rate_found2: - sr_shift = ii; - sr_code = jj; - bsid = 8 + ii; - for (ii = 0; ii < 19; ii++) - { - if ((ac3_bitrate_tab[ii] >> sr_shift) == bitrate) - break; - } - if ( ii >= 19 ) - { - hb_error("Unknown AC3 bitrate"); - ii = 0; - } - bit_rate_code = ii; - - switch( audio->config.out.mixdown ) + hb_error("Unknown AC3 samplerate"); + ii = jj = 0; + rate_found1: + sr_shift = ii; + sr_code = jj; + bsid = 8 + ii; + for (ii = 0; ii < 19; ii++) + { + if ((ac3_bitrate_tab[ii] >> sr_shift)*1000 == bitrate) + break; + } + if ( ii >= 19 ) + { + hb_error("Unknown AC3 bitrate"); + ii = 0; + } + bit_rate_code = ii; + + mux_data->track = MP4AddAC3AudioTrack( + m->file, + freq, + sr_code, + bsid, + bsmod, + acmod, + lfeon, + bit_rate_code); + + /* Tune track chunk duration */ + MP4TuneTrackDurationPerChunk( m, mux_data->track ); + + if (audio->config.out.name == NULL) { + MP4SetTrackBytesProperty( + m->file, mux_data->track, + "udta.name.value", + (const uint8_t*)"Surround", strlen("Surround")); + } + else { + MP4SetTrackBytesProperty( + m->file, mux_data->track, + "udta.name.value", + (const uint8_t*)(audio->config.out.name), + strlen(audio->config.out.name)); + } + } break; + + case HB_ACODEC_FAAC: + case HB_ACODEC_FFAAC: + case HB_ACODEC_CA_AAC: + case HB_ACODEC_CA_HAAC: + case HB_ACODEC_LAME: + case HB_ACODEC_MP3: + case HB_ACODEC_DCA_HD: + case HB_ACODEC_DCA: { - case HB_AMIXDOWN_MONO: - acmod = 1; - break; - - case HB_AMIXDOWN_STEREO: - case HB_AMIXDOWN_DOLBY: - case HB_AMIXDOWN_DOLBYPLII: - acmod = 2; - break; + uint8_t audio_type; + int samplerate, samples_per_frame, channels, config_len; + uint8_t *config_bytes = NULL; - case HB_AMIXDOWN_6CH: - acmod = 7; - lfeon = 1; - break; - - default: - hb_log(" MP4Init: bad mixdown" ); - break; - } - - mux_data->track = MP4AddAC3AudioTrack( - m->file, - audio->config.out.samplerate, - sr_code, - bsid, - bsmod, - acmod, - lfeon, - bit_rate_code); - - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - - if (audio->config.out.name == NULL) { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)"Surround", strlen("Surround")); - } - else { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)(audio->config.out.name), - strlen(audio->config.out.name)); - } - } - else if( audio->config.out.codec == HB_ACODEC_FAAC || - audio->config.out.codec == HB_ACODEC_FFAAC || - audio->config.out.codec == HB_ACODEC_CA_AAC || - audio->config.out.codec == HB_ACODEC_CA_HAAC ) - { - int samples_per_frame = ( audio->config.out.codec == HB_ACODEC_CA_HAAC ) ? 2048 : 1024; - mux_data->track = MP4AddAudioTrack( - m->file, - audio->config.out.samplerate, samples_per_frame, MP4_MPEG4_AUDIO_TYPE ); - - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); - - if (audio->config.out.name == NULL) { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)"Stereo", strlen("Stereo")); - } - else { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)(audio->config.out.name), - strlen(audio->config.out.name)); - } - - MP4SetAudioProfileLevel( m->file, 0x0F ); - MP4SetTrackESConfiguration( - m->file, mux_data->track, - audio->priv.config.aac.bytes, audio->priv.config.aac.length ); - - /* Set the correct number of channels for this track */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown)); - } else if( audio->config.out.codec == HB_ACODEC_LAME ) { - mux_data->track = MP4AddAudioTrack( - m->file, - audio->config.out.samplerate, 1152, MP4_MPEG2_AUDIO_TYPE ); + switch ( audio->config.out.codec & HB_ACODEC_MASK ) + { + case HB_ACODEC_FAAC: + case HB_ACODEC_FFAAC: + case HB_ACODEC_CA_AAC: + case HB_ACODEC_CA_HAAC: + { + audio_type = MP4_MPEG4_AUDIO_TYPE; + config_bytes = audio->priv.config.aac.bytes; + config_len = audio->priv.config.aac.length; + } break; + case HB_ACODEC_LAME: + case HB_ACODEC_MP3: + { + audio_type = MP4_MPEG2_AUDIO_TYPE; + } break; + case HB_ACODEC_DCA: + case HB_ACODEC_DCA_HD: + { + audio_type = 0xA9; + } break; + } + if( audio->config.out.codec & HB_ACODEC_PASS_FLAG ) + { + samplerate = audio->config.in.samplerate; + samples_per_frame = audio->config.in.samples_per_frame; + channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT( + audio->config.in.channel_layout ); + } + else + { + samplerate = audio->config.out.samplerate; + samples_per_frame = audio->config.out.samples_per_frame; + channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( + audio->config.out.mixdown ); + } + mux_data->track = MP4AddAudioTrack( m->file, samplerate, + samples_per_frame, audio_type ); - /* Tune track chunk duration */ - MP4TuneTrackDurationPerChunk( m, mux_data->track ); + /* Tune track chunk duration */ + MP4TuneTrackDurationPerChunk( m, mux_data->track ); - if (audio->config.out.name == NULL) { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)"Stereo", strlen("Stereo")); - } - else { - MP4SetTrackBytesProperty( - m->file, mux_data->track, - "udta.name.value", - (const uint8_t*)(audio->config.out.name), - strlen(audio->config.out.name)); - } + if (audio->config.out.name == NULL) { + MP4SetTrackBytesProperty( + m->file, mux_data->track, + "udta.name.value", + (const uint8_t*)"Stereo", strlen("Stereo")); + } + else { + MP4SetTrackBytesProperty( + m->file, mux_data->track, + "udta.name.value", + (const uint8_t*)(audio->config.out.name), + strlen(audio->config.out.name)); + } - MP4SetAudioProfileLevel( m->file, 0x0F ); + MP4SetAudioProfileLevel( m->file, 0x0F ); + if ( config_bytes ) + { + MP4SetTrackESConfiguration( m->file, mux_data->track, + config_bytes, config_len ); + } + /* Set the correct number of channels for this track */ + MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.*.channels", channels); + } break; - /* Set the correct number of channels for this track */ - MP4SetTrackIntegerProperty(m->file, mux_data->track, "mdia.minf.stbl.stsd.mp4a.channels", (uint16_t)HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown)); + default: + { + hb_log("MP4Mux: Unsupported audio codec %x", audio->config.out.codec); + } break; } /* Set the language for this track */ diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c index 1bca23910..35b737e79 100644 --- a/libhb/platform/macosx/encca_aac.c +++ b/libhb/platform/macosx/encca_aac.c @@ -241,7 +241,7 @@ int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job, enum AAC_MODE mode ) // set sizes pv->isamplesiz = input.mBytesPerPacket; - pv->isamples = output.mFramesPerPacket; + pv->isamples = audio->config.out.samples_per_frame = output.mFramesPerPacket; pv->osamplerate = output.mSampleRate; // set channel map and layout (for remapping) diff --git a/libhb/scan.c b/libhb/scan.c index 8999dc15c..43b4825bc 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -1030,6 +1030,7 @@ static void LookForAudio( hb_title_t * title, hb_buffer_t * b ) hb_fifo_close( &audio->priv.scan_cache ); audio->config.in.samplerate = info.rate; + audio->config.in.samples_per_frame = info.samples_per_frame; audio->config.in.bitrate = info.bitrate; audio->config.in.channel_layout = info.channel_layout; audio->config.in.channel_map = info.channel_map; diff --git a/libhb/stream.c b/libhb/stream.c index 84d31fe0b..d4f810c99 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -57,7 +57,7 @@ static const stream2codec_t st2codec[256] = { st(0x0c, N, 0, 0, "ISO 13818-6 Stream descriptors"), st(0x0d, N, 0, 0, "ISO 13818-6 Sections"), st(0x0e, N, 0, 0, "ISO 13818-1 auxiliary"), - st(0x0f, A, HB_ACODEC_FFMPEG, CODEC_ID_AAC, "AAC"), + st(0x0f, A, HB_ACODEC_FFAAC, CODEC_ID_AAC, "AAC"), st(0x10, V, WORK_DECAVCODECV, CODEC_ID_MPEG4, "MPEG4"), st(0x11, A, HB_ACODEC_FFMPEG, CODEC_ID_AAC_LATM, "LATM AAC"), st(0x12, U, 0, 0, "MPEG4 generic"), @@ -1984,7 +1984,7 @@ static void add_audio_to_title(hb_title_t *title, int id) switch ( id >> 12 ) { case 0x0: - audio->config.in.codec = HB_ACODEC_FFMPEG; + audio->config.in.codec = HB_ACODEC_MP3; hb_log("add_audio_to_title: added MPEG audio stream 0x%x", id); break; case 0x2: @@ -3204,6 +3204,17 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) { audio->config.in.codec = HB_ACODEC_DCA_HD; } + else if ( codec->codec_id == CODEC_ID_AAC ) + { + int len = MIN(codec->extradata_size, HB_CONFIG_MAX_SIZE); + memcpy(audio->priv.config.aac.bytes, codec->extradata, len); + audio->priv.config.aac.length = len; + audio->config.in.codec = HB_ACODEC_FFAAC; + } + else if ( codec->codec_id == CODEC_ID_MP3 ) + { + audio->config.in.codec = HB_ACODEC_MP3; + } else { audio->config.in.codec = HB_ACODEC_FFMPEG; @@ -3212,6 +3223,7 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) audio->config.in.bitrate = codec->bit_rate? codec->bit_rate : 1; audio->config.in.samplerate = codec->sample_rate; + audio->config.in.samples_per_frame = codec->frame_size; audio->config.in.channel_layout = layout; audio->config.in.channel_map = &hb_smpte_chan_map; } @@ -3698,7 +3710,7 @@ hb_buffer_t * hb_ffmpeg_read( hb_stream_t *stream ) { buf->renderOffset = buf->start; } - + /* * Fill out buf->stop for subtitle packets * diff --git a/libhb/sync.c b/libhb/sync.c index b754a54cc..b1ec99619 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -14,8 +14,6 @@ #endif #define INT64_MIN (-9223372036854775807LL-1) -#define AC3_SAMPLES_PER_FRAME 1536 - typedef struct { hb_lock_t * mutex; @@ -44,9 +42,10 @@ typedef struct SRC_STATE * state; SRC_DATA data; - /* AC-3 */ - int ac3_size; - uint8_t * ac3_buf; + int silence_size; + uint8_t * silence_buf; + + int drop_video_to_sync; double gain_factor; } hb_sync_audio_t; @@ -261,7 +260,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_subtitle_t * subtitle; hb_sync_video_t * sync = &pv->type.video; int i; - int64_t start, next_start; + int64_t next_start; *buf_out = NULL; next = *buf_in; @@ -456,16 +455,12 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_DONE; } - hb_lock( pv->common->mutex ); - start = cur->start - pv->common->video_pts_slip; - hb_unlock( pv->common->mutex ); - /* Check for end of point-to-point pts encoding */ if( job->pts_to_stop && sync->next_start >= job->pts_to_stop ) { // Drop an empty buffer into our output to ensure that things // get flushed all the way out. - hb_log( "sync: reached pts %"PRId64", exiting early", start ); + hb_log( "sync: reached pts %"PRId64", exiting early", cur->start ); hb_buffer_close( &sync->cur ); hb_buffer_close( &next ); *buf_out = hb_buffer_init( 0 ); @@ -487,7 +482,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, if( sync->first_frame ) { /* This is our first frame */ - if ( start > 0 ) + if ( cur->start > 0 ) { /* * The first pts from a dvd should always be zero but @@ -497,8 +492,8 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * as if it started at zero so that our audio timing will * be in sync. */ - hb_log( "sync: first pts is %"PRId64, start ); - start = 0; + hb_log( "sync: first pts is %"PRId64, cur->start ); + cur->start = 0; } sync->first_frame = 0; } @@ -514,7 +509,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * can deal with overlaps of up to a frame time but anything larger * we handle by dropping frames here. */ - if ( next_start - start <= 0 ) + if ( next_start - cur->start <= 0 ) { if ( sync->first_drop == 0 ) { @@ -533,8 +528,8 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { hb_log( "sync: video time didn't advance - dropped %d frames " "(delta %d ms, current %"PRId64", next %"PRId64", dur %d)", - sync->drop_count, (int)( start - sync->first_drop ) / 90, - start, next_start, (int)( next_start - start ) ); + sync->drop_count, (int)( cur->start - sync->first_drop ) / 90, + cur->start, next_start, (int)( next_start - cur->start ) ); sync->first_drop = 0; sync->drop_count = 0; } @@ -766,14 +761,16 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * explicit stop time from the start time of the next frame. */ *buf_out = cur; + int64_t duration = next_start - cur->start; sync->cur = cur = next; cur->sub = NULL; - int64_t duration = next_start - start; + cur->start -= pv->common->video_pts_slip; + cur->stop -= pv->common->video_pts_slip; sync->pts_skip = 0; if ( duration <= 0 ) { hb_log( "sync: invalid video duration %"PRId64", start %"PRId64", next %"PRId64"", - duration, start, next_start ); + duration, cur->start, next_start ); } (*buf_out)->start = sync->next_start; @@ -837,11 +834,11 @@ void syncAudioClose( hb_work_object_t * w ) hb_work_private_t * pv = w->private_data; hb_sync_audio_t * sync = &pv->type.audio; - if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if( sync->silence_buf ) { - free( sync->ac3_buf ); + free( sync->silence_buf ); } - else + if ( sync->state ) { src_delete( sync->state ); } @@ -985,29 +982,26 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_DONE; } - if ( start - sync->next_start < 0 ) + // audio time went backwards. + // If our output clock is more than a half frame ahead of the + // input clock drop this frame to move closer to sync. + // Otherwise drop frames until the input clock matches the output clock. + if ( sync->next_start - start > 90*15 ) { - // audio time went backwards. - // If our output clock is more than a half frame ahead of the - // input clock drop this frame to move closer to sync. - // Otherwise drop frames until the input clock matches the output clock. - if ( sync->first_drop || sync->next_start - start > 90*15 ) + // Discard data that's in the past. + if ( sync->first_drop == 0 ) { - // Discard data that's in the past. - if ( sync->first_drop == 0 ) - { - sync->first_drop = sync->next_start; - } - ++sync->drop_count; - hb_buffer_close( &buf ); - return HB_WORK_OK; + sync->first_drop = start; } + ++sync->drop_count; + hb_buffer_close( &buf ); + return HB_WORK_OK; } if ( sync->first_drop ) { // we were dropping old data but input buf time is now current hb_log( "sync: audio 0x%x time went backwards %d ms, dropped %d frames " - "(next %"PRId64", current %"PRId64")", w->audio->id, + "(start %"PRId64", next %"PRId64")", w->audio->id, (int)( sync->next_start - sync->first_drop ) / 90, sync->drop_count, sync->first_drop, (int64_t)sync->next_start ); sync->first_drop = 0; @@ -1033,8 +1027,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * Or in the case of DCA, skip some frames from the * other streams. */ - if( w->audio->config.out.codec == HB_ACODEC_DCA_PASS || - w->audio->config.out.codec == HB_ACODEC_DCA_HD_PASS ) + if ( sync->drop_video_to_sync ) { hb_log( "sync: audio gap %d ms. Skipping frames. Audio 0x%x" " start %"PRId64", next %"PRId64, @@ -1103,21 +1096,41 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) w->fifo_out = w->audio->priv.fifo_sync; } - if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS || + w->audio->config.out.codec == HB_ACODEC_AAC_PASS ) { - /* Have a silent AC-3 frame ready in case we have to fill a + /* Have a silent AC-3/AAC frame ready in case we have to fill a gap */ AVCodec * codec; AVCodecContext * c; short * zeros; - codec = avcodec_find_encoder( CODEC_ID_AC3 ); + switch ( w->audio->config.out.codec ) + { + case HB_ACODEC_AC3_PASS: + { + codec = avcodec_find_encoder( CODEC_ID_AC3 ); + } break; + case HB_ACODEC_AAC_PASS: + { + codec = avcodec_find_encoder( CODEC_ID_AAC ); + } break; + case HB_ACODEC_MP3_PASS: + { + codec = avcodec_find_encoder( CODEC_ID_MP3 ); + } break; + default: + { + // Never gets here + } break; + } + c = avcodec_alloc_context3( codec ); c->bit_rate = w->audio->config.in.bitrate; c->sample_rate = w->audio->config.in.samplerate; c->channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT( w->audio->config.in.channel_layout ); - c->sample_fmt = AV_SAMPLE_FMT_FLT; + hb_ff_set_sample_fmt( c, codec ); switch( w->audio->config.in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK ) { @@ -1167,14 +1180,26 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) return; } - zeros = calloc( AC3_SAMPLES_PER_FRAME * - sizeof( float ) * c->channels, 1 ); - sync->ac3_size = w->audio->config.in.bitrate * AC3_SAMPLES_PER_FRAME / - w->audio->config.in.samplerate / 8; - sync->ac3_buf = malloc( sync->ac3_size ); + int input_size = c->frame_size * av_get_bytes_per_sample( c->sample_fmt ) * c->channels; + zeros = calloc( 1, input_size ); + // Allocate enough space for the encoded silence + // The output should be < the input + sync->silence_buf = malloc( input_size ); + + // There is some delay in getting output from some audio encoders. + // So encode a few packets till we get output. + int ii; + for ( ii = 0; ii < 10; ii++ ) + { + sync->silence_size = avcodec_encode_audio( c, sync->silence_buf, + input_size, zeros ); - if( avcodec_encode_audio( c, sync->ac3_buf, sync->ac3_size, - zeros ) != sync->ac3_size ) + if (sync->silence_size) + { + break; + } + } + if (!sync->silence_size) { hb_log( "sync: avcodec_encode_audio failed" ); } @@ -1185,12 +1210,19 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) } else { - /* Initialize libsamplerate */ - int error; - sync->state = src_new( SRC_SINC_MEDIUM_QUALITY, - HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( - w->audio->config.out.mixdown), &error ); - sync->data.end_of_input = 0; + if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) + { + sync->drop_video_to_sync = 1; + } + else + { + /* Not passthru, Initialize libsamplerate */ + int error; + sync->state = src_new( SRC_SINC_MEDIUM_QUALITY, + HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( + w->audio->config.out.mixdown), &error ); + sync->data.end_of_input = 0; + } } sync->gain_factor = pow(LVL_PLUS1DB, w->audio->config.out.gain); @@ -1293,29 +1325,39 @@ static void InsertSilence( hb_work_object_t * w, int64_t duration ) hb_sync_audio_t *sync = &pv->type.audio; hb_buffer_t *buf; hb_fifo_t *fifo; + int frame_dur, frame_count; // to keep pass-thru and regular audio in sync we generate silence in - // AC3 frame-sized units. If the silence duration isn't an integer multiple - // of the AC3 frame duration we will truncate or round up depending on + // frame-sized units. If the silence duration isn't an integer multiple + // of the frame duration we will truncate or round up depending on // which minimizes the timing error. - const int frame_dur = ( 90000 * AC3_SAMPLES_PER_FRAME ) / - w->audio->config.in.samplerate; - int frame_count = ( duration + (frame_dur >> 1) ) / frame_dur; + if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) + { + frame_dur = ( 90000 * w->audio->config.in.samples_per_frame ) / + w->audio->config.in.samplerate; + } + else + { + frame_dur = ( 90000 * w->audio->config.out.samples_per_frame ) / + w->audio->config.in.samplerate; + } + frame_count = ( duration + (frame_dur >> 1) ) / frame_dur; while ( --frame_count >= 0 ) { - if( w->audio->config.out.codec == HB_ACODEC_AC3_PASS ) + if( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) { - buf = hb_buffer_init( sync->ac3_size ); + buf = hb_buffer_init( sync->silence_size ); buf->start = sync->next_start; buf->stop = buf->start + frame_dur; - memcpy( buf->data, sync->ac3_buf, buf->size ); + memcpy( buf->data, sync->silence_buf, buf->size ); fifo = w->audio->priv.fifo_out; } else { - buf = hb_buffer_init( AC3_SAMPLES_PER_FRAME * sizeof( float ) * - HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( + buf = hb_buffer_init( w->audio->config.out.samples_per_frame * + sizeof( float ) * + HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( w->audio->config.out.mixdown) ); buf->start = sync->next_start; buf->stop = buf->start + frame_dur; diff --git a/libhb/work.c b/libhb/work.c index ffd48ec4b..222ae240f 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -378,6 +378,8 @@ void hb_display_job_info( hb_job_t * job ) 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"); diff --git a/macosx/HBAudio.m b/macosx/HBAudio.m index e92e578e4..b7fdbcc85 100644 --- a/macosx/HBAudio.m +++ b/macosx/HBAudio.m @@ -107,41 +107,55 @@ static NSMutableArray *masterBitRateArray = nil; [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, nil]]; [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"MP3 (lame)", @"MP3 (lame)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_LAME], keyAudioCodec, + NSLocalizedString(@"AAC Passthru", @"AAC Passthru"), keyAudioCodecName, + [NSNumber numberWithInt: HB_ACODEC_AAC_PASS], keyAudioCodec, [NSNumber numberWithBool: YES], keyAudioMP4, [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, + [NSNumber numberWithInt: HB_ACODEC_FFAAC], keyAudioMustMatchTrack, nil]]; [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioCodec, + NSLocalizedString(@"AC3 (ffmpeg)", @"AC3 (ffmpeg)"), keyAudioCodecName, + [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioCodec, [NSNumber numberWithBool: YES], keyAudioMP4, [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioMustMatchTrack, + [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, nil]]; [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: - NSLocalizedString(@"AC3 (ffmpeg)", @"AC3 (ffmpeg)"), keyAudioCodecName, - [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioCodec, + NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioCodecName, + [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioCodec, [NSNumber numberWithBool: YES], keyAudioMP4, [NSNumber numberWithBool: YES], keyAudioMKV, - [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, + [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: NO], keyAudioMP4, + [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: NO], keyAudioMP4, + [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, diff --git a/macosx/HBAudioController.m b/macosx/HBAudioController.m index ec9314697..b2de10c98 100644 --- a/macosx/HBAudioController.m +++ b/macosx/HBAudioController.m @@ -299,6 +299,13 @@ 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"; + } if ([[NSUserDefaults standardUserDefaults] boolForKey: @"AC3PassthruDefaultsToAC3"] && [key isEqualToString: @"AC3 Passthru"]) { diff --git a/test/test.c b/test/test.c index d9f360dec..4fd728537 100644 --- a/test/test.c +++ b/test/test.c @@ -2563,17 +2563,39 @@ static void ShowHelp() #ifdef __APPLE_CC__ fprintf( out, " -E, --aencoder <string> Audio encoder(s)\n" - " (ca_aac/ca_haac/faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\n" - " copy, copy:ac3 and copy:dts meaning passthrough.\n" - " copy will passthrough either ac3 or dts.\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" + " 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" ); #else fprintf( out, " -E, --aencoder <string> Audio encoder(s):\n" - " (faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\n" - " copy, copy:ac3 and copy:dts meaning passthrough.\n" - " copy will passthrough either ac3 or dts.\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" ); #endif @@ -3427,6 +3449,10 @@ static int ParseOptions( int argc, char ** argv ) 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; } str_vfree( allowed ); } break; @@ -3600,6 +3626,10 @@ static int get_acodec_for_string( char *codec ) { 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; @@ -3612,6 +3642,10 @@ static int get_acodec_for_string( char *codec ) { 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; |