FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 478 531 90.0%
Functions: 28 28 100.0%
Branches: 351 434 80.9%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /**
22 * @file
23 * audio channel layout utility functions
24 */
25
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "avassert.h"
31 #include "channel_layout.h"
32 #include "bprint.h"
33 #include "common.h"
34 #include "error.h"
35 #include "macros.h"
36 #include "mem.h"
37 #include "opt.h"
38
39 #define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\
40 (x) <= AV_CHAN_AMBISONIC_END)
41
42 struct channel_name {
43 const char *name;
44 const char *description;
45 };
46
47 static const struct channel_name channel_names[] = {
48 [AV_CHAN_FRONT_LEFT ] = { "FL", "front left" },
49 [AV_CHAN_FRONT_RIGHT ] = { "FR", "front right" },
50 [AV_CHAN_FRONT_CENTER ] = { "FC", "front center" },
51 [AV_CHAN_LOW_FREQUENCY ] = { "LFE", "low frequency" },
52 [AV_CHAN_BACK_LEFT ] = { "BL", "back left" },
53 [AV_CHAN_BACK_RIGHT ] = { "BR", "back right" },
54 [AV_CHAN_FRONT_LEFT_OF_CENTER ] = { "FLC", "front left-of-center" },
55 [AV_CHAN_FRONT_RIGHT_OF_CENTER] = { "FRC", "front right-of-center" },
56 [AV_CHAN_BACK_CENTER ] = { "BC", "back center" },
57 [AV_CHAN_SIDE_LEFT ] = { "SL", "side left" },
58 [AV_CHAN_SIDE_RIGHT ] = { "SR", "side right" },
59 [AV_CHAN_TOP_CENTER ] = { "TC", "top center" },
60 [AV_CHAN_TOP_FRONT_LEFT ] = { "TFL", "top front left" },
61 [AV_CHAN_TOP_FRONT_CENTER ] = { "TFC", "top front center" },
62 [AV_CHAN_TOP_FRONT_RIGHT ] = { "TFR", "top front right" },
63 [AV_CHAN_TOP_BACK_LEFT ] = { "TBL", "top back left" },
64 [AV_CHAN_TOP_BACK_CENTER ] = { "TBC", "top back center" },
65 [AV_CHAN_TOP_BACK_RIGHT ] = { "TBR", "top back right" },
66 [AV_CHAN_STEREO_LEFT ] = { "DL", "downmix left" },
67 [AV_CHAN_STEREO_RIGHT ] = { "DR", "downmix right" },
68 [AV_CHAN_WIDE_LEFT ] = { "WL", "wide left" },
69 [AV_CHAN_WIDE_RIGHT ] = { "WR", "wide right" },
70 [AV_CHAN_SURROUND_DIRECT_LEFT ] = { "SDL", "surround direct left" },
71 [AV_CHAN_SURROUND_DIRECT_RIGHT] = { "SDR", "surround direct right" },
72 [AV_CHAN_LOW_FREQUENCY_2 ] = { "LFE2", "low frequency 2" },
73 [AV_CHAN_TOP_SIDE_LEFT ] = { "TSL", "top side left" },
74 [AV_CHAN_TOP_SIDE_RIGHT ] = { "TSR", "top side right" },
75 [AV_CHAN_BOTTOM_FRONT_CENTER ] = { "BFC", "bottom front center" },
76 [AV_CHAN_BOTTOM_FRONT_LEFT ] = { "BFL", "bottom front left" },
77 [AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" },
78 [AV_CHAN_SIDE_SURROUND_LEFT ] = { "SSL", "side surround left" },
79 [AV_CHAN_SIDE_SURROUND_RIGHT ] = { "SSR", "side surround right" },
80 [AV_CHAN_TOP_SURROUND_LEFT ] = { "TTL", "top surround left" },
81 [AV_CHAN_TOP_SURROUND_RIGHT ] = { "TTR", "top surround right" },
82 [AV_CHAN_BINAURAL_LEFT ] = { "BIL", "binaural left" },
83 [AV_CHAN_BINAURAL_RIGHT ] = { "BIR", "binaural right" },
84 };
85
86 1728 void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
87 {
88
3/4
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 1149 times.
✓ Branch 2 taken 579 times.
✗ Branch 3 not taken.
1728 if (channel_id >= AV_CHAN_AMBISONIC_BASE &&
89 channel_id <= AV_CHAN_AMBISONIC_END)
90 579 av_bprintf(bp, "AMBI%d", channel_id - AV_CHAN_AMBISONIC_BASE);
91
2/2
✓ Branch 0 taken 1132 times.
✓ Branch 1 taken 17 times.
1149 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
92
1/2
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
1132 channel_names[channel_id].name)
93 1132 av_bprintf(bp, "%s", channel_names[channel_id].name);
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 else if (channel_id == AV_CHAN_NONE)
95 av_bprintf(bp, "NONE");
96
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 else if (channel_id == AV_CHAN_UNKNOWN)
97 5 av_bprintf(bp, "UNK");
98
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 else if (channel_id == AV_CHAN_UNUSED)
99 3 av_bprintf(bp, "UNSD");
100 else
101 9 av_bprintf(bp, "USR%d", channel_id);
102 1728 }
103
104 365 int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
105 {
106 AVBPrint bp;
107
108
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
365 if (!buf && buf_size)
109 return AVERROR(EINVAL);
110
111 365 av_bprint_init_for_buffer(&bp, buf, buf_size);
112 365 av_channel_name_bprint(&bp, channel_id);
113
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 365 times.
365 if (bp.len >= INT_MAX)
115 return AVERROR(ERANGE);
116 365 return bp.len + 1;
117 }
118
119 15 void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
120 {
121
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
15 if (channel_id >= AV_CHAN_AMBISONIC_BASE &&
122 channel_id <= AV_CHAN_AMBISONIC_END)
123 6 av_bprintf(bp, "ambisonic ACN %d", channel_id - AV_CHAN_AMBISONIC_BASE);
124
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
125
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 channel_names[channel_id].description)
126 6 av_bprintf(bp, "%s", channel_names[channel_id].description);
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (channel_id == AV_CHAN_NONE)
128 av_bprintf(bp, "none");
129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (channel_id == AV_CHAN_UNKNOWN)
130 av_bprintf(bp, "unknown");
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (channel_id == AV_CHAN_UNUSED)
132 av_bprintf(bp, "unused");
133 else
134 3 av_bprintf(bp, "user %d", channel_id);
135 15 }
136
137 10 int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel_id)
138 {
139 AVBPrint bp;
140
141
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
10 if (!buf && buf_size)
142 return AVERROR(EINVAL);
143
144 10 av_bprint_init_for_buffer(&bp, buf, buf_size);
145 10 av_channel_description_bprint(&bp, channel_id);
146
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (bp.len >= INT_MAX)
148 return AVERROR(ERANGE);
149 10 return bp.len + 1;
150 }
151
152 639 enum AVChannel av_channel_from_string(const char *str)
153 {
154 int i;
155 639 char *endptr = (char *)str;
156 639 enum AVChannel id = AV_CHAN_NONE;
157
158
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 379 times.
639 if (!strncmp(str, "AMBI", 4)) {
159 260 i = strtol(str + 4, NULL, 0);
160
3/4
✓ Branch 0 taken 260 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 259 times.
260 if (i < 0 || i > AV_CHAN_AMBISONIC_END - AV_CHAN_AMBISONIC_BASE)
161 1 return AV_CHAN_NONE;
162 259 return AV_CHAN_AMBISONIC_BASE + i;
163 }
164
165
2/2
✓ Branch 0 taken 8475 times.
✓ Branch 1 taken 119 times.
8594 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
166
4/4
✓ Branch 0 taken 5218 times.
✓ Branch 1 taken 3257 times.
✓ Branch 2 taken 260 times.
✓ Branch 3 taken 4958 times.
8475 if (channel_names[i].name && !strcmp(str, channel_names[i].name))
167 260 return i;
168 }
169
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 118 times.
119 if (!strcmp(str, "UNK"))
170 1 return AV_CHAN_UNKNOWN;
171
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 117 times.
118 if (!strcmp(str, "UNSD"))
172 1 return AV_CHAN_UNUSED;
173
174
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 110 times.
117 if (!strncmp(str, "USR", 3)) {
175 7 const char *p = str + 3;
176 7 id = strtol(p, &endptr, 0);
177 }
178
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
117 if (id >= 0 && !*endptr)
179 7 return id;
180
181 110 return AV_CHAN_NONE;
182 }
183
184 struct channel_layout_name {
185 const char *name;
186 AVChannelLayout layout;
187 };
188
189 static const struct channel_layout_name channel_layout_map[] = {
190 { "mono", AV_CHANNEL_LAYOUT_MONO },
191 { "stereo", AV_CHANNEL_LAYOUT_STEREO },
192 { "2.1", AV_CHANNEL_LAYOUT_2POINT1 },
193 { "3.0", AV_CHANNEL_LAYOUT_SURROUND },
194 { "3.0(back)", AV_CHANNEL_LAYOUT_2_1 },
195 { "4.0", AV_CHANNEL_LAYOUT_4POINT0 },
196 { "quad", AV_CHANNEL_LAYOUT_QUAD },
197 { "quad(side)", AV_CHANNEL_LAYOUT_2_2 },
198 { "3.1", AV_CHANNEL_LAYOUT_3POINT1 },
199 { "5.0", AV_CHANNEL_LAYOUT_5POINT0_BACK },
200 { "5.0(side)", AV_CHANNEL_LAYOUT_5POINT0 },
201 { "4.1", AV_CHANNEL_LAYOUT_4POINT1 },
202 { "5.1", AV_CHANNEL_LAYOUT_5POINT1_BACK },
203 { "5.1(side)", AV_CHANNEL_LAYOUT_5POINT1 },
204 { "6.0", AV_CHANNEL_LAYOUT_6POINT0 },
205 { "6.0(front)", AV_CHANNEL_LAYOUT_6POINT0_FRONT },
206 { "3.1.2", AV_CHANNEL_LAYOUT_3POINT1POINT2 },
207 { "hexagonal", AV_CHANNEL_LAYOUT_HEXAGONAL },
208 { "6.1", AV_CHANNEL_LAYOUT_6POINT1 },
209 { "6.1(back)", AV_CHANNEL_LAYOUT_6POINT1_BACK },
210 { "6.1(front)", AV_CHANNEL_LAYOUT_6POINT1_FRONT },
211 { "7.0", AV_CHANNEL_LAYOUT_7POINT0 },
212 { "7.0(front)", AV_CHANNEL_LAYOUT_7POINT0_FRONT },
213 { "7.1", AV_CHANNEL_LAYOUT_7POINT1 },
214 { "7.1(wide)", AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK },
215 { "7.1(wide-side)", AV_CHANNEL_LAYOUT_7POINT1_WIDE },
216 { "5.1.2", AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK },
217 { "octagonal", AV_CHANNEL_LAYOUT_OCTAGONAL },
218 { "cube", AV_CHANNEL_LAYOUT_CUBE },
219 { "5.1.4", AV_CHANNEL_LAYOUT_5POINT1POINT4_BACK },
220 { "7.1.2", AV_CHANNEL_LAYOUT_7POINT1POINT2 },
221 { "7.1.4", AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK },
222 { "7.2.3", AV_CHANNEL_LAYOUT_7POINT2POINT3 },
223 { "9.1.4", AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK },
224 { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL },
225 { "binaural", AV_CHANNEL_LAYOUT_BINAURAL },
226 { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, },
227 { "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
228 };
229
230 54 int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
231 {
232 AVChannelCustom *map;
233
234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (nb_channels <= 0)
235 return AVERROR(EINVAL);
236
237 54 map = av_calloc(nb_channels, sizeof(*channel_layout->u.map));
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!map)
239 return AVERROR(ENOMEM);
240
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 54 times.
171 for (int i = 0; i < nb_channels; i++)
241 117 map[i].id = AV_CHAN_UNKNOWN;
242
243 54 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
244 54 channel_layout->nb_channels = nb_channels;
245 54 channel_layout->u.map = map;
246
247 54 return 0;
248 }
249
250 24229 int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
251 uint64_t mask)
252 {
253
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 24189 times.
24229 if (!mask)
254 40 return AVERROR(EINVAL);
255
256 24189 channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
257 24189 channel_layout->nb_channels = av_popcount64(mask);
258 24189 channel_layout->u.mask = mask;
259
260 24189 return 0;
261 }
262
263 169 static int parse_channel_list(AVChannelLayout *ch_layout, const char *str)
264 {
265 int ret;
266 169 int nb_channels = 0;
267 169 AVChannelCustom *map = NULL;
268 169 AVChannelCustom custom = {0};
269
270
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 72 times.
360 while (*str) {
271 char *channel, *chname;
272 288 int ret = av_opt_get_key_value(&str, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
288 if (ret < 0) {
274 av_freep(&map);
275 97 return ret;
276 }
277
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 167 times.
288 if (*str)
278 121 str++; // skip separator
279
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 14 times.
288 if (!channel) {
280 274 channel = chname;
281 274 chname = NULL;
282 }
283
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 274 times.
288 av_strlcpy(custom.name, chname ? chname : "", sizeof(custom.name));
284 288 custom.id = av_channel_from_string(channel);
285 288 av_free(channel);
286 288 av_free(chname);
287
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 191 times.
288 if (custom.id == AV_CHAN_NONE) {
288 97 av_freep(&map);
289 97 return AVERROR(EINVAL);
290 }
291
292 191 av_dynarray2_add((void **)&map, &nb_channels, sizeof(custom), (void *)&custom);
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 191 times.
191 if (!map)
294 return AVERROR(ENOMEM);
295 }
296
297
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 71 times.
72 if (!nb_channels)
298 1 return AVERROR(EINVAL);
299
300 71 ch_layout->order = AV_CHANNEL_ORDER_CUSTOM;
301 71 ch_layout->u.map = map;
302 71 ch_layout->nb_channels = nb_channels;
303
304 71 ret = av_channel_layout_retype(ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 av_assert0(ret == 0);
306
307 71 return 0;
308 }
309
310 2058 int av_channel_layout_from_string(AVChannelLayout *channel_layout,
311 const char *str)
312 {
313 int i, matches, ret;
314 2058 int channels = 0, nb_channels = 0;
315 char *chlist, *end;
316 2058 uint64_t mask = 0;
317
318 /* channel layout names */
319
2/2
✓ Branch 0 taken 14877 times.
✓ Branch 1 taken 182 times.
15059 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
320
3/4
✓ Branch 0 taken 14877 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1876 times.
✓ Branch 3 taken 13001 times.
14877 if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
321 1876 *channel_layout = channel_layout_map[i].layout;
322 1876 return 0;
323 }
324 }
325
326 /* This function is a channel layout initializer, so we have to
327 * zero-initialize before we start setting fields individually. */
328 182 memset(channel_layout, 0, sizeof(*channel_layout));
329
330 /* ambisonic */
331
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 169 times.
182 if (!strncmp(str, "ambisonic ", 10)) {
332 13 const char *p = str + 10;
333 char *endptr;
334 13 AVChannelLayout extra = {0};
335 int order;
336
337 13 order = strtol(p, &endptr, 0);
338
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 if (order < 0 || order + 1 > INT_MAX / (order + 1) ||
339
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
13 (*endptr && *endptr != '+'))
340 return AVERROR(EINVAL);
341
342 13 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
343 13 channel_layout->nb_channels = (order + 1) * (order + 1);
344
345
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3 times.
13 if (*endptr) {
346 10 int ret = av_channel_layout_from_string(&extra, endptr + 1);
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
348 return ret;
349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) {
350 av_channel_layout_uninit(&extra);
351 return AVERROR(EINVAL);
352 }
353
354
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (extra.order == AV_CHANNEL_ORDER_NATIVE) {
355 8 channel_layout->u.mask = extra.u.mask;
356 } else {
357 2 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
358 2 channel_layout->u.map =
359 2 av_calloc(channel_layout->nb_channels + extra.nb_channels,
360 sizeof(*channel_layout->u.map));
361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!channel_layout->u.map) {
362 av_channel_layout_uninit(&extra);
363 return AVERROR(ENOMEM);
364 }
365
366
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (i = 0; i < channel_layout->nb_channels; i++)
367 13 channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i;
368
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < extra.nb_channels; i++) {
369 3 enum AVChannel ch = av_channel_layout_channel_from_index(&extra, i);
370
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (CHAN_IS_AMBI(ch)) {
371 av_channel_layout_uninit(channel_layout);
372 av_channel_layout_uninit(&extra);
373 return AVERROR(EINVAL);
374 }
375 3 channel_layout->u.map[channel_layout->nb_channels + i].id = ch;
376
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (extra.order == AV_CHANNEL_ORDER_CUSTOM &&
377
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 extra.u.map[i].name[0])
378 1 av_strlcpy(channel_layout->u.map[channel_layout->nb_channels + i].name,
379 1 extra.u.map[i].name,
380 sizeof(channel_layout->u.map[channel_layout->nb_channels + i].name));
381 }
382 }
383 10 channel_layout->nb_channels += extra.nb_channels;
384 10 av_channel_layout_uninit(&extra);
385 }
386
387 13 return 0;
388 }
389
390 169 chlist = av_strdup(str);
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
169 if (!chlist)
392 return AVERROR(ENOMEM);
393
394 /* channel names */
395 169 matches = av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
396 169 ret = parse_channel_list(channel_layout, chlist);
397 169 av_freep(&chlist);
398
3/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 71 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
169 if (ret < 0 && ret != AVERROR(EINVAL))
399 return ret;
400
401
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 98 times.
169 if (ret >= 0) {
402 71 end = strchr(str, ')');
403
7/8
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 28 times.
71 if (matches == 2 && (nb_channels != channel_layout->nb_channels || !end || *++end)) {
404 3 av_channel_layout_uninit(channel_layout);
405 3 return AVERROR(EINVAL);
406 }
407 68 return 0;
408 }
409
410 98 errno = 0;
411 98 mask = strtoull(str, &end, 0);
412
413 /* channel layout mask */
414
7/8
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 53 times.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 43 times.
✓ Branch 7 taken 1 times.
98 if (!errno && !*end && !strchr(str, '-') && mask) {
415 43 av_channel_layout_from_mask(channel_layout, mask);
416 43 return 0;
417 }
418
419 55 errno = 0;
420 55 channels = strtol(str, &end, 10);
421
422 /* number of channels */
423
5/6
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 43 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 1 times.
55 if (!errno && !strcmp(end, "c") && channels > 0) {
424 11 av_channel_layout_default(channel_layout, channels);
425
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
426 9 return 0;
427 }
428
429 /* number of unordered channels */
430
5/6
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 21 times.
46 if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels"))
431
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 && channels > 0) {
432 25 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
433 25 channel_layout->nb_channels = channels;
434 25 return 0;
435 }
436
437 21 return AVERROR(EINVAL);
438 }
439
440 10646900 void av_channel_layout_uninit(AVChannelLayout *channel_layout)
441 {
442
2/2
✓ Branch 0 taken 1630 times.
✓ Branch 1 taken 10645270 times.
10646900 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
443 1630 av_freep(&channel_layout->u.map);
444 10646900 memset(channel_layout, 0, sizeof(*channel_layout));
445 10646900 }
446
447 2498804 int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
448 {
449 2498804 av_channel_layout_uninit(dst);
450 2498804 *dst = *src;
451
2/2
✓ Branch 0 taken 1431 times.
✓ Branch 1 taken 2497373 times.
2498804 if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
452 1431 dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1431 times.
1431 if (!dst->u.map)
454 return AVERROR(ENOMEM);
455 1431 memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
456 }
457 2498804 return 0;
458 }
459
460 709 static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel)
461 {
462 709 uint64_t mask = 0;
463
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 223 times.
1263 for (int i = start_channel; i < channel_layout->nb_channels; i++) {
464 1040 enum AVChannel ch = channel_layout->u.map[i].id;
465
5/6
✓ Branch 0 taken 1040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 585 times.
✓ Branch 3 taken 455 times.
✓ Branch 4 taken 554 times.
✓ Branch 5 taken 31 times.
1040 if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
466 554 mask |= (1ULL << ch);
467 else
468 486 return AVERROR(EINVAL);
469 }
470 223 return mask;
471 }
472
473 725 static int has_channel_names(const AVChannelLayout *channel_layout)
474 {
475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 725 times.
725 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
476 return 0;
477
2/2
✓ Branch 0 taken 1131 times.
✓ Branch 1 taken 706 times.
1837 for (int i = 0; i < channel_layout->nb_channels; i++)
478
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1112 times.
1131 if (channel_layout->u.map[i].name[0])
479 19 return 1;
480 706 return 0;
481 }
482
483 526 int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout)
484 {
485 int i, highest_ambi, order;
486
487
2/2
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 16 times.
526 if (channel_layout->order != AV_CHANNEL_ORDER_AMBISONIC &&
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
489 return AVERROR(EINVAL);
490
491 526 highest_ambi = -1;
492
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 510 times.
526 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC)
493 16 highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1;
494 else {
495 510 const AVChannelCustom *map = channel_layout->u.map;
496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 av_assert0(channel_layout->order == AV_CHANNEL_ORDER_CUSTOM);
497
498
2/2
✓ Branch 0 taken 660 times.
✓ Branch 1 taken 65 times.
725 for (i = 0; i < channel_layout->nb_channels; i++) {
499
3/4
✓ Branch 0 taken 519 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 519 times.
✗ Branch 3 not taken.
660 int is_ambi = CHAN_IS_AMBI(map[i].id);
500
501 /* ambisonic following non-ambisonic */
502
6/8
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 91 times.
✓ Branch 4 taken 59 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 59 times.
660 if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id))
503 return AVERROR(EINVAL);
504
505 /* non-default ordering */
506
4/4
✓ Branch 0 taken 519 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 445 times.
✓ Branch 3 taken 74 times.
660 if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i)
507 445 return AVERROR(EINVAL);
508
509
3/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 74 times.
✗ Branch 3 not taken.
215 if (CHAN_IS_AMBI(map[i].id))
510 74 highest_ambi = i;
511 }
512 }
513 /* no ambisonic channels*/
514
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 31 times.
81 if (highest_ambi < 0)
515 50 return AVERROR(EINVAL);
516
517 31 order = floor(sqrt(highest_ambi));
518 /* incomplete order - some harmonics are missing */
519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if ((order + 1) * (order + 1) != highest_ambi + 1)
520 return AVERROR(EINVAL);
521
522 31 return order;
523 }
524
525 307 static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout)
526 {
527 307 int has_known_channel = 0;
528 int order;
529
530
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 190 times.
307 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
531 117 return channel_layout->order;
532
533
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 186 times.
190 if (has_channel_names(channel_layout))
534 4 return AV_CHANNEL_ORDER_CUSTOM;
535
536
4/4
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 187 times.
✓ Branch 3 taken 83 times.
373 for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++)
537
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 1 times.
187 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN)
538 186 has_known_channel = 1;
539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186 times.
186 if (!has_known_channel)
540 return AV_CHANNEL_ORDER_UNSPEC;
541
542
2/2
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 77 times.
186 if (masked_description(channel_layout, 0) > 0)
543 109 return AV_CHANNEL_ORDER_NATIVE;
544
545 77 order = av_channel_layout_ambisonic_order(channel_layout);
546
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 76 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
77 if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0)
547 1 return AV_CHANNEL_ORDER_AMBISONIC;
548
549 76 return AV_CHANNEL_ORDER_CUSTOM;
550 }
551
552 /**
553 * If the custom layout is n-th order standard-order ambisonic, with optional
554 * extra non-diegetic channels at the end, write its string description in bp.
555 * Return a negative error code otherwise.
556 */
557 446 static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
558 {
559 int nb_ambi_channels;
560 446 int order = av_channel_layout_ambisonic_order(channel_layout);
561
2/2
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 29 times.
446 if (order < 0)
562 417 return order;
563
564 29 av_bprintf(bp, "ambisonic %d", order);
565
566 /* extra channels present */
567 29 nb_ambi_channels = (order + 1) * (order + 1);
568
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 17 times.
29 if (nb_ambi_channels < channel_layout->nb_channels) {
569 12 AVChannelLayout extra = { 0 };
570
571
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) {
572 5 extra.order = AV_CHANNEL_ORDER_NATIVE;
573 5 extra.nb_channels = av_popcount64(channel_layout->u.mask);
574 5 extra.u.mask = channel_layout->u.mask;
575 } else {
576 int64_t mask;
577
4/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
11 if (!has_channel_names(channel_layout) &&
578 4 (mask = masked_description(channel_layout, nb_ambi_channels)) > 0) {
579 1 extra.order = AV_CHANNEL_ORDER_NATIVE;
580 1 extra.nb_channels = av_popcount64(mask);
581 1 extra.u.mask = mask;
582 } else {
583 6 extra.order = AV_CHANNEL_ORDER_CUSTOM;
584 6 extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
585 6 extra.u.map = channel_layout->u.map + nb_ambi_channels;
586 }
587 }
588
589 12 av_bprint_chars(bp, '+', 1);
590 12 av_channel_layout_describe_bprint(&extra, bp);
591 /* Not calling uninit here on extra because we don't own the u.map pointer */
592 }
593
594 29 return 0;
595 }
596
597 16605 int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
598 AVBPrint *bp)
599 {
600 int i;
601
602
4/5
✓ Branch 0 taken 16043 times.
✓ Branch 1 taken 430 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
16605 switch (channel_layout->order) {
603 16043 case AV_CHANNEL_ORDER_NATIVE:
604
2/2
✓ Branch 0 taken 53851 times.
✓ Branch 1 taken 181 times.
54032 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
605
2/2
✓ Branch 0 taken 15862 times.
✓ Branch 1 taken 37989 times.
53851 if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
606 15862 av_bprintf(bp, "%s", channel_layout_map[i].name);
607 15862 return 0;
608 }
609 // fall-through
610 case AV_CHANNEL_ORDER_CUSTOM:
611
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 181 times.
611 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
612 int64_t mask;
613 430 int res = try_describe_ambisonic(bp, channel_layout);
614
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 417 times.
430 if (res >= 0)
615 13 return 0;
616
4/4
✓ Branch 1 taken 406 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 405 times.
823 if (!has_channel_names(channel_layout) &&
617 406 (mask = masked_description(channel_layout, 0)) > 0) {
618 1 AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE,
619 1 .nb_channels = av_popcount64(mask),
620 .u.mask = mask };
621 1 return av_channel_layout_describe_bprint(&native, bp);
622 }
623 }
624
1/2
✓ Branch 0 taken 597 times.
✗ Branch 1 not taken.
597 if (channel_layout->nb_channels)
625 597 av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
626
2/2
✓ Branch 0 taken 1094 times.
✓ Branch 1 taken 597 times.
1691 for (i = 0; i < channel_layout->nb_channels; i++) {
627 1094 enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
628
629
2/2
✓ Branch 0 taken 497 times.
✓ Branch 1 taken 597 times.
1094 if (i)
630 497 av_bprintf(bp, "+");
631 1094 av_channel_name_bprint(bp, ch);
632
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 621 times.
1094 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
633
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 456 times.
473 channel_layout->u.map[i].name[0])
634 17 av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
635 }
636
1/2
✓ Branch 0 taken 597 times.
✗ Branch 1 not taken.
597 if (channel_layout->nb_channels) {
637 597 av_bprintf(bp, ")");
638 597 return 0;
639 }
640 // fall-through
641 case AV_CHANNEL_ORDER_UNSPEC:
642 116 av_bprintf(bp, "%d channels", channel_layout->nb_channels);
643 116 return 0;
644 16 case AV_CHANNEL_ORDER_AMBISONIC:
645 16 return try_describe_ambisonic(bp, channel_layout);
646 default:
647 return AVERROR(EINVAL);
648 }
649 }
650
651 11315 int av_channel_layout_describe(const AVChannelLayout *channel_layout,
652 char *buf, size_t buf_size)
653 {
654 AVBPrint bp;
655 int ret;
656
657
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11293 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
11315 if (!buf && buf_size)
658 return AVERROR(EINVAL);
659
660 11315 av_bprint_init_for_buffer(&bp, buf, buf_size);
661 11315 ret = av_channel_layout_describe_bprint(channel_layout, &bp);
662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11315 times.
11315 if (ret < 0)
663 return ret;
664
665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11315 times.
11315 if (bp.len >= INT_MAX)
666 return AVERROR(ERANGE);
667 11315 return bp.len + 1;
668 }
669
670 enum AVChannel
671 3238 av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout,
672 unsigned int idx)
673 {
674 int i;
675
676
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 3217 times.
3238 if (idx >= channel_layout->nb_channels)
677 21 return AV_CHAN_NONE;
678
679
3/4
✓ Branch 0 taken 1922 times.
✓ Branch 1 taken 344 times.
✓ Branch 2 taken 951 times.
✗ Branch 3 not taken.
3217 switch (channel_layout->order) {
680 1922 case AV_CHANNEL_ORDER_CUSTOM:
681 1922 return channel_layout->u.map[idx].id;
682 344 case AV_CHANNEL_ORDER_AMBISONIC: {
683 344 int ambi_channels = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask);
684
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 14 times.
344 if (idx < ambi_channels)
685 330 return AV_CHAN_AMBISONIC_BASE + idx;
686 14 idx -= ambi_channels;
687 }
688 // fall-through
689 965 case AV_CHANNEL_ORDER_NATIVE:
690
1/2
✓ Branch 0 taken 5762 times.
✗ Branch 1 not taken.
5762 for (i = 0; i < 64; i++) {
691
4/4
✓ Branch 0 taken 2446 times.
✓ Branch 1 taken 3316 times.
✓ Branch 2 taken 965 times.
✓ Branch 3 taken 1481 times.
5762 if ((1ULL << i) & channel_layout->u.mask && !idx--)
692 965 return i;
693 }
694 default:
695 return AV_CHAN_NONE;
696 }
697 }
698
699 enum AVChannel
700 19 av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout,
701 const char *str)
702 {
703 19 int index = av_channel_layout_index_from_string(channel_layout, str);
704
705
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12 times.
19 if (index < 0)
706 7 return AV_CHAN_NONE;
707
708 12 return av_channel_layout_channel_from_index(channel_layout, index);
709 }
710
711 10648 int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout,
712 enum AVChannel channel)
713 {
714 int i;
715
716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10648 times.
10648 if (channel == AV_CHAN_NONE)
717 return AVERROR(EINVAL);
718
719
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 10630 times.
✗ Branch 2 not taken.
10648 switch (channel_layout->order) {
720 18 case AV_CHANNEL_ORDER_CUSTOM:
721
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 5 times.
44 for (i = 0; i < channel_layout->nb_channels; i++)
722
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (channel_layout->u.map[i].id == channel)
723 13 return i;
724 5 return AVERROR(EINVAL);
725 10630 case AV_CHANNEL_ORDER_AMBISONIC:
726 case AV_CHANNEL_ORDER_NATIVE: {
727 10630 uint64_t mask = channel_layout->u.mask;
728 10630 int ambi_channels = channel_layout->nb_channels - av_popcount64(mask);
729
4/4
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 10428 times.
✓ Branch 2 taken 193 times.
✓ Branch 3 taken 9 times.
10630 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC &&
730 channel >= AV_CHAN_AMBISONIC_BASE) {
731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
193 if (channel - AV_CHAN_AMBISONIC_BASE >= ambi_channels)
732 return AVERROR(EINVAL);
733 193 return channel - AV_CHAN_AMBISONIC_BASE;
734 }
735
3/4
✓ Branch 0 taken 10437 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5314 times.
✓ Branch 3 taken 5123 times.
10437 if ((unsigned)channel > 63 || !(mask & (1ULL << channel)))
736 5314 return AVERROR(EINVAL);
737 5123 mask &= (1ULL << channel) - 1;
738 5123 return av_popcount64(mask) + ambi_channels;
739 }
740 default:
741 return AVERROR(EINVAL);
742 }
743 }
744
745 35 int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout,
746 const char *str)
747 {
748 char *chname;
749 35 enum AVChannel ch = AV_CHAN_NONE;
750
751
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
35 switch (channel_layout->order) {
752 18 case AV_CHANNEL_ORDER_CUSTOM:
753 18 chname = strstr(str, "@");
754
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (chname) {
755 char buf[16];
756 8 chname++;
757 8 av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str));
758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!*chname)
759 chname = NULL;
760 8 ch = av_channel_from_string(buf);
761
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
8 if (ch == AV_CHAN_NONE && *buf)
762 return AVERROR(EINVAL);
763 }
764
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 2 times.
32 for (int i = 0; chname && i < channel_layout->nb_channels; i++) {
765
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 2 times.
20 if (!strcmp(chname, channel_layout->u.map[i].name) &&
766
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id))
767 6 return i;
768 }
769 // fall-through
770 case AV_CHANNEL_ORDER_AMBISONIC:
771 case AV_CHANNEL_ORDER_NATIVE:
772 29 ch = av_channel_from_string(str);
773
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
29 if (ch == AV_CHAN_NONE)
774 7 return AVERROR(EINVAL);
775 22 return av_channel_layout_index_from_channel(channel_layout, ch);
776 }
777
778 return AVERROR(EINVAL);
779 }
780
781 298523 int av_channel_layout_check(const AVChannelLayout *channel_layout)
782 {
783
2/2
✓ Branch 0 taken 6498 times.
✓ Branch 1 taken 292025 times.
298523 if (channel_layout->nb_channels <= 0)
784 6498 return 0;
785
786
4/5
✓ Branch 0 taken 286973 times.
✓ Branch 1 taken 405 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 4637 times.
✗ Branch 4 not taken.
292025 switch (channel_layout->order) {
787 286973 case AV_CHANNEL_ORDER_NATIVE:
788 286973 return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
789 405 case AV_CHANNEL_ORDER_CUSTOM:
790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 405 times.
405 if (!channel_layout->u.map)
791 return 0;
792
2/2
✓ Branch 0 taken 620 times.
✓ Branch 1 taken 405 times.
1025 for (int i = 0; i < channel_layout->nb_channels; i++) {
793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 620 times.
620 if (channel_layout->u.map[i].id == AV_CHAN_NONE)
794 return 0;
795 }
796 405 return 1;
797 10 case AV_CHANNEL_ORDER_AMBISONIC:
798 /* If non-diegetic channels are present, ensure they are taken into account */
799 10 return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels;
800 4637 case AV_CHANNEL_ORDER_UNSPEC:
801 4637 return 1;
802 default:
803 return 0;
804 }
805 }
806
807 1446497 int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
808 {
809 int i;
810
811 /* different channel counts -> not equal */
812
2/2
✓ Branch 0 taken 7043 times.
✓ Branch 1 taken 1439454 times.
1446497 if (chl->nb_channels != chl1->nb_channels)
813 7043 return 1;
814
815 /* if only one is unspecified -> not equal */
816 1439454 if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
817
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1439452 times.
1439454 (chl1->order == AV_CHANNEL_ORDER_UNSPEC))
818 2 return 1;
819 /* both are unspecified -> equal */
820
2/2
✓ Branch 0 taken 10269 times.
✓ Branch 1 taken 1429183 times.
1439452 else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
821 10269 return 0;
822
823 /* can compare masks directly */
824
2/2
✓ Branch 0 taken 462 times.
✓ Branch 1 taken 1428721 times.
1429183 if ((chl->order == AV_CHANNEL_ORDER_NATIVE ||
825
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 450 times.
462 chl->order == AV_CHANNEL_ORDER_AMBISONIC) &&
826
1/2
✓ Branch 0 taken 1428733 times.
✗ Branch 1 not taken.
1428733 chl->order == chl1->order)
827 1428733 return chl->u.mask != chl1->u.mask;
828
829 /* compare channel by channel */
830
2/2
✓ Branch 0 taken 716 times.
✓ Branch 1 taken 450 times.
1166 for (i = 0; i < chl->nb_channels; i++)
831
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 716 times.
1432 if (av_channel_layout_channel_from_index(chl, i) !=
832 716 av_channel_layout_channel_from_index(chl1, i))
833 return 1;
834 450 return 0;
835 }
836
837 27620 void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
838 {
839 int i;
840
2/2
✓ Branch 0 taken 45421 times.
✓ Branch 1 taken 15 times.
45436 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
841
2/2
✓ Branch 0 taken 27605 times.
✓ Branch 1 taken 17816 times.
45421 if (nb_channels == channel_layout_map[i].layout.nb_channels) {
842 27605 *ch_layout = channel_layout_map[i].layout;
843 27605 return;
844 }
845
846 15 ch_layout->order = AV_CHANNEL_ORDER_UNSPEC;
847 15 ch_layout->nb_channels = nb_channels;
848 }
849
850 39 const AVChannelLayout *av_channel_layout_standard(void **opaque)
851 {
852 39 uintptr_t i = (uintptr_t)*opaque;
853 39 const AVChannelLayout *ch_layout = NULL;
854
855
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1 times.
39 if (i < FF_ARRAY_ELEMS(channel_layout_map)) {
856 38 ch_layout = &channel_layout_map[i].layout;
857 38 *opaque = (void*)(i + 1);
858 }
859
860 39 return ch_layout;
861 }
862
863 1119 uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
864 uint64_t mask)
865 {
866 1119 uint64_t ret = 0;
867 int i;
868
869
3/3
✓ Branch 0 taken 749 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 368 times.
1119 switch (channel_layout->order) {
870 749 case AV_CHANNEL_ORDER_NATIVE:
871 case AV_CHANNEL_ORDER_AMBISONIC:
872 749 return channel_layout->u.mask & mask;
873 2 case AV_CHANNEL_ORDER_CUSTOM:
874
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 2 times.
130 for (i = 0; i < 64; i++)
875
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 122 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2 times.
128 if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0)
876 4 ret |= (1ULL << i);
877 2 break;
878 }
879
880 370 return ret;
881 }
882
883 327 int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
884 {
885 327 int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
886 int lossy;
887
888
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 327 times.
327 if (!av_channel_layout_check(channel_layout))
889 return AVERROR(EINVAL);
890
891
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 20 times.
327 if (flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL)
892 307 order = canonical_order(channel_layout);
893
894
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 125 times.
327 if (channel_layout->order == order)
895 202 return 0;
896
897
4/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 113 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
125 switch (order) {
898 4 case AV_CHANNEL_ORDER_UNSPEC: {
899 4 int nb_channels = channel_layout->nb_channels;
900
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
901 2 lossy = 0;
902
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 for (int i = 0; i < nb_channels; i++) {
903
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
904 2 lossy = 1;
905 2 break;
906 }
907 }
908 } else {
909 2 lossy = 1;
910 }
911
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (!lossy || allow_lossy) {
912 4 void *opaque = channel_layout->opaque;
913 4 av_channel_layout_uninit(channel_layout);
914 4 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
915 4 channel_layout->nb_channels = nb_channels;
916 4 channel_layout->opaque = opaque;
917 4 return lossy;
918 }
919 return AVERROR(ENOSYS);
920 }
921 113 case AV_CHANNEL_ORDER_NATIVE:
922
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2 times.
113 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
923 111 int64_t mask = masked_description(channel_layout, 0);
924
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 110 times.
111 if (mask < 0)
925 1 return AVERROR(ENOSYS);
926 110 lossy = has_channel_names(channel_layout);
927
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
110 if (!lossy || allow_lossy) {
928 110 void *opaque = channel_layout->opaque;
929 110 av_channel_layout_uninit(channel_layout);
930 110 av_channel_layout_from_mask(channel_layout, mask);
931 110 channel_layout->opaque = opaque;
932 110 return lossy;
933 }
934 }
935 2 return AVERROR(ENOSYS);
936 3 case AV_CHANNEL_ORDER_CUSTOM: {
937 3 AVChannelLayout custom = { 0 };
938 3 int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
939 3 void *opaque = channel_layout->opaque;
940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < 0)
941 return ret;
942
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
943
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (int i = 0; i < channel_layout->nb_channels; i++)
944 13 custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
945 3 av_channel_layout_uninit(channel_layout);
946 3 *channel_layout = custom;
947 3 channel_layout->opaque = opaque;
948 3 return 0;
949 }
950 5 case AV_CHANNEL_ORDER_AMBISONIC:
951
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
952 int64_t mask;
953 3 int nb_channels = channel_layout->nb_channels;
954 3 int order = av_channel_layout_ambisonic_order(channel_layout);
955
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (order < 0)
956 2 return AVERROR(ENOSYS);
957 1 mask = masked_description(channel_layout, (order + 1) * (order + 1));
958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (mask < 0)
959 return AVERROR(ENOSYS);
960 1 lossy = has_channel_names(channel_layout);
961
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!lossy || allow_lossy) {
962 1 void *opaque = channel_layout->opaque;
963 1 av_channel_layout_uninit(channel_layout);
964 1 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
965 1 channel_layout->nb_channels = nb_channels;
966 1 channel_layout->u.mask = mask;
967 1 channel_layout->opaque = opaque;
968 1 return lossy;
969 }
970 }
971 2 return AVERROR(ENOSYS);
972 default:
973 return AVERROR(EINVAL);
974 }
975 }
976