lavc/audiotoolboxenc: fix a number of config issues

- 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
This commit is contained in:
Rodger Combs 2016-03-23 16:46:39 -05:00
parent 7524b67817
commit c820e600ea
1 changed files with 176 additions and 22 deletions

View File

@ -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);
AudioConverterSetProperty(at->converter, kAudioConverterInputChannelLayout,
size, &channel_layout);
AudioConverterSetProperty(at->converter, kAudioConverterOutputChannelLayout,
size, &channel_layout);
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;
}
if (avctx->bits_per_raw_sample) {
size = sizeof(avctx->bits_per_raw_sample);
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)
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)