[FFmpeg-devel] [PATCH 2/6] lavc/audiotoolboxenc: fix a number of config issues
Rodger Combs
rodger.combs at gmail.com
Sun Mar 27 19:20:23 CEST 2016
- size variables were used in a confusing way
- incorrect size var use led to channel layouts not being set properly
- channel layouts were incorrectly mapped for >2-channel AAC
- bitrates not accepted by the encoder were discarded instead of being clamped
- some minor style/indentation fixes
---
libavcodec/audiotoolboxenc.c | 198 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 176 insertions(+), 22 deletions(-)
diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c
index 4797b2a..22352da 100644
--- a/libavcodec/audiotoolboxenc.c
+++ b/libavcodec/audiotoolboxenc.c
@@ -146,6 +146,86 @@ static int get_ilbc_mode(AVCodecContext *avctx)
return 30;
}
+static av_cold int get_channel_label(int channel)
+{
+ uint64_t map = 1 << channel;
+ if (map <= AV_CH_LOW_FREQUENCY)
+ return channel + 1;
+ else if (map <= AV_CH_BACK_RIGHT)
+ return channel + 29;
+ else if (map <= AV_CH_BACK_CENTER)
+ return channel - 1;
+ else if (map <= AV_CH_SIDE_RIGHT)
+ return channel - 4;
+ else if (map <= AV_CH_TOP_BACK_RIGHT)
+ return channel + 1;
+ else if (map <= AV_CH_STEREO_RIGHT)
+ return -1;
+ else if (map <= AV_CH_WIDE_RIGHT)
+ return channel + 4;
+ else if (map <= AV_CH_SURROUND_DIRECT_RIGHT)
+ return channel - 23;
+ else if (map == AV_CH_LOW_FREQUENCY_2)
+ return kAudioChannelLabel_LFE2;
+ else
+ return -1;
+}
+
+static int remap_layout(AudioChannelLayout *layout, uint64_t in_layout, int count)
+{
+ int i;
+ int c = 0;
+ layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+ layout->mNumberChannelDescriptions = count;
+ for (i = 0; i < count; i++) {
+ int label;
+ while (!(in_layout & (1 << c)) && c < 64)
+ c++;
+ if (c == 64)
+ return AVERROR(EINVAL); // This should never happen
+ label = get_channel_label(c);
+ layout->mChannelDescriptions[i].mChannelLabel = label;
+ if (label < 0)
+ return AVERROR(EINVAL);
+ c++;
+ }
+ return 0;
+}
+
+static int get_aac_tag(uint64_t in_layout)
+{
+ switch (in_layout) {
+ case AV_CH_LAYOUT_MONO:
+ return kAudioChannelLayoutTag_Mono;
+ case AV_CH_LAYOUT_STEREO:
+ return kAudioChannelLayoutTag_Stereo;
+ case AV_CH_LAYOUT_QUAD:
+ return kAudioChannelLayoutTag_AAC_Quadraphonic;
+ case AV_CH_LAYOUT_OCTAGONAL:
+ return kAudioChannelLayoutTag_AAC_Octagonal;
+ case AV_CH_LAYOUT_SURROUND:
+ return kAudioChannelLayoutTag_AAC_3_0;
+ case AV_CH_LAYOUT_4POINT0:
+ return kAudioChannelLayoutTag_AAC_4_0;
+ case AV_CH_LAYOUT_5POINT0:
+ return kAudioChannelLayoutTag_AAC_5_0;
+ case AV_CH_LAYOUT_5POINT1:
+ return kAudioChannelLayoutTag_AAC_5_1;
+ case AV_CH_LAYOUT_6POINT0:
+ return kAudioChannelLayoutTag_AAC_6_0;
+ case AV_CH_LAYOUT_6POINT1:
+ return kAudioChannelLayoutTag_AAC_6_1;
+ case AV_CH_LAYOUT_7POINT0:
+ return kAudioChannelLayoutTag_AAC_7_0;
+ case AV_CH_LAYOUT_7POINT1_WIDE_BACK:
+ return kAudioChannelLayoutTag_AAC_7_1;
+ case AV_CH_LAYOUT_7POINT1:
+ return kAudioChannelLayoutTag_MPEG_7_1_C;
+ default:
+ return 0;
+ }
+}
+
static av_cold int ffat_init_encoder(AVCodecContext *avctx)
{
ATDecodeContext *at = avctx->priv_data;
@@ -170,11 +250,12 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx)
.mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile),
.mChannelsPerFrame = in_format.mChannelsPerFrame,
};
- AudioChannelLayout channel_layout = {
- .mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelBitmap,
- .mChannelBitmap = avctx->channel_layout,
- };
- UInt32 size = sizeof(channel_layout);
+ UInt32 layout_size = sizeof(AudioChannelLayout) +
+ sizeof(AudioChannelDescription) * avctx->channels;
+ AudioChannelLayout *channel_layout = av_malloc(layout_size);
+
+ if (!channel_layout)
+ return AVERROR(ENOMEM);
if (avctx->codec_id == AV_CODEC_ID_ILBC) {
int mode = get_ilbc_mode(avctx);
@@ -186,22 +267,45 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx)
if (status != 0) {
av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n", (int)status);
+ av_free(channel_layout);
return AVERROR_UNKNOWN;
}
- size = sizeof(UInt32);
+ if (!avctx->channel_layout)
+ avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
+
+ if ((status = remap_layout(channel_layout, avctx->channel_layout, avctx->channels)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid channel layout\n");
+ av_free(channel_layout);
+ return status;
+ }
- AudioConverterSetProperty(at->converter, kAudioConverterInputChannelLayout,
- size, &channel_layout);
- AudioConverterSetProperty(at->converter, kAudioConverterOutputChannelLayout,
- size, &channel_layout);
+ if (AudioConverterSetProperty(at->converter, kAudioConverterInputChannelLayout,
+ layout_size, channel_layout)) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported input channel layout\n");
+ av_free(channel_layout);
+ return AVERROR(EINVAL);
+ }
+ if (avctx->codec_id == AV_CODEC_ID_AAC) {
+ int tag = get_aac_tag(avctx->channel_layout);
+ if (tag) {
+ channel_layout->mChannelLayoutTag = tag;
+ channel_layout->mNumberChannelDescriptions = 0;
+ }
+ }
+ if (AudioConverterSetProperty(at->converter, kAudioConverterOutputChannelLayout,
+ layout_size, channel_layout)) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported output channel layout\n");
+ av_free(channel_layout);
+ return AVERROR(EINVAL);
+ }
+ av_free(channel_layout);
- if (avctx->bits_per_raw_sample) {
- size = sizeof(avctx->bits_per_raw_sample);
+ if (avctx->bits_per_raw_sample)
AudioConverterSetProperty(at->converter,
kAudioConverterPropertyBitDepthHint,
- size, &avctx->bits_per_raw_sample);
- }
+ sizeof(avctx->bits_per_raw_sample),
+ &avctx->bits_per_raw_sample);
if (at->mode == -1)
at->mode = (avctx->flags & AV_CODEC_FLAG_QSCALE) ?
@@ -209,7 +313,7 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx)
kAudioCodecBitRateControlMode_Constant;
AudioConverterSetProperty(at->converter, kAudioCodecPropertyBitRateControlMode,
- size, &at->mode);
+ sizeof(at->mode), &at->mode);
if (at->mode == kAudioCodecBitRateControlMode_Variable) {
int q = avctx->global_quality / FF_QP2LAMBDA;
@@ -220,16 +324,50 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx)
}
q = 127 - q * 9;
AudioConverterSetProperty(at->converter, kAudioCodecPropertySoundQualityForVBR,
- size, &q);
+ sizeof(q), &q);
} else if (avctx->bit_rate > 0) {
UInt32 rate = avctx->bit_rate;
+ UInt32 size;
+ status = AudioConverterGetPropertyInfo(at->converter,
+ kAudioConverterApplicableEncodeBitRates,
+ &size, NULL);
+ if (!status && size) {
+ UInt32 new_rate = rate;
+ int count;
+ int i;
+ AudioValueRange *ranges = av_malloc(size);
+ if (!ranges)
+ return AVERROR(ENOMEM);
+ AudioConverterGetProperty(at->converter,
+ kAudioConverterApplicableEncodeBitRates,
+ &size, ranges);
+ count = size / sizeof(AudioValueRange);
+ for (i = 0; i < count; i++) {
+ AudioValueRange *range = &ranges[i];
+ if (rate >= range->mMinimum && rate <= range->mMaximum) {
+ new_rate = rate;
+ break;
+ } else if (rate > range->mMaximum) {
+ new_rate = range->mMaximum;
+ } else {
+ new_rate = range->mMinimum;
+ break;
+ }
+ }
+ if (new_rate != rate) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Bitrate %u not allowed; changing to %u\n", rate, new_rate);
+ rate = new_rate;
+ }
+ av_free(ranges);
+ }
AudioConverterSetProperty(at->converter, kAudioConverterEncodeBitRate,
- size, &rate);
+ sizeof(rate), &rate);
}
at->quality = 96 - at->quality * 32;
AudioConverterSetProperty(at->converter, kAudioConverterCodecQuality,
- size, &at->quality);
+ sizeof(at->quality), &at->quality);
if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterCompressionMagicCookie,
&avctx->extradata_size, NULL) &&
@@ -289,10 +427,10 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx)
#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
if (at->mode == kAudioCodecBitRateControlMode_Variable && avctx->rc_max_rate) {
- int max_size = avctx->rc_max_rate * avctx->frame_size / avctx->sample_rate;
+ UInt32 max_size = avctx->rc_max_rate * avctx->frame_size / avctx->sample_rate;
if (max_size)
- AudioConverterSetProperty(at->converter, kAudioCodecPropertyPacketSizeLimitForVBR,
- size, &max_size);
+ AudioConverterSetProperty(at->converter, kAudioCodecPropertyPacketSizeLimitForVBR,
+ sizeof(max_size), &max_size);
}
#endif
@@ -455,7 +593,23 @@ static const AVOption options[] = {
.profiles = PROFILES, \
};
-FFAT_ENC(aac, AV_CODEC_ID_AAC, aac_profiles)
+static const uint64_t aac_at_channel_layouts[] = {
+ AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_SURROUND,
+ AV_CH_LAYOUT_4POINT0,
+ AV_CH_LAYOUT_5POINT0,
+ AV_CH_LAYOUT_5POINT1,
+ AV_CH_LAYOUT_6POINT0,
+ AV_CH_LAYOUT_6POINT1,
+ AV_CH_LAYOUT_7POINT0,
+ AV_CH_LAYOUT_7POINT1_WIDE_BACK,
+ AV_CH_LAYOUT_QUAD,
+ AV_CH_LAYOUT_OCTAGONAL,
+ 0,
+};
+
+FFAT_ENC(aac, AV_CODEC_ID_AAC, aac_profiles, , .channel_layouts = aac_at_channel_layouts)
//FFAT_ENC(adpcm_ima_qt, AV_CODEC_ID_ADPCM_IMA_QT, NULL)
FFAT_ENC(alac, AV_CODEC_ID_ALAC, NULL, | AV_CODEC_CAP_VARIABLE_FRAME_SIZE | AV_CODEC_CAP_LOSSLESS)
FFAT_ENC(ilbc, AV_CODEC_ID_ILBC, NULL)
--
2.7.3
More information about the ffmpeg-devel
mailing list