#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"
put_ics_info(s, &sce->ics);
if (s->coder->encode_main_pred)
s->coder->encode_main_pred(s, sce);
+ if (s->coder->encode_ltp_info)
+ s->coder->encode_ltp_info(s, sce, 0);
}
encode_band_info(s, sce);
encode_scale_factors(avctx, s, sce);
float **samples = s->planar_samples, *samples2, *la, *overlap;
ChannelElement *cpe;
SingleChannelElement *sce;
+ IndividualChannelStream *ics;
int i, its, ch, w, chans, tag, start_ch, ret, frame_bits;
int target_bits, rate_bits, too_many_bits, too_few_bits;
int ms_mode = 0, is_mode = 0, tns_mode = 0, pred_mode = 0;
chans = tag == TYPE_CPE ? 2 : 1;
cpe = &s->cpe[i];
for (ch = 0; ch < chans; ch++) {
- IndividualChannelStream *ics = &cpe->ch[ch].ics;
- int cur_channel = start_ch + ch;
float clip_avoidance_factor;
- overlap = &samples[cur_channel][0];
+ sce = &cpe->ch[ch];
+ ics = &sce->ics;
+ s->cur_channel = start_ch + ch;
+ overlap = &samples[s->cur_channel][0];
samples2 = overlap + 1024;
la = samples2 + (448+64);
if (!frame)
*/
ics->num_swb = s->samplerate_index >= 8 ? 1 : 3;
} else {
- wi[ch] = s->psy.model->window(&s->psy, samples2, la, cur_channel,
+ wi[ch] = s->psy.model->window(&s->psy, samples2, la, s->cur_channel,
ics->window_sequence[0]);
}
ics->window_sequence[1] = ics->window_sequence[0];
ics->clip_avoidance_factor = 1.0f;
}
- apply_window_and_mdct(s, &cpe->ch[ch], overlap);
+ apply_window_and_mdct(s, sce, overlap);
+
+ if (s->options.ltp && s->coder->update_ltp) {
+ s->coder->update_ltp(s, sce);
+ apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, &sce->ltp_state[0]);
+ s->mdct1024.mdct_calc(&s->mdct1024, sce->lcoeffs, sce->ret_buf);
+ }
+
if (isnan(cpe->ch->coeffs[0])) {
av_log(avctx, AV_LOG_ERROR, "Input contains NaN\n");
return AVERROR(EINVAL);
}
- avoid_clipping(s, &cpe->ch[ch]);
+ avoid_clipping(s, sce);
}
start_ch += chans;
}
sce = &cpe->ch[ch];
coeffs[ch] = sce->coeffs;
sce->ics.predictor_present = 0;
- memset(&sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used));
+ sce->ics.ltp.present = 0;
+ memset(sce->ics.ltp.used, 0, sizeof(sce->ics.ltp.used));
+ memset(sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used));
memset(&sce->tns, 0, sizeof(TemporalNoiseShaping));
for (w = 0; w < 128; w++)
if (sce->band_type[w] > RESERVED_BT)
apply_mid_side_stereo(cpe);
}
adjust_frame_information(cpe, chans);
+ if (s->options.ltp) { /* LTP */
+ for (ch = 0; ch < chans; ch++) {
+ sce = &cpe->ch[ch];
+ s->cur_channel = start_ch + ch;
+ if (s->coder->search_for_ltp)
+ s->coder->search_for_ltp(s, sce, cpe->common_window);
+ if (sce->ics.ltp.present) pred_mode = 1;
+ }
+ s->cur_channel = start_ch;
+ if (s->coder->adjust_common_ltp)
+ s->coder->adjust_common_ltp(s, cpe);
+ }
if (chans == 2) {
put_bits(&s->pb, 1, cpe->common_window);
if (cpe->common_window) {
put_ics_info(s, &cpe->ch[0].ics);
if (s->coder->encode_main_pred)
s->coder->encode_main_pred(s, &cpe->ch[0]);
+ if (s->coder->encode_ltp_info)
+ s->coder->encode_ltp_info(s, &cpe->ch[0], 1);
encode_ms_info(&s->pb, cpe);
if (cpe->ms_mode) ms_mode = 1;
}
}
} while (1);
+ if (s->options.ltp && s->coder->ltp_insert_new_frame)
+ s->coder->ltp_insert_new_frame(s);
+
put_bits(&s->pb, 3, TYPE_END);
flush_put_bits(&s->pb);
avctx->frame_bits = put_bits_count(&s->pb);
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];
WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels,
"Too many bits per frame requested, clamping to max\n");
- for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++) {
- if (avctx->profile == aacenc_profiles[i].profile) {
- p_opt = &aacenc_profiles[i].opts;
+ for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++)
+ if (avctx->profile == aacenc_profiles[i])
break;
- }
+ ERROR_IF(i == FF_ARRAY_ELEMS(aacenc_profiles),
+ "Unsupported encoding profile: %d\n", avctx->profile);
+ if (avctx->profile == FF_PROFILE_MPEG2_AAC_LOW) {
+ avctx->profile = FF_PROFILE_AAC_LOW;
+ ERROR_IF(s->options.pred,
+ "Main prediction unavailable in the \"mpeg2_aac_low\" profile\n");
+ ERROR_IF(s->options.ltp,
+ "LTP prediction unavailable in the \"mpeg2_aac_low\" profile\n");
+ WARN_IF(s->options.pns,
+ "PNS unavailable in the \"mpeg2_aac_low\" profile, turning off\n");
+ s->options.pns = 0;
+ } else if (avctx->profile == FF_PROFILE_AAC_LTP) {
+ s->options.ltp = 1;
+ ERROR_IF(s->options.pred,
+ "Main prediction unavailable in the \"aac_ltp\" profile\n");
+ } else if (avctx->profile == FF_PROFILE_AAC_MAIN) {
+ s->options.pred = 1;
+ ERROR_IF(s->options.ltp,
+ "LTP prediction unavailable in the \"aac_main\" profile\n");
+ } else if (s->options.ltp) {
+ avctx->profile = FF_PROFILE_AAC_LTP;
+ WARN_IF(1,
+ "Chainging profile to \"aac_ltp\"\n");
+ ERROR_IF(s->options.pred,
+ "Main prediction unavailable in the \"aac_ltp\" profile\n");
+ } else if (s->options.pred) {
+ avctx->profile = FF_PROFILE_AAC_MAIN;
+ WARN_IF(1,
+ "Chainging profile to \"aac_main\"\n");
+ ERROR_IF(s->options.pred,
+ "LTP prediction unavailable in the \"aac_main\" profile\n");
}
- 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->profile = avctx->profile;
s->coder = &ff_aac_coders[s->options.coder];
if (s->options.coder != AAC_CODER_TWOLOOP) {
{"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},
+ {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS},
+ {"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
+ {"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
+ {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
+ {"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
+ {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
{NULL}
};