diff --git a/libavcodec/aaccoder_twoloop.h b/libavcodec/aaccoder_twoloop.h index 2cc9a52d73..e53257fbaa 100644 --- a/libavcodec/aaccoder_twoloop.h +++ b/libavcodec/aaccoder_twoloop.h @@ -142,7 +142,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, * No need to be overly precise, this only controls RD * 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; /** diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 8041127009..78e292b246 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -46,6 +46,44 @@ #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. * @see 1.6.2.1 "Syntax - AudioSpecificConfig" @@ -690,8 +728,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } s->cur_channel = start_ch; } - if (s->options.stereo_mode) { /* Mid/Side stereo */ - if (s->options.stereo_mode == -1 && s->coder->search_for_ms) + if (s->options.mid_side) { /* Mid/Side stereo */ + if (s->options.mid_side == -1 && s->coder->search_for_ms) s->coder->search_for_ms(s, cpe); else if (cpe->common_window) memset(cpe->ms_mask, 1, sizeof(cpe->ms_mask)); @@ -852,82 +890,88 @@ alloc_fail: static av_cold int aac_encode_init(AVCodecContext *avctx) { AACEncContext *s = avctx->priv_data; + const AACEncOptions *p_opt = NULL; int i, ret = 0; const uint8_t *sizes[2]; uint8_t grouping[AAC_MAX_CHANNELS]; 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->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++) if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[i]) break; + s->samplerate_index = i; - s->channels = avctx->channels; - - ERROR_IF(i == 16 || i >= ff_aac_swb_size_1024_len || i >= ff_aac_swb_size_128_len, + ERROR_IF(s->samplerate_index == 16 || + s->samplerate_index >= ff_aac_swb_size_1024_len || + s->samplerate_index >= ff_aac_swb_size_128_len, "Unsupported sample rate %d\n", avctx->sample_rate); ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7, "Unsupported number of channels: %d\n", 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"); - if (avctx->profile == FF_PROFILE_AAC_MAIN) { - s->options.pred = 1; - } else if ((avctx->profile == FF_PROFILE_AAC_LOW || - avctx->profile == FF_PROFILE_UNKNOWN) && s->options.pred) { - s->profile = 0; /* Main */ - 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); + + for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++) { + if (avctx->profile == aacenc_profiles[i].profile) { + p_opt = &aacenc_profiles[i].opts; + break; + } } + 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.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) goto fail; if ((ret = alloc_buffers(avctx, s)) < 0) goto fail; - avctx->extradata_size = 5; put_audio_specific_config(avctx); - sizes[0] = ff_aac_swb_size_1024[i]; - sizes[1] = ff_aac_swb_size_128[i]; - lengths[0] = ff_aac_num_swb_1024[i]; - lengths[1] = ff_aac_num_swb_128[i]; + sizes[0] = ff_aac_swb_size_1024[s->samplerate_index]; + sizes[1] = ff_aac_swb_size_128[s->samplerate_index]; + lengths[0] = ff_aac_num_swb_1024[s->samplerate_index]; + lengths[1] = ff_aac_num_swb_128[s->samplerate_index]; for (i = 0; i < s->chan_map[0]; i++) grouping[i] = s->chan_map[i + 1] == TYPE_CPE; if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths, s->chan_map[0], grouping)) < 0) goto fail; 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); if (HAVE_MIPSDSPR1) ff_aac_coder_init_mips(s); - s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120; - s->random_state = 0x1f2e3d4c; - ff_aac_tableinit(); - avctx->initial_padding = 1024; ff_af_queue_init(avctx, &s->afq); return 0; @@ -938,19 +982,16 @@ fail: #define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM 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"}, - {"auto", "Selected by the Encoder", 0, AV_OPT_TYPE_CONST, {.i64 = -1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"}, - {"ms_off", "Disable Mid/Side coding", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"}, - {"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"}, - {"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"}, - {"faac", "FAAC-inspired method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAAC}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, - {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, - {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, - {"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"}, - {"aac_pns", "Perceptual Noise Substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 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}, + {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, -1, AAC_CODER_NB-1, AACENC_FLAGS, "coder"}, + {"faac", "FAAC-inspired method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAAC}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, + {"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), 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 = OPT_AUTO}, -1, 1, AACENC_FLAGS}, + {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = OPT_AUTO}, -1, 1, AACENC_FLAGS}, + {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = OPT_AUTO}, -1, 1, AACENC_FLAGS}, {NULL} }; diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index 98b38a4bde..b29fdf5307 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -42,11 +42,11 @@ typedef enum AACCoder { }AACCoder; typedef struct AACEncOptions { - int stereo_mode; - int aac_coder; + int coder; int pns; int tns; int pred; + int mid_side; int intensity_stereo; } AACEncOptions; diff --git a/libavcodec/aacenc_utils.h b/libavcodec/aacenc_utils.h index 16dad63f61..2fbe4c95bd 100644 --- a/libavcodec/aacenc_utils.h +++ b/libavcodec/aacenc_utils.h @@ -201,5 +201,43 @@ static inline int lcg_random(unsigned previous_val) 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 */ diff --git a/libavcodec/aacenctab.h b/libavcodec/aacenctab.h index 78b4d400c3..c6658a4a6f 100644 --- a/libavcodec/aacenctab.h +++ b/libavcodec/aacenctab.h @@ -36,6 +36,13 @@ /** Total number of codebooks, including special ones **/ #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 extern const uint8_t *ff_aac_swb_size_1024[];