diff options
author | sr55 <[email protected]> | 2011-04-18 12:10:07 +0000 |
---|---|---|
committer | sr55 <[email protected]> | 2011-04-18 12:10:07 +0000 |
commit | e63f490b2e0a90bafb690e1d1f1f1e2f44729309 (patch) | |
tree | ba6efe28059341ad798d5e20d1682233e057e55c | |
parent | 4d2dce20625d08032eb25dd2d98c3d4319d8e0d9 (diff) |
HE-AAC support for the OSX port. Thanks go to amarcus, ritsuka and rodeo.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3937 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | libhb/common.c | 65 | ||||
-rw-r--r-- | libhb/common.h | 2 | ||||
-rw-r--r-- | libhb/hb.c | 55 | ||||
-rw-r--r-- | libhb/hb.h | 8 | ||||
-rw-r--r-- | libhb/internal.h | 1 | ||||
-rw-r--r-- | libhb/muxmkv.c | 1 | ||||
-rw-r--r-- | libhb/muxmp4.c | 6 | ||||
-rw-r--r-- | libhb/platform/macosx/encca_aac.c | 65 | ||||
-rw-r--r-- | libhb/work.c | 21 | ||||
-rw-r--r-- | macosx/HBAudio.m | 9 | ||||
-rw-r--r-- | test/test.c | 6 |
11 files changed, 209 insertions, 30 deletions
diff --git a/libhb/common.c b/libhb/common.c index a3887b680..90bd23cb6 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -118,15 +118,14 @@ ffac3 24kHz 318 (320) 318 (320) 318 (320) 48kHz 636 (640) 636 (640) 636 (640) -Core Audio (core audio api provides range of allowed bitrates) -24kHz 16-64 32-128 80-320 -44.1kHz 64-320 160-768 -48kHz 32-256 64-320 160-768 - -Core Audio (minimum limits found in testing) -24kHz 16 32 96 -44.1kHz 32 64 160 -48kHz 40 80 240 +Core Audio AAC (core audio api provides range of allowed bitrates) +24kHz 16-64 32-128 80-320 +32kHz 24-96 48-192 128-448 +48kHz 32-256 64-320 160-768 + +Core Audio HE-AAC (core audio api provides range of allowed bitrates) +32kHz 12-40 24-80 64-192 +48kHz 16-40 32-80 80-192 */ void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high) @@ -149,27 +148,27 @@ void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, in break; case HB_ACODEC_CA_AAC: - if (samplerate > 44100) + if (samplerate > 32000) { - *low = channels * 40; - *high = 256; + *low = channels * 32; + if (channels == 1) + *high = 256; if (channels == 2) *high = 320; if (channels == 6) { + *low = 160; *high = 768; } } else if (samplerate > 24000) { - *low = channels * 32; - *high = 256; - if (channels == 2) - *high = 320; + *low = channels * 24; + *high = channels * 96; if (channels == 6) { - *low = 160; - *high = 768; + *low = 128; + *high = 448; } } else @@ -178,11 +177,35 @@ void hb_get_audio_bitrate_limits(uint32_t codec, int samplerate, int mixdown, in *high = channels * 64; if (channels == 6) { + *low = 80; *high = 320; } } break; + case HB_ACODEC_CA_HAAC: + if (samplerate > 32000) + { + *low = channels * 16; + *high = channels * 40; + if (channels == 6) + { + *low = 80; + *high = 192; + } + } + else + { + *low = channels * 12; + *high = channels * 40; + if (channels == 6) + { + *low = 64; + *high = 192; + } + } + break; + case HB_ACODEC_FAAC: *low = 32 * channels; if (samplerate > 24000) @@ -280,6 +303,9 @@ int hb_get_default_audio_bitrate( uint32_t codec, int samplerate, int mixdown ) else bitrate = 640; break; + case HB_ACODEC_CA_HAAC: + bitrate = channels * 32; + break; default: bitrate = channels * 80; } @@ -611,6 +637,9 @@ int hb_calc_bitrate( hb_job_t * job, int size ) case HB_ACODEC_DCA: samples_per_frame = 1536; break; + case HB_ACODEC_CA_HAAC: + samples_per_frame = 2048; + break; default: return 0; } diff --git a/libhb/common.h b/libhb/common.h index b945200e7..1125ec5d3 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -322,6 +322,7 @@ struct hb_job_s #define HB_ACODEC_DCA 0x00004000 #define HB_ACODEC_FFMPEG 0x00008000 #define HB_ACODEC_CA_AAC 0x00010000 +#define HB_ACODEC_CA_HAAC 0x00020000 #define HB_ACODEC_PASS_FLAG 0x40000000 #define HB_ACODEC_PASS_MASK (HB_ACODEC_AC3 | HB_ACODEC_DCA) #define HB_ACODEC_AC3_PASS (HB_ACODEC_AC3 | HB_ACODEC_PASS_FLAG) @@ -784,6 +785,7 @@ extern hb_work_object_t hb_enclame; extern hb_work_object_t hb_encvorbis; extern hb_work_object_t hb_muxer; extern hb_work_object_t hb_encca_aac; +extern hb_work_object_t hb_encca_haac; extern hb_work_object_t hb_encac3; #define FILTER_OK 0 diff --git a/libhb/hb.c b/libhb/hb.c index 8588f7ff4..411e4bd66 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -412,6 +412,7 @@ hb_handle_t * hb_init( int verbose, int update_check ) hb_register( &hb_muxer ); #ifdef __APPLE__ hb_register( &hb_encca_aac ); + hb_register( &hb_encca_haac ); #endif hb_register( &hb_encac3 ); @@ -513,6 +514,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) hb_register( &hb_muxer ); #ifdef __APPLE__ hb_register( &hb_encca_aac ); + hb_register( &hb_encca_haac ); #endif hb_register( &hb_encac3 ); @@ -1940,3 +1942,56 @@ hb_interjob_t * hb_interjob_get( hb_handle_t * h ) { return h->interjob; } + +/************************************************************************ + * encca_haac_available() + ************************************************************************ + * Returns whether the Core Audio HE-AAC encoder is available for use + * on the system. Under 10.5, if the encoder is available, register it. + * The registration is actually only performed on the first call. + ************************************************************************/ +int encca_haac_available() +{ +#ifdef __APPLE__ + static int encca_haac_available = -1; + + if (encca_haac_available != -1) + return encca_haac_available; + + encca_haac_available = 0; + + long minorVersion, majorVersion, quickTimeVersion; + Gestalt(gestaltSystemVersionMajor, &majorVersion); + Gestalt(gestaltSystemVersionMinor, &minorVersion); + Gestalt(gestaltQuickTime, &quickTimeVersion); + + if (majorVersion > 10 || (majorVersion == 10 && minorVersion >= 6)) + { + // OS X 10.6+ - ca_haac is available and ready to use + encca_haac_available = 1; + } + else if (majorVersion == 10 && minorVersion >= 5 && quickTimeVersion >= 0x07630000) + { + // OS X 10.5, QuickTime 7.6.3+ - register the component + ComponentDescription cd; + cd.componentType = kAudioEncoderComponentType; + cd.componentSubType = kAudioFormatMPEG4AAC_HE; + cd.componentManufacturer = kAudioUnitManufacturer_Apple; + cd.componentFlags = 0; + cd.componentFlagsMask = 0; + ComponentResult (*ComponentRoutine) (ComponentParameters * cp, Handle componentStorage); + void *handle = dlopen("/System/Library/Components/AudioCodecs.component/Contents/MacOS/AudioCodecs", RTLD_LAZY|RTLD_LOCAL); + if (handle) + { + ComponentRoutine = dlsym(handle, "ACMP4AACHighEfficiencyEncoderEntry"); + if (ComponentRoutine) + if (RegisterComponent(&cd, ComponentRoutine, 0, NULL, NULL, NULL)) + encca_haac_available = 1; + } + } + + return encca_haac_available; +#else + return 0; +#endif +} diff --git a/libhb/hb.h b/libhb/hb.h index 783da11cd..0a3af6019 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -8,6 +8,14 @@ extern "C" { #include "project.h" #include "common.h" +#ifdef __APPLE__ +#include <CoreServices/CoreServices.h> // for Gestalt +#include <AudioToolbox/AudioToolbox.h> +#include <dlfcn.h> +#endif +/* Whether the Core Audio HE-AAC encoder is available on the system. */ +int encca_haac_available(); + /* hb_init() Initializes a libhb session (launches his own thread, detects CPUs, etc) */ diff --git a/libhb/internal.h b/libhb/internal.h index 5d71cdadf..eec560efb 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -357,6 +357,7 @@ enum WORK_ENCLAME, WORK_ENCVORBIS, WORK_ENC_CA_AAC, + WORK_ENC_CA_HAAC, WORK_ENCAC3, WORK_MUX }; diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index ddb0028d1..445447f9c 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -230,6 +230,7 @@ static int MKVInit( hb_mux_object_t * m ) break; case HB_ACODEC_FAAC: case HB_ACODEC_CA_AAC: + case HB_ACODEC_CA_HAAC: track->codecPrivate = audio->priv.config.aac.bytes; track->codecPrivateSize = audio->priv.config.aac.length; track->codecID = MK_ACODEC_AAC; diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index b1148819a..3df70dc17 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -420,11 +420,13 @@ rate_found2: } } else if( audio->config.out.codec == HB_ACODEC_FAAC || - audio->config.out.codec == HB_ACODEC_CA_AAC ) + 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, 1024, MP4_MPEG4_AUDIO_TYPE ); + audio->config.out.samplerate, samples_per_frame, MP4_MPEG4_AUDIO_TYPE ); /* Tune track chunk duration */ MP4TuneTrackDurationPerChunk( m, mux_data->track ); diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c index 21b458960..85c9c2d88 100644 --- a/libhb/platform/macosx/encca_aac.c +++ b/libhb/platform/macosx/encca_aac.c @@ -6,7 +6,11 @@ #include <AudioToolbox/AudioToolbox.h> #include <CoreAudio/CoreAudio.h> -int encCoreAudioInit( hb_work_object_t *, hb_job_t * ); +enum AAC_MODE { AAC_MODE_LC, AAC_MODE_HE }; + +int encCoreAudioInitLC( hb_work_object_t *, hb_job_t * ); +int encCoreAudioInitHE( hb_work_object_t *, hb_job_t * ); +int encCoreAudioInit( hb_work_object_t *, hb_job_t *, enum AAC_MODE mode ); int encCoreAudioWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); void encCoreAudioClose( hb_work_object_t * ); @@ -14,7 +18,16 @@ hb_work_object_t hb_encca_aac = { WORK_ENC_CA_AAC, "AAC encoder (Apple)", - encCoreAudioInit, + encCoreAudioInitLC, + encCoreAudioWork, + encCoreAudioClose +}; + +hb_work_object_t hb_encca_haac = +{ + WORK_ENC_CA_HAAC, + "HE-AAC encoder (Apple)", + encCoreAudioInitHE, encCoreAudioWork, encCoreAudioClose }; @@ -93,11 +106,26 @@ static long ReadESDSDescExt(void* descExt, UInt8 **buffer, UInt32 *size, int ver } /*********************************************************************** + * hb_work_encCoreAudio_init switches + *********************************************************************** + * + **********************************************************************/ +int encCoreAudioInitLC( hb_work_object_t * w, hb_job_t * job ) +{ + return encCoreAudioInit( w, job, AAC_MODE_LC ); +} + +int encCoreAudioInitHE( hb_work_object_t * w, hb_job_t * job ) +{ + return encCoreAudioInit( w, job, AAC_MODE_HE ); +} + +/*********************************************************************** * hb_work_encCoreAudio_init *********************************************************************** * **********************************************************************/ -int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job ) +int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job, enum AAC_MODE mode ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); hb_audio_t * audio = w->audio; @@ -122,7 +150,16 @@ int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job ) input.mBitsPerChannel = 32; bzero( &output, sizeof( AudioStreamBasicDescription ) ); - output.mFormatID = kAudioFormatMPEG4AAC; + switch ( mode ) + { + case AAC_MODE_HE: + output.mFormatID = kAudioFormatMPEG4AAC_HE; + break; + case AAC_MODE_LC: + default: + output.mFormatID = kAudioFormatMPEG4AAC; + break; + } output.mSampleRate = ( Float64 ) audio->config.out.samplerate; output.mChannelsPerFrame = pv->nchannels; // let CoreAudio decide the rest... @@ -133,7 +170,16 @@ int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job ) { // Retry without the samplerate bzero( &output, sizeof( AudioStreamBasicDescription ) ); - output.mFormatID = kAudioFormatMPEG4AAC; + switch ( mode ) + { + case AAC_MODE_HE: + output.mFormatID = kAudioFormatMPEG4AAC_HE; + break; + case AAC_MODE_LC: + default: + output.mFormatID = kAudioFormatMPEG4AAC; + break; + } output.mChannelsPerFrame = pv->nchannels; err = AudioConverterNew( &input, &output, &pv->converter ); @@ -161,7 +207,7 @@ int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job ) // set encoder bitrate control mode to constrained variable tmp = kAudioCodecBitRateControlMode_VariableConstrained; AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode, - sizeof( tmp ), &tmp ); + sizeof( tmp ), &tmp ); // get available bitrates AudioValueRange *bitrates; @@ -180,8 +226,11 @@ int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job ) if( tmp > bitrates[bitrateCounts-1].mMinimum ) tmp = bitrates[bitrateCounts-1].mMinimum; free( bitrates ); + if( tmp != audio->config.out.bitrate * 1000 ) + hb_log( "encca_aac: sanitizing track %d audio bitrate %d to %"PRIu32"", + audio->config.out.track, audio->config.out.bitrate, tmp/1000 ); AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate, - sizeof( tmp ), &tmp ); + sizeof( tmp ), &tmp ); // get real input tmpsiz = sizeof( input ); @@ -256,7 +305,7 @@ static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets, { *npackets = 0; hb_log( "CoreAudio: no data to use in inInputDataProc" ); - return noErr; + return 1; } if( pv->buf != NULL ) diff --git a/libhb/work.c b/libhb/work.c index 8c182fa66..29dac4d7a 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -127,6 +127,7 @@ hb_work_object_t * hb_codec_encoder( int codec ) case HB_ACODEC_LAME: return hb_get_work( WORK_ENCLAME ); case HB_ACODEC_VORBIS: return hb_get_work( WORK_ENCVORBIS ); case HB_ACODEC_CA_AAC: return hb_get_work( WORK_ENC_CA_AAC ); + case HB_ACODEC_CA_HAAC:return hb_get_work( WORK_ENC_CA_HAAC ); case HB_ACODEC_AC3: return hb_get_work( WORK_ENCAC3 ); } return NULL; @@ -369,8 +370,9 @@ void hb_display_job_info( hb_job_t * job ) ( 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_AC3 ) ? "ffac3" : - "vorbis" ) ) ) ); + "vorbis" ) ) ) ) ); hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate ); } } @@ -556,6 +558,23 @@ static void do_job( hb_job_t * job ) audio->config.out.bitrate ); audio->config.out.bitrate = 640; } + if( audio->config.out.codec == HB_ACODEC_CA_HAAC ) + { + if( !encca_haac_available() ) + { + // user chose Core Audio HE-AAC but the encoder is unavailable + hb_log( "Core Audio HE-AAC unavailable. Using Core Audio AAC for track %d", + audio->config.out.track ); + audio->config.out.codec = HB_ACODEC_CA_AAC; + } + else if( audio->config.out.samplerate < 32000 ) + { + // Core Audio HE-AAC doesn't support samplerates < 32 kHz + hb_log( "Sample rate %d not supported (ca_haac). Using 32kHz for track %d", + audio->config.out.samplerate, audio->config.out.track ); + audio->config.out.samplerate = 32000; + } + } /* Adjust output track number, in case we removed one. * Output tracks sadly still need to be in sequential order. */ diff --git a/macosx/HBAudio.m b/macosx/HBAudio.m index c1c0cd591..7be16023f 100644 --- a/macosx/HBAudio.m +++ b/macosx/HBAudio.m @@ -75,6 +75,15 @@ static NSMutableArray *masterBitRateArray = nil; [NSNumber numberWithBool: YES], keyAudioMKV, [NSNumber numberWithBool: NO], keyAudioMustMatchTrack, nil]]; + if (encca_haac_available()) { + [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]]; + } [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: NSLocalizedString(@"AAC (faac)", @"AAC (faac)"), keyAudioCodecName, [NSNumber numberWithInt: HB_ACODEC_FAAC], keyAudioCodec, diff --git a/test/test.c b/test/test.c index c89267b9f..7cf65a5cf 100644 --- a/test/test.c +++ b/test/test.c @@ -2538,7 +2538,7 @@ static void ShowHelp() #ifdef __APPLE_CC__ fprintf( out, " -E, --aencoder <string> Audio encoder(s)\n" - " (ca_aac/faac/lame/vorbis/ac3/copy/copy:ac3/copy:dts)\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" " Separated by commas for more than one audio track.\n" @@ -3594,6 +3594,10 @@ static int get_acodec_for_string( char *codec ) { return HB_ACODEC_CA_AAC; } + else if( !strcasecmp( codec, "ca_haac") ) + { + return HB_ACODEC_CA_HAAC; + } #endif else { |