/src/ffmpeg/libavcodec/g728dec.c
Line | Count | Source |
1 | | /* |
2 | | * G.728 decoder |
3 | | * Copyright (c) 2025 Peter Ross |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include "avcodec.h" |
23 | | #include "celp_filters.h" |
24 | | #include "codec_internal.h" |
25 | | #include "decode.h" |
26 | | #include "get_bits.h" |
27 | | #include "g728data.h" |
28 | | #include "lpc_functions.h" |
29 | | #include "ra288.h" |
30 | | #include "libavutil/float_dsp.h" |
31 | | #include "libavutil/mem.h" |
32 | | #include "libavutil/mem_internal.h" |
33 | | #include "libavutil/opt.h" |
34 | | #include "libavutil/thread.h" |
35 | | |
36 | | #define MAX_BACKWARD_FILTER_ORDER LPC |
37 | | #define MAX_BACKWARD_FILTER_LEN NFRSZ |
38 | | #define MAX_BACKWARD_FILTER_NONREC NONR |
39 | 305M | #define ATTEN 0.75f |
40 | | #include "g728_template.c" |
41 | | |
42 | 9.86M | #define LPCW 10 /* Perceptual weighting filter order */ |
43 | 39.4M | #define GOFF 32.0f /* Log-gain offset value */ |
44 | | |
45 | | static float g728_gq_db[8]; |
46 | | static float g728_y_db[128]; |
47 | | static DECLARE_ALIGNED(32, float, g728_wnr_r)[FFALIGN(NSBSZ,16)]; |
48 | | static DECLARE_ALIGNED(32, float, g728_wnrg_r)[FFALIGN(NSBGSZ, 16)]; |
49 | | static DECLARE_ALIGNED(32, float, g728_facv_f)[FFALIGN(LPC, 16)]; |
50 | | |
51 | | static av_cold void g728_init_static_data(void) |
52 | 1 | { |
53 | 9 | for(int i = 0; i < FF_ARRAY_ELEMS(amptable); i++) |
54 | 8 | g728_gq_db[i] = 10.0f*log10f(amptable[i] * amptable[i]); |
55 | | |
56 | 129 | for (int i = 0; i < FF_ARRAY_ELEMS(codetable); i++) { |
57 | 128 | float cby[IDIM]; |
58 | 768 | for (int j = 0; j < IDIM; j++) |
59 | 640 | cby[j] = codetable[i][j] * (1.0f/(1<<11)); |
60 | 128 | g728_y_db[i] = 10.0f*log10f(ff_scalarproduct_float_c(cby, cby, IDIM) / IDIM); |
61 | 128 | } |
62 | | |
63 | 106 | for (int i = 0; i < NSBSZ; i++) |
64 | 105 | g728_wnr_r[i] = g728_wnr[NSBSZ - 1 - i] * (1.0f/(1<<15)); |
65 | 35 | for (int i = 0; i < NSBGSZ; i++) |
66 | 34 | g728_wnrg_r[i] = g728_wnrg[NSBGSZ - 1 - i] * (1.0f/(1<<15)); |
67 | 51 | for (int i = 0; i < LPC; i++) |
68 | 50 | g728_facv_f[i] = g728_facv[i] * (1.0f/(1<<14)); |
69 | 1 | } |
70 | | |
71 | | typedef struct { |
72 | | AVFloatDSPContext *fdsp; |
73 | | int valid; |
74 | | float a[LPC]; |
75 | | DECLARE_ALIGNED(32, float, sb)[NSBSZ]; |
76 | | DECLARE_ALIGNED(32, float, sbg)[NSBGSZ]; |
77 | | DECLARE_ALIGNED(32, float, gp)[FFALIGN(LPCLG, 16)]; |
78 | | DECLARE_ALIGNED(32, float, atmp)[FFALIGN(LPC, 16)]; |
79 | | float rexp[LPC + 1]; |
80 | | float rexpg[LPCLG + 1]; |
81 | | float r[LPC + 1]; |
82 | | float alpha; |
83 | | } G728Context; |
84 | | |
85 | | static av_cold int g728_decode_init(AVCodecContext *avctx) |
86 | 1.06k | { |
87 | 1.06k | static AVOnce init_static_once = AV_ONCE_INIT; |
88 | 1.06k | G728Context *s = avctx->priv_data; |
89 | | |
90 | 1.06k | s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); |
91 | 1.06k | if (!s->fdsp) |
92 | 0 | return AVERROR(ENOMEM); |
93 | | |
94 | 1.06k | s->gp[0] = -1.0f; |
95 | 5.32k | for (int i = 0; i < NUPDATE; i++) |
96 | 4.25k | s->sbg[NSBGSZ - 1 -i] = -GOFF; |
97 | | |
98 | 1.06k | avctx->sample_fmt = AV_SAMPLE_FMT_FLT; |
99 | 1.06k | if (!avctx->sample_rate) |
100 | 478 | avctx->sample_rate = 8000; |
101 | | |
102 | 1.06k | av_channel_layout_uninit(&avctx->ch_layout); |
103 | 1.06k | avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; |
104 | | |
105 | 1.06k | ff_thread_once(&init_static_once, g728_init_static_data); |
106 | 1.06k | return 0; |
107 | 1.06k | } |
108 | | |
109 | | static av_cold int g728_decode_close(AVCodecContext *avctx) |
110 | 1.06k | { |
111 | 1.06k | G728Context *s = avctx->priv_data; |
112 | 1.06k | av_freep(&s->fdsp); |
113 | 1.06k | return 0; |
114 | 1.06k | } |
115 | | |
116 | | static int hybrid_window(AVFloatDSPContext *fdsp, |
117 | | int order, int n, int non_rec, float *out, |
118 | | const float *hist, float *out2, const float *window) |
119 | 9.86M | { |
120 | 9.86M | do_hybrid_window(fdsp->vector_fmul, order, n, non_rec, out, hist, out2, window); |
121 | 9.86M | return out[order] != 0.0f; |
122 | 9.86M | } |
123 | | |
124 | | static void decode_frame(G728Context *s, GetBitContext *gb, float *dst) |
125 | 4.93M | { |
126 | 4.93M | float *gstate = s->sbg + NSBGSZ - 2; |
127 | | |
128 | 24.6M | for (int idx = 0; idx < NUPDATE; idx++) { |
129 | 19.7M | DECLARE_ALIGNED(32, float, et)[IDIM]; |
130 | 19.7M | float *statelpc = s->sb + NSBSZ - NFRSZ + idx*IDIM; |
131 | 19.7M | float gain, gain_db; |
132 | 19.7M | int is, ig; |
133 | | |
134 | 19.7M | gain_db = 0.0f; |
135 | 217M | for (int i = 0; i < LPCLG; i++) |
136 | 197M | gain_db -= s->gp[i] * gstate[-i]; |
137 | 19.7M | gain_db = av_clipf(gain_db, -GOFF, 28.0f); |
138 | | |
139 | 19.7M | is = get_bits(gb, 7); // shape index |
140 | 19.7M | ig = get_bits(gb, 3); // gain index |
141 | | |
142 | 19.7M | gain = powf(10.0f, (gain_db + GOFF) * .05f) * amptable[ig] * (1.0f/(1<<11)); |
143 | 118M | for (int i = 0; i < IDIM; i++) |
144 | 98.6M | et[i] = codetable[is][i] * gain; |
145 | | |
146 | 19.7M | ff_celp_lp_synthesis_filterf(statelpc, s->a, et, IDIM, LPC); |
147 | | |
148 | 118M | for (int i = 0; i < IDIM; i++) { |
149 | 98.6M | statelpc[i] = av_clipf(statelpc[i], -4095.0f, 4095.0f); |
150 | 98.6M | dst[idx*IDIM + i] = statelpc[i] * (1.0f/(1<<12)); |
151 | 98.6M | } |
152 | | |
153 | 19.7M | gstate++; |
154 | 19.7M | *gstate = FFMAX(-GOFF, g728_gq_db[ig] + g728_y_db[is] + gain_db); |
155 | | |
156 | 19.7M | if (idx == 0) { |
157 | 4.93M | DECLARE_ALIGNED(32, float, gptmp)[FFALIGN(LPCLG, 16)]; |
158 | 4.93M | if (s->valid && (s->valid = !compute_lpc_coefs(s->r + 1, LPCW, LPC, s->atmp, 0, 0, 1, &s->alpha))) { |
159 | 4.93M | s->fdsp->vector_fmul(s->atmp, s->atmp, g728_facv_f, FFALIGN(LPC, 16)); |
160 | 4.93M | } |
161 | 4.93M | if (hybrid_window(s->fdsp, LPCLG, NUPDATE, NONRLG, s->r, s->sbg, s->rexpg, g728_wnrg_r) && |
162 | 4.93M | !compute_lpc_coefs(s->r, 0, LPCLG, gptmp, 0, 0, 1, &s->alpha)) { |
163 | 4.93M | s->fdsp->vector_fmul(s->gp, gptmp, gain_bw_tab, FFALIGN(LPCLG, 16)); |
164 | 4.93M | } |
165 | 4.93M | memmove(s->sbg, s->sbg + NUPDATE, sizeof(float)*(LPCLG + NONRLG)); |
166 | 4.93M | gstate = s->sbg + NSBGSZ - 1 - NUPDATE; |
167 | 14.8M | } else if (idx == 1) { |
168 | 4.93M | if (s->valid) |
169 | 4.93M | memcpy(s->a, s->atmp, sizeof(float)*LPC); |
170 | 4.93M | } |
171 | 19.7M | } |
172 | | |
173 | 4.93M | s->valid = 0; |
174 | 4.93M | if (hybrid_window(s->fdsp, LPC, NFRSZ, NONR, s->r, s->sb, s->rexp, g728_wnr_r)) { |
175 | 4.93M | s->valid = !compute_lpc_coefs(s->r, 0, LPCW, s->atmp, 0, 0, 1, &s->alpha); |
176 | 4.93M | } |
177 | | |
178 | 4.93M | memmove(s->sb, s->sb + NFRSZ, sizeof(float)*(LPC + NONR)); |
179 | 4.93M | } |
180 | | |
181 | | static int g728_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
182 | | int *got_frame_ptr, AVPacket *avpkt) |
183 | 332k | { |
184 | 332k | G728Context *s = avctx->priv_data; |
185 | 332k | GetBitContext gb; |
186 | 332k | int ret; |
187 | 332k | int nb_frames = avpkt->size / 5; |
188 | | |
189 | 332k | if (!nb_frames) |
190 | 145k | return AVERROR_INVALIDDATA; |
191 | | |
192 | 186k | if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) |
193 | 0 | return ret; |
194 | | |
195 | 186k | #define SAMPLES_PER_FRAME 20 |
196 | | |
197 | 186k | frame->nb_samples = nb_frames * SAMPLES_PER_FRAME; |
198 | 186k | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
199 | 0 | return ret; |
200 | | |
201 | 5.12M | for (int i = 0; i < nb_frames; i++) |
202 | 4.93M | decode_frame(s, &gb, (float *)frame->data[0] + i * 20); |
203 | | |
204 | 186k | *got_frame_ptr = 1; |
205 | | |
206 | 186k | return nb_frames * 5; |
207 | 186k | } |
208 | | |
209 | | const FFCodec ff_g728_decoder = { |
210 | | .p.name = "g728", |
211 | | CODEC_LONG_NAME("G.728)"), |
212 | | .p.type = AVMEDIA_TYPE_AUDIO, |
213 | | .p.id = AV_CODEC_ID_G728, |
214 | | .priv_data_size = sizeof(G728Context), |
215 | | .init = g728_decode_init, |
216 | | .close = g728_decode_close, |
217 | | FF_CODEC_DECODE_CB(g728_decode_frame), |
218 | | .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | |
219 | | AV_CODEC_CAP_DR1, |
220 | | }; |