summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/common.c65
-rw-r--r--libhb/common.h2
-rw-r--r--libhb/hb.c55
-rw-r--r--libhb/hb.h8
-rw-r--r--libhb/internal.h1
-rw-r--r--libhb/muxmkv.c1
-rw-r--r--libhb/muxmp4.c6
-rw-r--r--libhb/platform/macosx/encca_aac.c65
-rw-r--r--libhb/work.c21
-rw-r--r--macosx/HBAudio.m9
-rw-r--r--test/test.c6
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
{