FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/amr.c
Date: 2024-06-18 16:06:53
Exec Total Coverage
Lines: 80 121 66.1%
Functions: 5 7 71.4%
Branches: 44 60 73.3%

Line Branch Exec Source
1 /*
2 * amr file format
3 * Copyright (c) 2001 FFmpeg project
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 /*
23 Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267
24 */
25
26 #include "config_components.h"
27
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/intreadwrite.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "demux.h"
33 #include "internal.h"
34 #include "mux.h"
35 #include "rawdec.h"
36 #include "rawenc.h"
37
38 typedef struct AMRContext {
39 FFRawDemuxerContext rawctx;
40 } AMRContext;
41
42 static const uint8_t AMR_header[6] = "#!AMR\x0a";
43 static const uint8_t AMRMC_header[12] = "#!AMR_MC1.0\x0a";
44 static const uint8_t AMRWB_header[9] = "#!AMR-WB\x0a";
45 static const uint8_t AMRWBMC_header[15] = "#!AMR-WB_MC1.0\x0a";
46
47 static const uint8_t amrnb_packed_size[16] = {
48 13, 14, 16, 18, 20, 21, 27, 32, 6, 1, 1, 1, 1, 1, 1, 1
49 };
50 static const uint8_t amrwb_packed_size[16] = {
51 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 1, 1, 1, 1, 1, 1
52 };
53
54 #if CONFIG_AMR_DEMUXER
55 7132 static int amr_probe(const AVProbeData *p)
56 {
57 // Only check for "#!AMR" which could be amr-wb, amr-nb.
58 // This will also trigger multichannel files: "#!AMR_MC1.0\n" and
59 // "#!AMR-WB_MC1.0\n"
60
61
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 7122 times.
7132 if (!memcmp(p->buf, AMR_header, 5))
62 10 return AVPROBE_SCORE_MAX;
63 else
64 7122 return 0;
65 }
66
67 /* amr input */
68 12 static int amr_read_header(AVFormatContext *s)
69 {
70 12 AVIOContext *pb = s->pb;
71 AVStream *st;
72 12 uint8_t header[19] = { 0 };
73 12 int read, back = 0, ret;
74
75 12 ret = ffio_ensure_seekback(s->pb, sizeof(header));
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (ret < 0)
77 return ret;
78
79 12 read = avio_read(pb, header, sizeof(header));
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (read < 0)
81 return read;
82
83 12 st = avformat_new_stream(s, NULL);
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!st)
85 return AVERROR(ENOMEM);
86
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (!memcmp(header, AMR_header, sizeof(AMR_header))) {
87 11 st->codecpar->codec_tag = MKTAG('s', 'a', 'm', 'r');
88 11 st->codecpar->codec_id = AV_CODEC_ID_AMR_NB;
89 11 st->codecpar->sample_rate = 8000;
90 11 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
91 11 back = read - sizeof(AMR_header);
92
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (!memcmp(header, AMRWB_header, sizeof(AMRWB_header))) {
93 1 st->codecpar->codec_tag = MKTAG('s', 'a', 'w', 'b');
94 1 st->codecpar->codec_id = AV_CODEC_ID_AMR_WB;
95 1 st->codecpar->sample_rate = 16000;
96 1 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
97 1 back = read - sizeof(AMRWB_header);
98 } else if (!memcmp(header, AMRMC_header, sizeof(AMRMC_header))) {
99 st->codecpar->codec_tag = MKTAG('s', 'a', 'm', 'r');
100 st->codecpar->codec_id = AV_CODEC_ID_AMR_NB;
101 st->codecpar->sample_rate = 8000;
102 st->codecpar->ch_layout.nb_channels = AV_RL32(header + 12);
103 back = read - 4 - sizeof(AMRMC_header);
104 } else if (!memcmp(header, AMRWBMC_header, sizeof(AMRWBMC_header))) {
105 st->codecpar->codec_tag = MKTAG('s', 'a', 'w', 'b');
106 st->codecpar->codec_id = AV_CODEC_ID_AMR_WB;
107 st->codecpar->sample_rate = 16000;
108 st->codecpar->ch_layout.nb_channels = AV_RL32(header + 15);
109 back = read - 4 - sizeof(AMRWBMC_header);
110 } else {
111 return AVERROR_INVALIDDATA;
112 }
113
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (st->codecpar->ch_layout.nb_channels < 1)
115 return AVERROR_INVALIDDATA;
116
117 12 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
118 12 ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
119 12 avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
120
121
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (back > 0)
122 12 avio_seek(pb, -back, SEEK_CUR);
123
124 12 return 0;
125 }
126
127 const FFInputFormat ff_amr_demuxer = {
128 .p.name = "amr",
129 .p.long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
130 .p.flags = AVFMT_GENERIC_INDEX,
131 .p.priv_class = &ff_raw_demuxer_class,
132 .priv_data_size = sizeof(AMRContext),
133 .read_probe = amr_probe,
134 .read_header = amr_read_header,
135 .read_packet = ff_raw_read_partial_packet,
136 };
137 #endif
138
139 #if CONFIG_AMRNB_DEMUXER
140 7132 static int amrnb_probe(const AVProbeData *p)
141 {
142 7132 int mode, i = 0, valid = 0, invalid = 0;
143 7132 const uint8_t *b = p->buf;
144
145
2/2
✓ Branch 0 taken 106714977 times.
✓ Branch 1 taken 7132 times.
106722109 while (i < p->buf_size) {
146 106714977 mode = b[i] >> 3 & 0x0F;
147
4/4
✓ Branch 0 taken 51758012 times.
✓ Branch 1 taken 54956965 times.
✓ Branch 2 taken 15726476 times.
✓ Branch 3 taken 36031536 times.
122441453 if (mode < 9 && (b[i] & 0x4) == 0x4) {
148 15726476 int last = b[i];
149 15726476 int size = amrnb_packed_size[mode];
150
2/2
✓ Branch 0 taken 15811821 times.
✓ Branch 1 taken 1178 times.
15812999 while (size--) {
151
2/2
✓ Branch 0 taken 15725298 times.
✓ Branch 1 taken 86523 times.
15811821 if (b[++i] != last)
152 15725298 break;
153 }
154
2/2
✓ Branch 0 taken 15725197 times.
✓ Branch 1 taken 1279 times.
15726476 if (size > 0) {
155 15725197 valid++;
156 15725197 i += size;
157 }
158 } else {
159 90988501 valid = 0;
160 90988501 invalid++;
161 90988501 i++;
162 }
163 }
164
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7114 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
7132 if (valid > 100 && valid >> 4 > invalid)
165 12 return AVPROBE_SCORE_EXTENSION / 2 + 1;
166 7120 return 0;
167 }
168
169 static int amrnb_read_header(AVFormatContext *s)
170 {
171 AVStream *st = avformat_new_stream(s, NULL);
172 if (!st)
173 return AVERROR(ENOMEM);
174 st->codecpar->codec_id = AV_CODEC_ID_AMR_NB;
175 st->codecpar->sample_rate = 8000;
176 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
177 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
178 ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
179 avpriv_set_pts_info(st, 64, 1, 8000);
180
181 return 0;
182 }
183
184 const FFInputFormat ff_amrnb_demuxer = {
185 .p.name = "amrnb",
186 .p.long_name = NULL_IF_CONFIG_SMALL("raw AMR-NB"),
187 .p.flags = AVFMT_GENERIC_INDEX,
188 .p.priv_class = &ff_raw_demuxer_class,
189 .priv_data_size = sizeof(AMRContext),
190 .read_probe = amrnb_probe,
191 .read_header = amrnb_read_header,
192 .read_packet = ff_raw_read_partial_packet,
193 };
194 #endif
195
196 #if CONFIG_AMRWB_DEMUXER
197 7132 static int amrwb_probe(const AVProbeData *p)
198 {
199 7132 int mode, i = 0, valid = 0, invalid = 0;
200 7132 const uint8_t *b = p->buf;
201
202
2/2
✓ Branch 0 taken 66170102 times.
✓ Branch 1 taken 7132 times.
66177234 while (i < p->buf_size) {
203 66170102 mode = b[i] >> 3 & 0x0F;
204
4/4
✓ Branch 0 taken 34377077 times.
✓ Branch 1 taken 31793025 times.
✓ Branch 2 taken 8976798 times.
✓ Branch 3 taken 25400279 times.
75146900 if (mode < 10 && (b[i] & 0x4) == 0x4) {
205 8976798 int last = b[i];
206 8976798 int size = amrwb_packed_size[mode];
207
2/2
✓ Branch 0 taken 9031486 times.
✓ Branch 1 taken 435 times.
9031921 while (size--) {
208
2/2
✓ Branch 0 taken 8976363 times.
✓ Branch 1 taken 55123 times.
9031486 if (b[++i] != last)
209 8976363 break;
210 }
211
2/2
✓ Branch 0 taken 8976350 times.
✓ Branch 1 taken 448 times.
8976798 if (size > 0) {
212 8976350 valid++;
213 8976350 i += size;
214 }
215 } else {
216 57193304 valid = 0;
217 57193304 invalid++;
218 57193304 i++;
219 }
220 }
221
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7129 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
7132 if (valid > 100 && valid >> 4 > invalid)
222 return AVPROBE_SCORE_EXTENSION / 2 + 1;
223 7132 return 0;
224 }
225
226 static int amrwb_read_header(AVFormatContext *s)
227 {
228 AVStream *st = avformat_new_stream(s, NULL);
229 if (!st)
230 return AVERROR(ENOMEM);
231 st->codecpar->codec_id = AV_CODEC_ID_AMR_WB;
232 st->codecpar->sample_rate = 16000;
233 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
234 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
235 ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
236 avpriv_set_pts_info(st, 64, 1, 16000);
237
238 return 0;
239 }
240
241 const FFInputFormat ff_amrwb_demuxer = {
242 .p.name = "amrwb",
243 .p.long_name = NULL_IF_CONFIG_SMALL("raw AMR-WB"),
244 .p.flags = AVFMT_GENERIC_INDEX,
245 .p.priv_class = &ff_raw_demuxer_class,
246 .priv_data_size = sizeof(AMRContext),
247 .read_probe = amrwb_probe,
248 .read_header = amrwb_read_header,
249 .read_packet = ff_raw_read_partial_packet,
250 };
251 #endif
252
253 #if CONFIG_AMR_MUXER
254 2 static int amr_write_header(AVFormatContext *s)
255 {
256 2 AVIOContext *pb = s->pb;
257 2 AVCodecParameters *par = s->streams[0]->codecpar;
258
259
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
260 1 avio_write(pb, AMR_header, sizeof(AMR_header)); /* magic number */
261
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (par->codec_id == AV_CODEC_ID_AMR_WB) {
262 1 avio_write(pb, AMRWB_header, sizeof(AMRWB_header)); /* magic number */
263 } else {
264 return -1;
265 }
266 2 return 0;
267 }
268
269 const FFOutputFormat ff_amr_muxer = {
270 .p.name = "amr",
271 .p.long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
272 .p.mime_type = "audio/amr",
273 .p.extensions = "amr",
274 .p.audio_codec = AV_CODEC_ID_AMR_NB,
275 .p.video_codec = AV_CODEC_ID_NONE,
276 .p.subtitle_codec = AV_CODEC_ID_NONE,
277 .p.flags = AVFMT_NOTIMESTAMPS,
278 .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH,
279 .write_header = amr_write_header,
280 .write_packet = ff_raw_write_packet,
281 };
282 #endif
283