Commit 0f4334df authored by Rostislav Pehlivanov's avatar Rostislav Pehlivanov

aacenc: add support for changing options based on a profile

This commit adds the ability for a profile to set the default
options, as well as for the user to override such options
by simply stating them in the command line while still keeping
the same profile, as long as those options are still permitted by
the profile.

Example: setting the profile to aac_low (the default) will turn
PNS and IS on. They can be disabled by -aac_pns 0 and -aac_is 0,
respectively. Turning on -aac_pred 1 will cause the profile to be
elevated to aac_main, as long as no options forbidding aac_main
have been entered (like AAC-LTP, which will be pushed soon).

A useful feature is that by setting the profile to mpeg2_aac_low,
all MPEG4 features will be disabled and if the user tries to enable
them then the program will exit with an error. This profile is
signalled with the same bitstream as aac_low (MPEG4) but some devices
and decoders will fail if any MPEG4 features have been enabled.
parent cf28490e
...@@ -142,7 +142,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, ...@@ -142,7 +142,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
* No need to be overly precise, this only controls RD * No need to be overly precise, this only controls RD
* adjustment CB limits when going overboard * adjustment CB limits when going overboard
*/ */
if (s->options.stereo_mode && s->cur_type == TYPE_CPE) if (s->options.mid_side && s->cur_type == TYPE_CPE)
destbits *= 2; destbits *= 2;
/** /**
......
...@@ -46,6 +46,44 @@ ...@@ -46,6 +46,44 @@
#include "psymodel.h" #include "psymodel.h"
struct AACProfileOptions {
int profile;
struct AACEncOptions opts;
};
/**
* List of currently supported profiles, anything not listed isn't supported.
*/
static const struct AACProfileOptions aacenc_profiles[] = {
{FF_PROFILE_AAC_MAIN,
{ /* Main profile, all advanced encoding abilities enabled */
.mid_side = 0,
.pns = 1,
.tns = 0,
.pred = OPT_REQUIRED,
.intensity_stereo = 1,
},
},
{FF_PROFILE_AAC_LOW,
{ /* Default profile, these are the settings that get set by default */
.mid_side = 0,
.pns = 1,
.tns = 0,
.pred = OPT_NEEDS_MAIN,
.intensity_stereo = 1,
},
},
{FF_PROFILE_MPEG2_AAC_LOW,
{ /* Strict MPEG 2 Part 7 compliance profile */
.mid_side = 0,
.pns = OPT_BANNED,
.tns = 0,
.pred = OPT_BANNED,
.intensity_stereo = 1,
},
},
};
/** /**
* Make AAC audio config object. * Make AAC audio config object.
* @see 1.6.2.1 "Syntax - AudioSpecificConfig" * @see 1.6.2.1 "Syntax - AudioSpecificConfig"
...@@ -690,8 +728,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ...@@ -690,8 +728,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
} }
s->cur_channel = start_ch; s->cur_channel = start_ch;
} }
if (s->options.stereo_mode) { /* Mid/Side stereo */ if (s->options.mid_side) { /* Mid/Side stereo */
if (s->options.stereo_mode == -1 && s->coder->search_for_ms) if (s->options.mid_side == -1 && s->coder->search_for_ms)
s->coder->search_for_ms(s, cpe); s->coder->search_for_ms(s, cpe);
else if (cpe->common_window) else if (cpe->common_window)
memset(cpe->ms_mask, 1, sizeof(cpe->ms_mask)); memset(cpe->ms_mask, 1, sizeof(cpe->ms_mask));
...@@ -852,82 +890,88 @@ alloc_fail: ...@@ -852,82 +890,88 @@ alloc_fail:
static av_cold int aac_encode_init(AVCodecContext *avctx) static av_cold int aac_encode_init(AVCodecContext *avctx)
{ {
AACEncContext *s = avctx->priv_data; AACEncContext *s = avctx->priv_data;
const AACEncOptions *p_opt = NULL;
int i, ret = 0; int i, ret = 0;
const uint8_t *sizes[2]; const uint8_t *sizes[2];
uint8_t grouping[AAC_MAX_CHANNELS]; uint8_t grouping[AAC_MAX_CHANNELS];
int lengths[2]; int lengths[2];
s->channels = avctx->channels;
s->chan_map = aac_chan_configs[s->channels-1];
s->random_state = 0x1f2e3d4c;
s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120;
avctx->extradata_size = 5;
avctx->frame_size = 1024; avctx->frame_size = 1024;
avctx->initial_padding = 1024;
avctx->bit_rate = (int)FFMIN(
6144 * s->channels / 1024.0 * avctx->sample_rate,
avctx->bit_rate);
avctx->profile = avctx->profile == FF_PROFILE_UNKNOWN ? FF_PROFILE_AAC_LOW :
avctx->profile;
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[i]) if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[i])
break; break;
s->samplerate_index = i;
s->channels = avctx->channels; ERROR_IF(s->samplerate_index == 16 ||
s->samplerate_index >= ff_aac_swb_size_1024_len ||
ERROR_IF(i == 16 || i >= ff_aac_swb_size_1024_len || i >= ff_aac_swb_size_128_len, s->samplerate_index >= ff_aac_swb_size_128_len,
"Unsupported sample rate %d\n", avctx->sample_rate); "Unsupported sample rate %d\n", avctx->sample_rate);
ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7, ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7,
"Unsupported number of channels: %d\n", s->channels); "Unsupported number of channels: %d\n", s->channels);
WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels, WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels,
"Too many bits per frame requested, clamping to max\n"); "Too many bits per frame requested, clamping to max\n");
if (avctx->profile == FF_PROFILE_AAC_MAIN) {
s->options.pred = 1; for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++) {
} else if ((avctx->profile == FF_PROFILE_AAC_LOW || if (avctx->profile == aacenc_profiles[i].profile) {
avctx->profile == FF_PROFILE_UNKNOWN) && s->options.pred) { p_opt = &aacenc_profiles[i].opts;
s->profile = 0; /* Main */ break;
WARN_IF(1, "Prediction requested, changing profile to AAC-Main\n"); }
} else if (avctx->profile == FF_PROFILE_AAC_LOW ||
avctx->profile == FF_PROFILE_UNKNOWN) {
s->profile = 1; /* Low */
} else {
ERROR_IF(1, "Unsupported profile %d\n", avctx->profile);
} }
ERROR_IF(!p_opt, "Unsupported encoding profile: %d\n", avctx->profile);
AAC_OPT_SET(&s->options, p_opt, 1, coder);
AAC_OPT_SET(&s->options, p_opt, 0, pns);
AAC_OPT_SET(&s->options, p_opt, 0, tns);
AAC_OPT_SET(&s->options, p_opt, 0, pred);
AAC_OPT_SET(&s->options, p_opt, 1, mid_side);
AAC_OPT_SET(&s->options, p_opt, 0, intensity_stereo);
if (avctx->profile == FF_PROFILE_MPEG2_AAC_LOW)
s->profile = FF_PROFILE_AAC_LOW;
else
s->profile = avctx->profile;
s->coder = &ff_aac_coders[s->options.coder];
if (s->options.aac_coder != AAC_CODER_TWOLOOP) { if (s->options.coder != AAC_CODER_TWOLOOP) {
s->options.intensity_stereo = 0; s->options.intensity_stereo = 0;
s->options.pns = 0; s->options.pns = 0;
} }
avctx->bit_rate = (int)FFMIN(
6144 * s->channels / 1024.0 * avctx->sample_rate,
avctx->bit_rate);
s->samplerate_index = i;
s->chan_map = aac_chan_configs[s->channels-1];
if ((ret = dsp_init(avctx, s)) < 0) if ((ret = dsp_init(avctx, s)) < 0)
goto fail; goto fail;
if ((ret = alloc_buffers(avctx, s)) < 0) if ((ret = alloc_buffers(avctx, s)) < 0)
goto fail; goto fail;
avctx->extradata_size = 5;
put_audio_specific_config(avctx); put_audio_specific_config(avctx);
sizes[0] = ff_aac_swb_size_1024[i]; sizes[0] = ff_aac_swb_size_1024[s->samplerate_index];
sizes[1] = ff_aac_swb_size_128[i]; sizes[1] = ff_aac_swb_size_128[s->samplerate_index];
lengths[0] = ff_aac_num_swb_1024[i]; lengths[0] = ff_aac_num_swb_1024[s->samplerate_index];
lengths[1] = ff_aac_num_swb_128[i]; lengths[1] = ff_aac_num_swb_128[s->samplerate_index];
for (i = 0; i < s->chan_map[0]; i++) for (i = 0; i < s->chan_map[0]; i++)
grouping[i] = s->chan_map[i + 1] == TYPE_CPE; grouping[i] = s->chan_map[i + 1] == TYPE_CPE;
if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths, if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths,
s->chan_map[0], grouping)) < 0) s->chan_map[0], grouping)) < 0)
goto fail; goto fail;
s->psypp = ff_psy_preprocess_init(avctx); s->psypp = ff_psy_preprocess_init(avctx);
s->coder = &ff_aac_coders[s->options.aac_coder];
ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON); ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON);
if (HAVE_MIPSDSPR1) if (HAVE_MIPSDSPR1)
ff_aac_coder_init_mips(s); ff_aac_coder_init_mips(s);
s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120;
s->random_state = 0x1f2e3d4c;
ff_aac_tableinit(); ff_aac_tableinit();
avctx->initial_padding = 1024;
ff_af_queue_init(avctx, &s->afq); ff_af_queue_init(avctx, &s->afq);
return 0; return 0;
...@@ -938,19 +982,16 @@ fail: ...@@ -938,19 +982,16 @@ fail:
#define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM #define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
static const AVOption aacenc_options[] = { static const AVOption aacenc_options[] = {
{"stereo_mode", "Stereo coding method", offsetof(AACEncContext, options.stereo_mode), AV_OPT_TYPE_INT, {.i64 = 0}, -1, 1, AACENC_FLAGS, "stereo_mode"}, {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, -1, AAC_CODER_NB-1, AACENC_FLAGS, "coder"},
{"auto", "Selected by the Encoder", 0, AV_OPT_TYPE_CONST, {.i64 = -1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"}, {"faac", "FAAC-inspired method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAAC}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"ms_off", "Disable Mid/Side coding", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"}, {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"ms_force", "Force Mid/Side for the whole frame if possible", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"}, {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.aac_coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "aac_coder"}, {"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"faac", "FAAC-inspired method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAAC}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
{"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, {"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = OPT_AUTO}, -1, 1, AACENC_FLAGS},
{"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, {"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = OPT_AUTO}, -1, 1, AACENC_FLAGS},
{"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = OPT_AUTO}, -1, 1, AACENC_FLAGS},
{"aac_pns", "Perceptual Noise Substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AACENC_FLAGS}, {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = OPT_AUTO}, -1, 1, AACENC_FLAGS},
{"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AACENC_FLAGS},
{"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AACENC_FLAGS},
{"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AACENC_FLAGS},
{NULL} {NULL}
}; };
......
...@@ -42,11 +42,11 @@ typedef enum AACCoder { ...@@ -42,11 +42,11 @@ typedef enum AACCoder {
}AACCoder; }AACCoder;
typedef struct AACEncOptions { typedef struct AACEncOptions {
int stereo_mode; int coder;
int aac_coder;
int pns; int pns;
int tns; int tns;
int pred; int pred;
int mid_side;
int intensity_stereo; int intensity_stereo;
} AACEncOptions; } AACEncOptions;
......
...@@ -201,5 +201,43 @@ static inline int lcg_random(unsigned previous_val) ...@@ -201,5 +201,43 @@ static inline int lcg_random(unsigned previous_val)
av_log(avctx, AV_LOG_WARNING, __VA_ARGS__); \ av_log(avctx, AV_LOG_WARNING, __VA_ARGS__); \
} }
#define AAC_OPT_SET(e_opt, p_opt, bypass, name) \
ERROR_IF ((e_opt)->name == 1 && (p_opt)->name == OPT_BANNED, \
"Profile %i does not allow %s\n", avctx->profile, #name); \
ERROR_IF ((e_opt)->name == 0 && (p_opt)->name == OPT_REQUIRED, \
"Option %s is a requirement for this profile (%i)\n", \
#name, avctx->profile); \
if ((e_opt)->name == 1 && (p_opt)->name == OPT_NEEDS_MAIN && \
avctx->profile == FF_PROFILE_AAC_LOW) { \
WARN_IF(1, "Profile %i does not allow for %s, setting profile to " \
"\"aac_main\"(%i)\n", avctx->profile, #name, \
FF_PROFILE_AAC_MAIN); \
avctx->profile = FF_PROFILE_AAC_MAIN; \
p_opt = &aacenc_profiles[FF_PROFILE_AAC_MAIN].opts; \
} \
if ((e_opt)->name == 1 && (p_opt)->name == OPT_NEEDS_LTP && \
avctx->profile == FF_PROFILE_AAC_LOW) { \
WARN_IF(1, "Profile %i does not allow for %s, setting profile to " \
"\"aac_ltp\"(%i)\n", avctx->profile, #name, \
FF_PROFILE_AAC_LTP); \
avctx->profile = FF_PROFILE_AAC_LTP; \
p_opt = &aacenc_profiles[FF_PROFILE_AAC_LTP].opts; \
} \
if ((e_opt)->name == OPT_AUTO) { \
if ((p_opt)->name == OPT_BANNED) { \
(e_opt)->name = 0; \
} else if ((p_opt)->name == OPT_NEEDS_LTP) { \
(e_opt)->name = 0; \
} else if ((p_opt)->name == OPT_NEEDS_MAIN) { \
(e_opt)->name = 0; \
} else if ((p_opt)->name == OPT_REQUIRED) { \
(e_opt)->name = 1; \
} else if (bypass) { \
(e_opt)->name = (e_opt)->name; \
} else { \
(e_opt)->name = (p_opt)->name; \
} \
} \
av_log(avctx, AV_LOG_VERBOSE, "Option %s set to %i\n", #name, (e_opt)->name);
#endif /* AVCODEC_AACENC_UTILS_H */ #endif /* AVCODEC_AACENC_UTILS_H */
...@@ -36,6 +36,13 @@ ...@@ -36,6 +36,13 @@
/** Total number of codebooks, including special ones **/ /** Total number of codebooks, including special ones **/
#define CB_TOT_ALL 15 #define CB_TOT_ALL 15
/** Profile option settings **/
#define OPT_AUTO -1
#define OPT_BANNED -256
#define OPT_NEEDS_LTP -384
#define OPT_NEEDS_MAIN -512
#define OPT_REQUIRED -768
#define AAC_MAX_CHANNELS 8 #define AAC_MAX_CHANNELS 8
extern const uint8_t *ff_aac_swb_size_1024[]; extern const uint8_t *ff_aac_swb_size_1024[];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment