diff options
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/common.c | 150 | ||||
-rw-r--r-- | libhb/common.h | 19 | ||||
-rw-r--r-- | libhb/work.c | 107 |
3 files changed, 209 insertions, 67 deletions
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", |