1 /* This file is part of the HandBrake source code.
2 Homepage: <http://handbrake.fr/>.
3 It may be used under the terms of the GNU General Public License. */
6 #include <AudioToolbox/AudioToolbox.h>
7 #include <CoreAudio/CoreAudio.h>
9 int encCoreAudioInit( hb_work_object_t *, hb_job_t * );
10 int encCoreAudioWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
11 void encCoreAudioClose( hb_work_object_t * );
13 hb_work_object_t hb_encca_aac =
16 "AAC encoder (Apple)",
22 struct hb_work_private_s
26 AudioConverterRef converter;
30 unsigned long isamples, isamplesiz, omaxpacket, nchannels;
35 #define MP4ESDescrTag 0x03
36 #define MP4DecConfigDescrTag 0x04
37 #define MP4DecSpecificDescrTag 0x05
39 // based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat
40 static int readDescrLen(UInt8 **buffer)
46 len = (len << 7) | (c & 0x7f);
53 // based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat
54 static int readDescr(UInt8 **buffer, int *tag)
57 return readDescrLen(buffer);
60 // based off of mov_read_esds from mov.c in ffmpeg's libavformat
61 static long ReadESDSDescExt(void* descExt, UInt8 **buffer, UInt32 *size, int versionFlags)
63 UInt8 *esds = (UInt8 *) descExt;
68 esds += 4; // version + flags
69 readDescr(&esds, &tag);
71 if (tag == MP4ESDescrTag)
74 readDescr(&esds, &tag);
75 if (tag == MP4DecConfigDescrTag) {
76 esds++; // object type id
77 esds++; // stream type
78 esds += 3; // buffer size db
79 esds += 4; // max bitrate
80 esds += 4; // average bitrate
82 len = readDescr(&esds, &tag);
83 if (tag == MP4DecSpecificDescrTag) {
84 *buffer = calloc(1, len + 8);
86 memcpy(*buffer, esds, len);
95 /***********************************************************************
96 * hb_work_encCoreAudio_init
97 ***********************************************************************
99 **********************************************************************/
100 int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job )
102 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
103 hb_audio_t * audio = w->audio;
104 AudioStreamBasicDescription input, output;
105 UInt32 tmp, tmpsiz = sizeof( tmp );
108 w->private_data = pv;
111 // pass the number of channels used into the private work data
112 pv->nchannels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( audio->config.out.mixdown );
114 bzero( &input, sizeof( AudioStreamBasicDescription ) );
115 input.mSampleRate = ( Float64 ) audio->config.out.samplerate;
116 input.mFormatID = kAudioFormatLinearPCM;
117 input.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian;
118 input.mBytesPerPacket = 4 * pv->nchannels;
119 input.mFramesPerPacket = 1;
120 input.mBytesPerFrame = input.mBytesPerPacket * input.mFramesPerPacket;
121 input.mChannelsPerFrame = pv->nchannels;
122 input.mBitsPerChannel = 32;
124 bzero( &output, sizeof( AudioStreamBasicDescription ) );
125 output.mFormatID = kAudioFormatMPEG4AAC;
126 output.mSampleRate = ( Float64 ) audio->config.out.samplerate;
127 output.mChannelsPerFrame = pv->nchannels;
128 // let CoreAudio decide the rest...
130 // initialise encoder
131 err = AudioConverterNew( &input, &output, &pv->converter );
134 // Retry without the samplerate
135 bzero( &output, sizeof( AudioStreamBasicDescription ) );
136 output.mFormatID = kAudioFormatMPEG4AAC;
137 output.mChannelsPerFrame = pv->nchannels;
139 err = AudioConverterNew( &input, &output, &pv->converter );
143 hb_log( "Error creating an AudioConverter err=%"PRId64" %"PRIu64, (int64_t)err, (uint64_t)output.mBytesPerFrame );
149 if( ( audio->config.out.mixdown == HB_AMIXDOWN_6CH ) && ( audio->config.in.codec == HB_ACODEC_AC3) )
151 SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 };
152 AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap,
153 sizeof( channelMap ), channelMap );
156 // set encoder quality to maximum
157 tmp = kAudioConverterQuality_Max;
158 AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality,
159 sizeof( tmp ), &tmp );
161 // set encoder bitrate control mode to constrained variable
162 tmp = kAudioCodecBitRateControlMode_VariableConstrained;
163 AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode,
164 sizeof( tmp ), &tmp );
166 // get available bitrates
167 AudioValueRange *bitrates;
168 ssize_t bitrateCounts;
169 err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates,
171 bitrates = malloc( tmpsiz );
172 err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates,
174 bitrateCounts = tmpsiz / sizeof( AudioValueRange );
177 tmp = audio->config.out.bitrate * 1000;
178 if( tmp < bitrates[0].mMinimum )
179 tmp = bitrates[0].mMinimum;
180 if( tmp > bitrates[bitrateCounts-1].mMinimum )
181 tmp = bitrates[bitrateCounts-1].mMinimum;
183 AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate,
184 sizeof( tmp ), &tmp );
187 tmpsiz = sizeof( input );
188 AudioConverterGetProperty( pv->converter,
189 kAudioConverterCurrentInputStreamDescription,
192 tmpsiz = sizeof( output );
193 AudioConverterGetProperty( pv->converter,
194 kAudioConverterCurrentOutputStreamDescription,
198 pv->isamplesiz = input.mBytesPerPacket;
199 pv->isamples = output.mFramesPerPacket;
200 pv->osamplerate = output.mSampleRate;
202 // get maximum output size
203 AudioConverterGetProperty( pv->converter,
204 kAudioConverterPropertyMaximumOutputPacketSize,
206 pv->omaxpacket = tmp;
208 // get magic cookie (elementary stream descriptor)
209 tmp = HB_CONFIG_MAX_SIZE;
210 AudioConverterGetProperty( pv->converter,
211 kAudioConverterCompressionMagicCookie,
212 &tmp, w->config->aac.bytes );
213 // CoreAudio returns a complete ESDS, but we only need
214 // the DecoderSpecific info.
215 UInt8* buffer = NULL;
216 ReadESDSDescExt(w->config->aac.bytes, &buffer, &tmpsiz, 0);
217 w->config->aac.length = tmpsiz;
218 memmove( w->config->aac.bytes, buffer,
219 w->config->aac.length );
221 pv->list = hb_list_init();
227 /***********************************************************************
229 ***********************************************************************
231 **********************************************************************/
232 void encCoreAudioClose( hb_work_object_t * w )
234 hb_work_private_t * pv = w->private_data;
238 AudioConverterDispose( pv->converter );
239 hb_list_empty( &pv->list );
243 w->private_data = NULL;
247 /* Called whenever necessary by AudioConverterFillComplexBuffer */
248 static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets,
249 AudioBufferList *buffers,
250 AudioStreamPacketDescription** ignored,
253 hb_work_private_t *pv = userdata;
255 if( pv->ibytes == 0 )
258 hb_log( "CoreAudio: no data to use in inInputDataProc" );
262 if( pv->buf != NULL )
266 buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes );
267 buffers->mBuffers[0].mData = pv->buf = calloc(1 , buffers->mBuffers[0].mDataByteSize );
269 if( hb_list_bytes( pv->list ) >= buffers->mBuffers[0].mDataByteSize )
271 hb_list_getbytes( pv->list, buffers->mBuffers[0].mData,
272 buffers->mBuffers[0].mDataByteSize, &pts, &pos );
276 hb_log( "CoreAudio: Not enought data, exiting inInputDataProc" );
281 *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
283 /* transform data from [-32768,32767] to [-1.0,1.0] */
284 float *fdata = buffers->mBuffers[0].mData;
287 for( i = 0; i < *npackets * pv->nchannels; i++ ) {
288 fdata[i] = fdata[i] / 32768.f;
291 pv->ibytes -= buffers->mBuffers[0].mDataByteSize;
296 /***********************************************************************
298 ***********************************************************************
300 **********************************************************************/
301 static hb_buffer_t * Encode( hb_work_object_t * w )
303 hb_work_private_t * pv = w->private_data;
306 /* check if we need more data */
307 if( ( pv->ibytes = hb_list_bytes( pv->list ) ) < pv->isamples * pv->isamplesiz )
311 AudioStreamPacketDescription odesc = { 0 };
312 AudioBufferList obuflist = { .mNumberBuffers = 1,
313 .mBuffers = { { .mNumberChannels = pv->nchannels } },
316 obuf = hb_buffer_init( pv->omaxpacket );
317 obuflist.mBuffers[0].mDataByteSize = obuf->size;
318 obuflist.mBuffers[0].mData = obuf->data;
320 OSStatus err = AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv,
321 &npackets, &obuflist, &odesc );
323 hb_log( "CoreAudio: Not enough data" );
326 if( odesc.mDataByteSize == 0 || npackets == 0 ) {
328 hb_log( "CoreAudio: 0 packets returned " );
331 obuf->start = pv->pts;
332 pv->pts += 90000LL * pv->isamples / pv->osamplerate;
333 obuf->stop = pv->pts;
334 obuf->size = odesc.mDataByteSize;
335 obuf->frametype = HB_FRAME_AUDIO;
340 static hb_buffer_t *Flush( hb_work_object_t *w, hb_buffer_t *bufin )
342 hb_work_private_t *pv = w->private_data;
344 // pad whatever data we have out to four input frames.
345 int nbytes = hb_list_bytes( pv->list );
346 int pad = pv->isamples * pv->isamplesiz - nbytes;
349 hb_buffer_t *tmp = hb_buffer_init( pad );
350 memset( tmp->data, 0, pad );
351 hb_list_add( pv->list, tmp );
354 hb_buffer_t *bufout = NULL, *buf = NULL;
355 while ( hb_list_bytes( pv->list ) >= pv->isamples * pv->isamplesiz )
357 hb_buffer_t *b = Encode( w );
360 if ( bufout == NULL )
371 // add the eof marker to the end of our buf chain
379 /***********************************************************************
381 ***********************************************************************
383 **********************************************************************/
384 int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
385 hb_buffer_t ** buf_out )
387 hb_work_private_t * pv = w->private_data;
390 if( (*buf_in)->size <= 0 )
392 // EOF on input. Finish encoding what we have buffered then send
393 // it & the eof downstream.
394 *buf_out = Flush( w, *buf_in );
399 hb_list_add( pv->list, *buf_in );
402 *buf_out = buf = Encode( w );
406 buf->next = Encode( w );