FFmpeg
Loading...
Searching...
No Matches
amrgen.c
Go to the documentation of this file.
1/*
2 * Generate the AMR streams used by the DTX FATE tests.
3 *
4 * The storage format is a header plus one table-of-contents byte and the
5 * payload of each frame (RFC 4867). These files are built from that layout
6 * here, the same way audiogen builds its wave files, so the tests do not
7 * need media from the fate-suite.
8 *
9 * Copyright (c) 2026 Jun Zhao
10 *
11 * This file is part of FFmpeg.
12 *
13 * FFmpeg is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * FFmpeg is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with FFmpeg; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28#include <errno.h>
29#include <stdint.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34/* Narrowband speech is one repeated 4.75 kbit/s frame: pitch lag 40 on the
35 first subframe (coded index 61) and gain index 3. Comfort-noise energy is
36 the 6-bit index carried by a SID_UPDATE. A silent period mutes once more
37 than 50 frames have passed with no SID update. */
38
39enum {
42};
43
44static void die(const char *path)
45{
46 fprintf(stderr, "amrgen: %s: %s\n", path, strerror(errno));
47 exit(1);
48}
49
50static void put_msb(uint8_t *data, int *pos, int n, unsigned value)
51{
52 int i;
53
54 for (i = n - 1; i >= 0; i--) {
55 int bit = (*pos)++;
56
57 if (value & (1u << i))
58 data[bit >> 3] |= 1u << (7 - (bit & 7));
59 }
60}
61
62static void set_lsb_field(uint8_t *data, const uint8_t *bits, int n,
63 unsigned value)
64{
65 int i;
66
67 for (i = 0; i < n; i++) {
68 if (value & (1u << (n - 1 - i)))
69 data[bits[i] >> 3] |= 1u << (bits[i] & 7);
70 }
71}
72
73static void write_nb_speech(FILE *f)
74{
75 /* Bit positions are those consumed by order_MODE_4k75[], MSB first. */
76 static const uint8_t lag0[] = { 23, 22, 21, 20, 19, 18, 43, 42 };
77 static const uint8_t gain0[] = { 54, 55, 40, 41, 24, 25, 26, 27 };
78 static const uint8_t gain2[] = { 44, 45, 46, 47, 36, 37, 38, 39 };
79 uint8_t frame[13] = { 0x04 };
80
81 set_lsb_field(frame + 1, lag0, 8, 61);
82 set_lsb_field(frame + 1, gain0, 8, 3);
83 set_lsb_field(frame + 1, gain2, 8, 3);
84 if (fwrite(frame, 1, sizeof(frame), f) != sizeof(frame))
85 die("write");
86}
87
88/* energy is the 6-bit index. update selects SID_UPDATE over SID_FIRST. */
89static void write_nb_sid(FILE *f, int energy, int update)
90{
91 uint8_t frame[6] = { 0x44 };
92 int pos = 0;
93
94 put_msb(frame + 1, &pos, 3, 0);
95 put_msb(frame + 1, &pos, 8, 0);
96 put_msb(frame + 1, &pos, 9, 0);
97 put_msb(frame + 1, &pos, 9, 0);
98 put_msb(frame + 1, &pos, 6, energy);
99 put_msb(frame + 1, &pos, 1, update);
100 put_msb(frame + 1, &pos, 3, 0);
101 if (fwrite(frame, 1, sizeof(frame), f) != sizeof(frame))
102 die("write");
103}
104
105static void write_nodata(FILE *f, int q)
106{
107 uint8_t toc = q ? 0x7c : 0x78;
108
109 if (fwrite(&toc, 1, 1, f) != 1)
110 die("write");
111}
112
113/* Frame types 9..14 are reserved and decoded as NO_DATA. */
114static void write_reserved(FILE *f)
115{
116 uint8_t toc = 0x4c;
117
118 if (fwrite(&toc, 1, 1, f) != 1)
119 die("write");
120}
121
122static void write_wb_sid(FILE *f, int energy)
123{
124 uint8_t frame[6] = { 0x4c };
125 int pos = 0;
126 int i;
127
128 for (i = 0; i < 3; i++)
129 put_msb(frame + 1, &pos, 6, 0);
130 put_msb(frame + 1, &pos, 5, 0);
131 put_msb(frame + 1, &pos, 5, 0);
132 put_msb(frame + 1, &pos, 6, energy);
133 put_msb(frame + 1, &pos, 1, 0); /* dither */
134 put_msb(frame + 1, &pos, 1, 1); /* SID_UPDATE */
135 if (fwrite(frame, 1, sizeof(frame), f) != sizeof(frame))
136 die("write");
137}
138
139static FILE *open_out(const char *path, const char *header)
140{
141 FILE *f = fopen(path, "wb");
142
143 if (!f)
144 die(path);
145 if (fwrite(header, 1, strlen(header), f) != strlen(header))
146 die(path);
147 return f;
148}
149
150/* 8 speech, SID, 4 NO_DATA, SID, 4 NO_DATA, 8 speech.
151 Frame 13 is the second SID. Frame 18 is the first speech after it. */
152static void gen_sid_update(const char *path)
153{
154 FILE *f = open_out(path, "#!AMR\n");
155 int i;
156
157 for (i = 0; i < 8; i++)
159 write_nb_sid(f, 16, 1);
160 for (i = 0; i < 4; i++)
161 write_nodata(f, 1);
162 write_nb_sid(f, 16, 1);
163 for (i = 0; i < 4; i++)
164 write_nodata(f, 1);
165 for (i = 0; i < 8; i++)
167 if (fclose(f))
168 die(path);
169}
170
171/* 8 speech, quiet SID, 4 NO_DATA, loud SID, 4 NO_DATA, 4 speech.
172 Frame 18 is the first speech frame after the loud update. */
173static void gen_state_resume(const char *path)
174{
175 FILE *f = open_out(path, "#!AMR\n");
176 int i;
177
178 for (i = 0; i < 8; i++)
180 write_nb_sid(f, 8, 1);
181 for (i = 0; i < 4; i++)
182 write_nodata(f, 1);
183 write_nb_sid(f, 32, 1);
184 for (i = 0; i < 4; i++)
185 write_nodata(f, 1);
186 for (i = 0; i < 4; i++)
188 if (fclose(f))
189 die(path);
190}
191
192/* Speech, then one NO_DATA or reserved frame, repeated.
193 q1_at_first selects the Q bit of the first NO_DATA frame only.
194 Frame 8 is that NO_DATA, frame 17 is a Q=0 NO_DATA, frame 26 is reserved. */
195static void gen_nodata(const char *path, int q1_at_first)
196{
197 FILE *f = open_out(path, "#!AMR\n");
198 int i;
199
200 for (i = 0; i < 8; i++)
202 write_nodata(f, q1_at_first);
203 for (i = 0; i < 8; i++)
205 write_nodata(f, 0);
206 for (i = 0; i < 8; i++)
209 for (i = 0; i < 8; i++)
211 if (fclose(f))
212 die(path);
213}
214
215/* 8 speech, one lost frame, SID_UPDATE, 4 NO_DATA, 4 speech.
216 Frame 10 is the first comfort-noise frame after that SID. */
217static void gen_sid_after_nodata(const char *path)
218{
219 FILE *f = open_out(path, "#!AMR\n");
220 int i;
221
222 for (i = 0; i < 8; i++)
224 write_nodata(f, 1);
225 write_nb_sid(f, 20, 1);
226 for (i = 0; i < 4; i++)
227 write_nodata(f, 1);
228 for (i = 0; i < 4; i++)
230 if (fclose(f))
231 die(path);
232}
233
234/* 11 speech, one SID, 51 NO_DATA (past the 50-frame mute threshold), 2 speech.
235 Eleven speech frames (44 subframes) take fixed_gain_smooth() past its
236 40-subframe hangover before silence begins. Frame 63 is the first speech
237 frame after the muted period. 65 frames * 160 samples = 10400. */
238static void gen_mute_resume(const char *path)
239{
240 FILE *f = open_out(path, "#!AMR\n");
241 int i;
242
243 for (i = 0; i < 11; i++)
245 write_nb_sid(f, 15, 1);
246 for (i = 0; i < 51; i++)
247 write_nodata(f, 1);
248 for (i = 0; i < 2; i++)
250 if (fclose(f))
251 die(path);
252}
253
254/* One SID_UPDATE and 10 NO_DATA frames. 11 * 320 = 3520 samples. */
255static void gen_wb(const char *path)
256{
257 FILE *f = open_out(path, "#!AMR-WB\n");
258 int i;
259
260 write_wb_sid(f, 20);
261 for (i = 0; i < 10; i++)
262 write_nodata(f, 1);
263 if (fclose(f))
264 die(path);
265}
266
267int main(int argc, char **argv)
268{
269 const char *base;
270
271 if (argc != 2) {
272 fprintf(stderr, "usage: amrgen <output.amr>\n");
273 return 1;
274 }
275
276 base = strrchr(argv[1], '/');
277 base = base ? base + 1 : argv[1];
278
279 if (!strcmp(base, "amrnb-sid-update.amr"))
280 gen_sid_update(argv[1]);
281 else if (!strcmp(base, "amrnb-state-resume-update.amr"))
282 gen_state_resume(argv[1]);
283 else if (!strcmp(base, "amrnb-nodata-cases.amr"))
284 gen_nodata(argv[1], 1);
285 else if (!strcmp(base, "amrnb-nodata-qswap-q0.amr"))
286 gen_nodata(argv[1], 0);
287 else if (!strcmp(base, "amrnb-sid-after-nodata.amr"))
288 gen_sid_after_nodata(argv[1]);
289 else if (!strcmp(base, "amrnb-dtx-mute-resume.amr"))
290 gen_mute_resume(argv[1]);
291 else if (!strcmp(base, "amrwb-dtx.amr"))
292 gen_wb(argv[1]);
293 else {
294 fprintf(stderr, "amrgen: unknown stream '%s'\n", base);
295 return 1;
296 }
297 return 0;
298}
static av_always_inline void update(AVFilterContext *ctx, AVFrame *insamples, int is_silence, int current_sample, int64_t nb_samples_notify, AVRational time_base)
static void write_nb_speech(FILE *f)
Definition amrgen.c:73
static void gen_mute_resume(const char *path)
Definition amrgen.c:238
static void die(const char *path)
Definition amrgen.c:44
static void write_nb_sid(FILE *f, int energy, int update)
Definition amrgen.c:89
static void put_msb(uint8_t *data, int *pos, int n, unsigned value)
Definition amrgen.c:50
static void gen_nodata(const char *path, int q1_at_first)
Definition amrgen.c:195
static void gen_wb(const char *path)
Definition amrgen.c:255
@ NB_FRAME_SAMPLES
Definition amrgen.c:40
@ WB_FRAME_SAMPLES
Definition amrgen.c:41
static void write_wb_sid(FILE *f, int energy)
Definition amrgen.c:122
static void gen_sid_update(const char *path)
Definition amrgen.c:152
static void set_lsb_field(uint8_t *data, const uint8_t *bits, int n, unsigned value)
Definition amrgen.c:62
static void write_reserved(FILE *f)
Definition amrgen.c:114
static void gen_state_resume(const char *path)
Definition amrgen.c:173
static void gen_sid_after_nodata(const char *path)
Definition amrgen.c:217
static void write_nodata(FILE *f, int q)
Definition amrgen.c:105
static FILE * open_out(const char *path, const char *header)
Definition amrgen.c:139
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define bit(string, value)
Definition cbs_mpeg2.c:56
#define f(width, name)
Definition cbs_vp8.c:236
static AVFrame * frame
int main
Definition dovi_rpuenc.c:38
double value
Definition eval.c:102
static const uint8_t bits[8]
Definition fastaudio.c:100
char * path
Definition ffplay.c:385
const char data[16]
Definition mxf.c:149
static const uint8_t header[24]
Definition sdr2.c:68
unsigned int pos
Definition spdifenc.c:431
uint8_t base
Definition vp3data.h:128