[FFmpeg-devel] [PATCH] avcodec/aacenc_quantization: Fix undefined behavior and instead detect and print an error

Claudio Freire klaussfreire at gmail.com
Wed Mar 30 07:04:20 CEST 2016


On Wed, Mar 30, 2016 at 1:18 AM, Claudio Freire <klaussfreire at gmail.com> wrote:
> On Tue, Mar 29, 2016 at 10:51 PM, Michael Niedermayer
> <michael at niedermayer.cc> wrote:
>> This is a hotfix and not a real fix of the underlaying bug
>> The underlaying bug is ATM not fully understood
>>
>> iam not sure if we should apply this or not
>>
>> Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
>> ---
>>  libavcodec/aacenc_quantization.h |   13 +++++++++++--
>>  1 file changed, 11 insertions(+), 2 deletions(-)
>>
>> diff --git a/libavcodec/aacenc_quantization.h b/libavcodec/aacenc_quantization.h
>> index 4250407..d367be0 100644
>> --- a/libavcodec/aacenc_quantization.h
>> +++ b/libavcodec/aacenc_quantization.h
>> @@ -141,8 +141,17 @@ static av_always_inline float quantize_and_encode_band_cost_template(
>>              if (BT_ESC) {
>>                  for (j = 0; j < 2; j++) {
>>                      if (ff_aac_codebook_vectors[cb-1][curidx*2+j] == 64.0f) {
>> -                        int coef = av_clip_uintp2(quant(fabsf(in[i+j]), Q, ROUNDING), 13);
>> -                        int len = av_log2(coef);
>> +                        float a = fabsf(in[i+j]) * Q;
>> +                        double f = sqrtf(a * sqrtf(a)) + ROUNDING;
>> +                        int coef, len;
>> +
>> +                        if (f > INT_MAX || f < 16) {
>> +                            av_log(NULL, AV_LOG_ERROR, "f %f is out of range this is a internal error\n", f);
>> +                            f = INT_MAX;
>> +                        }
>> +
>> +                        coef = av_clip_uintp2(f, 13);
>> +                        len = av_log2(coef);
>>
>>                          put_bits(pb, len - 4 + 1, (1 << (len - 4 + 1)) - 2);
>>                          put_sbits(pb, len, coef);
>
> Actually I just understood the underlying bug and am testing a fix.
>
> Basically, scalefactors need to be bound by (roughly)
> coef2minsf(maxval), which isn't being done atm, and some signals
> prompt the encoder to pick lower and lower scalefactors trying to
> consume unspent bits that cannot really be consumed.

Try the attached diff instead (I'm not able to reproduce the issue with gcc)
-------------- next part --------------
diff --git a/libavcodec/aaccoder_twoloop.h b/libavcodec/aaccoder_twoloop.h
index 397a4db..4747c79 100644
--- a/libavcodec/aaccoder_twoloop.h
+++ b/libavcodec/aaccoder_twoloop.h
@@ -77,7 +77,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
     int toomanybits, toofewbits;
     char nzs[128];
     uint8_t nextband[128];
-    int maxsf[128];
+    int maxsf[128], minsf[128];
     float dists[128] = { 0 }, qenergies[128] = { 0 }, uplims[128], euplims[128], energies[128];
     float maxvals[128], spread_thr_r[128];
     float min_spread_thr_r, max_spread_thr_r;
@@ -294,11 +294,14 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
     abs_pow34_v(s->scoefs, sce->coeffs, 1024);
     ff_quantize_band_cost_cache_init(s);
 
+    for (i = 0; i < sizeof(minsf) / sizeof(minsf[0]); ++i)
+        minsf[i] = 0;
     for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
         start = w*128;
         for (g = 0;  g < sce->ics.num_swb; g++) {
             const float *scaled = s->scoefs + start;
             maxvals[w*16+g] = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], scaled);
+            minsf[w*16+g] = coef2minsf(maxvals[w*16+g]);
             start += sce->ics.swb_sizes[g];
         }
     }
@@ -425,7 +428,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
                 recomprd = 1;
                 for (i = 0; i < 128; i++) {
                     if (sce->sf_idx[i] > SCALE_ONE_POS) {
-                        int new_sf = FFMAX(SCALE_ONE_POS, sce->sf_idx[i] - qstep);
+                        int new_sf = FFMAX3(minsf[i], SCALE_ONE_POS, sce->sf_idx[i] - qstep);
                         if (new_sf != sce->sf_idx[i]) {
                             sce->sf_idx[i] = new_sf;
                             changed = 1;
@@ -595,7 +598,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
                     int cmb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
                     int mindeltasf = FFMAX(0, prev - SCALE_MAX_DIFF);
                     int maxdeltasf = FFMIN(SCALE_MAX_POS - SCALE_DIV_512, prev + SCALE_MAX_DIFF);
-                    if ((!cmb || dists[w*16+g] > uplims[w*16+g]) && sce->sf_idx[w*16+g] > mindeltasf) {
+                    if ((!cmb || dists[w*16+g] > uplims[w*16+g]) && sce->sf_idx[w*16+g] > FFMAX(mindeltasf, minsf[w*16+g])) {
                         /* Try to make sure there is some energy in every nonzero band
                          * NOTE: This algorithm must be forcibly imbalanced, pushing harder
                          *  on holes or more distorted bands at first, otherwise there's


More information about the ffmpeg-devel mailing list