blob: d999e5e8a2fcfe904c4d2071cfbb20ff2c222c33 [file] [log] [blame]
Rodger Combs65cff812016-02-24 03:01:241/*
2 * Audio Toolbox system codecs
3 *
rcombseabf5e62021-01-20 07:02:564 * copyright (c) 2016 rcombs
Rodger Combs65cff812016-02-24 03:01:245 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <AudioToolbox/AudioToolbox.h>
24
Rick Kern143685a2016-06-02 06:25:2125#define FF_BUFQUEUE_SIZE 256
26#include "libavfilter/bufferqueue.h"
27
Rodger Combs65cff812016-02-24 03:01:2428#include "config.h"
29#include "audio_frame_queue.h"
30#include "avcodec.h"
31#include "bytestream.h"
Andreas Rheinhardta688f3c2022-03-16 17:18:2832#include "codec_internal.h"
Andreas Rheinhardt56e9e022021-05-11 13:17:1333#include "encode.h"
Rodger Combs65cff812016-02-24 03:01:2434#include "internal.h"
35#include "libavformat/isom.h"
36#include "libavutil/avassert.h"
Andreas Rheinhardt1be3d8a2021-06-11 23:10:5837#include "libavutil/channel_layout.h"
Andreas Rheinhardt790f7932024-03-25 00:30:3738#include "libavutil/mem.h"
Rodger Combs65cff812016-02-24 03:01:2439#include "libavutil/opt.h"
40#include "libavutil/log.h"
41
42typedef struct ATDecodeContext {
43 AVClass *av_class;
44 int mode;
45 int quality;
46
47 AudioConverterRef converter;
Rick Kern143685a2016-06-02 06:25:2148 struct FFBufQueue frame_queue;
49 struct FFBufQueue used_frame_queue;
Rodger Combs65cff812016-02-24 03:01:2450
51 unsigned pkt_size;
52 AudioFrameQueue afq;
53 int eof;
54 int frame_size;
Jiejun Zhang677701c2018-01-03 04:54:2055
56 AVFrame* encoding_frame;
Rodger Combs65cff812016-02-24 03:01:2457} ATDecodeContext;
58
59static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile)
60{
61 switch (codec) {
62 case AV_CODEC_ID_AAC:
63 switch (profile) {
Andreas Rheinhardt8238bc02023-09-02 12:57:4164 case AV_PROFILE_AAC_LOW:
Rodger Combs65cff812016-02-24 03:01:2465 default:
66 return kAudioFormatMPEG4AAC;
Andreas Rheinhardt8238bc02023-09-02 12:57:4167 case AV_PROFILE_AAC_HE:
Rodger Combs65cff812016-02-24 03:01:2468 return kAudioFormatMPEG4AAC_HE;
Andreas Rheinhardt8238bc02023-09-02 12:57:4169 case AV_PROFILE_AAC_HE_V2:
Rodger Combs65cff812016-02-24 03:01:2470 return kAudioFormatMPEG4AAC_HE_V2;
Andreas Rheinhardt8238bc02023-09-02 12:57:4171 case AV_PROFILE_AAC_LD:
Rodger Combs65cff812016-02-24 03:01:2472 return kAudioFormatMPEG4AAC_LD;
Pavel Koshevoy35342dc2023-07-15 19:36:0373#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
Andreas Rheinhardt8238bc02023-09-02 12:57:4174 case AV_PROFILE_AAC_ELD:
Rodger Combs65cff812016-02-24 03:01:2475 return kAudioFormatMPEG4AAC_ELD;
Pavel Koshevoy35342dc2023-07-15 19:36:0376#endif
Rodger Combs65cff812016-02-24 03:01:2477 }
78 case AV_CODEC_ID_ADPCM_IMA_QT:
79 return kAudioFormatAppleIMA4;
80 case AV_CODEC_ID_ALAC:
81 return kAudioFormatAppleLossless;
Pavel Koshevoy35342dc2023-07-15 19:36:0382#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
Rodger Combs65cff812016-02-24 03:01:2483 case AV_CODEC_ID_ILBC:
84 return kAudioFormatiLBC;
Pavel Koshevoy35342dc2023-07-15 19:36:0385#endif
Rodger Combs65cff812016-02-24 03:01:2486 case AV_CODEC_ID_PCM_ALAW:
87 return kAudioFormatALaw;
88 case AV_CODEC_ID_PCM_MULAW:
89 return kAudioFormatULaw;
90 default:
91 av_assert0(!"Invalid codec ID!");
92 return 0;
93 }
94}
95
Zhao Zhili80cd6e62024-02-05 12:02:3096static int ffat_update_ctx(AVCodecContext *avctx)
Rodger Combs65cff812016-02-24 03:01:2497{
98 ATDecodeContext *at = avctx->priv_data;
99 UInt32 size = sizeof(unsigned);
100 AudioConverterPrimeInfo prime_info;
101 AudioStreamBasicDescription out_format;
102
103 AudioConverterGetProperty(at->converter,
104 kAudioConverterPropertyMaximumOutputPacketSize,
105 &size, &at->pkt_size);
106
107 if (at->pkt_size <= 0)
108 at->pkt_size = 1024 * 50;
109
110 size = sizeof(prime_info);
111
112 if (!AudioConverterGetProperty(at->converter,
113 kAudioConverterPrimeInfo,
114 &size, &prime_info)) {
115 avctx->initial_padding = prime_info.leadingFrames;
116 }
117
118 size = sizeof(out_format);
119 if (!AudioConverterGetProperty(at->converter,
120 kAudioConverterCurrentOutputStreamDescription,
121 &size, &out_format)) {
Zhao Zhili80cd6e62024-02-05 12:02:30122 if (out_format.mFramesPerPacket) {
Rodger Combs65cff812016-02-24 03:01:24123 avctx->frame_size = out_format.mFramesPerPacket;
Zhao Zhili80cd6e62024-02-05 12:02:30124 } else {
125 /* The doc on mFramesPerPacket says:
126 * For formats with a variable number of frames per packet, such as
127 * Ogg Vorbis, set this field to 0.
128 * Looks like it means for decoding. There is no known case that
129 * mFramesPerPacket is zero for encoding. Use a default value for safety.
130 */
131 avctx->frame_size = 1024;
132 av_log(avctx, AV_LOG_WARNING, "Missing mFramesPerPacket\n");
133 }
Rodger Combs65cff812016-02-24 03:01:24134 if (out_format.mBytesPerPacket && avctx->codec_id == AV_CODEC_ID_ILBC)
135 avctx->block_align = out_format.mBytesPerPacket;
Zhao Zhili80cd6e62024-02-05 12:02:30136 } else {
137 av_log(avctx, AV_LOG_ERROR, "Get OutputStreamDescription failed\n");
138 return AVERROR_EXTERNAL;
Rodger Combs65cff812016-02-24 03:01:24139 }
140
141 at->frame_size = avctx->frame_size;
142 if (avctx->codec_id == AV_CODEC_ID_PCM_MULAW ||
143 avctx->codec_id == AV_CODEC_ID_PCM_ALAW) {
144 at->pkt_size *= 1024;
145 avctx->frame_size *= 1024;
146 }
Zhao Zhili80cd6e62024-02-05 12:02:30147
148 return 0;
Rodger Combs65cff812016-02-24 03:01:24149}
150
151static int read_descr(GetByteContext *gb, int *tag)
152{
153 int len = 0;
154 int count = 4;
155 *tag = bytestream2_get_byte(gb);
156 while (count--) {
157 int c = bytestream2_get_byte(gb);
158 len = (len << 7) | (c & 0x7f);
159 if (!(c & 0x80))
160 break;
161 }
162 return len;
163}
164
165static int get_ilbc_mode(AVCodecContext *avctx)
166{
167 if (avctx->block_align == 38)
168 return 20;
169 else if (avctx->block_align == 50)
170 return 30;
171 else if (avctx->bit_rate > 0)
172 return avctx->bit_rate <= 14000 ? 30 : 20;
173 else
174 return 30;
175}
176
Rodger Combsc820e602016-03-23 21:46:39177static av_cold int get_channel_label(int channel)
178{
179 uint64_t map = 1 << channel;
180 if (map <= AV_CH_LOW_FREQUENCY)
181 return channel + 1;
182 else if (map <= AV_CH_BACK_RIGHT)
183 return channel + 29;
184 else if (map <= AV_CH_BACK_CENTER)
185 return channel - 1;
186 else if (map <= AV_CH_SIDE_RIGHT)
187 return channel - 4;
188 else if (map <= AV_CH_TOP_BACK_RIGHT)
189 return channel + 1;
190 else if (map <= AV_CH_STEREO_RIGHT)
191 return -1;
192 else if (map <= AV_CH_WIDE_RIGHT)
193 return channel + 4;
194 else if (map <= AV_CH_SURROUND_DIRECT_RIGHT)
195 return channel - 23;
196 else if (map == AV_CH_LOW_FREQUENCY_2)
197 return kAudioChannelLabel_LFE2;
198 else
199 return -1;
200}
201
Anton Khirnov411f2e02019-06-04 15:20:50202static int remap_layout(AudioChannelLayout *layout, const AVChannelLayout *in_layout)
Rodger Combsc820e602016-03-23 21:46:39203{
204 int i;
Rodger Combsc820e602016-03-23 21:46:39205 layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
Anton Khirnov411f2e02019-06-04 15:20:50206 layout->mNumberChannelDescriptions = in_layout->nb_channels;
207 for (i = 0; i < in_layout->nb_channels; i++) {
208 int c, label;
209
James Almer793c85b2022-03-15 13:18:53210 c = av_channel_layout_channel_from_index(in_layout, i);
Anton Khirnov411f2e02019-06-04 15:20:50211 if (c < 0 || c >= 64)
212 return AVERROR(EINVAL);
Rodger Combsc820e602016-03-23 21:46:39213 label = get_channel_label(c);
214 layout->mChannelDescriptions[i].mChannelLabel = label;
215 if (label < 0)
216 return AVERROR(EINVAL);
217 c++;
218 }
219 return 0;
220}
221
Anton Khirnov411f2e02019-06-04 15:20:50222static int get_aac_tag(const AVChannelLayout *in_layout)
Rodger Combsc820e602016-03-23 21:46:39223{
Anton Khirnov411f2e02019-06-04 15:20:50224 static const struct {
225 AVChannelLayout chl;
226 int tag;
227 } map[] = {
James Almera02663d2022-03-15 13:26:40228 { AV_CHANNEL_LAYOUT_MONO, kAudioChannelLayoutTag_Mono },
229 { AV_CHANNEL_LAYOUT_STEREO, kAudioChannelLayoutTag_Stereo },
230 { AV_CHANNEL_LAYOUT_QUAD, kAudioChannelLayoutTag_AAC_Quadraphonic },
231 { AV_CHANNEL_LAYOUT_OCTAGONAL, kAudioChannelLayoutTag_AAC_Octagonal },
232 { AV_CHANNEL_LAYOUT_SURROUND, kAudioChannelLayoutTag_AAC_3_0 },
233 { AV_CHANNEL_LAYOUT_4POINT0, kAudioChannelLayoutTag_AAC_4_0 },
234 { AV_CHANNEL_LAYOUT_5POINT0, kAudioChannelLayoutTag_AAC_5_0 },
235 { AV_CHANNEL_LAYOUT_5POINT1, kAudioChannelLayoutTag_AAC_5_1 },
236 { AV_CHANNEL_LAYOUT_6POINT0, kAudioChannelLayoutTag_AAC_6_0 },
237 { AV_CHANNEL_LAYOUT_6POINT1, kAudioChannelLayoutTag_AAC_6_1 },
238 { AV_CHANNEL_LAYOUT_7POINT0, kAudioChannelLayoutTag_AAC_7_0 },
239 { AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK, kAudioChannelLayoutTag_AAC_7_1 },
240 { AV_CHANNEL_LAYOUT_7POINT1, kAudioChannelLayoutTag_MPEG_7_1_C },
Anton Khirnov411f2e02019-06-04 15:20:50241 };
242 int i;
243
Martin Storsjö63838622022-03-15 13:25:04244 for (i = 0; i < FF_ARRAY_ELEMS(map); i++)
Anton Khirnov411f2e02019-06-04 15:20:50245 if (!av_channel_layout_compare(in_layout, &map[i].chl))
246 return map[i].tag;
247
248 return 0;
Rodger Combsc820e602016-03-23 21:46:39249}
250
Rodger Combs65cff812016-02-24 03:01:24251static av_cold int ffat_init_encoder(AVCodecContext *avctx)
252{
253 ATDecodeContext *at = avctx->priv_data;
254 OSStatus status;
Zhao Zhili80cd6e62024-02-05 12:02:30255 int ret;
Rodger Combs65cff812016-02-24 03:01:24256
257 AudioStreamBasicDescription in_format = {
258 .mSampleRate = avctx->sample_rate,
259 .mFormatID = kAudioFormatLinearPCM,
260 .mFormatFlags = ((avctx->sample_fmt == AV_SAMPLE_FMT_FLT ||
261 avctx->sample_fmt == AV_SAMPLE_FMT_DBL) ? kAudioFormatFlagIsFloat
262 : avctx->sample_fmt == AV_SAMPLE_FMT_U8 ? 0
263 : kAudioFormatFlagIsSignedInteger)
264 | kAudioFormatFlagIsPacked,
Anton Khirnov411f2e02019-06-04 15:20:50265 .mBytesPerPacket = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels,
Rodger Combs65cff812016-02-24 03:01:24266 .mFramesPerPacket = 1,
Anton Khirnov411f2e02019-06-04 15:20:50267 .mBytesPerFrame = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels,
268 .mChannelsPerFrame = avctx->ch_layout.nb_channels,
Rodger Combs65cff812016-02-24 03:01:24269 .mBitsPerChannel = av_get_bytes_per_sample(avctx->sample_fmt) * 8,
270 };
271 AudioStreamBasicDescription out_format = {
272 .mSampleRate = avctx->sample_rate,
273 .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
274 .mChannelsPerFrame = in_format.mChannelsPerFrame,
275 };
Rodger Combsc820e602016-03-23 21:46:39276 UInt32 layout_size = sizeof(AudioChannelLayout) +
Anton Khirnov411f2e02019-06-04 15:20:50277 sizeof(AudioChannelDescription) * avctx->ch_layout.nb_channels;
Rodger Combsc820e602016-03-23 21:46:39278 AudioChannelLayout *channel_layout = av_malloc(layout_size);
279
280 if (!channel_layout)
281 return AVERROR(ENOMEM);
Rodger Combs65cff812016-02-24 03:01:24282
283 if (avctx->codec_id == AV_CODEC_ID_ILBC) {
284 int mode = get_ilbc_mode(avctx);
285 out_format.mFramesPerPacket = 8000 * mode / 1000;
286 out_format.mBytesPerPacket = (mode == 20 ? 38 : 50);
287 }
288
289 status = AudioConverterNew(&in_format, &out_format, &at->converter);
290
291 if (status != 0) {
292 av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n", (int)status);
Rodger Combsc820e602016-03-23 21:46:39293 av_free(channel_layout);
Rodger Combs65cff812016-02-24 03:01:24294 return AVERROR_UNKNOWN;
295 }
296
Anton Khirnov411f2e02019-06-04 15:20:50297 if (avctx->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
298 av_channel_layout_default(&avctx->ch_layout, avctx->ch_layout.nb_channels);
Rodger Combs65cff812016-02-24 03:01:24299
Anton Khirnov411f2e02019-06-04 15:20:50300 if ((status = remap_layout(channel_layout, &avctx->ch_layout)) < 0) {
Rodger Combsc820e602016-03-23 21:46:39301 av_log(avctx, AV_LOG_ERROR, "Invalid channel layout\n");
302 av_free(channel_layout);
303 return status;
304 }
Rodger Combs65cff812016-02-24 03:01:24305
Rodger Combsc820e602016-03-23 21:46:39306 if (AudioConverterSetProperty(at->converter, kAudioConverterInputChannelLayout,
307 layout_size, channel_layout)) {
308 av_log(avctx, AV_LOG_ERROR, "Unsupported input channel layout\n");
309 av_free(channel_layout);
310 return AVERROR(EINVAL);
311 }
312 if (avctx->codec_id == AV_CODEC_ID_AAC) {
Anton Khirnov411f2e02019-06-04 15:20:50313 int tag = get_aac_tag(&avctx->ch_layout);
Rodger Combsc820e602016-03-23 21:46:39314 if (tag) {
315 channel_layout->mChannelLayoutTag = tag;
316 channel_layout->mNumberChannelDescriptions = 0;
317 }
318 }
319 if (AudioConverterSetProperty(at->converter, kAudioConverterOutputChannelLayout,
320 layout_size, channel_layout)) {
321 av_log(avctx, AV_LOG_ERROR, "Unsupported output channel layout\n");
322 av_free(channel_layout);
323 return AVERROR(EINVAL);
324 }
325 av_free(channel_layout);
326
327 if (avctx->bits_per_raw_sample)
Rodger Combs65cff812016-02-24 03:01:24328 AudioConverterSetProperty(at->converter,
329 kAudioConverterPropertyBitDepthHint,
Rodger Combsc820e602016-03-23 21:46:39330 sizeof(avctx->bits_per_raw_sample),
331 &avctx->bits_per_raw_sample);
Rodger Combs65cff812016-02-24 03:01:24332
Rodger Combs06673272016-03-24 15:17:42333#if !TARGET_OS_IPHONE
Rodger Combs65cff812016-02-24 03:01:24334 if (at->mode == -1)
335 at->mode = (avctx->flags & AV_CODEC_FLAG_QSCALE) ?
336 kAudioCodecBitRateControlMode_Variable :
337 kAudioCodecBitRateControlMode_Constant;
338
339 AudioConverterSetProperty(at->converter, kAudioCodecPropertyBitRateControlMode,
Rodger Combsc820e602016-03-23 21:46:39340 sizeof(at->mode), &at->mode);
Rodger Combs65cff812016-02-24 03:01:24341
342 if (at->mode == kAudioCodecBitRateControlMode_Variable) {
343 int q = avctx->global_quality / FF_QP2LAMBDA;
344 if (q < 0 || q > 14) {
345 av_log(avctx, AV_LOG_WARNING,
346 "VBR quality %d out of range, should be 0-14\n", q);
347 q = av_clip(q, 0, 14);
348 }
349 q = 127 - q * 9;
350 AudioConverterSetProperty(at->converter, kAudioCodecPropertySoundQualityForVBR,
Rodger Combsc820e602016-03-23 21:46:39351 sizeof(q), &q);
Rodger Combs06673272016-03-24 15:17:42352 } else
353#endif
354 if (avctx->bit_rate > 0) {
Rodger Combs65cff812016-02-24 03:01:24355 UInt32 rate = avctx->bit_rate;
Rodger Combsc820e602016-03-23 21:46:39356 UInt32 size;
357 status = AudioConverterGetPropertyInfo(at->converter,
358 kAudioConverterApplicableEncodeBitRates,
359 &size, NULL);
360 if (!status && size) {
361 UInt32 new_rate = rate;
362 int count;
363 int i;
364 AudioValueRange *ranges = av_malloc(size);
365 if (!ranges)
366 return AVERROR(ENOMEM);
367 AudioConverterGetProperty(at->converter,
368 kAudioConverterApplicableEncodeBitRates,
369 &size, ranges);
370 count = size / sizeof(AudioValueRange);
371 for (i = 0; i < count; i++) {
372 AudioValueRange *range = &ranges[i];
373 if (rate >= range->mMinimum && rate <= range->mMaximum) {
374 new_rate = rate;
375 break;
376 } else if (rate > range->mMaximum) {
377 new_rate = range->mMaximum;
378 } else {
379 new_rate = range->mMinimum;
380 break;
381 }
382 }
383 if (new_rate != rate) {
384 av_log(avctx, AV_LOG_WARNING,
385 "Bitrate %u not allowed; changing to %u\n", rate, new_rate);
386 rate = new_rate;
387 }
388 av_free(ranges);
389 }
Rodger Combs65cff812016-02-24 03:01:24390 AudioConverterSetProperty(at->converter, kAudioConverterEncodeBitRate,
Rodger Combsc820e602016-03-23 21:46:39391 sizeof(rate), &rate);
Rodger Combs65cff812016-02-24 03:01:24392 }
393
394 at->quality = 96 - at->quality * 32;
395 AudioConverterSetProperty(at->converter, kAudioConverterCodecQuality,
Rodger Combsc820e602016-03-23 21:46:39396 sizeof(at->quality), &at->quality);
Rodger Combs65cff812016-02-24 03:01:24397
398 if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterCompressionMagicCookie,
399 &avctx->extradata_size, NULL) &&
400 avctx->extradata_size) {
401 int extradata_size = avctx->extradata_size;
402 uint8_t *extradata;
403 if (!(avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE)))
404 return AVERROR(ENOMEM);
405 if (avctx->codec_id == AV_CODEC_ID_ALAC) {
406 avctx->extradata_size = 0x24;
407 AV_WB32(avctx->extradata, 0x24);
408 AV_WB32(avctx->extradata + 4, MKBETAG('a','l','a','c'));
409 extradata = avctx->extradata + 12;
410 avctx->extradata_size = 0x24;
411 } else {
412 extradata = avctx->extradata;
413 }
414 status = AudioConverterGetProperty(at->converter,
415 kAudioConverterCompressionMagicCookie,
416 &extradata_size, extradata);
417 if (status != 0) {
418 av_log(avctx, AV_LOG_ERROR, "AudioToolbox cookie error: %i\n", (int)status);
419 return AVERROR_UNKNOWN;
420 } else if (avctx->codec_id == AV_CODEC_ID_AAC) {
421 GetByteContext gb;
422 int tag, len;
423 bytestream2_init(&gb, extradata, extradata_size);
424 do {
425 len = read_descr(&gb, &tag);
426 if (tag == MP4DecConfigDescrTag) {
427 bytestream2_skip(&gb, 13);
428 len = read_descr(&gb, &tag);
429 if (tag == MP4DecSpecificDescrTag) {
430 len = FFMIN(gb.buffer_end - gb.buffer, len);
431 memmove(extradata, gb.buffer, len);
432 avctx->extradata_size = len;
433 break;
434 }
435 } else if (tag == MP4ESDescrTag) {
436 int flags;
437 bytestream2_skip(&gb, 2);
438 flags = bytestream2_get_byte(&gb);
439 if (flags & 0x80) //streamDependenceFlag
440 bytestream2_skip(&gb, 2);
441 if (flags & 0x40) //URL_Flag
442 bytestream2_skip(&gb, bytestream2_get_byte(&gb));
443 if (flags & 0x20) //OCRstreamFlag
444 bytestream2_skip(&gb, 2);
445 }
446 } while (bytestream2_get_bytes_left(&gb));
447 } else if (avctx->codec_id != AV_CODEC_ID_ALAC) {
448 avctx->extradata_size = extradata_size;
449 }
450 }
451
Zhao Zhili80cd6e62024-02-05 12:02:30452 ret = ffat_update_ctx(avctx);
453 if (ret < 0)
454 return ret;
Rodger Combs65cff812016-02-24 03:01:24455
Rodger Combs36770d82016-03-27 17:17:25456#if !TARGET_OS_IPHONE && defined(__MAC_10_9)
Rodger Combs65cff812016-02-24 03:01:24457 if (at->mode == kAudioCodecBitRateControlMode_Variable && avctx->rc_max_rate) {
Rodger Combsc820e602016-03-23 21:46:39458 UInt32 max_size = avctx->rc_max_rate * avctx->frame_size / avctx->sample_rate;
Rodger Combs65cff812016-02-24 03:01:24459 if (max_size)
Rodger Combsc820e602016-03-23 21:46:39460 AudioConverterSetProperty(at->converter, kAudioCodecPropertyPacketSizeLimitForVBR,
461 sizeof(max_size), &max_size);
Rodger Combs65cff812016-02-24 03:01:24462 }
Dan Dennedy28688d72016-03-25 04:13:18463#endif
Rodger Combs65cff812016-02-24 03:01:24464
465 ff_af_queue_init(avctx, &at->afq);
466
Jiejun Zhang677701c2018-01-03 04:54:20467 at->encoding_frame = av_frame_alloc();
468 if (!at->encoding_frame)
469 return AVERROR(ENOMEM);
470
Rodger Combs65cff812016-02-24 03:01:24471 return 0;
472}
473
474static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_packets,
475 AudioBufferList *data,
476 AudioStreamPacketDescription **packets,
477 void *inctx)
478{
479 AVCodecContext *avctx = inctx;
480 ATDecodeContext *at = avctx->priv_data;
Rick Kern143685a2016-06-02 06:25:21481 AVFrame *frame;
Jiejun Zhang677701c2018-01-03 04:54:20482 int ret;
Rodger Combs65cff812016-02-24 03:01:24483
Rick Kern143685a2016-06-02 06:25:21484 if (!at->frame_queue.available) {
485 if (at->eof) {
486 *nb_packets = 0;
487 return 0;
488 } else {
489 *nb_packets = 0;
490 return 1;
491 }
Rodger Combs65cff812016-02-24 03:01:24492 }
493
Rick Kern143685a2016-06-02 06:25:21494 frame = ff_bufqueue_get(&at->frame_queue);
Rodger Combs65cff812016-02-24 03:01:24495
496 data->mNumberBuffers = 1;
Anton Khirnov411f2e02019-06-04 15:20:50497 data->mBuffers[0].mNumberChannels = avctx->ch_layout.nb_channels;
Rick Kern143685a2016-06-02 06:25:21498 data->mBuffers[0].mDataByteSize = frame->nb_samples *
Rodger Combs65cff812016-02-24 03:01:24499 av_get_bytes_per_sample(avctx->sample_fmt) *
Anton Khirnov411f2e02019-06-04 15:20:50500 avctx->ch_layout.nb_channels;
Rick Kern143685a2016-06-02 06:25:21501 data->mBuffers[0].mData = frame->data[0];
502 if (*nb_packets > frame->nb_samples)
503 *nb_packets = frame->nb_samples;
504
Andreas Rheinhardtcfa47fd2023-09-07 10:02:26505 ret = av_frame_replace(at->encoding_frame, frame);
Jiejun Zhang677701c2018-01-03 04:54:20506 if (ret < 0) {
507 *nb_packets = 0;
508 return ret;
509 }
510
Rick Kern143685a2016-06-02 06:25:21511 ff_bufqueue_add(avctx, &at->used_frame_queue, frame);
Rodger Combs65cff812016-02-24 03:01:24512
513 return 0;
514}
515
516static int ffat_encode(AVCodecContext *avctx, AVPacket *avpkt,
517 const AVFrame *frame, int *got_packet_ptr)
518{
519 ATDecodeContext *at = avctx->priv_data;
520 OSStatus ret;
521
522 AudioBufferList out_buffers = {
523 .mNumberBuffers = 1,
524 .mBuffers = {
525 {
Anton Khirnov411f2e02019-06-04 15:20:50526 .mNumberChannels = avctx->ch_layout.nb_channels,
Rodger Combs65cff812016-02-24 03:01:24527 .mDataByteSize = at->pkt_size,
528 }
529 }
530 };
531 AudioStreamPacketDescription out_pkt_desc = {0};
532
Rodger Combs65cff812016-02-24 03:01:24533 if (frame) {
Rick Kern143685a2016-06-02 06:25:21534 AVFrame *in_frame;
535
536 if (ff_bufqueue_is_full(&at->frame_queue)) {
537 /*
538 * The frame queue is significantly larger than needed in practice,
539 * but no clear way to determine the minimum number of samples to
540 * get output from AudioConverterFillComplexBuffer().
541 */
542 av_log(avctx, AV_LOG_ERROR, "Bug: frame queue is too small.\n");
543 return AVERROR_BUG;
544 }
545
Rodger Combs65cff812016-02-24 03:01:24546 if ((ret = ff_af_queue_add(&at->afq, frame)) < 0)
547 return ret;
Rick Kern143685a2016-06-02 06:25:21548
549 in_frame = av_frame_clone(frame);
550 if (!in_frame)
551 return AVERROR(ENOMEM);
552
553 ff_bufqueue_add(avctx, &at->frame_queue, in_frame);
Rodger Combs65cff812016-02-24 03:01:24554 } else {
555 at->eof = 1;
556 }
557
Andreas Rheinhardt56e9e022021-05-11 13:17:13558 if ((ret = ff_alloc_packet(avctx, avpkt, at->pkt_size)) < 0)
Rick Kern143685a2016-06-02 06:25:21559 return ret;
560
561
Rodger Combs65cff812016-02-24 03:01:24562 out_buffers.mBuffers[0].mData = avpkt->data;
563
564 *got_packet_ptr = avctx->frame_size / at->frame_size;
565
566 ret = AudioConverterFillComplexBuffer(at->converter, ffat_encode_callback, avctx,
567 got_packet_ptr, &out_buffers,
568 (avctx->frame_size > at->frame_size) ? NULL : &out_pkt_desc);
Rick Kern143685a2016-06-02 06:25:21569
570 ff_bufqueue_discard_all(&at->used_frame_queue);
571
Rodger Combs65cff812016-02-24 03:01:24572 if ((!ret || ret == 1) && *got_packet_ptr) {
573 avpkt->size = out_buffers.mBuffers[0].mDataByteSize;
574 ff_af_queue_remove(&at->afq, out_pkt_desc.mVariableFramesInPacket ?
575 out_pkt_desc.mVariableFramesInPacket :
576 avctx->frame_size,
577 &avpkt->pts,
578 &avpkt->duration);
James Almer495c8912024-11-24 23:24:40579 avpkt->flags |= AV_PKT_FLAG_KEY;
Rodger Combs65cff812016-02-24 03:01:24580 } else if (ret && ret != 1) {
Steven Liu7c05b792022-06-24 05:55:41581 av_log(avctx, AV_LOG_ERROR, "Encode error: %i\n", ret);
Steven Liu627543f2022-06-28 16:14:08582 return AVERROR_EXTERNAL;
Rodger Combs65cff812016-02-24 03:01:24583 }
584
Steven Liu627543f2022-06-28 16:14:08585 return 0;
Rodger Combs65cff812016-02-24 03:01:24586}
587
588static av_cold void ffat_encode_flush(AVCodecContext *avctx)
589{
590 ATDecodeContext *at = avctx->priv_data;
591 AudioConverterReset(at->converter);
Rick Kern143685a2016-06-02 06:25:21592 ff_bufqueue_discard_all(&at->frame_queue);
593 ff_bufqueue_discard_all(&at->used_frame_queue);
Rodger Combs65cff812016-02-24 03:01:24594}
595
596static av_cold int ffat_close_encoder(AVCodecContext *avctx)
597{
598 ATDecodeContext *at = avctx->priv_data;
599 AudioConverterDispose(at->converter);
Rick Kern143685a2016-06-02 06:25:21600 ff_bufqueue_discard_all(&at->frame_queue);
601 ff_bufqueue_discard_all(&at->used_frame_queue);
Rodger Combs65cff812016-02-24 03:01:24602 ff_af_queue_close(&at->afq);
Jiejun Zhang677701c2018-01-03 04:54:20603 av_frame_free(&at->encoding_frame);
Rodger Combs65cff812016-02-24 03:01:24604 return 0;
605}
606
607static const AVProfile aac_profiles[] = {
Andreas Rheinhardt8238bc02023-09-02 12:57:41608 { AV_PROFILE_AAC_LOW, "LC" },
609 { AV_PROFILE_AAC_HE, "HE-AAC" },
610 { AV_PROFILE_AAC_HE_V2, "HE-AACv2" },
611 { AV_PROFILE_AAC_LD, "LD" },
612 { AV_PROFILE_AAC_ELD, "ELD" },
613 { AV_PROFILE_UNKNOWN },
Rodger Combs65cff812016-02-24 03:01:24614};
615
616#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
617static const AVOption options[] = {
Rodger Combs06673272016-03-24 15:17:42618#if !TARGET_OS_IPHONE
Anton Khirnov1e7d2002024-02-11 14:41:05619 {"aac_at_mode", "ratecontrol mode", offsetof(ATDecodeContext, mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, kAudioCodecBitRateControlMode_Variable, AE, .unit = "mode"},
620 {"auto", "VBR if global quality is given; CBR otherwise", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, INT_MIN, INT_MAX, AE, .unit = "mode"},
621 {"cbr", "constant bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_Constant}, INT_MIN, INT_MAX, AE, .unit = "mode"},
622 {"abr", "long-term average bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_LongTermAverage}, INT_MIN, INT_MAX, AE, .unit = "mode"},
623 {"cvbr", "constrained variable bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_VariableConstrained}, INT_MIN, INT_MAX, AE, .unit = "mode"},
624 {"vbr" , "variable bitrate", 0, AV_OPT_TYPE_CONST, {.i64 = kAudioCodecBitRateControlMode_Variable}, INT_MIN, INT_MAX, AE, .unit = "mode"},
Rodger Combs06673272016-03-24 15:17:42625#endif
Rodger Combs65cff812016-02-24 03:01:24626 {"aac_at_quality", "quality vs speed control", offsetof(ATDecodeContext, quality), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, AE},
627 { NULL },
628};
629
630#define FFAT_ENC_CLASS(NAME) \
631 static const AVClass ffat_##NAME##_enc_class = { \
632 .class_name = "at_" #NAME "_enc", \
Anton Khirnov08bebeb2024-01-19 12:33:28633 .item_name = av_default_item_name, \
Rodger Combs65cff812016-02-24 03:01:24634 .option = options, \
635 .version = LIBAVUTIL_VERSION_INT, \
636 };
637
James Almerf0be7c12022-03-15 13:57:08638#define FFAT_ENC(NAME, ID, PROFILES, CAPS, CHANNEL_LAYOUTS, CH_LAYOUTS) \
Rodger Combs65cff812016-02-24 03:01:24639 FFAT_ENC_CLASS(NAME) \
Andreas Rheinhardt20f97272022-03-16 20:09:54640 const FFCodec ff_##NAME##_at_encoder = { \
641 .p.name = #NAME "_at", \
Andreas Rheinhardt48286d42022-08-29 11:38:02642 CODEC_LONG_NAME(#NAME " (AudioToolbox)"), \
Andreas Rheinhardt20f97272022-03-16 20:09:54643 .p.type = AVMEDIA_TYPE_AUDIO, \
644 .p.id = ID, \
Rodger Combs65cff812016-02-24 03:01:24645 .priv_data_size = sizeof(ATDecodeContext), \
646 .init = ffat_init_encoder, \
647 .close = ffat_close_encoder, \
Andreas Rheinhardt4243da42022-03-30 21:28:24648 FF_CODEC_ENCODE_CB(ffat_encode), \
Rodger Combs65cff812016-02-24 03:01:24649 .flush = ffat_encode_flush, \
Andreas Rheinhardt20f97272022-03-16 20:09:54650 .p.priv_class = &ffat_##NAME##_enc_class, \
651 .p.capabilities = AV_CODEC_CAP_DELAY | \
James Almerf0be7c12022-03-15 13:57:08652 AV_CODEC_CAP_ENCODER_FLUSH CAPS, \
Andreas Rheinhardt20f97272022-03-16 20:09:54653 .p.profiles = PROFILES, \
654 .p.wrapper_name = "at", \
Andreas Rheinhardt0971fcf2025-03-07 00:19:27655 CODEC_CH_LAYOUTS_ARRAY(CH_LAYOUTS), \
656 CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), \
Rodger Combs65cff812016-02-24 03:01:24657 };
658
James Almerf0be7c12022-03-15 13:57:08659static const AVChannelLayout aac_at_ch_layouts[] = {
660 AV_CHANNEL_LAYOUT_MONO,
661 AV_CHANNEL_LAYOUT_STEREO,
662 AV_CHANNEL_LAYOUT_SURROUND,
663 AV_CHANNEL_LAYOUT_4POINT0,
664 AV_CHANNEL_LAYOUT_5POINT0,
665 AV_CHANNEL_LAYOUT_5POINT1,
666 AV_CHANNEL_LAYOUT_6POINT0,
667 AV_CHANNEL_LAYOUT_6POINT1,
668 AV_CHANNEL_LAYOUT_7POINT0,
669 AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK,
670 AV_CHANNEL_LAYOUT_QUAD,
671 AV_CHANNEL_LAYOUT_OCTAGONAL,
672 { 0 },
673};
674
James Almerf0be7c12022-03-15 13:57:08675FFAT_ENC(aac, AV_CODEC_ID_AAC, aac_profiles, , aac_at_channel_layouts, aac_at_ch_layouts)
Rodger Combs65cff812016-02-24 03:01:24676//FFAT_ENC(adpcm_ima_qt, AV_CODEC_ID_ADPCM_IMA_QT, NULL)
Zhao Zhili338e33b2024-02-05 11:57:25677FFAT_ENC(alac, AV_CODEC_ID_ALAC, NULL, , NULL, NULL)
James Almerf0be7c12022-03-15 13:57:08678FFAT_ENC(ilbc, AV_CODEC_ID_ILBC, NULL, , NULL, NULL)
679FFAT_ENC(pcm_alaw, AV_CODEC_ID_PCM_ALAW, NULL, , NULL, NULL)
680FFAT_ENC(pcm_mulaw, AV_CODEC_ID_PCM_MULAW, NULL, , NULL, NULL)