1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * DCA ADPCM engine
3cabdff1aSopenharmony_ci * Copyright (C) 2017 Daniil Cherednik
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "dcaadpcm.h"
24cabdff1aSopenharmony_ci#include "dcaenc.h"
25cabdff1aSopenharmony_ci#include "dca_core.h"
26cabdff1aSopenharmony_ci#include "mathops.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_citypedef int32_t premultiplied_coeffs[10];
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci//assume we have DCA_ADPCM_COEFFS values before x
31cabdff1aSopenharmony_cistatic inline int64_t calc_corr(const int32_t *x, int len, int j, int k)
32cabdff1aSopenharmony_ci{
33cabdff1aSopenharmony_ci    int n;
34cabdff1aSopenharmony_ci    int64_t s = 0;
35cabdff1aSopenharmony_ci    for (n = 0; n < len; n++)
36cabdff1aSopenharmony_ci        s += MUL64(x[n-j], x[n-k]);
37cabdff1aSopenharmony_ci    return s;
38cabdff1aSopenharmony_ci}
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cistatic inline int64_t apply_filter(const int16_t a[DCA_ADPCM_COEFFS], const int64_t corr[15], const int32_t aa[10])
41cabdff1aSopenharmony_ci{
42cabdff1aSopenharmony_ci    int64_t err = 0;
43cabdff1aSopenharmony_ci    int64_t tmp = 0;
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_ci    err = corr[0];
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    tmp += MUL64(a[0], corr[1]);
48cabdff1aSopenharmony_ci    tmp += MUL64(a[1], corr[2]);
49cabdff1aSopenharmony_ci    tmp += MUL64(a[2], corr[3]);
50cabdff1aSopenharmony_ci    tmp += MUL64(a[3], corr[4]);
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci    tmp = norm__(tmp, 13);
53cabdff1aSopenharmony_ci    tmp += tmp;
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_ci    err -= tmp;
56cabdff1aSopenharmony_ci    tmp = 0;
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    tmp += MUL64(corr[5], aa[0]);
59cabdff1aSopenharmony_ci    tmp += MUL64(corr[6], aa[1]);
60cabdff1aSopenharmony_ci    tmp += MUL64(corr[7], aa[2]);
61cabdff1aSopenharmony_ci    tmp += MUL64(corr[8], aa[3]);
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_ci    tmp += MUL64(corr[9], aa[4]);
64cabdff1aSopenharmony_ci    tmp += MUL64(corr[10], aa[5]);
65cabdff1aSopenharmony_ci    tmp += MUL64(corr[11], aa[6]);
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci    tmp += MUL64(corr[12], aa[7]);
68cabdff1aSopenharmony_ci    tmp += MUL64(corr[13], aa[8]);
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    tmp += MUL64(corr[14], aa[9]);
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_ci    tmp = norm__(tmp, 26);
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    err += tmp;
75cabdff1aSopenharmony_ci
76cabdff1aSopenharmony_ci    return llabs(err);
77cabdff1aSopenharmony_ci}
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_cistatic int64_t find_best_filter(const DCAADPCMEncContext *s, const int32_t *in, int len)
80cabdff1aSopenharmony_ci{
81cabdff1aSopenharmony_ci    const premultiplied_coeffs *precalc_data = s->private_data;
82cabdff1aSopenharmony_ci    int i, j, k = 0;
83cabdff1aSopenharmony_ci    int vq = -1;
84cabdff1aSopenharmony_ci    int64_t err;
85cabdff1aSopenharmony_ci    int64_t min_err = 1ll << 62;
86cabdff1aSopenharmony_ci    int64_t corr[15];
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci    for (i = 0; i <= DCA_ADPCM_COEFFS; i++)
89cabdff1aSopenharmony_ci        for (j = i; j <= DCA_ADPCM_COEFFS; j++)
90cabdff1aSopenharmony_ci            corr[k++] = calc_corr(in+4, len, i, j);
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_ci    for (i = 0; i < DCA_ADPCM_VQCODEBOOK_SZ; i++) {
93cabdff1aSopenharmony_ci        err = apply_filter(ff_dca_adpcm_vb[i], corr, *precalc_data);
94cabdff1aSopenharmony_ci        if (err < min_err) {
95cabdff1aSopenharmony_ci            min_err = err;
96cabdff1aSopenharmony_ci            vq = i;
97cabdff1aSopenharmony_ci        }
98cabdff1aSopenharmony_ci        precalc_data++;
99cabdff1aSopenharmony_ci    }
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    return vq;
102cabdff1aSopenharmony_ci}
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_cistatic inline int64_t calc_prediction_gain(int pred_vq, const int32_t *in, int32_t *out, int len)
105cabdff1aSopenharmony_ci{
106cabdff1aSopenharmony_ci    int i;
107cabdff1aSopenharmony_ci    int32_t error;
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci    int64_t signal_energy = 0;
110cabdff1aSopenharmony_ci    int64_t error_energy = 0;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    for (i = 0; i < len; i++) {
113cabdff1aSopenharmony_ci        error = in[DCA_ADPCM_COEFFS + i] - ff_dcaadpcm_predict(pred_vq, in + i);
114cabdff1aSopenharmony_ci        out[i] = error;
115cabdff1aSopenharmony_ci        signal_energy += MUL64(in[DCA_ADPCM_COEFFS + i], in[DCA_ADPCM_COEFFS + i]);
116cabdff1aSopenharmony_ci        error_energy += MUL64(error, error);
117cabdff1aSopenharmony_ci    }
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci    if (!error_energy)
120cabdff1aSopenharmony_ci        return -1;
121cabdff1aSopenharmony_ci
122cabdff1aSopenharmony_ci    return signal_energy / error_energy;
123cabdff1aSopenharmony_ci}
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ciint ff_dcaadpcm_subband_analysis(const DCAADPCMEncContext *s, const int32_t *in, int len, int *diff)
126cabdff1aSopenharmony_ci{
127cabdff1aSopenharmony_ci    int pred_vq, i;
128cabdff1aSopenharmony_ci    int32_t input_buffer[16 + DCA_ADPCM_COEFFS];
129cabdff1aSopenharmony_ci    int32_t input_buffer2[16 + DCA_ADPCM_COEFFS];
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci    int32_t max = 0;
132cabdff1aSopenharmony_ci    int shift_bits;
133cabdff1aSopenharmony_ci    uint64_t pg = 0;
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_ci    for (i = 0; i < len + DCA_ADPCM_COEFFS; i++)
136cabdff1aSopenharmony_ci        max |= FFABS(in[i]);
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci    // normalize input to simplify apply_filter
139cabdff1aSopenharmony_ci    shift_bits = av_log2(max) - 11;
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    for (i = 0; i < len + DCA_ADPCM_COEFFS; i++) {
142cabdff1aSopenharmony_ci        input_buffer[i] = norm__(in[i], 7);
143cabdff1aSopenharmony_ci        input_buffer2[i] = norm__(in[i], shift_bits);
144cabdff1aSopenharmony_ci    }
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci    pred_vq = find_best_filter(s, input_buffer2, len);
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    if (pred_vq < 0)
149cabdff1aSopenharmony_ci        return -1;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci    pg = calc_prediction_gain(pred_vq, input_buffer, diff, len);
152cabdff1aSopenharmony_ci
153cabdff1aSopenharmony_ci    // Greater than 10db (10*log(10)) prediction gain to use ADPCM.
154cabdff1aSopenharmony_ci    // TODO: Tune it.
155cabdff1aSopenharmony_ci    if (pg < 10)
156cabdff1aSopenharmony_ci        return -1;
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    for (i = 0; i < len; i++)
159cabdff1aSopenharmony_ci        diff[i] <<= 7;
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci    return pred_vq;
162cabdff1aSopenharmony_ci}
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_cistatic void precalc(premultiplied_coeffs *data)
165cabdff1aSopenharmony_ci{
166cabdff1aSopenharmony_ci    int i, j, k;
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    for (i = 0; i < DCA_ADPCM_VQCODEBOOK_SZ; i++) {
169cabdff1aSopenharmony_ci        int id = 0;
170cabdff1aSopenharmony_ci        int32_t t = 0;
171cabdff1aSopenharmony_ci        for (j = 0; j < DCA_ADPCM_COEFFS; j++) {
172cabdff1aSopenharmony_ci            for (k = j; k < DCA_ADPCM_COEFFS; k++) {
173cabdff1aSopenharmony_ci                t = (int32_t)ff_dca_adpcm_vb[i][j] * (int32_t)ff_dca_adpcm_vb[i][k];
174cabdff1aSopenharmony_ci                if (j != k)
175cabdff1aSopenharmony_ci                    t *= 2;
176cabdff1aSopenharmony_ci                (*data)[id++] = t;
177cabdff1aSopenharmony_ci             }
178cabdff1aSopenharmony_ci        }
179cabdff1aSopenharmony_ci        data++;
180cabdff1aSopenharmony_ci    }
181cabdff1aSopenharmony_ci}
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ciint ff_dcaadpcm_do_real(int pred_vq_index,
184cabdff1aSopenharmony_ci                        softfloat quant, int32_t scale_factor, int32_t step_size,
185cabdff1aSopenharmony_ci                        const int32_t *prev_hist, const int32_t *in, int32_t *next_hist, int32_t *out,
186cabdff1aSopenharmony_ci                        int len, int32_t peak)
187cabdff1aSopenharmony_ci{
188cabdff1aSopenharmony_ci    int i;
189cabdff1aSopenharmony_ci    int64_t delta;
190cabdff1aSopenharmony_ci    int32_t dequant_delta;
191cabdff1aSopenharmony_ci    int32_t work_bufer[16 + DCA_ADPCM_COEFFS];
192cabdff1aSopenharmony_ci
193cabdff1aSopenharmony_ci    memcpy(work_bufer, prev_hist, sizeof(int32_t) * DCA_ADPCM_COEFFS);
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    for (i = 0; i < len; i++) {
196cabdff1aSopenharmony_ci        work_bufer[DCA_ADPCM_COEFFS + i] = ff_dcaadpcm_predict(pred_vq_index, &work_bufer[i]);
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_ci        delta = (int64_t)in[i] - ((int64_t)work_bufer[DCA_ADPCM_COEFFS + i] << 7);
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_ci        out[i] = quantize_value(av_clip64(delta, -peak, peak), quant);
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci        ff_dca_core_dequantize(&dequant_delta, &out[i], step_size, scale_factor, 0, 1);
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci        work_bufer[DCA_ADPCM_COEFFS+i] += dequant_delta;
205cabdff1aSopenharmony_ci    }
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    memcpy(next_hist, &work_bufer[len], sizeof(int32_t) * DCA_ADPCM_COEFFS);
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    return 0;
210cabdff1aSopenharmony_ci}
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ciav_cold int ff_dcaadpcm_init(DCAADPCMEncContext *s)
213cabdff1aSopenharmony_ci{
214cabdff1aSopenharmony_ci    if (!s)
215cabdff1aSopenharmony_ci        return -1;
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci    s->private_data = av_malloc(sizeof(premultiplied_coeffs) * DCA_ADPCM_VQCODEBOOK_SZ);
218cabdff1aSopenharmony_ci    if (!s->private_data)
219cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    precalc(s->private_data);
222cabdff1aSopenharmony_ci    return 0;
223cabdff1aSopenharmony_ci}
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ciav_cold void ff_dcaadpcm_free(DCAADPCMEncContext *s)
226cabdff1aSopenharmony_ci{
227cabdff1aSopenharmony_ci    if (!s)
228cabdff1aSopenharmony_ci        return;
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    av_freep(&s->private_data);
231cabdff1aSopenharmony_ci}
232