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;
34 #define MP4ESDescrTag 0x03
35 #define MP4DecConfigDescrTag 0x04
36 #define MP4DecSpecificDescrTag 0x05
38 // based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat
39 static int readDescrLen(UInt8 **buffer)
45 len = (len << 7) | (c & 0x7f);
52 // based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat
53 static int readDescr(UInt8 **buffer, int *tag)
56 return readDescrLen(buffer);
59 // based off of mov_read_esds from mov.c in ffmpeg's libavformat
60 static long ReadESDSDescExt(void* descExt, UInt8 **buffer, UInt32 *size, int versionFlags)
62 UInt8 *esds = (UInt8 *) descExt;
67 esds += 4; // version + flags
68 readDescr(&esds, &tag);
70 if (tag == MP4ESDescrTag)
73 readDescr(&esds, &tag);
74 if (tag == MP4DecConfigDescrTag) {
75 esds++; // object type id
76 esds++; // stream type
77 esds += 3; // buffer size db
78 esds += 4; // max bitrate
79 esds += 4; // average bitrate
81 len = readDescr(&esds, &tag);
82 if (tag == MP4DecSpecificDescrTag) {
83 *buffer = calloc(1, len + 8);
85 memcpy(*buffer, esds, len);
94 /***********************************************************************
95 * hb_work_encCoreAudio_init
96 ***********************************************************************
98 **********************************************************************/
99 int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job )
101 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
102 hb_audio_t * audio = w->audio;
103 AudioStreamBasicDescription input, output;
104 UInt32 tmp, tmpsiz = sizeof( tmp );
107 w->private_data = pv;
110 // pass the number of channels used into the private work data
111 pv->nchannels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( audio->config.out.mixdown );
113 bzero( &input, sizeof( AudioStreamBasicDescription ) );
114 input.mSampleRate = ( Float64 ) audio->config.out.samplerate;
115 input.mFormatID = kAudioFormatLinearPCM;
116 input.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian;
117 input.mBytesPerPacket = 4 * pv->nchannels;
118 input.mFramesPerPacket = 1;
119 input.mBytesPerFrame = input.mBytesPerPacket * input.mFramesPerPacket;
120 input.mChannelsPerFrame = pv->nchannels;
121 input.mBitsPerChannel = 32;
123 bzero( &output, sizeof( AudioStreamBasicDescription ) );
124 output.mSampleRate = ( Float64 ) audio->config.out.samplerate;
125 output.mFormatID = kAudioFormatMPEG4AAC;
126 output.mChannelsPerFrame = pv->nchannels;
127 // let CoreAudio decide the rest...
129 // initialise encoder
130 err = AudioConverterNew( &input, &output, &pv->converter );
133 hb_log( "Error creating an AudioConverter %x %d", err, output.mBytesPerFrame );
138 if( audio->config.out.mixdown == HB_AMIXDOWN_6CH && audio->config.in.codec == HB_ACODEC_AC3 )
140 SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 };
141 AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap,
142 sizeof( channelMap ), channelMap );
145 // set encoder quality to maximum
146 tmp = kAudioConverterQuality_Max;
147 AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality,
148 sizeof( tmp ), &tmp );
150 // set encoder bitrate control mode to constrained variable
151 tmp = kAudioCodecBitRateControlMode_VariableConstrained;
152 AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode,
153 sizeof( tmp ), &tmp );
155 // get available bitrates
156 AudioValueRange *bitrates;
157 ssize_t bitrateCounts;
158 err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates,
160 bitrates = malloc( tmpsiz );
161 err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates,
163 bitrateCounts = tmpsiz / sizeof( AudioValueRange );
166 tmp = audio->config.out.bitrate * 1000;
167 if( tmp < bitrates[0].mMinimum )
168 tmp = bitrates[0].mMinimum;
169 if( tmp > bitrates[bitrateCounts-1].mMinimum )
170 tmp = bitrates[bitrateCounts-1].mMinimum;
172 AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate,
173 sizeof( tmp ), &tmp );
176 tmpsiz = sizeof( input );
177 AudioConverterGetProperty( pv->converter,
178 kAudioConverterCurrentInputStreamDescription,
181 tmpsiz = sizeof( output );
182 AudioConverterGetProperty( pv->converter,
183 kAudioConverterCurrentOutputStreamDescription,
187 pv->isamplesiz = input.mBytesPerPacket;
188 pv->isamples = output.mFramesPerPacket;
190 // get maximum output size
191 AudioConverterGetProperty( pv->converter,
192 kAudioConverterPropertyMaximumOutputPacketSize,
194 pv->omaxpacket = tmp;
196 // get magic cookie (elementary stream descriptor)
197 tmp = HB_CONFIG_MAX_SIZE;
198 AudioConverterGetProperty( pv->converter,
199 kAudioConverterCompressionMagicCookie,
200 &tmp, w->config->aac.bytes );
201 // CoreAudio returns a complete ESDS, but we only need
202 // the DecoderSpecific info.
203 UInt8* buffer = NULL;
204 ReadESDSDescExt(w->config->aac.bytes, &buffer, &tmpsiz, 0);
205 w->config->aac.length = tmpsiz;
206 memmove( w->config->aac.bytes, buffer,
207 w->config->aac.length );
209 pv->list = hb_list_init();
215 /***********************************************************************
217 ***********************************************************************
219 **********************************************************************/
220 void encCoreAudioClose( hb_work_object_t * w )
222 hb_work_private_t * pv = w->private_data;
226 AudioConverterDispose( pv->converter );
227 hb_list_empty( &pv->list );
231 w->private_data = NULL;
235 /* Called whenever necessary by AudioConverterFillComplexBuffer */
236 static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets,
237 AudioBufferList *buffers,
238 AudioStreamPacketDescription** ignored,
241 hb_work_private_t *pv = userdata;
242 pv->ibytes = hb_list_bytes( pv->list );
244 if( pv->ibytes == 0 ) {
249 if( pv->buf != NULL )
253 pv->ibytes = buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes );
254 buffers->mBuffers[0].mData = pv->buf = malloc( buffers->mBuffers[0].mDataByteSize );
256 hb_list_getbytes( pv->list, buffers->mBuffers[0].mData,
257 buffers->mBuffers[0].mDataByteSize, &pts, &pos );
259 *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
261 /* transform data from [-32768,32767] to [-1.0,1.0] */
262 float *fdata = buffers->mBuffers[0].mData;
265 for( i = 0; i < *npackets * pv->nchannels; i++ )
266 fdata[i] = fdata[i] / 32768.f;
271 /***********************************************************************
273 ***********************************************************************
275 **********************************************************************/
276 static hb_buffer_t * Encode( hb_work_object_t * w )
278 hb_work_private_t * pv = w->private_data;
281 /* check if we need more data */
282 if( hb_list_bytes( pv->list ) < pv->isamples * pv->isamplesiz )
286 AudioStreamPacketDescription odesc = { 0 };
287 AudioBufferList obuflist = { .mNumberBuffers = 1,
288 .mBuffers = { { .mNumberChannels = pv->nchannels } },
291 obuf = hb_buffer_init( pv->omaxpacket );
292 obuflist.mBuffers[0].mDataByteSize = obuf->size;
293 obuflist.mBuffers[0].mData = obuf->data;
295 AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv,
296 &npackets, &obuflist, &odesc );
298 if( odesc.mDataByteSize == 0 )
301 obuf->start = pv->pts;
302 pv->pts += 90000LL * pv->isamples / w->audio->config.out.samplerate;
303 obuf->stop = pv->pts;
304 obuf->size = odesc.mDataByteSize;
305 obuf->frametype = HB_FRAME_AUDIO;
310 /***********************************************************************
312 ***********************************************************************
314 **********************************************************************/
315 int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
316 hb_buffer_t ** buf_out )
318 hb_work_private_t * pv = w->private_data;
321 if( (*buf_in)->size <= 0 )
323 // EOF on input - send it downstream & say we're done
329 hb_list_add( pv->list, *buf_in );
332 *buf_out = buf = Encode( w );
336 buf->next = Encode( w );