]> git.sesse.net Git - ffmpeg/commitdiff
aacenc: add support for encoding files using Long Term Prediction
authorRostislav Pehlivanov <atomnuker@gmail.com>
Sat, 17 Oct 2015 01:22:51 +0000 (02:22 +0100)
committerRostislav Pehlivanov <atomnuker@gmail.com>
Sat, 17 Oct 2015 01:31:20 +0000 (02:31 +0100)
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.

libavcodec/Makefile
libavcodec/aac.h
libavcodec/aaccoder.c
libavcodec/aacenc.c
libavcodec/aacenc.h
libavcodec/aacenc_ltp.c [new file with mode: 0644]
libavcodec/aacenc_ltp.h [new file with mode: 0644]

index 1e1e47947376440f3b1cfca14842d3ff1a918fd5..af93f8acb9737e0be96b7c1f4eebaeceeb954ce2 100644 (file)
@@ -135,6 +135,7 @@ OBJS-$(CONFIG_AAC_ENCODER)             += aacenc.o aaccoder.o aacenctab.o    \
                                           aacpsy.o aactab.o      \
                                           aacenc_is.o \
                                           aacenc_tns.o \
+                                          aacenc_ltp.o \
                                           aacenc_pred.o \
                                           psymodel.o mpeg4audio.o kbdwin.o
 OBJS-$(CONFIG_AASC_DECODER)            += aasc.o msrledec.o
index 37f98adb31f8a6d6bff335fe6829314ff68c6107..3333bfe5b2e36878d6d21ad50d26bfbf090353bb 100644 (file)
@@ -161,6 +161,7 @@ typedef struct PredictorState {
 typedef struct LongTermPrediction {
     int8_t present;
     int16_t lag;
+    int coef_idx;
     INTFLOAT coef;
     int8_t used[MAX_LTP_LONG_SFB];
 } LongTermPrediction;
@@ -260,6 +261,7 @@ typedef struct SingleChannelElement {
     DECLARE_ALIGNED(32, INTFLOAT, saved)[1536];     ///< overlap
     DECLARE_ALIGNED(32, INTFLOAT, ret_buf)[2048];   ///< PCM output buffer
     DECLARE_ALIGNED(16, INTFLOAT, ltp_state)[3072]; ///< time signal for LTP
+    DECLARE_ALIGNED(32, AAC_FLOAT, lcoeffs)[1024];  ///< MDCT of LTP coefficients (used by encoder)
     DECLARE_ALIGNED(32, AAC_FLOAT, prcoeffs)[1024]; ///< Main prediction coefs (used by encoder)
     PredictorState predictor_state[MAX_PREDICTORS];
     INTFLOAT *ret;                                  ///< PCM output
index c25189dbda330024262fb3a756b5b706f3eb2032..fd9785e26a46b91b076360b0867021dbb15f3dfe 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "aacenc_is.h"
 #include "aacenc_tns.h"
+#include "aacenc_ltp.h"
 #include "aacenc_pred.h"
 
 #include "libavcodec/aaccoder_twoloop.h"
@@ -911,14 +912,19 @@ AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
         encode_window_bands_info,
         quantize_and_encode_band,
         ff_aac_encode_tns_info,
+        ff_aac_encode_ltp_info,
         ff_aac_encode_main_pred,
         ff_aac_adjust_common_pred,
+        ff_aac_adjust_common_ltp,
         ff_aac_apply_main_pred,
         ff_aac_apply_tns,
+        ff_aac_update_ltp,
+        ff_aac_ltp_insert_new_frame,
         set_special_band_scalefactors,
         search_for_pns,
         mark_pns,
         ff_aac_search_for_tns,
+        ff_aac_search_for_ltp,
         search_for_ms,
         ff_aac_search_for_is,
         ff_aac_search_for_pred,
@@ -928,14 +934,19 @@ AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
         encode_window_bands_info,
         quantize_and_encode_band,
         ff_aac_encode_tns_info,
+        ff_aac_encode_ltp_info,
         ff_aac_encode_main_pred,
         ff_aac_adjust_common_pred,
+        ff_aac_adjust_common_ltp,
         ff_aac_apply_main_pred,
         ff_aac_apply_tns,
+        ff_aac_update_ltp,
+        ff_aac_ltp_insert_new_frame,
         set_special_band_scalefactors,
         search_for_pns,
         mark_pns,
         ff_aac_search_for_tns,
+        ff_aac_search_for_ltp,
         search_for_ms,
         ff_aac_search_for_is,
         ff_aac_search_for_pred,
@@ -945,14 +956,19 @@ AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
         codebook_trellis_rate,
         quantize_and_encode_band,
         ff_aac_encode_tns_info,
+        ff_aac_encode_ltp_info,
         ff_aac_encode_main_pred,
         ff_aac_adjust_common_pred,
+        ff_aac_adjust_common_ltp,
         ff_aac_apply_main_pred,
         ff_aac_apply_tns,
+        ff_aac_update_ltp,
+        ff_aac_ltp_insert_new_frame,
         set_special_band_scalefactors,
         search_for_pns,
         mark_pns,
         ff_aac_search_for_tns,
+        ff_aac_search_for_ltp,
         search_for_ms,
         ff_aac_search_for_is,
         ff_aac_search_for_pred,
@@ -962,14 +978,19 @@ AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
         encode_window_bands_info,
         quantize_and_encode_band,
         ff_aac_encode_tns_info,
+        ff_aac_encode_ltp_info,
         ff_aac_encode_main_pred,
         ff_aac_adjust_common_pred,
+        ff_aac_adjust_common_ltp,
         ff_aac_apply_main_pred,
         ff_aac_apply_tns,
+        ff_aac_update_ltp,
+        ff_aac_ltp_insert_new_frame,
         set_special_band_scalefactors,
         search_for_pns,
         mark_pns,
         ff_aac_search_for_tns,
+        ff_aac_search_for_ltp,
         search_for_ms,
         ff_aac_search_for_is,
         ff_aac_search_for_pred,
index 8d5f4387f3f856fb2d61de4ced89c2e266ce5ab4..9454a9491bab3ae9dd5a93fb1943b76bbea1762e 100644 (file)
@@ -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}
 };
index 0f4fc05e3d8fbe3a996ed7c4f63ef74d056362a9..d8bed82abe7c789f46294635c71bcdd90e135679 100644 (file)
@@ -45,6 +45,7 @@ typedef struct AACEncOptions {
     int coder;
     int pns;
     int tns;
+    int ltp;
     int pred;
     int mid_side;
     int intensity_stereo;
@@ -60,14 +61,19 @@ typedef struct AACCoefficientsEncoder {
     void (*quantize_and_encode_band)(struct AACEncContext *s, PutBitContext *pb, const float *in, float *out, int size,
                                      int scale_idx, int cb, const float lambda, int rtz);
     void (*encode_tns_info)(struct AACEncContext *s, SingleChannelElement *sce);
+    void (*encode_ltp_info)(struct AACEncContext *s, SingleChannelElement *sce, int common_window);
     void (*encode_main_pred)(struct AACEncContext *s, SingleChannelElement *sce);
     void (*adjust_common_pred)(struct AACEncContext *s, ChannelElement *cpe);
+    void (*adjust_common_ltp)(struct AACEncContext *s, ChannelElement *cpe);
     void (*apply_main_pred)(struct AACEncContext *s, SingleChannelElement *sce);
     void (*apply_tns_filt)(struct AACEncContext *s, SingleChannelElement *sce);
+    void (*update_ltp)(struct AACEncContext *s, SingleChannelElement *sce);
+    void (*ltp_insert_new_frame)(struct AACEncContext *s);
     void (*set_special_band_scalefactors)(struct AACEncContext *s, SingleChannelElement *sce);
     void (*search_for_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce);
     void (*mark_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce);
     void (*search_for_tns)(struct AACEncContext *s, SingleChannelElement *sce);
+    void (*search_for_ltp)(struct AACEncContext *s, SingleChannelElement *sce, int common_window);
     void (*search_for_ms)(struct AACEncContext *s, ChannelElement *cpe);
     void (*search_for_is)(struct AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe);
     void (*search_for_pred)(struct AACEncContext *s, SingleChannelElement *sce);
diff --git a/libavcodec/aacenc_ltp.c b/libavcodec/aacenc_ltp.c
new file mode 100644 (file)
index 0000000..066e195
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * AAC encoder TNS
+ * Copyright (C) 2015 Rostislav Pehlivanov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * AAC encoder long term prediction
+ * @author Rostislav Pehlivanov ( atomnuker gmail com )
+ */
+
+#include "aacenc_ltp.h"
+#include "aacenc_quantization.h"
+#include "aacenc_utils.h"
+
+/**
+ * Encode LTP data.
+ */
+void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce,
+                            int common_window)
+{
+    int i;
+    IndividualChannelStream *ics = &sce->ics;
+    if (s->profile != FF_PROFILE_AAC_LTP || !ics->predictor_present)
+        return;
+    if (common_window)
+        put_bits(&s->pb, 1, 0);
+    put_bits(&s->pb, 1, ics->ltp.present);
+    if (!ics->ltp.present)
+        return;
+    put_bits(&s->pb, 11, ics->ltp.lag);
+    put_bits(&s->pb, 3,  ics->ltp.coef_idx);
+    for (i = 0; i < FFMIN(ics->max_sfb, MAX_LTP_LONG_SFB); i++)
+        put_bits(&s->pb, 1, ics->ltp.used[i]);
+}
+
+void ff_aac_ltp_insert_new_frame(AACEncContext *s)
+{
+    int i, ch, tag, chans, cur_channel, start_ch = 0;
+    ChannelElement *cpe;
+    SingleChannelElement *sce;
+    for (i = 0; i < s->chan_map[0]; i++) {
+        cpe = &s->cpe[i];
+        tag      = s->chan_map[i+1];
+        chans    = tag == TYPE_CPE ? 2 : 1;
+        for (ch = 0; ch < chans; ch++) {
+            sce = &cpe->ch[ch];
+            cur_channel = start_ch + ch;
+            /* New sample + overlap */
+            memcpy(&sce->ltp_state[0],    &sce->ltp_state[1024], 1024*sizeof(sce->ltp_state[0]));
+            memcpy(&sce->ltp_state[1024], &s->planar_samples[cur_channel][2048], 1024*sizeof(sce->ltp_state[0]));
+            memcpy(&sce->ltp_state[2048], &sce->ret_buf[0], 1024*sizeof(sce->ltp_state[0]));
+        }
+        start_ch += chans;
+    }
+}
+
+/**
+ * Process LTP parameters
+ * @see Patent WO2006070265A1
+ */
+void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce)
+{
+    int i, j, lag;
+    float corr, s0, s1, max_corr = 0.0f;
+    float *samples = &s->planar_samples[s->cur_channel][1024];
+    float *pred_signal = &sce->ltp_state[0];
+    int samples_num = 2048;
+
+    if (s->profile != FF_PROFILE_AAC_LTP)
+        return;
+
+    /* Calculate lag */
+    for (i = 0; i < samples_num; i++) {
+        s0 = s1 = 0.0f;
+        for (j = 0; j < samples_num; j++) {
+            if (j + 1024 < i)
+                continue;
+            s0 += samples[j]*pred_signal[j-i+1024];
+            s1 += pred_signal[j-i+1024]*pred_signal[j-i+1024];
+        }
+        corr = s1 > 0.0f ? s0/sqrt(s1) : 0.0f;
+        if (corr > max_corr) {
+            max_corr = corr;
+            lag = i;
+        }
+    }
+    lag = av_clip(lag, 0, 2048); /* 11 bits => 2^11 = 2048 */
+
+    if (!lag) {
+        sce->ics.ltp.lag = lag;
+        return;
+    }
+
+    s0 = s1 = 0.0f;
+    for (i = 0; i < lag; i++) {
+        s0 += samples[i];
+        s1 += pred_signal[i-lag+1024];
+    }
+
+    sce->ics.ltp.coef_idx = quant_array_idx(s0/s1, ltp_coef, 8);
+    sce->ics.ltp.coef     = ltp_coef[sce->ics.ltp.coef_idx];
+
+    /* Predict the new samples */
+    if (lag < 1024)
+        samples_num = lag + 1024;
+    for (i = 0; i < samples_num; i++)
+        pred_signal[i+1024] = sce->ics.ltp.coef*pred_signal[i-lag+1024];
+    memset(&pred_signal[samples_num], 0, (2048 - samples_num)*sizeof(float));
+
+    sce->ics.ltp.lag = lag;
+}
+
+void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe)
+{
+    int sfb, count = 0;
+    SingleChannelElement *sce0 = &cpe->ch[0];
+    SingleChannelElement *sce1 = &cpe->ch[1];
+
+    if (!cpe->common_window ||
+        sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE ||
+        sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE)
+        return;
+
+    for (sfb = 0; sfb < FFMIN(sce0->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) {
+        int sum = sce0->ics.ltp.used[sfb] + sce1->ics.ltp.used[sfb];
+        if (sum != 2) {
+            sce0->ics.ltp.used[sfb] = 0;
+        } else if (sum == 2) {
+            count++;
+        }
+    }
+
+    sce0->ics.ltp.present = !!count;
+    sce0->ics.predictor_present = !!count;
+}
+
+/**
+ * Mark LTP sfb's
+ */
+void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce,
+                           int common_window)
+{
+    int w, g, w2, i, start = 0, count = 0;
+    int saved_bits = -(15 + FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB));
+    float *C34 = &s->scoefs[128*0], *PCD = &s->scoefs[128*1];
+    float *PCD34 = &s->scoefs[128*2];
+    const int max_ltp = FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB);
+
+    if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE ||
+        !sce->ics.ltp.lag)
+        return;
+
+    for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+        start = 0;
+        for (g = 0;  g < sce->ics.num_swb; g++) {
+            int bits1 = 0, bits2 = 0;
+            float dist1 = 0.0f, dist2 = 0.0f;
+            if (w*16+g > max_ltp) {
+                start += sce->ics.swb_sizes[g];
+                continue;
+            }
+            for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
+                int bits_tmp1, bits_tmp2;
+                FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
+                for (i = 0; i < sce->ics.swb_sizes[g]; i++)
+                    PCD[i] = sce->coeffs[start+(w+w2)*128+i] - sce->lcoeffs[start+(w+w2)*128+i];
+                abs_pow34_v(C34,  &sce->coeffs[start+(w+w2)*128],  sce->ics.swb_sizes[g]);
+                abs_pow34_v(PCD34, PCD, sce->ics.swb_sizes[g]);
+                dist1 += quantize_band_cost(s, &sce->coeffs[start+(w+w2)*128], C34, sce->ics.swb_sizes[g],
+                                            sce->sf_idx[(w+w2)*16+g], sce->band_type[(w+w2)*16+g],
+                                            s->lambda/band->threshold, INFINITY, &bits_tmp1, NULL, 0);
+                dist2 += quantize_band_cost(s, PCD, PCD34, sce->ics.swb_sizes[g],
+                                            sce->sf_idx[(w+w2)*16+g],
+                                            sce->band_type[(w+w2)*16+g],
+                                            s->lambda/band->threshold, INFINITY, &bits_tmp2, NULL, 0);
+                bits1 += bits_tmp1;
+                bits2 += bits_tmp2;
+            }
+            if (dist2 < dist1 && bits2 < bits1) {
+                for (w2 = 0; w2 < sce->ics.group_len[w]; w2++)
+                    for (i = 0; i < sce->ics.swb_sizes[g]; i++)
+                        sce->coeffs[start+(w+w2)*128+i] -= sce->lcoeffs[start+(w+w2)*128+i];
+                sce->ics.ltp.used[w*16+g] = 1;
+                saved_bits += bits1 - bits2;
+                count++;
+            }
+            start += sce->ics.swb_sizes[g];
+        }
+    }
+
+    sce->ics.ltp.present = !!count && (saved_bits >= 0);
+    sce->ics.predictor_present = !!sce->ics.ltp.present;
+
+    /* Reset any marked sfbs */
+    if (!sce->ics.ltp.present && !!count) {
+        for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+            start = 0;
+            for (g = 0;  g < sce->ics.num_swb; g++) {
+                if (sce->ics.ltp.used[w*16+g]) {
+                    for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
+                        for (i = 0; i < sce->ics.swb_sizes[g]; i++) {
+                            sce->coeffs[start+(w+w2)*128+i] += sce->lcoeffs[start+(w+w2)*128+i];
+                        }
+                    }
+                }
+                start += sce->ics.swb_sizes[g];
+            }
+        }
+    }
+}
diff --git a/libavcodec/aacenc_ltp.h b/libavcodec/aacenc_ltp.h
new file mode 100644 (file)
index 0000000..7276878
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * AAC encoder long term prediction extension
+ * Copyright (C) 2015 Rostislav Pehlivanov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * AAC encoder long term prediction extension
+ * @author Rostislav Pehlivanov ( atomnuker gmail com )
+ */
+
+#ifndef AVCODEC_AACENC_LTP_H
+#define AVCODEC_AACENC_LTP_H
+
+#include "aacenc.h"
+
+void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce,
+                            int common_window);
+void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce);
+void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe);
+void ff_aac_ltp_insert_new_frame(AACEncContext *s);
+void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce,
+                           int common_window);
+
+#endif /* AVCODEC_AACENC_LTP_H */