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.mFormatID = kAudioFormatMPEG4AAC;
125 output.mChannelsPerFrame = pv->nchannels;
126 // let CoreAudio decide the rest...
128 // initialise encoder
129 err = AudioConverterNew( &input, &output, &pv->converter );
132 hb_log( "Error creating an AudioConverter err=%"PRId64" %"PRIu64, (int64_t)err, (uint64_t)output.mBytesPerFrame );
137 if( audio->config.out.mixdown == HB_AMIXDOWN_6CH && audio->config.in.codec == HB_ACODEC_AC3 )
139 SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 };
140 AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap,
141 sizeof( channelMap ), channelMap );
144 // set encoder quality to maximum
145 tmp = kAudioConverterQuality_Max;
146 AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality,
147 sizeof( tmp ), &tmp );
149 // set encoder bitrate control mode to constrained variable
150 tmp = kAudioCodecBitRateControlMode_VariableConstrained;
151 AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode,
152 sizeof( tmp ), &tmp );
154 // get available bitrates
155 AudioValueRange *bitrates;
156 ssize_t bitrateCounts;
157 err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates,
159 bitrates = malloc( tmpsiz );
160 err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates,
162 bitrateCounts = tmpsiz / sizeof( AudioValueRange );
165 tmp = audio->config.out.bitrate * 1000;
166 if( tmp < bitrates[0].mMinimum )
167 tmp = bitrates[0].mMinimum;
168 if( tmp > bitrates[bitrateCounts-1].mMinimum )
169 tmp = bitrates[bitrateCounts-1].mMinimum;
171 AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate,
172 sizeof( tmp ), &tmp );
175 tmpsiz = sizeof( input );
176 AudioConverterGetProperty( pv->converter,
177 kAudioConverterCurrentInputStreamDescription,
180 tmpsiz = sizeof( output );
181 AudioConverterGetProperty( pv->converter,
182 kAudioConverterCurrentOutputStreamDescription,
186 pv->isamplesiz = input.mBytesPerPacket;
187 pv->isamples = output.mFramesPerPacket;
189 // get maximum output size
190 AudioConverterGetProperty( pv->converter,
191 kAudioConverterPropertyMaximumOutputPacketSize,
193 pv->omaxpacket = tmp;
195 // get magic cookie (elementary stream descriptor)
196 tmp = HB_CONFIG_MAX_SIZE;
197 AudioConverterGetProperty( pv->converter,
198 kAudioConverterCompressionMagicCookie,
199 &tmp, w->config->aac.bytes );
200 // CoreAudio returns a complete ESDS, but we only need
201 // the DecoderSpecific info.
202 UInt8* buffer = NULL;
203 ReadESDSDescExt(w->config->aac.bytes, &buffer, &tmpsiz, 0);
204 w->config->aac.length = tmpsiz;
205 memmove( w->config->aac.bytes, buffer,
206 w->config->aac.length );
208 pv->list = hb_list_init();
214 /***********************************************************************
216 ***********************************************************************
218 **********************************************************************/
219 void encCoreAudioClose( hb_work_object_t * w )
221 hb_work_private_t * pv = w->private_data;
225 AudioConverterDispose( pv->converter );
226 hb_list_empty( &pv->list );
230 w->private_data = NULL;
234 /* Called whenever necessary by AudioConverterFillComplexBuffer */
235 static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets,
236 AudioBufferList *buffers,
237 AudioStreamPacketDescription** ignored,
240 hb_work_private_t *pv = userdata;
241 pv->ibytes = hb_list_bytes( pv->list );
243 if( pv->ibytes == 0 ) {
248 if( pv->buf != NULL )
252 pv->ibytes = buffers->mBuffers[0].mDataByteSize = MIN( *npackets * pv->isamplesiz, pv->ibytes );
253 buffers->mBuffers[0].mData = pv->buf = malloc( buffers->mBuffers[0].mDataByteSize );
255 hb_list_getbytes( pv->list, buffers->mBuffers[0].mData,
256 buffers->mBuffers[0].mDataByteSize, &pts, &pos );
258 *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
260 /* transform data from [-32768,32767] to [-1.0,1.0] */
261 float *fdata = buffers->mBuffers[0].mData;
264 for( i = 0; i < *npackets * pv->nchannels; i++ )
265 fdata[i] = fdata[i] / 32768.f;
270 /***********************************************************************
272 ***********************************************************************
274 **********************************************************************/
275 static hb_buffer_t * Encode( hb_work_object_t * w )
277 hb_work_private_t * pv = w->private_data;
280 /* check if we need more data */
281 if( hb_list_bytes( pv->list ) < pv->isamples * pv->isamplesiz )
285 AudioStreamPacketDescription odesc = { 0 };
286 AudioBufferList obuflist = { .mNumberBuffers = 1,
287 .mBuffers = { { .mNumberChannels = pv->nchannels } },
290 obuf = hb_buffer_init( pv->omaxpacket );
291 obuflist.mBuffers[0].mDataByteSize = obuf->size;
292 obuflist.mBuffers[0].mData = obuf->data;
294 AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv,
295 &npackets, &obuflist, &odesc );
297 if( odesc.mDataByteSize == 0 )
300 obuf->start = pv->pts;
301 pv->pts += 90000LL * pv->isamples / w->audio->config.out.samplerate;
302 obuf->stop = pv->pts;
303 obuf->size = odesc.mDataByteSize;
304 obuf->frametype = HB_FRAME_AUDIO;
309 /***********************************************************************
311 ***********************************************************************
313 **********************************************************************/
314 int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
315 hb_buffer_t ** buf_out )
317 hb_work_private_t * pv = w->private_data;
320 if( (*buf_in)->size <= 0 )
322 // EOF on input - send it downstream & say we're done
328 hb_list_add( pv->list, *buf_in );
331 *buf_out = buf = Encode( w );
335 buf->next = Encode( w );