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;
254 pv->ibytes = hb_list_bytes( pv->list );
256 if( pv->ibytes == 0 ) {
261 if( pv->buf != NULL )
265 pv->ibytes = buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes );
266 buffers->mBuffers[0].mData = pv->buf = malloc( buffers->mBuffers[0].mDataByteSize );
268 hb_list_getbytes( pv->list, buffers->mBuffers[0].mData,
269 buffers->mBuffers[0].mDataByteSize, &pts, &pos );
271 *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
273 /* transform data from [-32768,32767] to [-1.0,1.0] */
274 float *fdata = buffers->mBuffers[0].mData;
277 for( i = 0; i < *npackets * pv->nchannels; i++ )
278 fdata[i] = fdata[i] / 32768.f;
283 /***********************************************************************
285 ***********************************************************************
287 **********************************************************************/
288 static hb_buffer_t * Encode( hb_work_object_t * w )
290 hb_work_private_t * pv = w->private_data;
293 /* check if we need more data */
294 if( hb_list_bytes( pv->list ) < pv->isamples * pv->isamplesiz )
298 AudioStreamPacketDescription odesc = { 0 };
299 AudioBufferList obuflist = { .mNumberBuffers = 1,
300 .mBuffers = { { .mNumberChannels = pv->nchannels } },
303 obuf = hb_buffer_init( pv->omaxpacket );
304 obuflist.mBuffers[0].mDataByteSize = obuf->size;
305 obuflist.mBuffers[0].mData = obuf->data;
307 AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv,
308 &npackets, &obuflist, &odesc );
310 if( odesc.mDataByteSize == 0 )
313 obuf->start = pv->pts;
314 pv->pts += 90000LL * pv->isamples / pv->osamplerate;
315 obuf->stop = pv->pts;
316 obuf->size = odesc.mDataByteSize;
317 obuf->frametype = HB_FRAME_AUDIO;
322 /***********************************************************************
324 ***********************************************************************
326 **********************************************************************/
327 int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
328 hb_buffer_t ** buf_out )
330 hb_work_private_t * pv = w->private_data;
333 if( (*buf_in)->size <= 0 )
335 // EOF on input - send it downstream & say we're done
341 hb_list_add( pv->list, *buf_in );
344 *buf_out = buf = Encode( w );
348 buf->next = Encode( w );