coreaudio-encoder: Use HE-AAC for low bitrates

master
Palana 2015-06-24 12:08:14 +02:00
parent eb6aa9ba47
commit e45f9f1b9a
2 changed files with 86 additions and 9 deletions

View File

@ -1,2 +1,3 @@
CoreAudioAAC="CoreAudio AAC encoder"
Bitrate="Bitrate"
AllowHEAAC="Allow HE-AAC"

View File

@ -23,6 +23,10 @@
struct ca_encoder {
obs_encoder_t *encoder;
const char *format_name;
UInt32 format_id;
const UInt32 *allowed_formats;
size_t num_allowed_formats;
AudioConverterRef converter;
@ -292,15 +296,29 @@ static bool create_encoder(ca_encoder *ca, AudioStreamBasicDescription *in,
sizeof(rate_control), &rate_control));
if (!bitrate_valid(ca, NULL, bitrate)) {
CA_BLOG(LOG_ERROR, "Encoder does not support bitrate %u",
(uint32_t)bitrate);
CA_BLOG(LOG_ERROR, "Encoder does not support bitrate %u for "
"format %s (0x%x)",
(uint32_t)bitrate, format_id_to_str(format_id),
(uint32_t)format_id);
return false;
}
ca->format_id = format_id;
return true;
#undef STATUS_CHECK
}
static const UInt32 aac_formats[] = {
kAudioFormatMPEG4AAC_HE_V2,
kAudioFormatMPEG4AAC_HE,
kAudioFormatMPEG4AAC,
};
static const UInt32 aac_lc_formats[] = {
kAudioFormatMPEG4AAC,
};
static void *aac_create(obs_data_t *settings, obs_encoder_t *encoder)
{
#define STATUS_CHECK(c) \
@ -355,9 +373,41 @@ static void *aac_create(obs_data_t *settings, obs_encoder_t *encoder)
AudioStreamBasicDescription out;
UInt32 rate_control = kAudioCodecBitRateControlMode_Constant;
if (!create_encoder(ca, &in, &out, kAudioFormatMPEG4AAC, bitrate,
rate_control))
#define USE_FORMATS(x) { \
ca->allowed_formats = x; \
ca->num_allowed_formats = sizeof(x)/sizeof(x[0]); \
}
if (obs_data_get_bool(settings, "allow he-aac")) {
USE_FORMATS(aac_formats);
} else {
USE_FORMATS(aac_lc_formats);
}
#undef USE_FORMATS
bool encoder_created = false;
for (size_t i = 0; i < ca->num_allowed_formats; i++) {
UInt32 format_id = ca->allowed_formats[i];
CA_BLOG(LOG_INFO, "Trying format %s (0x%x)",
format_id_to_str(format_id),
(uint32_t)format_id);
if (!create_encoder(ca, &in, &out, format_id, bitrate,
rate_control))
continue;
encoder_created = true;
break;
}
if (!encoder_created) {
CA_BLOG(LOG_ERROR, "Could not create encoder for "
"selected format%s",
ca->num_allowed_formats == 1 ? "" : "s");
goto free;
}
OSStatus code;
UInt32 converter_quality = kAudioConverterQuality_Max;
@ -407,12 +457,16 @@ static void *aac_create(obs_data_t *settings, obs_encoder_t *encoder)
ca->output_buffer = bmalloc(ca->output_buffer_size);
const char *format_name =
out.mFormatID == kAudioFormatMPEG4AAC_HE_V2 ? "HE-AAC v2" :
out.mFormatID == kAudioFormatMPEG4AAC_HE ? "HE-AAC" : "AAC";
CA_BLOG(LOG_INFO, "settings:\n"
"\tmode: %s\n"
"\tbitrate: %u\n"
"\tsample rate: %llu\n"
"\tcbr: %s\n"
"\toutput buffer: %lu",
bitrate / 1000, ca->samples_per_second,
format_name, bitrate / 1000, ca->samples_per_second,
rate_control == kAudioCodecBitRateControlMode_Constant ?
"on" : "off",
(unsigned long)ca->output_buffer_size);
@ -640,7 +694,7 @@ static bool aac_extra_data(void *data, uint8_t **extra_data, size_t *size)
return true;
}
static AudioConverterRef aac_default_converter(void)
static AudioConverterRef get_default_converter(UInt32 format_id)
{
UInt32 bytes_per_frame = 8;
UInt32 channels = 2;
@ -666,7 +720,7 @@ static AudioConverterRef aac_default_converter(void)
.mBytesPerFrame = 0,
.mFramesPerPacket = 0,
.mBitsPerChannel = 0,
.mFormatID = kAudioFormatMPEG4AAC,
.mFormatID = format_id,
.mFormatFlags = 0
};
@ -688,6 +742,16 @@ static AudioConverterRef aac_default_converter(void)
return converter;
}
static AudioConverterRef aac_default_converter(void)
{
return get_default_converter(kAudioFormatMPEG4AAC);
}
static AudioConverterRef he_aac_default_converter(void)
{
return get_default_converter(kAudioFormatMPEG4AAC_HE);
}
struct find_matching_bitrate_helper {
UInt32 bitrate;
UInt32 best_match;
@ -752,6 +816,7 @@ static void aac_defaults(obs_data_t *settings)
{
obs_data_set_default_int(settings, "bitrate",
find_matching_bitrate(128));
obs_data_set_default_bool(settings, "allow he-aac", true);
}
struct add_bitrates_helper {
@ -781,8 +846,16 @@ static void add_bitrates(obs_property_t *prop, ca_encoder *ca)
{
add_bitrates_helper helper = { 0 };
if (!enumerate_bitrates(ca, ca ? NULL : aac_default_converter(),
add_bitrates_func, &helper))
const size_t num_formats = ca ?
ca->num_allowed_formats :
sizeof(aac_formats)/sizeof(aac_formats[0]);
const UInt32 *allowed_formats = ca ? ca->allowed_formats : aac_formats;
for (size_t i = 0; i < num_formats; i++)
enumerate_bitrates(ca,
get_default_converter(allowed_formats[i]),
add_bitrates_func, &helper);
if (!helper.bitrates.num)
return;
qsort(helper.bitrates.array, helper.bitrates.num, sizeof(UInt32),
@ -809,6 +882,9 @@ static obs_properties_t *aac_properties(void *data)
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
add_bitrates(p, ca);
obs_properties_add_bool(props, "allow he-aac",
obs_module_text("AllowHEAAC"));
return props;
}