diff options
author | Paul B Mahol <onemda@gmail.com> | 2023-10-16 12:42:30 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2023-10-18 23:01:37 +0200 |
commit | b206056c8285c72dd528546dc532f6c6b51d39d4 (patch) | |
tree | bd041d693aeb1105431883a6fa9acb70354406bd | |
parent | 727ee32da705a6186feeba9fa6929e299b54ae8b (diff) | |
download | ffmpeg-b206056c8285c72dd528546dc532f6c6b51d39d4.tar.gz |
avcodec/mlpenc: implement advanced stereo rematrix
-rw-r--r-- | libavcodec/mlpenc.c | 142 |
1 files changed, 84 insertions, 58 deletions
diff --git a/libavcodec/mlpenc.c b/libavcodec/mlpenc.c index 333f96422c..3418c1b134 100644 --- a/libavcodec/mlpenc.c +++ b/libavcodec/mlpenc.c @@ -135,6 +135,7 @@ typedef struct MLPEncodeContext { int min_restart_interval; ///< Min interval of access units in between two major frames. int cur_restart_interval; int lpc_coeff_precision; + int rematrix_precision; int lpc_type; int lpc_passes; int prediction_order; @@ -263,8 +264,8 @@ static int compare_matrix_params(MLPEncodeContext *ctx, const MatrixParams *prev if (!mp->count) return 0; - for (unsigned int channel = rh->min_channel; channel <= rh->max_channel; channel++) - if (prev->fbits[channel] != mp->fbits[channel]) + for (unsigned int ch = rh->min_channel; ch <= rh->max_channel; ch++) + if (prev->fbits[ch] != mp->fbits[ch]) return 1; for (unsigned int mat = 0; mat < mp->count; mat++) { @@ -274,8 +275,8 @@ static int compare_matrix_params(MLPEncodeContext *ctx, const MatrixParams *prev if (prev->lsb_bypass[mat] != mp->lsb_bypass[mat]) return 1; - for (unsigned int channel = 0; channel < ctx->num_channels; channel++) - if (prev->coeff[mat][channel] != mp->coeff[mat][channel]) + for (unsigned int ch = 0; ch <= rh->max_matrix_channel; ch++) + if (prev->coeff[mat][ch] != mp->coeff[mat][ch]) return 1; } @@ -1143,8 +1144,7 @@ static int write_access_unit(MLPEncodeContext *ctx, uint8_t *buf, * lossless_check_data that will be written to the restart header. */ static void input_data_internal(MLPEncodeContext *ctx, const uint8_t *samples, - int nb_samples, - int is24) + int nb_samples, int is24) { int32_t *lossless_check_data = &ctx->b[ctx->frame_index].lossless_check_data; const int32_t *samples_32 = (const int32_t *) samples; @@ -1167,6 +1167,14 @@ static void input_data_internal(MLPEncodeContext *ctx, const uint8_t *samples, } } + for (int i = nb_samples; i < ctx->avctx->frame_size; i++) { + for (unsigned int ch = 0; ch <= rh->max_channel; ch++) { + int32_t *sample_buffer = ctx->b[ctx->frame_index].inout_buffer[ch]; + + sample_buffer[i] = 0; + } + } + ctx->b[ctx->frame_index].max_output_bits = bits; *lossless_check_data++ = temp_lossless_check_data; @@ -1330,8 +1338,11 @@ static int estimate_coeff(MLPEncodeContext *ctx, MatrixParams *mp, unsigned int ch0, unsigned int ch1) { - int first = 1, x, x0; - int64_t g = 0, g0 = 0; + int32_t maxl = INT32_MIN, maxr = INT32_MIN, minl = INT32_MAX, minr = INT32_MAX; + int64_t summ = 0, sums = 0, suml = 0, sumr = 0, enl = 0, enr = 0; + const int shift = 14 - ctx->rematrix_precision; + int32_t cf0, cf1, e[4], d[4], ml, mr; + int i, count = 0; for (int j = 0; j <= ctx->cur_restart_interval; j++) { DecodingParams *dp = &ctx->b[j].decoding_params; @@ -1341,56 +1352,63 @@ static int estimate_coeff(MLPEncodeContext *ctx, ch[1] = dp->sample_buffer[ch1]; for (int i = 0; i < dp->blocksize; i++) { - int64_t c0, c1; - int32_t a0, a1; - - c0 = ch[0][i]; - c1 = ch[1][i]; + int32_t lm = ch[0][i], rm = ch[1][i]; - if (!c0 && !c1) - continue; + enl += FFABS(lm); + enr += FFABS(rm); - if (!c0 || !c1) { - g0 = 0; - goto end; - } + summ += FFABS(lm + rm); + sums += FFABS(lm - rm); - a0 = FFABS(c0); - a1 = FFABS(c1); + suml += lm; + sumr += rm; - if (a0 >= a1) { - g = (c1 * (1 << 14)) / c0; - x = ch1; - } else if (a0 < a1) { - g = (c0 * (1 << 14)) / c1; - x = ch0; - } + maxl = FFMAX(maxl, lm); + maxr = FFMAX(maxr, rm); - if (first) { - g0 = g; - x0 = x; - first = 0; - } else if (g != g0 || x != x0) { - g0 = 0; - goto end; - } + minl = FFMIN(minl, lm); + minr = FFMIN(minr, rm); } } -end: - if (g0) { - mp->outch[0] = (x0 == ch0) ? ch0 : ch1; + summ -= FFABS(suml + sumr); + sums -= FFABS(suml - sumr); - mp->coeff[0][ch0] = (x0 == ch1) ? g0 : 0; - mp->coeff[0][ch1] = (x0 == ch0) ? g0 : 0; + ml = maxl - minl; + mr = maxr - minr; - mp->forco[0][ch0] = 0; - mp->forco[0][ch1] = 0; + if (!summ && !sums) + return 0; - return 1; - } + if (!ml || !mr) + return 0; - return 0; + if ((FFABS(ml) + FFABS(mr)) >= (1 << 24)) + return 0; + + cf0 = (FFMIN(FFABS(mr), FFABS(ml)) * (1LL << 14)) / FFMAX(FFABS(ml), FFABS(mr)); + cf0 = (cf0 >> shift) << shift; + cf1 = -cf0; + + if (sums > summ) + FFSWAP(int32_t, cf0, cf1); + + count = 1; + i = enl < enr; + mp->outch[0] = i; + + d[!i] = cf0; + d[ i] = 1 << 14; + e[!i] = cf1; + e[ i] = 1 << 14; + + mp->coeff[0][ch0] = av_clip_intp2(d[0], 15); + mp->coeff[0][ch1] = av_clip_intp2(d[1], 15); + + mp->forco[0][ch0] = av_clip_intp2(e[0], 15); + mp->forco[0][ch1] = av_clip_intp2(e[1], 15); + + return count; } /** Determines how many fractional bits are needed to encode matrix @@ -1400,10 +1418,11 @@ static void code_matrix_coeffs(MLPEncodeContext *ctx, DecodingParams *dp, unsigned int mat) { + RestartHeader *rh = ctx->cur_restart_header; MatrixParams *mp = &dp->matrix_params; int32_t coeff_mask = 0; - for (unsigned int channel = 0; channel < ctx->num_channels; channel++) { + for (unsigned int channel = 0; channel <= rh->max_matrix_channel; channel++) { coeff_mask |= mp->coeff[mat][channel]; } @@ -1787,10 +1806,12 @@ static void generate_2_noise_channels(MLPEncodeContext *ctx) /** Rematrixes all channels using chosen coefficients. */ static void rematrix_channels(MLPEncodeContext *ctx) { + RestartHeader *rh = ctx->cur_restart_header; DecodingParams *dp1 = &ctx->b[1].decoding_params; MatrixParams *mp1 = &dp1->matrix_params; - unsigned int maxchan = ctx->num_channels; - int32_t input_samples[MAX_NCHANNELS]; + unsigned int maxchan = rh->max_matrix_channel; + int32_t orig_samples[MAX_NCHANNELS]; + int32_t rematrix_samples[MAX_NCHANNELS]; uint8_t lsb_bypass[MAX_MATRICES] = { 0 }; for (unsigned int j = 0; j <= ctx->cur_restart_interval; j++) { @@ -1798,35 +1819,39 @@ static void rematrix_channels(MLPEncodeContext *ctx) MatrixParams *mp = &dp->matrix_params; for (unsigned int i = 0; i < dp->blocksize; i++) { - for (unsigned int ch = 0; ch < maxchan; ch++) - input_samples[ch] = dp->sample_buffer[ch][i]; + for (unsigned int ch = 0; ch <= maxchan; ch++) + orig_samples[ch] = rematrix_samples[ch] = dp->sample_buffer[ch][i]; - for (unsigned int mat = 0; mat < mp1->count; mat++) { + for (int mat = 0; mat < mp1->count; mat++) { unsigned int outch = mp1->outch[mat]; int64_t accum = 0; - for (unsigned int ch = 0; ch < maxchan; ch++) { - int32_t sample = input_samples[ch]; + for (int ch = 0; ch <= maxchan; ch++) { + int32_t sample = rematrix_samples[ch]; accum += (int64_t)sample * mp1->forco[mat][ch]; } - dp->sample_buffer[outch][i] = accum >> 14; + rematrix_samples[outch] = accum >> 14; } + for (unsigned int ch = 0; ch <= maxchan; ch++) + dp->sample_buffer[ch][i] = rematrix_samples[ch]; + for (unsigned int mat = 0; mat < mp1->count; mat++) { int8_t *bypassed_lsbs = mp->bypassed_lsbs[mat]; unsigned int outch = mp1->outch[mat]; int64_t accum = 0; int8_t bit; - for (unsigned int ch = 0; ch < maxchan; ch++) { - int32_t sample = dp->sample_buffer[ch][i]; + for (unsigned int ch = 0; ch <= maxchan; ch++) { + int32_t sample = rematrix_samples[ch]; accum += (int64_t)sample * mp1->coeff[mat][ch]; } - bit = (accum >> 14) != input_samples[outch]; + rematrix_samples[outch] = accum >> 14; + bit = rematrix_samples[outch] != orig_samples[outch]; bypassed_lsbs[i] = bit; lsb_bypass[mat] |= bit; @@ -2170,6 +2195,7 @@ static const AVOption mlp_options[] = { { "prediction_order", "Search method for selecting prediction order", OFFSET(prediction_order), AV_OPT_TYPE_INT, {.i64 = ORDER_METHOD_EST }, ORDER_METHOD_EST, ORDER_METHOD_SEARCH, FLAGS, "predm" }, { "estimation", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_EST }, 0, 0, FLAGS, "predm" }, { "search", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = ORDER_METHOD_SEARCH }, 0, 0, FLAGS, "predm" }, +{ "rematrix_precision", "Rematrix coefficient precision", OFFSET(rematrix_precision), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 14, FLAGS }, { NULL }, }; |