[FFmpeg-cvslog] avcodec/mlpenc: fix stereo decorrelation

Paul B Mahol git at videolan.org
Mon Oct 9 19:44:59 EEST 2023


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Mon Oct  9 16:36:10 2023 +0200| [27c623b3d59439b8916abc4677feb902b6a279f9] | committer: Paul B Mahol

avcodec/mlpenc: fix stereo decorrelation

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=27c623b3d59439b8916abc4677feb902b6a279f9
---

 libavcodec/mlpenc.c | 145 +++++++++++++++++++++++++++-------------------------
 1 file changed, 74 insertions(+), 71 deletions(-)

diff --git a/libavcodec/mlpenc.c b/libavcodec/mlpenc.c
index 0191431eed..8ba7c04a75 100644
--- a/libavcodec/mlpenc.c
+++ b/libavcodec/mlpenc.c
@@ -645,6 +645,8 @@ static av_cold int mlp_encode_init(AVCodecContext *avctx)
     /* FIXME: this works for 1 and 2 channels, but check for more */
     rh->max_matrix_channel = rh->max_channel;
 
+    ctx->number_of_samples = avctx->frame_size * MAJOR_HEADER_INTERVAL;
+
     if ((ret = ff_lpc_init(&ctx->lpc_ctx, ctx->number_of_samples,
                            MLP_MAX_LPC_ORDER, ctx->lpc_type)) < 0)
         return ret;
@@ -1211,9 +1213,9 @@ static void input_to_sample_buffer(MLPEncodeContext *ctx)
  ****************************************************************************/
 
 /** Counts the number of trailing zeroes in a value */
-static int number_trailing_zeroes(int32_t sample)
+static int number_trailing_zeroes(int32_t sample, unsigned int max, unsigned int def)
 {
-    return sample ? FFMIN(15, ff_ctz(sample)) : 0;
+    return sample ? FFMIN(max, ff_ctz(sample)) : def;
 }
 
 /** Determines how many bits are zero at the end of all samples so they can be
@@ -1237,7 +1239,7 @@ static void determine_quant_step_size(MLPEncodeContext *ctx)
     }
 
     for (unsigned int channel = 0; channel <= rh->max_channel; channel++)
-        dp->quant_step_size[channel] = number_trailing_zeroes(sample_mask[channel]) - mp->shift[channel];
+        dp->quant_step_size[channel] = number_trailing_zeroes(sample_mask[channel], 15, 0) - mp->shift[channel];
 }
 
 /** Determines the smallest number of bits needed to encode the filter
@@ -1322,41 +1324,74 @@ static void determine_filters(MLPEncodeContext *ctx)
     }
 }
 
-enum MLPChMode {
-    MLP_CHMODE_LEFT_RIGHT,
-    MLP_CHMODE_LEFT_SIDE,
-    MLP_CHMODE_RIGHT_SIDE,
-    MLP_CHMODE_MID_SIDE,
-};
-
-static enum MLPChMode estimate_stereo_mode(MLPEncodeContext *ctx)
+static int estimate_coeff(MLPEncodeContext *ctx,
+                          MatrixParams *mp,
+                          unsigned int ch0, unsigned int ch1)
 {
-    uint64_t score[4], sum[4] = { 0, 0, 0, 0, };
-    int32_t *right_ch = ctx->sample_buffer + 1;
-    int32_t *left_ch  = ctx->sample_buffer;
-    int i;
-    enum MLPChMode best = 0;
-
-    for(i = 2; i < ctx->number_of_samples; i++) {
-        int32_t left  = left_ch [i * ctx->num_channels] - 2 * left_ch [(i - 1) * ctx->num_channels] + left_ch [(i - 2) * ctx->num_channels];
-        int32_t right = right_ch[i * ctx->num_channels] - 2 * right_ch[(i - 1) * ctx->num_channels] + right_ch[(i - 2) * ctx->num_channels];
-
-        sum[0] += FFABS( left        );
-        sum[1] += FFABS(        right);
-        sum[2] += FFABS((left + right) >> 1);
-        sum[3] += FFABS( left - right);
+    const int number_of_samples = ctx->number_of_samples;
+    const int num_channels = ctx->num_channels;
+    int first = 1, x, x0;
+    const int32_t *ch[2];
+    int64_t g = 0, g0 = 0;
+
+    ch[0] = ctx->sample_buffer + ch0;
+    ch[1] = ctx->sample_buffer + ch1;
+
+    for (int n = 0, i = 0; n < number_of_samples; n++) {
+        int64_t c0, c1;
+        int32_t a0, a1;
+
+        c0 = ch[0][i];
+        c1 = ch[1][i];
+
+        if (!c0 && !c1)
+            goto next;
+
+        if (!c0 || !c1) {
+            g0 = 0;
+            break;
+        }
+
+        a0 = FFABS(c0);
+        a1 = FFABS(c1);
+
+        if (a0 >= a1) {
+            g = (c1 * (1 << 14)) / c0;
+            x = ch1;
+        } else if (a0 < a1) {
+            g = (c0 * (1 << 14)) / c1;
+            x = ch0;
+        }
+
+        if (first) {
+            g0 = g;
+            x0 = x;
+            first = 0;
+        } else if (g != g0 || x != x0) {
+            g0 = 0;
+            break;
+        }
+
+next:
+        i += num_channels;
     }
 
-    score[MLP_CHMODE_LEFT_RIGHT] = sum[0] + sum[1];
-    score[MLP_CHMODE_LEFT_SIDE]  = sum[0] + sum[3];
-    score[MLP_CHMODE_RIGHT_SIDE] = sum[1] + sum[3];
-    score[MLP_CHMODE_MID_SIDE]   = sum[2] + sum[3];
+    if (g0) {
+        mp->outch[0] = (x0 == ch0) ? ch0 : ch1;
+
+        mp->coeff[0][ch0] = (x0 == ch1) ? g0 : 0;
+        mp->coeff[0][ch1] = (x0 == ch0) ? g0 : 0;
+
+        mp->forco[0][ch0] = 0;
+        mp->forco[0][ch1] = 0;
+
+        mp->coeff[0][num_channels - 2] = mp->coeff[0][num_channels - 1] = 0;
+        mp->forco[0][num_channels - 2] = mp->forco[0][num_channels - 1] = 0;
 
-    for(i = 1; i < 3; i++)
-        if(score[i] < score[best])
-            best = i;
+        return 1;
+    }
 
-    return best;
+    return 0;
 }
 
 /** Determines how many fractional bits are needed to encode matrix
@@ -1367,16 +1402,12 @@ static void code_matrix_coeffs(MLPEncodeContext *ctx, unsigned int mat)
     DecodingParams *dp = ctx->cur_decoding_params;
     MatrixParams *mp = &dp->matrix_params;
     int32_t coeff_mask = 0;
-    unsigned int bits;
 
     for (unsigned int channel = 0; channel < ctx->num_channels; channel++) {
-        int32_t coeff = mp->coeff[mat][channel];
-        coeff_mask |= coeff;
+        coeff_mask |= mp->coeff[mat][channel];
     }
 
-    for (bits = 0; bits < 14 && !(coeff_mask & (1<<bits)); bits++);
-
-    mp->fbits   [mat] = 14 - bits;
+    mp->fbits[mat] = 14 - number_trailing_zeroes(coeff_mask, 14, 14);
 }
 
 /** Determines best coefficients to use for the lossless matrix. */
@@ -1385,38 +1416,12 @@ static void lossless_matrix_coeffs(MLPEncodeContext *ctx)
     DecodingParams *dp = ctx->cur_decoding_params;
     MatrixParams *mp = &dp->matrix_params;
     unsigned int shift = 0;
-    enum MLPChMode mode;
 
-    if (1 || ctx->num_channels - 2 != 2) {
-        mp->count = 0;
+    mp->count = 0;
+    if (ctx->num_channels - 2 != 2)
         return;
-    }
 
-    mode = estimate_stereo_mode(ctx);
-
-    switch (mode) {
-    /* TODO: add matrix for MID_SIDE */
-    case MLP_CHMODE_MID_SIDE:
-    case MLP_CHMODE_LEFT_RIGHT:
-        mp->count    = 0;
-        break;
-    case MLP_CHMODE_LEFT_SIDE:
-        mp->count    = 1;
-        mp->outch[0] = 1;
-        mp->coeff[0][0] =  1 << 14; mp->coeff[0][1] = -(1 << 14);
-        mp->coeff[0][2] =  0 << 14; mp->coeff[0][2] =   0 << 14;
-        mp->forco[0][0] =  1 << 14; mp->forco[0][1] = -(1 << 14);
-        mp->forco[0][2] =  0 << 14; mp->forco[0][2] =   0 << 14;
-        break;
-    case MLP_CHMODE_RIGHT_SIDE:
-        mp->count    = 1;
-        mp->outch[0] = 0;
-        mp->coeff[0][0] =  1 << 14; mp->coeff[0][1] =   1 << 14;
-        mp->coeff[0][2] =  0 << 14; mp->coeff[0][2] =   0 << 14;
-        mp->forco[0][0] =  1 << 14; mp->forco[0][1] = -(1 << 14);
-        mp->forco[0][2] =  0 << 14; mp->forco[0][2] =   0 << 14;
-        break;
-    }
+    mp->count = estimate_coeff(ctx, mp, 0, 1);
 
     for (int mat = 0; mat < mp->count; mat++)
         code_matrix_coeffs(ctx, mat);
@@ -1775,8 +1780,6 @@ static void rematrix_channels(MLPEncodeContext *ctx)
     unsigned int maxchan = ctx->num_channels;
 
     for (unsigned int mat = 0; mat < mp->count; mat++) {
-        unsigned int msb_mask_bits = (ctx->avctx->sample_fmt == AV_SAMPLE_FMT_S16 ? 8 : 0) - mp->shift[mat];
-        int32_t mask = MSB_MASK(msb_mask_bits);
         unsigned int outch = mp->outch[mat];
 
         sample_buffer = ctx->sample_buffer;
@@ -1787,7 +1790,7 @@ static void rematrix_channels(MLPEncodeContext *ctx)
                 int32_t sample = *(sample_buffer + src_ch);
                 accum += (int64_t) sample * mp->forco[mat][src_ch];
             }
-            sample_buffer[outch] = (accum >> 14) & mask;
+            sample_buffer[outch] = accum >> 14;
 
             sample_buffer += ctx->num_channels;
         }



More information about the ffmpeg-cvslog mailing list