diff options
author | ritsuka <[email protected]> | 2009-05-23 09:46:36 +0000 |
---|---|---|
committer | ritsuka <[email protected]> | 2009-05-23 09:46:36 +0000 |
commit | 9cd4b18874948ed58b5724de086338eb3c036b07 (patch) | |
tree | 4de94af339e96401dc4c77d0741643a0cb0ed82e /libhb | |
parent | 8690c484f325fab8335f8a87a10406726994961d (diff) |
- Add CoreAudio AAC as one of the encoder on Mac OS X.
- Remove hb_init() and hb_init_express() macro. Rename hb_init_real() to hb_init()
- Add two more bitrate combination for audio codecs in common.h
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2441 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/common.c | 4 | ||||
-rw-r--r-- | libhb/common.h | 2 | ||||
-rw-r--r-- | libhb/hb.c | 39 | ||||
-rw-r--r-- | libhb/hb.h | 44 | ||||
-rw-r--r-- | libhb/internal.h | 3 | ||||
-rw-r--r-- | libhb/module.defs | 1 | ||||
-rw-r--r-- | libhb/muxmkv.c | 1 | ||||
-rw-r--r-- | libhb/platform/macosx/encca_aac.c | 341 | ||||
-rw-r--r-- | libhb/work.c | 6 |
9 files changed, 386 insertions, 55 deletions
diff --git a/libhb/common.c b/libhb/common.c index 88a8ea8ec..b84f907ab 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -31,7 +31,8 @@ hb_rate_t hb_audio_bitrates[] = { { "32", 32 }, { "40", 40 }, { "48", 48 }, { "56", 56 }, { "64", 64 }, { "80", 80 }, { "96", 96 }, { "112", 112 }, { "128", 128 }, { "160", 160 }, { "192", 192 }, { "224", 224 }, - { "256", 256 }, { "320", 320 }, { "384", 384 } }; + { "256", 256 }, { "320", 320 }, { "384", 384 }, { "448", 448 } + { "768", 768 } }; int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) / sizeof( hb_rate_t ); int hb_audio_bitrates_default = 8; /* 128 kbps */ @@ -227,6 +228,7 @@ int hb_calc_bitrate( hb_job_t * job, int size ) switch( audio->config.out.codec ) { case HB_ACODEC_FAAC: + case HB_ACODEC_CA_AAC: case HB_ACODEC_VORBIS: samples_per_frame = 1024; break; diff --git a/libhb/common.h b/libhb/common.h index 224b40c78..d7649f4c9 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -286,6 +286,7 @@ struct hb_job_s #define HB_ACODEC_LPCM 0x002000 #define HB_ACODEC_DCA 0x004000 #define HB_ACODEC_FFMPEG 0x008000 +#define HB_ACODEC_CA_AAC 0x010000 /* Audio Mixdown */ /* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */ @@ -675,6 +676,7 @@ extern hb_work_object_t hb_declpcm; extern hb_work_object_t hb_encfaac; extern hb_work_object_t hb_enclame; extern hb_work_object_t hb_encvorbis; +extern hb_work_object_t hb_encca_aac; #define FILTER_OK 0 #define FILTER_DELAY 1 diff --git a/libhb/hb.c b/libhb/hb.c index 661e1df47..4f484208d 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -86,7 +86,7 @@ void hb_register( hb_work_object_t * w ) * @param update_check signals libhb to check for updated version from HandBrake website. * @return Handle to hb_handle_t for use on all subsequent calls to libhb. */ -hb_handle_t * hb_init_real( int verbose, int update_check ) +hb_handle_t * hb_init( int verbose, int update_check ) { hb_handle_t * h = calloc( sizeof( hb_handle_t ), 1 ); uint64_t date; @@ -150,11 +150,31 @@ hb_handle_t * hb_init_real( int verbose, int update_check ) h->die = 0; h->main_thread = hb_thread_init( "libhb", thread_func, h, HB_NORMAL_PRIORITY ); + hb_register( &hb_sync ); + hb_register( &hb_decmpeg2 ); + hb_register( &hb_decvobsub ); + hb_register( &hb_encvobsub ); + hb_register( &hb_deccc608 ); + hb_register( &hb_render ); + hb_register( &hb_encavcodec ); + hb_register( &hb_encxvid ); + hb_register( &hb_encx264 ); + hb_register( &hb_enctheora ); + hb_register( &hb_deca52 ); + hb_register( &hb_decdca ); + hb_register( &hb_decavcodec ); + hb_register( &hb_decavcodecv ); + hb_register( &hb_decavcodecvi ); + hb_register( &hb_decavcodecai ); + hb_register( &hb_declpcm ); + hb_register( &hb_encfaac ); + hb_register( &hb_enclame ); + hb_register( &hb_encvorbis ); +#ifdef __APPLE__ + hb_register( &hb_encca_aac ); +#endif return h; - - /* Set the scan count to start at 0 */ - //scan_count = 0; } /** @@ -230,13 +250,13 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) hb_register( &hb_sync ); hb_register( &hb_decmpeg2 ); hb_register( &hb_decvobsub ); - hb_register( &hb_encvobsub ); - hb_register( &hb_deccc608 ); + hb_register( &hb_encvobsub ); + hb_register( &hb_deccc608 ); hb_register( &hb_render ); hb_register( &hb_encavcodec ); hb_register( &hb_encxvid ); hb_register( &hb_encx264 ); - hb_register( &hb_enctheora ); + hb_register( &hb_enctheora ); hb_register( &hb_deca52 ); hb_register( &hb_decdca ); hb_register( &hb_decavcodec ); @@ -247,6 +267,9 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) hb_register( &hb_encfaac ); hb_register( &hb_enclame ); hb_register( &hb_encvorbis ); +#ifdef __APPLE__ + hb_register( &hb_encca_aac ); +#endif return h; } @@ -1301,7 +1324,7 @@ int hb_get_scancount( hb_handle_t * h) } /** - * Closes access to libhb by freeing the hb_handle_t handle ontained in hb_init_real. + * Closes access to libhb by freeing the hb_handle_t handle ontained in hb_init. * @param _h Pointer to handle to hb_handle_t. */ void hb_close( hb_handle_t ** _h ) diff --git a/libhb/hb.h b/libhb/hb.h index 3cf308e3a..cc7a7eecc 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -14,51 +14,9 @@ extern "C" { #define HB_DEBUG_NONE 0 #define HB_DEBUG_ALL 1 void hb_register( hb_work_object_t * ); -hb_handle_t * hb_init_real( int verbose, int update_check ); +hb_handle_t * hb_init( int verbose, int update_check ); hb_handle_t * hb_init_dl ( int verbose, int update_check ); // hb_init for use with dylib -#define hb_init(v,u) \ -hb_init_real( v, u ); \ -hb_register( &hb_sync ); \ -hb_register( &hb_decmpeg2 ); \ -hb_register( &hb_decvobsub ); \ -hb_register( &hb_encvobsub ); \ -hb_register( &hb_deccc608 ); \ -hb_register( &hb_render ); \ -hb_register( &hb_encavcodec ); \ -hb_register( &hb_encxvid ); \ -hb_register( &hb_encx264 ); \ -hb_register( &hb_enctheora ); \ -hb_register( &hb_deca52 ); \ -hb_register( &hb_decdca ); \ -hb_register( &hb_decavcodec ); \ -hb_register( &hb_decavcodecv ); \ -hb_register( &hb_decavcodecvi ); \ -hb_register( &hb_decavcodecai ); \ -hb_register( &hb_declpcm ); \ -hb_register( &hb_encfaac ); \ -hb_register( &hb_enclame ); \ -hb_register( &hb_encvorbis ); \ - -#define hb_init_express(v,u) \ -hb_init_real( v, u ); \ -hb_register( &hb_sync ); \ -hb_register( &hb_decmpeg2 ); \ -hb_register( &hb_decvobsub ); \ -hb_register( &hb_encvobsub ); \ -hb_register( &hb_deccc608 ); \ -hb_register( &hb_render ); \ -hb_register( &hb_encavcodec ); \ -hb_register( &hb_encx264 ); \ -hb_register( &hb_deca52 ); \ -hb_register( &hb_decdca ); \ -hb_register( &hb_decavcodec ); \ -hb_register( &hb_decavcodecv ); \ -hb_register( &hb_decavcodecvi ); \ -hb_register( &hb_decavcodecai ); \ -hb_register( &hb_declpcm ); \ -hb_register( &hb_encfaac ); \ - /* hb_get_version() */ char * hb_get_version( hb_handle_t * ); int hb_get_build( hb_handle_t * ); diff --git a/libhb/internal.h b/libhb/internal.h index b05e50a48..1e5afdc1f 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -271,7 +271,8 @@ enum WORK_DECLPCM, WORK_ENCFAAC, WORK_ENCLAME, - WORK_ENCVORBIS + WORK_ENCVORBIS, + WORK_ENC_CA_AAC }; enum diff --git a/libhb/module.defs b/libhb/module.defs index 725ebc116..e5ecf9722 100644 --- a/libhb/module.defs +++ b/libhb/module.defs @@ -41,6 +41,7 @@ ifeq ($(BUILD.system),cygwin) LIBHB.GCC.D += SYS_CYGWIN else ifeq ($(BUILD.system),darwin) LIBHB.GCC.D += SYS_DARWIN + LIBHB.c += $(wildcard $(LIBHB.src/)platform/macosx/*.c) else ifeq ($(BUILD.system),linux) LIBHB.GCC.D += SYS_LINUX _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64 else ifeq ($(BUILD.system),mingw) diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index 04f9ae595..6a8a55cbe 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -226,6 +226,7 @@ static int MKVInit( hb_mux_object_t * m ) } break; case HB_ACODEC_FAAC: + case HB_ACODEC_CA_AAC: track->codecPrivate = audio->priv.config.aac.bytes; track->codecPrivateSize = audio->priv.config.aac.length; track->codecID = MK_ACODEC_AAC; diff --git a/libhb/platform/macosx/encca_aac.c b/libhb/platform/macosx/encca_aac.c new file mode 100644 index 000000000..69b29ec4b --- /dev/null +++ b/libhb/platform/macosx/encca_aac.c @@ -0,0 +1,341 @@ +/* This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" +#include <AudioToolbox/AudioToolbox.h> +#include <CoreAudio/CoreAudio.h> + +int encCoreAudioInit( hb_work_object_t *, hb_job_t * ); +int encCoreAudioWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); +void encCoreAudioClose( hb_work_object_t * ); + +hb_work_object_t hb_encca_aac = +{ + WORK_ENC_CA_AAC, + "AAC encoder (Apple)", + encCoreAudioInit, + encCoreAudioWork, + encCoreAudioClose +}; + +struct hb_work_private_s +{ + hb_job_t *job; + + AudioConverterRef converter; + uint8_t *obuf; + uint8_t *buf; + hb_list_t *list; + unsigned long isamples, isamplesiz, omaxpacket, nchannels; + uint64_t pts, ibytes; +}; + +#define MP4ESDescrTag 0x03 +#define MP4DecConfigDescrTag 0x04 +#define MP4DecSpecificDescrTag 0x05 + +// based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat +static int readDescrLen(UInt8 **buffer) +{ + int len = 0; + int count = 4; + while (count--) { + int c = *(*buffer)++; + len = (len << 7) | (c & 0x7f); + if (!(c & 0x80)) + break; + } + return len; +} + +// based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat +static int readDescr(UInt8 **buffer, int *tag) +{ + *tag = *(*buffer)++; + return readDescrLen(buffer); +} + +// based off of mov_read_esds from mov.c in ffmpeg's libavformat +static long ReadESDSDescExt(void* descExt, UInt8 **buffer, int *size, int versionFlags) +{ + UInt8 *esds = (UInt8 *) descExt; + int tag, len; + *size = 0; + + if (versionFlags) + esds += 4; // version + flags + readDescr(&esds, &tag); + esds += 2; // ID + if (tag == MP4ESDescrTag) + esds++; // priority + + readDescr(&esds, &tag); + if (tag == MP4DecConfigDescrTag) { + esds++; // object type id + esds++; // stream type + esds += 3; // buffer size db + esds += 4; // max bitrate + esds += 4; // average bitrate + + len = readDescr(&esds, &tag); + if (tag == MP4DecSpecificDescrTag) { + *buffer = calloc(1, len + 8); + if (*buffer) { + memcpy(*buffer, esds, len); + *size = len; + } + } + } + + return noErr; +} + +/*********************************************************************** + * hb_work_encCoreAudio_init + *********************************************************************** + * + **********************************************************************/ +int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job ) +{ + hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); + hb_audio_t * audio = w->audio; + AudioStreamBasicDescription input, output; + UInt32 tmp, tmpsiz = sizeof( tmp ); + OSStatus err; + + w->private_data = pv; + pv->job = job; + + // pass the number of channels used into the private work data + pv->nchannels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( audio->config.out.mixdown ); + + bzero( &input, sizeof( AudioStreamBasicDescription ) ); + input.mSampleRate = ( Float64 ) audio->config.out.samplerate; + input.mFormatID = kAudioFormatLinearPCM; + input.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian; + input.mBytesPerPacket = 4 * pv->nchannels; + input.mFramesPerPacket = 1; + input.mBytesPerFrame = input.mBytesPerPacket * input.mFramesPerPacket; + input.mChannelsPerFrame = pv->nchannels; + input.mBitsPerChannel = 32; + + bzero( &output, sizeof( AudioStreamBasicDescription ) ); + output.mSampleRate = ( Float64 ) audio->config.out.samplerate; + output.mFormatID = kAudioFormatMPEG4AAC; + output.mChannelsPerFrame = pv->nchannels; + // let CoreAudio decide the rest... + + // initialise encoder + err = AudioConverterNew( &input, &output, &pv->converter ); + if( err != noErr) + { + hb_log( "Error creating an AudioConverter %x %d", err, output.mBytesPerFrame ); + *job->die = 1; + return 0; + } + + if( audio->config.out.mixdown == HB_AMIXDOWN_6CH && audio->config.in.codec == HB_ACODEC_AC3 ) + { + SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 }; + AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap, + sizeof( channelMap ), channelMap ); + } + + // set encoder quality to maximum + tmp = kAudioConverterQuality_Max; + AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality, + sizeof( tmp ), &tmp ); + + // set encoder bitrate control mode to constrained variable + tmp = kAudioCodecBitRateControlMode_VariableConstrained; + AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode, + sizeof( tmp ), &tmp ); + + // get available bitrates + AudioValueRange *bitrates; + ssize_t bitrateCounts, n; + err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates, + &tmpsiz, NULL); + bitrates = malloc( tmpsiz ); + err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates, + &tmpsiz, bitrates); + bitrateCounts = tmpsiz / sizeof( AudioValueRange ); + + // set bitrate + tmp = audio->config.out.bitrate * 1000; + if( tmp < bitrates[0].mMinimum ) + tmp = bitrates[0].mMinimum; + if( tmp > bitrates[bitrateCounts-1].mMinimum ) + tmp = bitrates[bitrateCounts-1].mMinimum; + free( bitrates ); + AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate, + sizeof( tmp ), &tmp ); + + // get real input + tmpsiz = sizeof( input ); + AudioConverterGetProperty( pv->converter, + kAudioConverterCurrentInputStreamDescription, + &tmpsiz, &input ); + // get real output + tmpsiz = sizeof( output ); + AudioConverterGetProperty( pv->converter, + kAudioConverterCurrentOutputStreamDescription, + &tmpsiz, &output ); + + // set sizes + pv->isamplesiz = input.mBytesPerPacket; + pv->isamples = output.mFramesPerPacket; + + // get maximum output size + AudioConverterGetProperty( pv->converter, + kAudioConverterPropertyMaximumOutputPacketSize, + &tmpsiz, &tmp ); + pv->omaxpacket = tmp; + + // get magic cookie (elementary stream descriptor) + tmp = HB_CONFIG_MAX_SIZE; + AudioConverterGetProperty( pv->converter, + kAudioConverterCompressionMagicCookie, + &tmp, w->config->aac.bytes ); + // CoreAudio returns a complete ESDS, but we only need + // the DecoderSpecific info. + UInt8* buffer; + ReadESDSDescExt(w->config->aac.bytes, &buffer, &tmpsiz, 0); + w->config->aac.length = tmpsiz; + memmove( w->config->aac.bytes, buffer, + w->config->aac.length ); + + pv->list = hb_list_init(); + pv->buf = NULL; + + return 0; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +void encCoreAudioClose( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + + if( pv->converter ) + { + AudioConverterDispose( pv->converter ); + hb_list_empty( &pv->list ); + free( pv->obuf ); + free( pv->buf ); + free( pv ); + w->private_data = NULL; + } +} + +/* Called whenever necessary by AudioConverterFillComplexBuffer */ +static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets, + AudioBufferList *buffers, + AudioStreamPacketDescription** ignored, + void *userdata ) +{ + hb_work_private_t *pv = userdata; + pv->ibytes = hb_list_bytes( pv->list ); + + if( pv->ibytes == 0 ) { + *npackets = 0; + return noErr; + } + + if( pv->buf != NULL ) + free( pv->buf ); + + uint64_t pts, pos; + pv->ibytes = buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes ); + buffers->mBuffers[0].mData = pv->buf = malloc( buffers->mBuffers[0].mDataByteSize ); + + hb_list_getbytes( pv->list, buffers->mBuffers[0].mData, + buffers->mBuffers[0].mDataByteSize, &pts, &pos ); + + *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz; + + /* transform data from [-32768,32767] to [-1.0,1.0] */ + float *fdata = buffers->mBuffers[0].mData; + int i; + + for( i = 0; i < *npackets * pv->nchannels; i++ ) + fdata[i] = fdata[i] / 32768.f; + + return noErr; +} + +/*********************************************************************** + * Encode + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Encode( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + UInt32 npackets = 1; + + /* check if we need more data */ + if( hb_list_bytes( pv->list ) < pv->isamples * pv->isamplesiz ) + return NULL; + + hb_buffer_t * obuf; + AudioStreamPacketDescription odesc = { 0 }; + AudioBufferList obuflist = { .mNumberBuffers = 1, + .mBuffers = { { .mNumberChannels = pv->nchannels } }, + }; + + obuf = hb_buffer_init( pv->omaxpacket ); + obuflist.mBuffers[0].mDataByteSize = obuf->size; + obuflist.mBuffers[0].mData = obuf->data; + + AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv, + &npackets, &obuflist, &odesc ); + + if( odesc.mDataByteSize == 0 ) + return NULL; + + obuf->start = pv->pts; + pv->pts += 90000LL * pv->isamples / w->audio->config.out.samplerate; + obuf->stop = pv->pts; + obuf->size = odesc.mDataByteSize; + obuf->frametype = HB_FRAME_AUDIO; + + return obuf; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_work_private_t * pv = w->private_data; + hb_buffer_t * buf; + + if( (*buf_in)->size <= 0 ) + { + // EOF on input - send it downstream & say we're done + *buf_out = *buf_in; + *buf_in = NULL; + return HB_WORK_DONE; + } + + hb_list_add( pv->list, *buf_in ); + *buf_in = NULL; + + *buf_out = buf = Encode( w ); + + while( buf ) + { + buf->next = Encode( w ); + buf = buf->next; + } + + return HB_WORK_OK; +} diff --git a/libhb/work.c b/libhb/work.c index 59dea5dfe..21232debf 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -106,6 +106,7 @@ hb_work_object_t * hb_codec_encoder( int codec ) case HB_ACODEC_FAAC: return hb_get_work( WORK_ENCFAAC ); 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 ); } return NULL; } @@ -329,8 +330,9 @@ void hb_display_job_info( hb_job_t * job ) else { hb_log( " + encoder: %s", ( audio->config.out.codec == HB_ACODEC_FAAC ) ? - "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? "lame" : - "vorbis" ) ); + "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? + "lame" : ( ( audio->config.out.codec == HB_ACODEC_CA_AAC ) ? + "ca_aac" : "vorbis" ) ) ); hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate ); } } |