OSDN Git Service

- fixed gcc warnings for various unused vars, implicit function decls, signedness.
[handbrake-jp/handbrake-jp-git.git] / libhb / platform / macosx / encca_aac.c
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. */
4
5 #include "hb.h"
6 #include <AudioToolbox/AudioToolbox.h>
7 #include <CoreAudio/CoreAudio.h>
8
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 * );
12
13 hb_work_object_t hb_encca_aac =
14 {
15     WORK_ENC_CA_AAC,
16     "AAC encoder (Apple)",
17     encCoreAudioInit,
18     encCoreAudioWork,
19     encCoreAudioClose
20 };
21
22 struct hb_work_private_s
23 {
24     hb_job_t *job;
25     
26     AudioConverterRef converter;
27     uint8_t  *obuf;
28     uint8_t  *buf;
29     hb_list_t *list;
30     unsigned long isamples, isamplesiz, omaxpacket, nchannels;
31     uint64_t pts, ibytes;
32 };
33
34 #define MP4ESDescrTag                   0x03
35 #define MP4DecConfigDescrTag            0x04
36 #define MP4DecSpecificDescrTag          0x05
37
38 // based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat
39 static int readDescrLen(UInt8 **buffer)
40 {
41         int len = 0;
42         int count = 4;
43         while (count--) {
44                 int c = *(*buffer)++;
45                 len = (len << 7) | (c & 0x7f);
46                 if (!(c & 0x80))
47                         break;
48         }
49         return len;
50 }
51
52 // based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat
53 static int readDescr(UInt8 **buffer, int *tag)
54 {
55         *tag = *(*buffer)++;
56         return readDescrLen(buffer);
57 }
58
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)
61 {
62         UInt8 *esds = (UInt8 *) descExt;
63         int tag, len;
64         *size = 0;
65
66     if (versionFlags)
67         esds += 4;              // version + flags
68         readDescr(&esds, &tag);
69         esds += 2;              // ID
70         if (tag == MP4ESDescrTag)
71                 esds++;         // priority
72
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
80
81                 len = readDescr(&esds, &tag);
82                 if (tag == MP4DecSpecificDescrTag) {
83                         *buffer = calloc(1, len + 8);
84                         if (*buffer) {
85                                 memcpy(*buffer, esds, len);
86                                 *size = len;
87                         }
88                 }
89         }
90
91         return noErr;
92 }
93
94 /***********************************************************************
95  * hb_work_encCoreAudio_init
96  ***********************************************************************
97  *
98  **********************************************************************/
99 int encCoreAudioInit( hb_work_object_t * w, hb_job_t * job )
100 {
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 );
105     OSStatus err;
106
107     w->private_data = pv;
108     pv->job = job;
109
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 );
112
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;
122
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...
128
129     // initialise encoder
130     err = AudioConverterNew( &input, &output, &pv->converter );
131     if( err != noErr)
132     {
133         hb_log( "Error creating an AudioConverter %x %d", err, output.mBytesPerFrame );
134         *job->die = 1;
135         return 0;
136     }
137
138     if( audio->config.out.mixdown == HB_AMIXDOWN_6CH && audio->config.in.codec == HB_ACODEC_AC3 )
139     {
140         SInt32 channelMap[6] = { 2, 1, 3, 4, 5, 0 };
141         AudioConverterSetProperty( pv->converter, kAudioConverterChannelMap,
142                                    sizeof( channelMap ), channelMap );
143     }
144
145     // set encoder quality to maximum
146     tmp = kAudioConverterQuality_Max;
147     AudioConverterSetProperty( pv->converter, kAudioConverterCodecQuality,
148                                sizeof( tmp ), &tmp );
149
150     // set encoder bitrate control mode to constrained variable
151     tmp = kAudioCodecBitRateControlMode_VariableConstrained;
152     AudioConverterSetProperty( pv->converter, kAudioCodecPropertyBitRateControlMode,
153                               sizeof( tmp ), &tmp );
154
155     // get available bitrates
156     AudioValueRange *bitrates;
157     ssize_t bitrateCounts;
158     err = AudioConverterGetPropertyInfo( pv->converter, kAudioConverterApplicableEncodeBitRates,
159                                          &tmpsiz, NULL);
160     bitrates = malloc( tmpsiz );
161     err = AudioConverterGetProperty( pv->converter, kAudioConverterApplicableEncodeBitRates,
162                                      &tmpsiz, bitrates);
163     bitrateCounts = tmpsiz / sizeof( AudioValueRange );
164
165     // set bitrate
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;
171     free( bitrates );
172     AudioConverterSetProperty( pv->converter, kAudioConverterEncodeBitRate,
173                               sizeof( tmp ), &tmp );
174
175     // get real input
176     tmpsiz = sizeof( input );
177     AudioConverterGetProperty( pv->converter,
178                                kAudioConverterCurrentInputStreamDescription,
179                                &tmpsiz, &input );
180     // get real output
181     tmpsiz = sizeof( output );
182     AudioConverterGetProperty( pv->converter,
183                                kAudioConverterCurrentOutputStreamDescription,
184                                &tmpsiz, &output );
185
186     // set sizes
187     pv->isamplesiz = input.mBytesPerPacket;
188     pv->isamples   = output.mFramesPerPacket;
189
190     // get maximum output size
191     AudioConverterGetProperty( pv->converter,
192                                kAudioConverterPropertyMaximumOutputPacketSize,
193                                &tmpsiz, &tmp );
194     pv->omaxpacket = tmp;
195
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 );
208
209     pv->list = hb_list_init();
210     pv->buf = NULL;
211
212     return 0;
213 }
214
215 /***********************************************************************
216  * Close
217  ***********************************************************************
218  *
219  **********************************************************************/
220 void encCoreAudioClose( hb_work_object_t * w )
221 {
222     hb_work_private_t * pv = w->private_data;
223
224     if( pv->converter )
225     {
226         AudioConverterDispose( pv->converter );
227         hb_list_empty( &pv->list );
228         free( pv->obuf );
229         free( pv->buf );
230         free( pv );
231         w->private_data = NULL;
232     }
233 }
234
235 /* Called whenever necessary by AudioConverterFillComplexBuffer */
236 static OSStatus inInputDataProc( AudioConverterRef converter, UInt32 *npackets,
237                           AudioBufferList *buffers,
238                           AudioStreamPacketDescription** ignored,
239                           void *userdata )
240 {
241     hb_work_private_t *pv = userdata;
242     pv->ibytes = hb_list_bytes( pv->list );
243
244     if( pv->ibytes == 0 ) {
245         *npackets = 0;
246         return noErr;
247     }
248
249     if( pv->buf != NULL )
250         free( pv->buf );
251
252     uint64_t pts, pos;
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 );
255
256     hb_list_getbytes( pv->list, buffers->mBuffers[0].mData,
257                       buffers->mBuffers[0].mDataByteSize, &pts, &pos );
258
259     *npackets = buffers->mBuffers[0].mDataByteSize / pv->isamplesiz;
260
261     /* transform data from [-32768,32767] to [-1.0,1.0] */
262     float *fdata = buffers->mBuffers[0].mData;
263     int i;
264
265     for( i = 0; i < *npackets * pv->nchannels; i++ )
266         fdata[i] = fdata[i] / 32768.f;
267
268     return noErr;
269 }
270
271 /***********************************************************************
272  * Encode
273  ***********************************************************************
274  *
275  **********************************************************************/
276 static hb_buffer_t * Encode( hb_work_object_t * w )
277 {
278     hb_work_private_t * pv = w->private_data;
279     UInt32 npackets = 1;
280
281     /* check if we need more data */
282     if( hb_list_bytes( pv->list ) < pv->isamples * pv->isamplesiz )
283         return NULL;
284
285     hb_buffer_t * obuf;
286     AudioStreamPacketDescription odesc = { 0 };
287     AudioBufferList obuflist = { .mNumberBuffers = 1,
288                                  .mBuffers = { { .mNumberChannels = pv->nchannels } },
289                                };
290
291     obuf = hb_buffer_init( pv->omaxpacket );
292     obuflist.mBuffers[0].mDataByteSize = obuf->size;
293     obuflist.mBuffers[0].mData = obuf->data;
294
295     AudioConverterFillComplexBuffer( pv->converter, inInputDataProc, pv, 
296                                      &npackets, &obuflist, &odesc );
297
298     if( odesc.mDataByteSize == 0 )
299         return NULL;
300
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;
306
307     return obuf;
308 }
309
310 /***********************************************************************
311  * Work
312  ***********************************************************************
313  *
314  **********************************************************************/
315 int encCoreAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
316                   hb_buffer_t ** buf_out )
317 {
318     hb_work_private_t * pv = w->private_data;
319     hb_buffer_t * buf;
320
321     if( (*buf_in)->size <= 0 )
322     {
323         // EOF on input - send it downstream & say we're done
324         *buf_out = *buf_in;
325         *buf_in = NULL;
326         return HB_WORK_DONE;
327     }
328
329     hb_list_add( pv->list, *buf_in );
330     *buf_in = NULL;
331
332     *buf_out = buf = Encode( w );
333
334     while( buf )
335     {
336         buf->next = Encode( w );
337         buf       = buf->next;
338     }
339
340     return HB_WORK_OK;
341 }