Browse code

lavc: add AudioToolbox encoders

Fixes trac #4828

Rodger Combs authored on 2016/02/24 12:01:24
Showing 6 changed files
... ...
@@ -14,6 +14,7 @@ version <next>:
14 14
 - MediaCodec H264 decoding
15 15
 - VC-2 HQ RTP payload format (draft v1) depacketizer
16 16
 - AudioToolbox audio decoders
17
+- AudioToolbox audio encoders
17 18
 
18 19
 
19 20
 version 3.0:
... ...
@@ -2661,6 +2661,16 @@ pcm_alaw_at_decoder_deps="audiotoolbox"
2661 2661
 pcm_mulaw_at_decoder_deps="audiotoolbox"
2662 2662
 qdmc_at_decoder_deps="audiotoolbox"
2663 2663
 qdm2_at_decoder_deps="audiotoolbox"
2664
+aac_at_encoder_deps="audiotoolbox"
2665
+aac_at_encoder_select="audio_frame_queue"
2666
+alac_at_encoder_deps="audiotoolbox"
2667
+alac_at_encoder_select="audio_frame_queue"
2668
+ilbc_at_encoder_deps="audiotoolbox"
2669
+ilbc_at_encoder_select="audio_frame_queue"
2670
+pcm_alaw_at_encoder_deps="audiotoolbox"
2671
+pcm_alaw_at_encoder_select="audio_frame_queue"
2672
+pcm_mulaw_at_encoder_deps="audiotoolbox"
2673
+pcm_mulaw_at_encoder_select="audio_frame_queue"
2664 2674
 chromaprint_muxer_deps="chromaprint"
2665 2675
 h264_videotoolbox_encoder_deps="videotoolbox_encoder pthreads"
2666 2676
 libcelt_decoder_deps="libcelt"
... ...
@@ -815,6 +815,11 @@ OBJS-$(CONFIG_PCM_MULAW_AT_DECODER)       += audiotoolboxdec.o
815 815
 OBJS-$(CONFIG_PCM_ALAW_AT_DECODER)        += audiotoolboxdec.o
816 816
 OBJS-$(CONFIG_QDMC_AT_DECODER)            += audiotoolboxdec.o
817 817
 OBJS-$(CONFIG_QDM2_AT_DECODER)            += audiotoolboxdec.o
818
+OBJS-$(CONFIG_AAC_AT_ENCODER)             += audiotoolboxenc.o
819
+OBJS-$(CONFIG_ALAC_AT_ENCODER)            += audiotoolboxenc.o
820
+OBJS-$(CONFIG_ILBC_AT_ENCODER)            += audiotoolboxenc.o
821
+OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER)        += audiotoolboxenc.o
822
+OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER)       += audiotoolboxenc.o
818 823
 OBJS-$(CONFIG_LIBCELT_DECODER)            += libcelt_dec.o
819 824
 OBJS-$(CONFIG_LIBDCADEC_DECODER)          += libdcadec.o dca.o
820 825
 OBJS-$(CONFIG_LIBFAAC_ENCODER)            += libfaac.o
... ...
@@ -563,18 +563,18 @@ void avcodec_register_all(void)
563 563
     REGISTER_ENCDEC (XSUB,              xsub);
564 564
 
565 565
     /* external libraries */
566
-    REGISTER_DECODER(AAC_AT,            aac_at);
566
+    REGISTER_ENCDEC (AAC_AT,            aac_at);
567 567
     REGISTER_DECODER(AC3_AT,            ac3_at);
568 568
     REGISTER_DECODER(ADPCM_IMA_QT_AT,   adpcm_ima_qt_at);
569
-    REGISTER_DECODER(ALAC_AT,           alac_at);
569
+    REGISTER_ENCDEC (ALAC_AT,           alac_at);
570 570
     REGISTER_DECODER(AMR_NB_AT,         amr_nb_at);
571 571
     REGISTER_DECODER(GSM_MS_AT,         gsm_ms_at);
572
-    REGISTER_DECODER(ILBC_AT,           ilbc_at);
572
+    REGISTER_ENCDEC (ILBC_AT,           ilbc_at);
573 573
     REGISTER_DECODER(MP1_AT,            mp1_at);
574 574
     REGISTER_DECODER(MP2_AT,            mp2_at);
575 575
     REGISTER_DECODER(MP3_AT,            mp3_at);
576
-    REGISTER_DECODER(PCM_ALAW_AT,       pcm_alaw_at);
577
-    REGISTER_DECODER(PCM_MULAW_AT,      pcm_mulaw_at);
576
+    REGISTER_ENCDEC (PCM_ALAW_AT,       pcm_alaw_at);
577
+    REGISTER_ENCDEC (PCM_MULAW_AT,      pcm_mulaw_at);
578 578
     REGISTER_DECODER(QDMC_AT,           qdmc_at);
579 579
     REGISTER_DECODER(QDM2_AT,           qdm2_at);
580 580
     REGISTER_DECODER(LIBCELT,           libcelt);
581 581
new file mode 100644
... ...
@@ -0,0 +1,471 @@
0
+/*
1
+ * Audio Toolbox system codecs
2
+ *
3
+ * copyright (c) 2016 Rodger Combs
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#include <AudioToolbox/AudioToolbox.h>
23
+
24
+#include "config.h"
25
+#include "audio_frame_queue.h"
26
+#include "avcodec.h"
27
+#include "bytestream.h"
28
+#include "internal.h"
29
+#include "libavformat/isom.h"
30
+#include "libavutil/avassert.h"
31
+#include "libavutil/opt.h"
32
+#include "libavutil/log.h"
33
+
34
+typedef struct ATDecodeContext {
35
+    AVClass *av_class;
36
+    int mode;
37
+    int quality;
38
+
39
+    AudioConverterRef converter;
40
+    AudioStreamPacketDescription pkt_desc;
41
+    AVFrame in_frame;
42
+    AVFrame new_in_frame;
43
+
44
+    unsigned pkt_size;
45
+    AudioFrameQueue afq;
46
+    int eof;
47
+    int frame_size;
48
+} ATDecodeContext;
49
+
50
+static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile)
51
+{
52
+    switch (codec) {
53
+    case AV_CODEC_ID_AAC:
54
+        switch (profile) {
55
+        case FF_PROFILE_AAC_LOW:
56
+        default:
57
+            return kAudioFormatMPEG4AAC;
58
+        case FF_PROFILE_AAC_HE:
59
+            return kAudioFormatMPEG4AAC_HE;
60
+        case FF_PROFILE_AAC_HE_V2:
61
+            return kAudioFormatMPEG4AAC_HE_V2;
62
+        case FF_PROFILE_AAC_LD:
63
+            return kAudioFormatMPEG4AAC_LD;
64
+        case FF_PROFILE_AAC_ELD:
65
+            return kAudioFormatMPEG4AAC_ELD;
66
+        }
67
+    case AV_CODEC_ID_ADPCM_IMA_QT:
68
+        return kAudioFormatAppleIMA4;
69
+    case AV_CODEC_ID_ALAC:
70
+        return kAudioFormatAppleLossless;
71
+    case AV_CODEC_ID_ILBC:
72
+        return kAudioFormatiLBC;
73
+    case AV_CODEC_ID_PCM_ALAW:
74
+        return kAudioFormatALaw;
75
+    case AV_CODEC_ID_PCM_MULAW:
76
+        return kAudioFormatULaw;
77
+    default:
78
+        av_assert0(!"Invalid codec ID!");
79
+        return 0;
80
+    }
81
+}
82
+
83
+static void ffat_update_ctx(AVCodecContext *avctx)
84
+{
85
+    ATDecodeContext *at = avctx->priv_data;
86
+    UInt32 size = sizeof(unsigned);
87
+    AudioConverterPrimeInfo prime_info;
88
+    AudioStreamBasicDescription out_format;
89
+
90
+    AudioConverterGetProperty(at->converter,
91
+                              kAudioConverterPropertyMaximumOutputPacketSize,
92
+                              &size, &at->pkt_size);
93
+
94
+    if (at->pkt_size <= 0)
95
+        at->pkt_size = 1024 * 50;
96
+
97
+    size = sizeof(prime_info);
98
+
99
+    if (!AudioConverterGetProperty(at->converter,
100
+                                   kAudioConverterPrimeInfo,
101
+                                   &size, &prime_info)) {
102
+        avctx->initial_padding = prime_info.leadingFrames;
103
+    }
104
+
105
+    size = sizeof(out_format);
106
+    if (!AudioConverterGetProperty(at->converter,
107
+                                   kAudioConverterCurrentOutputStreamDescription,
108
+                                   &size, &out_format)) {
109
+        if (out_format.mFramesPerPacket)
110
+            avctx->frame_size = out_format.mFramesPerPacket;
111
+        if (out_format.mBytesPerPacket && avctx->codec_id == AV_CODEC_ID_ILBC)
112
+            avctx->block_align = out_format.mBytesPerPacket;
113
+    }
114
+
115
+    at->frame_size = avctx->frame_size;
116
+    if (avctx->codec_id == AV_CODEC_ID_PCM_MULAW ||
117
+        avctx->codec_id == AV_CODEC_ID_PCM_ALAW) {
118
+        at->pkt_size *= 1024;
119
+        avctx->frame_size *= 1024;
120
+    }
121
+}
122
+
123
+static int read_descr(GetByteContext *gb, int *tag)
124
+{
125
+    int len = 0;
126
+    int count = 4;
127
+    *tag = bytestream2_get_byte(gb);
128
+    while (count--) {
129
+        int c = bytestream2_get_byte(gb);
130
+        len = (len << 7) | (c & 0x7f);
131
+        if (!(c & 0x80))
132
+            break;
133
+    }
134
+    return len;
135
+}
136
+
137
+static int get_ilbc_mode(AVCodecContext *avctx)
138
+{
139
+    if (avctx->block_align == 38)
140
+        return 20;
141
+    else if (avctx->block_align == 50)
142
+        return 30;
143
+    else if (avctx->bit_rate > 0)
144
+        return avctx->bit_rate <= 14000 ? 30 : 20;
145
+    else
146
+        return 30;
147
+}
148
+
149
+static av_cold int ffat_init_encoder(AVCodecContext *avctx)
150
+{
151
+    ATDecodeContext *at = avctx->priv_data;
152
+    OSStatus status;
153
+
154
+    AudioStreamBasicDescription in_format = {
155
+        .mSampleRate = avctx->sample_rate,
156
+        .mFormatID = kAudioFormatLinearPCM,
157
+        .mFormatFlags = ((avctx->sample_fmt == AV_SAMPLE_FMT_FLT ||
158
+                          avctx->sample_fmt == AV_SAMPLE_FMT_DBL) ? kAudioFormatFlagIsFloat
159
+                        : avctx->sample_fmt == AV_SAMPLE_FMT_U8 ? 0
160
+                        : kAudioFormatFlagIsSignedInteger)
161
+                        | kAudioFormatFlagIsPacked,
162
+        .mBytesPerPacket = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->channels,
163
+        .mFramesPerPacket = 1,
164
+        .mBytesPerFrame = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->channels,
165
+        .mChannelsPerFrame = avctx->channels,
166
+        .mBitsPerChannel = av_get_bytes_per_sample(avctx->sample_fmt) * 8,
167
+    };
168
+    AudioStreamBasicDescription out_format = {
169
+        .mSampleRate = avctx->sample_rate,
170
+        .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
171
+        .mChannelsPerFrame = in_format.mChannelsPerFrame,
172
+    };
173
+    AudioChannelLayout channel_layout = {
174
+        .mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelBitmap,
175
+        .mChannelBitmap = avctx->channel_layout,
176
+    };
177
+    UInt32 size = sizeof(channel_layout);
178
+
179
+    if (avctx->codec_id == AV_CODEC_ID_ILBC) {
180
+        int mode = get_ilbc_mode(avctx);
181
+        out_format.mFramesPerPacket  = 8000 * mode / 1000;
182
+        out_format.mBytesPerPacket   = (mode == 20 ? 38 : 50);
183
+    }
184
+
185
+    status = AudioConverterNew(&in_format, &out_format, &at->converter);
186
+
187
+    if (status != 0) {
188
+        av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n", (int)status);
189
+        return AVERROR_UNKNOWN;
190
+    }
191
+
192
+    size = sizeof(UInt32);
193
+
194
+    AudioConverterSetProperty(at->converter, kAudioConverterInputChannelLayout,
195
+                              size, &channel_layout);
196
+    AudioConverterSetProperty(at->converter, kAudioConverterOutputChannelLayout,
197
+                              size, &channel_layout);
198
+
199
+    if (avctx->bits_per_raw_sample) {
200
+        size = sizeof(avctx->bits_per_raw_sample);
201
+        AudioConverterSetProperty(at->converter,
202
+                                  kAudioConverterPropertyBitDepthHint,
203
+                                  size, &avctx->bits_per_raw_sample);
204
+    }
205
+
206
+    if (at->mode == -1)
207
+        at->mode = (avctx->flags & AV_CODEC_FLAG_QSCALE) ?
208
+                   kAudioCodecBitRateControlMode_Variable :
209
+                   kAudioCodecBitRateControlMode_Constant;
210
+
211
+    AudioConverterSetProperty(at->converter, kAudioCodecPropertyBitRateControlMode,
212
+                              size, &at->mode);
213
+
214
+    if (at->mode == kAudioCodecBitRateControlMode_Variable) {
215
+        int q = avctx->global_quality / FF_QP2LAMBDA;
216
+        if (q < 0 || q > 14) {
217
+            av_log(avctx, AV_LOG_WARNING,
218
+                   "VBR quality %d out of range, should be 0-14\n", q);
219
+            q = av_clip(q, 0, 14);
220
+        }
221
+        q = 127 - q * 9;
222
+        AudioConverterSetProperty(at->converter, kAudioCodecPropertySoundQualityForVBR,
223
+                                  size, &q);
224
+    } else if (avctx->bit_rate > 0) {
225
+        UInt32 rate = avctx->bit_rate;
226
+        AudioConverterSetProperty(at->converter, kAudioConverterEncodeBitRate,
227
+                                  size, &rate);
228
+    }
229
+
230
+    at->quality = 96 - at->quality * 32;
231
+    AudioConverterSetProperty(at->converter, kAudioConverterCodecQuality,
232
+                              size, &at->quality);
233
+
234
+    if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterCompressionMagicCookie,
235
+                                       &avctx->extradata_size, NULL) &&
236
+        avctx->extradata_size) {
237
+        int extradata_size = avctx->extradata_size;
238
+        uint8_t *extradata;
239
+        if (!(avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE)))
240
+            return AVERROR(ENOMEM);
241
+        if (avctx->codec_id == AV_CODEC_ID_ALAC) {
242
+            avctx->extradata_size = 0x24;
243
+            AV_WB32(avctx->extradata,     0x24);
244
+            AV_WB32(avctx->extradata + 4, MKBETAG('a','l','a','c'));
245
+            extradata = avctx->extradata + 12;
246
+            avctx->extradata_size = 0x24;
247
+        } else {
248
+            extradata = avctx->extradata;
249
+        }
250
+        status = AudioConverterGetProperty(at->converter,
251
+                                           kAudioConverterCompressionMagicCookie,
252
+                                           &extradata_size, extradata);
253
+        if (status != 0) {
254
+            av_log(avctx, AV_LOG_ERROR, "AudioToolbox cookie error: %i\n", (int)status);
255
+            return AVERROR_UNKNOWN;
256
+        } else if (avctx->codec_id == AV_CODEC_ID_AAC) {
257
+            GetByteContext gb;
258
+            int tag, len;
259
+            bytestream2_init(&gb, extradata, extradata_size);
260
+            do {
261
+                len = read_descr(&gb, &tag);
262
+                if (tag == MP4DecConfigDescrTag) {
263
+                    bytestream2_skip(&gb, 13);
264
+                    len = read_descr(&gb, &tag);
265
+                    if (tag == MP4DecSpecificDescrTag) {
266
+                        len = FFMIN(gb.buffer_end - gb.buffer, len);
267
+                        memmove(extradata, gb.buffer, len);
268
+                        avctx->extradata_size = len;
269
+                        break;
270
+                    }
271
+                } else if (tag == MP4ESDescrTag) {
272
+                    int flags;
273
+                    bytestream2_skip(&gb, 2);
274
+                    flags = bytestream2_get_byte(&gb);
275
+                    if (flags & 0x80) //streamDependenceFlag
276
+                        bytestream2_skip(&gb, 2);
277
+                    if (flags & 0x40) //URL_Flag
278
+                        bytestream2_skip(&gb, bytestream2_get_byte(&gb));
279
+                    if (flags & 0x20) //OCRstreamFlag
280
+                        bytestream2_skip(&gb, 2);
281
+                }
282
+            } while (bytestream2_get_bytes_left(&gb));
283
+        } else if (avctx->codec_id != AV_CODEC_ID_ALAC) {
284
+            avctx->extradata_size = extradata_size;
285
+        }
286
+    }
287
+
288
+    ffat_update_ctx(avctx);
289
+
290
+    if (at->mode == kAudioCodecBitRateControlMode_Variable && avctx->rc_max_rate) {
291
+        int max_size = avctx->rc_max_rate * avctx->frame_size / avctx->sample_rate;
292
+        if (max_size)
293
+        AudioConverterSetProperty(at->converter, kAudioCodecPropertyPacketSizeLimitForVBR,
294
+                                  size, &max_size);
295
+    }
296
+
297
+    ff_af_queue_init(avctx, &at->afq);
298
+
299
+    return 0;
300
+}
301
+
302
+static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_packets,
303
+                                     AudioBufferList *data,
304
+                                     AudioStreamPacketDescription **packets,
305
+                                     void *inctx)
306
+{
307
+    AVCodecContext *avctx = inctx;
308
+    ATDecodeContext *at = avctx->priv_data;
309
+
310
+    if (at->eof) {
311
+        *nb_packets = 0;
312
+        if (packets) {
313
+            *packets = &at->pkt_desc;
314
+            at->pkt_desc.mDataByteSize = 0;
315
+        }
316
+        return 0;
317
+    }
318
+
319
+    av_frame_unref(&at->in_frame);
320
+    av_frame_move_ref(&at->in_frame, &at->new_in_frame);
321
+
322
+    if (!at->in_frame.data[0]) {
323
+        *nb_packets = 0;
324
+        return 1;
325
+    }
326
+
327
+    data->mNumberBuffers              = 1;
328
+    data->mBuffers[0].mNumberChannels = 0;
329
+    data->mBuffers[0].mDataByteSize   = at->in_frame.nb_samples *
330
+                                        av_get_bytes_per_sample(avctx->sample_fmt) *
331
+                                        avctx->channels;
332
+    data->mBuffers[0].mData           = at->in_frame.data[0];
333
+    *nb_packets = (at->in_frame.nb_samples + (at->frame_size - 1)) / at->frame_size;
334
+
335
+    if (packets) {
336
+        *packets = &at->pkt_desc;
337
+        at->pkt_desc.mDataByteSize = data->mBuffers[0].mDataByteSize;
338
+        at->pkt_desc.mVariableFramesInPacket = at->in_frame.nb_samples;
339
+    }
340
+
341
+    return 0;
342
+}
343
+
344
+static int ffat_encode(AVCodecContext *avctx, AVPacket *avpkt,
345
+                       const AVFrame *frame, int *got_packet_ptr)
346
+{
347
+    ATDecodeContext *at = avctx->priv_data;
348
+    OSStatus ret;
349
+
350
+    AudioBufferList out_buffers = {
351
+        .mNumberBuffers = 1,
352
+        .mBuffers = {
353
+            {
354
+                .mNumberChannels = avctx->channels,
355
+                .mDataByteSize = at->pkt_size,
356
+            }
357
+        }
358
+    };
359
+    AudioStreamPacketDescription out_pkt_desc = {0};
360
+
361
+    if ((ret = ff_alloc_packet2(avctx, avpkt, at->pkt_size, 0)) < 0)
362
+        return ret;
363
+
364
+    av_frame_unref(&at->new_in_frame);
365
+
366
+    if (frame) {
367
+        if ((ret = ff_af_queue_add(&at->afq, frame)) < 0)
368
+            return ret;
369
+        if ((ret = av_frame_ref(&at->new_in_frame, frame)) < 0)
370
+            return ret;
371
+    } else {
372
+        at->eof = 1;
373
+    }
374
+
375
+    out_buffers.mBuffers[0].mData = avpkt->data;
376
+
377
+    *got_packet_ptr = avctx->frame_size / at->frame_size;
378
+
379
+    ret = AudioConverterFillComplexBuffer(at->converter, ffat_encode_callback, avctx,
380
+                                          got_packet_ptr, &out_buffers,
381
+                                          (avctx->frame_size > at->frame_size) ? NULL : &out_pkt_desc);
382
+    if ((!ret || ret == 1) && *got_packet_ptr) {
383
+        avpkt->size = out_buffers.mBuffers[0].mDataByteSize;
384
+        ff_af_queue_remove(&at->afq, out_pkt_desc.mVariableFramesInPacket ?
385
+                                     out_pkt_desc.mVariableFramesInPacket :
386
+                                     avctx->frame_size,
387
+                           &avpkt->pts,
388
+                           &avpkt->duration);
389
+    } else if (ret && ret != 1) {
390
+        av_log(avctx, AV_LOG_WARNING, "Encode error: %i\n", ret);
391
+    }
392
+
393
+    return 0;
394
+}
395
+
396
+static av_cold void ffat_encode_flush(AVCodecContext *avctx)
397
+{
398
+    ATDecodeContext *at = avctx->priv_data;
399
+    AudioConverterReset(at->converter);
400
+    av_frame_unref(&at->new_in_frame);
401
+    av_frame_unref(&at->in_frame);
402
+}
403
+
404
+static av_cold int ffat_close_encoder(AVCodecContext *avctx)
405
+{
406
+    ATDecodeContext *at = avctx->priv_data;
407
+    AudioConverterDispose(at->converter);
408
+    av_frame_unref(&at->new_in_frame);
409
+    av_frame_unref(&at->in_frame);
410
+    ff_af_queue_close(&at->afq);
411
+    return 0;
412
+}
413
+
414
+static const AVProfile aac_profiles[] = {
415
+    { FF_PROFILE_AAC_LOW,   "LC"       },
416
+    { FF_PROFILE_AAC_HE,    "HE-AAC"   },
417
+    { FF_PROFILE_AAC_HE_V2, "HE-AACv2" },
418
+    { FF_PROFILE_AAC_LD,    "LD"       },
419
+    { FF_PROFILE_AAC_ELD,   "ELD"      },
420
+    { FF_PROFILE_UNKNOWN },
421
+};
422
+
423
+#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
424
+static const AVOption options[] = {
425
+    {"aac_at_mode", "ratecontrol mode", offsetof(ATDecodeContext, mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, kAudioCodecBitRateControlMode_Variable, AE, "mode"},
426
+        {"auto", "VBR if global quality is given; CBR otherwise", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, INT_MIN, INT_MAX, AE, "mode"},
427
+        {"cbr",  "constant bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_Constant}, INT_MIN, INT_MAX, AE, "mode"},
428
+        {"abr",  "long-term average bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_LongTermAverage}, INT_MIN, INT_MAX, AE, "mode"},
429
+        {"cvbr", "constrained variable bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_VariableConstrained}, INT_MIN, INT_MAX, AE, "mode"},
430
+        {"vbr" , "variable bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_Variable}, INT_MIN, INT_MAX, AE, "mode"},
431
+    {"aac_at_quality", "quality vs speed control", offsetof(ATDecodeContext, quality), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, AE},
432
+    { NULL },
433
+};
434
+
435
+#define FFAT_ENC_CLASS(NAME) \
436
+    static const AVClass ffat_##NAME##_enc_class = { \
437
+        .class_name = "at_" #NAME "_enc", \
438
+        .item_name  = av_default_item_name, \
439
+        .option     = options, \
440
+        .version    = LIBAVUTIL_VERSION_INT, \
441
+    };
442
+
443
+#define FFAT_ENC(NAME, ID, PROFILES, ...) \
444
+    FFAT_ENC_CLASS(NAME) \
445
+    AVCodec ff_##NAME##_at_encoder = { \
446
+        .name           = #NAME "_at", \
447
+        .long_name      = NULL_IF_CONFIG_SMALL(#NAME " (AudioToolbox)"), \
448
+        .type           = AVMEDIA_TYPE_AUDIO, \
449
+        .id             = ID, \
450
+        .priv_data_size = sizeof(ATDecodeContext), \
451
+        .init           = ffat_init_encoder, \
452
+        .close          = ffat_close_encoder, \
453
+        .encode2        = ffat_encode, \
454
+        .flush          = ffat_encode_flush, \
455
+        .priv_class     = &ffat_##NAME##_enc_class, \
456
+        .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY __VA_ARGS__, \
457
+        .sample_fmts    = (const enum AVSampleFormat[]) { \
458
+            AV_SAMPLE_FMT_S16, \
459
+            AV_SAMPLE_FMT_U8,  AV_SAMPLE_FMT_NONE \
460
+        }, \
461
+        .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE, \
462
+        .profiles       = PROFILES, \
463
+    };
464
+
465
+FFAT_ENC(aac,          AV_CODEC_ID_AAC,          aac_profiles)
466
+//FFAT_ENC(adpcm_ima_qt, AV_CODEC_ID_ADPCM_IMA_QT, NULL)
467
+FFAT_ENC(alac,         AV_CODEC_ID_ALAC,         NULL, | AV_CODEC_CAP_VARIABLE_FRAME_SIZE | AV_CODEC_CAP_LOSSLESS)
468
+FFAT_ENC(ilbc,         AV_CODEC_ID_ILBC,         NULL)
469
+FFAT_ENC(pcm_alaw,     AV_CODEC_ID_PCM_ALAW,     NULL)
470
+FFAT_ENC(pcm_mulaw,    AV_CODEC_ID_PCM_MULAW,    NULL)
... ...
@@ -28,7 +28,7 @@
28 28
 #include "libavutil/version.h"
29 29
 
30 30
 #define LIBAVCODEC_VERSION_MAJOR  57
31
-#define LIBAVCODEC_VERSION_MINOR  29
31
+#define LIBAVCODEC_VERSION_MINOR  30
32 32
 #define LIBAVCODEC_VERSION_MICRO 100
33 33
 
34 34
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \