summaryrefslogtreecommitdiff
path: root/libavcodec/aacenc.c
diff options
context:
space:
mode:
authorRostislav Pehlivanov <atomnuker@gmail.com>2015-10-17 02:22:51 +0100
committerRostislav Pehlivanov <atomnuker@gmail.com>2015-10-17 02:31:20 +0100
commit27d23ae07424a7c3a5d5e242ca702299cdd2e14c (patch)
treea0dbfe397948ae22e5ed1f591c00a90ed00a89e4 /libavcodec/aacenc.c
parent83900c0ed34c22487d6a97cdf9e9949d0795f5b0 (diff)
aacenc: add support for encoding files using Long Term Prediction
Long Term Prediction allows for prediction of spectral coefficients via the previously decoded time-dependent samples. This feature works well with harmonic content 2 or more frames long, like speech, human or non-human, piano music or any constant tones at very low bitrates. It should be noted that the current coder is highly efficient and the rate control system is unable to encode files at extremely low bitrates (less than 14kbps seems to be impossible) so this extension isn't capable of optimum operation. Dramatic difference is observable with some types of audio and speech but for the most part the audiable differences are subtle. The spectrum looks better however so the encoder is able to harvest the additional bits that this feature provies, should the user choose to enable it. So it's best to enable this feature only if encoding at the absolutely lowest bitrate that the encoder is capable of.
Diffstat (limited to 'libavcodec/aacenc.c')
-rw-r--r--libavcodec/aacenc.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c
index 8d5f4387f3..9454a9491b 100644
--- a/libavcodec/aacenc.c
+++ b/libavcodec/aacenc.c
@@ -60,6 +60,7 @@ static const struct AACProfileOptions aacenc_profiles[] = {
.mid_side = 0,
.pns = 1,
.tns = 0,
+ .ltp = OPT_BANNED,
.pred = OPT_REQUIRED,
.intensity_stereo = 1,
},
@@ -69,6 +70,7 @@ static const struct AACProfileOptions aacenc_profiles[] = {
.mid_side = 0,
.pns = 1,
.tns = 0,
+ .ltp = OPT_NEEDS_LTP,
.pred = OPT_NEEDS_MAIN,
.intensity_stereo = 1,
},
@@ -78,6 +80,17 @@ static const struct AACProfileOptions aacenc_profiles[] = {
.mid_side = 0,
.pns = OPT_BANNED,
.tns = 0,
+ .ltp = OPT_BANNED,
+ .pred = OPT_BANNED,
+ .intensity_stereo = 1,
+ },
+ },
+ {FF_PROFILE_AAC_LTP,
+ { /* Long term prediction profile */
+ .mid_side = 0,
+ .pns = 1,
+ .tns = 0,
+ .ltp = OPT_REQUIRED,
.pred = OPT_BANNED,
.intensity_stereo = 1,
},
@@ -475,6 +488,8 @@ static int encode_individual_channel(AVCodecContext *avctx, AACEncContext *s,
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);
@@ -625,6 +640,13 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
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);
@@ -659,6 +681,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
sce = &cpe->ch[ch];
coeffs[ch] = sce->coeffs;
sce->ics.predictor_present = 0;
+ 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++)
@@ -738,12 +762,26 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
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;
}
@@ -816,6 +854,9 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
} 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);
@@ -935,6 +976,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
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, 1, tns);
+ AAC_OPT_SET(&s->options, p_opt, 0, ltp);
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);
@@ -993,6 +1035,7 @@ static const AVOption aacenc_options[] = {
{"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 = 0}, -1, 1, AACENC_FLAGS},
+ {"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), 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}
};