FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/nellymoserenc.c
Date: 2024-04-20 14:10:07
Exec Total Coverage
Lines: 117 177 66.1%
Functions: 7 9 77.8%
Branches: 43 106 40.6%

Line Branch Exec Source
1 /*
2 * Nellymoser encoder
3 * This code is developed as part of Google Summer of Code 2008 Program.
4 *
5 * Copyright (c) 2008 Bartlomiej Wolowiec
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 /**
25 * @file
26 * Nellymoser encoder
27 * by Bartlomiej Wolowiec
28 *
29 * Generic codec information: libavcodec/nellymoserdec.c
30 *
31 * Some information also from: http://samples.mplayerhq.hu/A-codecs/Nelly_Moser/ASAO/ASAO.zip
32 * (Copyright Joseph Artsimovich and UAB "DKD")
33 *
34 * for more information about nellymoser format, visit:
35 * http://wiki.multimedia.cx/index.php?title=Nellymoser
36 */
37
38 #include "libavutil/common.h"
39 #include "libavutil/float_dsp.h"
40 #include "libavutil/mathematics.h"
41 #include "libavutil/mem.h"
42 #include "libavutil/thread.h"
43 #include "libavutil/tx.h"
44
45 #include "audio_frame_queue.h"
46 #include "avcodec.h"
47 #include "codec_internal.h"
48 #include "encode.h"
49 #include "nellymoser.h"
50 #include "sinewin.h"
51
52 #define BITSTREAM_WRITER_LE
53 #include "put_bits.h"
54
55 #define POW_TABLE_SIZE (1<<11)
56 #define POW_TABLE_OFFSET 3
57 #define OPT_SIZE ((1<<15) + 3000)
58
59 typedef struct NellyMoserEncodeContext {
60 AVCodecContext *avctx;
61 int last_frame;
62 AVFloatDSPContext *fdsp;
63 AVTXContext *mdct_ctx;
64 av_tx_fn mdct_fn;
65 AudioFrameQueue afq;
66 DECLARE_ALIGNED(32, float, mdct_out)[NELLY_SAMPLES];
67 DECLARE_ALIGNED(32, float, in_buff)[NELLY_SAMPLES];
68 DECLARE_ALIGNED(32, float, buf)[3 * NELLY_BUF_LEN]; ///< sample buffer
69 float (*opt )[OPT_SIZE];
70 uint8_t (*path)[OPT_SIZE];
71 } NellyMoserEncodeContext;
72
73 static float pow_table[POW_TABLE_SIZE]; ///< pow(2, -i / 2048.0 - 3.0);
74
75 static const uint8_t sf_lut[96] = {
76 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4,
77 5, 5, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 13, 14,
78 15, 15, 16, 17, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 25, 26,
79 27, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40,
80 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53,
81 54, 55, 55, 56, 57, 57, 58, 59, 59, 60, 60, 60, 61, 61, 61, 62,
82 };
83
84 static const uint8_t sf_delta_lut[78] = {
85 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4,
86 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, 11, 12,
87 13, 13, 14, 15, 16, 17, 17, 18, 19, 19, 20, 21, 21, 22, 22, 23,
88 23, 24, 24, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 27, 28,
89 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30,
90 };
91
92 static const uint8_t quant_lut[230] = {
93 0,
94
95 0, 1, 2,
96
97 0, 1, 2, 3, 4, 5, 6,
98
99 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11,
100 12, 13, 13, 13, 14,
101
102 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8,
103 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
104 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 29,
105 30,
106
107 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3,
108 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9,
109 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
110 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20,
111 21, 21, 22, 22, 23, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32,
112 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 42, 43, 44, 44, 45, 45,
113 46, 47, 47, 48, 48, 49, 49, 50, 50, 50, 51, 51, 51, 52, 52, 52,
114 53, 53, 53, 54, 54, 54, 55, 55, 55, 56, 56, 56, 57, 57, 57, 57,
115 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 60, 61, 61, 61,
116 61, 61, 61, 61, 62,
117 };
118
119 static const float quant_lut_mul[7] = { 0.0, 0.0, 2.0, 2.0, 5.0, 12.0, 36.6 };
120 static const float quant_lut_add[7] = { 0.0, 0.0, 2.0, 7.0, 21.0, 56.0, 157.0 };
121 static const uint8_t quant_lut_offset[8] = { 0, 0, 1, 4, 11, 32, 81, 230 };
122
123 376 static void apply_mdct(NellyMoserEncodeContext *s)
124 {
125 376 float *in0 = s->buf;
126 376 float *in1 = s->buf + NELLY_BUF_LEN;
127 376 float *in2 = s->buf + 2 * NELLY_BUF_LEN;
128
129 376 s->fdsp->vector_fmul (s->in_buff, in0, ff_sine_128, NELLY_BUF_LEN);
130 376 s->fdsp->vector_fmul_reverse(s->in_buff + NELLY_BUF_LEN, in1, ff_sine_128, NELLY_BUF_LEN);
131 376 s->mdct_fn(s->mdct_ctx, s->mdct_out, s->in_buff, sizeof(float));
132
133 376 s->fdsp->vector_fmul (s->in_buff, in1, ff_sine_128, NELLY_BUF_LEN);
134 376 s->fdsp->vector_fmul_reverse(s->in_buff + NELLY_BUF_LEN, in2, ff_sine_128, NELLY_BUF_LEN);
135 376 s->mdct_fn(s->mdct_ctx, s->mdct_out + NELLY_BUF_LEN, s->in_buff, sizeof(float));
136 376 }
137
138 1 static av_cold int encode_end(AVCodecContext *avctx)
139 {
140 1 NellyMoserEncodeContext *s = avctx->priv_data;
141
142 1 av_tx_uninit(&s->mdct_ctx);
143
144 1 av_freep(&s->opt);
145 1 av_freep(&s->path);
146 1 ff_af_queue_close(&s->afq);
147 1 av_freep(&s->fdsp);
148
149 1 return 0;
150 }
151
152 1 static av_cold void nellymoser_init_static(void)
153 {
154 /* faster way of doing
155 for (int i = 0; i < POW_TABLE_SIZE; i++)
156 pow_table[i] = 2^(-i / 2048.0 - 3.0 + POW_TABLE_OFFSET); */
157 1 pow_table[0] = 1;
158 1 pow_table[1024] = M_SQRT1_2;
159
2/2
✓ Branch 0 taken 512 times.
✓ Branch 1 taken 1 times.
513 for (int i = 1; i < 513; i++) {
160 512 double tmp = exp2(-i / 2048.0);
161 512 pow_table[i] = tmp;
162 512 pow_table[1024-i] = M_SQRT1_2 / tmp;
163 512 pow_table[1024+i] = tmp * M_SQRT1_2;
164 512 pow_table[2048-i] = 0.5 / tmp;
165 }
166 /* Generate overlap window */
167 1 ff_init_ff_sine_windows(7);
168 1 }
169
170 1 static av_cold int encode_init(AVCodecContext *avctx)
171 {
172 static AVOnce init_static_once = AV_ONCE_INIT;
173 1 NellyMoserEncodeContext *s = avctx->priv_data;
174 1 float scale = 32768.0;
175 int ret;
176
177
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (avctx->sample_rate != 8000 && avctx->sample_rate != 16000 &&
178 avctx->sample_rate != 11025 &&
179 avctx->sample_rate != 22050 && avctx->sample_rate != 44100 &&
180 avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
181 av_log(avctx, AV_LOG_ERROR, "Nellymoser works only with 8000, 16000, 11025, 22050 and 44100 sample rate\n");
182 return AVERROR(EINVAL);
183 }
184
185 1 avctx->frame_size = NELLY_SAMPLES;
186 1 avctx->initial_padding = NELLY_BUF_LEN;
187 1 ff_af_queue_init(avctx, &s->afq);
188 1 s->avctx = avctx;
189
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = av_tx_init(&s->mdct_ctx, &s->mdct_fn, AV_TX_FLOAT_MDCT, 0, 128, &scale, 0)) < 0)
190 return ret;
191 1 s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT);
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->fdsp)
193 return AVERROR(ENOMEM);
194
195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (s->avctx->trellis) {
196 s->opt = av_malloc(NELLY_BANDS * OPT_SIZE * sizeof(float ));
197 s->path = av_malloc(NELLY_BANDS * OPT_SIZE * sizeof(uint8_t));
198 if (!s->opt || !s->path)
199 return AVERROR(ENOMEM);
200 }
201
202 1 ff_thread_once(&init_static_once, nellymoser_init_static);
203
204 1 return 0;
205 }
206
207 #define find_best(val, table, LUT, LUT_add, LUT_size) \
208 best_idx = \
209 LUT[av_clip ((lrintf(val) >> 8) + LUT_add, 0, LUT_size - 1)]; \
210 if (fabs(val - table[best_idx]) > fabs(val - table[best_idx + 1])) \
211 best_idx++;
212
213 376 static void get_exponent_greedy(NellyMoserEncodeContext *s, float *cand, int *idx_table)
214 {
215 376 int band, best_idx, power_idx = 0;
216 float power_candidate;
217
218 //base exponent
219
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 168 times.
376 find_best(cand[0], ff_nelly_init_table, sf_lut, -20, 96);
220 376 idx_table[0] = best_idx;
221 376 power_idx = ff_nelly_init_table[best_idx];
222
223
2/2
✓ Branch 0 taken 8272 times.
✓ Branch 1 taken 376 times.
8648 for (band = 1; band < NELLY_BANDS; band++) {
224 8272 power_candidate = cand[band] - power_idx;
225
2/2
✓ Branch 0 taken 5822 times.
✓ Branch 1 taken 2450 times.
8272 find_best(power_candidate, ff_nelly_delta_table, sf_delta_lut, 37, 78);
226 8272 idx_table[band] = best_idx;
227 8272 power_idx += ff_nelly_delta_table[best_idx];
228 }
229 376 }
230
231 static inline float distance(float x, float y, int band)
232 {
233 //return pow(fabs(x-y), 2.0);
234 float tmp = x - y;
235 return tmp * tmp;
236 }
237
238 static void get_exponent_dynamic(NellyMoserEncodeContext *s, float *cand, int *idx_table)
239 {
240 int i, j, band, best_idx;
241 float power_candidate, best_val;
242
243 float (*opt )[OPT_SIZE] = s->opt ;
244 uint8_t(*path)[OPT_SIZE] = s->path;
245
246 for (i = 0; i < NELLY_BANDS * OPT_SIZE; i++) {
247 opt[0][i] = INFINITY;
248 }
249
250 for (i = 0; i < 64; i++) {
251 opt[0][ff_nelly_init_table[i]] = distance(cand[0], ff_nelly_init_table[i], 0);
252 path[0][ff_nelly_init_table[i]] = i;
253 }
254
255 for (band = 1; band < NELLY_BANDS; band++) {
256 int q, c = 0;
257 float tmp;
258 int idx_min, idx_max, idx;
259 power_candidate = cand[band];
260 for (q = 1000; !c && q < OPT_SIZE; q <<= 2) {
261 idx_min = FFMAX(0, cand[band] - q);
262 idx_max = FFMIN(OPT_SIZE, cand[band - 1] + q);
263 for (i = FFMAX(0, cand[band - 1] - q); i < FFMIN(OPT_SIZE, cand[band - 1] + q); i++) {
264 if ( isinf(opt[band - 1][i]) )
265 continue;
266 for (j = 0; j < 32; j++) {
267 idx = i + ff_nelly_delta_table[j];
268 if (idx > idx_max)
269 break;
270 if (idx >= idx_min) {
271 tmp = opt[band - 1][i] + distance(idx, power_candidate, band);
272 if (opt[band][idx] > tmp) {
273 opt[band][idx] = tmp;
274 path[band][idx] = j;
275 c = 1;
276 }
277 }
278 }
279 }
280 }
281 av_assert1(c); //FIXME
282 }
283
284 best_val = INFINITY;
285 best_idx = -1;
286 band = NELLY_BANDS - 1;
287 for (i = 0; i < OPT_SIZE; i++) {
288 if (best_val > opt[band][i]) {
289 best_val = opt[band][i];
290 best_idx = i;
291 }
292 }
293 for (band = NELLY_BANDS - 1; band >= 0; band--) {
294 idx_table[band] = path[band][best_idx];
295 if (band) {
296 best_idx -= ff_nelly_delta_table[path[band][best_idx]];
297 }
298 }
299 }
300
301 /**
302 * Encode NELLY_SAMPLES samples. It assumes, that samples contains 3 * NELLY_BUF_LEN values
303 * @param s encoder context
304 * @param output output buffer
305 * @param output_size size of output buffer
306 */
307 376 static void encode_block(NellyMoserEncodeContext *s, unsigned char *output, int output_size)
308 {
309 PutBitContext pb;
310 376 int i, j, band, block, best_idx, power_idx = 0;
311 float power_val, coeff, coeff_sum;
312 float pows[NELLY_FILL_LEN];
313 int bits[NELLY_BUF_LEN], idx_table[NELLY_BANDS];
314 float cand[NELLY_BANDS];
315
316 376 apply_mdct(s);
317
318 376 init_put_bits(&pb, output, output_size);
319
320 376 i = 0;
321
2/2
✓ Branch 0 taken 8648 times.
✓ Branch 1 taken 376 times.
9024 for (band = 0; band < NELLY_BANDS; band++) {
322 8648 coeff_sum = 0;
323
2/2
✓ Branch 0 taken 46624 times.
✓ Branch 1 taken 8648 times.
55272 for (j = 0; j < ff_nelly_band_sizes_table[band]; i++, j++) {
324 46624 coeff_sum += s->mdct_out[i ] * s->mdct_out[i ]
325 46624 + s->mdct_out[i + NELLY_BUF_LEN] * s->mdct_out[i + NELLY_BUF_LEN];
326 }
327 8648 cand[band] =
328
2/2
✓ Branch 0 taken 2655 times.
✓ Branch 1 taken 5993 times.
8648 log2(FFMAX(1.0, coeff_sum / (ff_nelly_band_sizes_table[band] << 7))) * 1024.0;
329 }
330
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 376 times.
376 if (s->avctx->trellis) {
332 get_exponent_dynamic(s, cand, idx_table);
333 } else {
334 376 get_exponent_greedy(s, cand, idx_table);
335 }
336
337 376 i = 0;
338
2/2
✓ Branch 0 taken 8648 times.
✓ Branch 1 taken 376 times.
9024 for (band = 0; band < NELLY_BANDS; band++) {
339
2/2
✓ Branch 0 taken 8272 times.
✓ Branch 1 taken 376 times.
8648 if (band) {
340 8272 power_idx += ff_nelly_delta_table[idx_table[band]];
341 8272 put_bits(&pb, 5, idx_table[band]);
342 } else {
343 376 power_idx = ff_nelly_init_table[idx_table[0]];
344 376 put_bits(&pb, 6, idx_table[0]);
345 }
346 8648 power_val = pow_table[power_idx & 0x7FF] / (1 << ((power_idx >> 11) + POW_TABLE_OFFSET));
347
2/2
✓ Branch 0 taken 46624 times.
✓ Branch 1 taken 8648 times.
55272 for (j = 0; j < ff_nelly_band_sizes_table[band]; i++, j++) {
348 46624 s->mdct_out[i] *= power_val;
349 46624 s->mdct_out[i + NELLY_BUF_LEN] *= power_val;
350 46624 pows[i] = power_idx;
351 }
352 }
353
354 376 ff_nelly_get_sample_bits(pows, bits);
355
356
2/2
✓ Branch 0 taken 752 times.
✓ Branch 1 taken 376 times.
1128 for (block = 0; block < 2; block++) {
357
2/2
✓ Branch 0 taken 93248 times.
✓ Branch 1 taken 752 times.
94000 for (i = 0; i < NELLY_FILL_LEN; i++) {
358
2/2
✓ Branch 0 taken 76548 times.
✓ Branch 1 taken 16700 times.
93248 if (bits[i] > 0) {
359 76548 const float *table = ff_nelly_dequantization_table + (1 << bits[i]) - 1;
360 76548 coeff = s->mdct_out[block * NELLY_BUF_LEN + i];
361 76548 best_idx =
362 76548 quant_lut[av_clip (
363 76548 coeff * quant_lut_mul[bits[i]] + quant_lut_add[bits[i]],
364 76548 quant_lut_offset[bits[i]],
365 76548 quant_lut_offset[bits[i]+1] - 1
366 )];
367
2/2
✓ Branch 0 taken 52418 times.
✓ Branch 1 taken 24130 times.
76548 if (fabs(coeff - table[best_idx]) > fabs(coeff - table[best_idx + 1]))
368 52418 best_idx++;
369
370 76548 put_bits(&pb, bits[i], best_idx);
371 }
372 }
373
2/2
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 376 times.
752 if (!block)
374 376 put_bits(&pb, NELLY_HEADER_BITS + NELLY_DETAIL_BITS - put_bits_count(&pb), 0);
375 }
376
377 376 flush_put_bits(&pb);
378 376 memset(put_bits_ptr(&pb), 0, output + output_size - put_bits_ptr(&pb));
379 376 }
380
381 377 static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
382 const AVFrame *frame, int *got_packet_ptr)
383 {
384 377 NellyMoserEncodeContext *s = avctx->priv_data;
385 int ret;
386
387
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 376 times.
377 if (s->last_frame)
388 1 return 0;
389
390 376 memcpy(s->buf, s->buf + NELLY_SAMPLES, NELLY_BUF_LEN * sizeof(*s->buf));
391
2/2
✓ Branch 0 taken 375 times.
✓ Branch 1 taken 1 times.
376 if (frame) {
392 375 memcpy(s->buf + NELLY_BUF_LEN, frame->data[0],
393 375 frame->nb_samples * sizeof(*s->buf));
394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 375 times.
375 if (frame->nb_samples < NELLY_SAMPLES) {
395 memset(s->buf + NELLY_BUF_LEN + frame->nb_samples, 0,
396 (NELLY_SAMPLES - frame->nb_samples) * sizeof(*s->buf));
397 if (frame->nb_samples >= NELLY_BUF_LEN)
398 s->last_frame = 1;
399 }
400
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 375 times.
375 if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
401 return ret;
402 } else {
403 1 memset(s->buf + NELLY_BUF_LEN, 0, NELLY_SAMPLES * sizeof(*s->buf));
404 1 s->last_frame = 1;
405 }
406
407
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 376 times.
376 if ((ret = ff_get_encode_buffer(avctx, avpkt, NELLY_BLOCK_LEN, 0)) < 0)
408 return ret;
409 376 encode_block(s, avpkt->data, avpkt->size);
410
411 /* Get the next frame pts/duration */
412 376 ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts,
413 &avpkt->duration);
414
415 376 *got_packet_ptr = 1;
416 376 return 0;
417 }
418
419 const FFCodec ff_nellymoser_encoder = {
420 .p.name = "nellymoser",
421 CODEC_LONG_NAME("Nellymoser Asao"),
422 .p.type = AVMEDIA_TYPE_AUDIO,
423 .p.id = AV_CODEC_ID_NELLYMOSER,
424 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
425 AV_CODEC_CAP_SMALL_LAST_FRAME,
426 .priv_data_size = sizeof(NellyMoserEncodeContext),
427 .init = encode_init,
428 FF_CODEC_ENCODE_CB(encode_frame),
429 .close = encode_end,
430 .p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT,
431 AV_SAMPLE_FMT_NONE },
432 .p.ch_layouts = (const AVChannelLayout[]){ AV_CHANNEL_LAYOUT_MONO, { 0 } },
433 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
434 };
435