FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2024-02-16 17:37:06
Exec Total Coverage
Lines: 463 630 73.5%
Functions: 32 39 82.1%
Branches: 364 548 66.4%

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 "opt.h"
37
38 #define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\
39 (x) <= AV_CHAN_AMBISONIC_END)
40
41 struct channel_name {
42 const char *name;
43 const char *description;
44 };
45
46 static const struct channel_name channel_names[] = {
47 [AV_CHAN_FRONT_LEFT ] = { "FL", "front left" },
48 [AV_CHAN_FRONT_RIGHT ] = { "FR", "front right" },
49 [AV_CHAN_FRONT_CENTER ] = { "FC", "front center" },
50 [AV_CHAN_LOW_FREQUENCY ] = { "LFE", "low frequency" },
51 [AV_CHAN_BACK_LEFT ] = { "BL", "back left" },
52 [AV_CHAN_BACK_RIGHT ] = { "BR", "back right" },
53 [AV_CHAN_FRONT_LEFT_OF_CENTER ] = { "FLC", "front left-of-center" },
54 [AV_CHAN_FRONT_RIGHT_OF_CENTER] = { "FRC", "front right-of-center" },
55 [AV_CHAN_BACK_CENTER ] = { "BC", "back center" },
56 [AV_CHAN_SIDE_LEFT ] = { "SL", "side left" },
57 [AV_CHAN_SIDE_RIGHT ] = { "SR", "side right" },
58 [AV_CHAN_TOP_CENTER ] = { "TC", "top center" },
59 [AV_CHAN_TOP_FRONT_LEFT ] = { "TFL", "top front left" },
60 [AV_CHAN_TOP_FRONT_CENTER ] = { "TFC", "top front center" },
61 [AV_CHAN_TOP_FRONT_RIGHT ] = { "TFR", "top front right" },
62 [AV_CHAN_TOP_BACK_LEFT ] = { "TBL", "top back left" },
63 [AV_CHAN_TOP_BACK_CENTER ] = { "TBC", "top back center" },
64 [AV_CHAN_TOP_BACK_RIGHT ] = { "TBR", "top back right" },
65 [AV_CHAN_STEREO_LEFT ] = { "DL", "downmix left" },
66 [AV_CHAN_STEREO_RIGHT ] = { "DR", "downmix right" },
67 [AV_CHAN_WIDE_LEFT ] = { "WL", "wide left" },
68 [AV_CHAN_WIDE_RIGHT ] = { "WR", "wide right" },
69 [AV_CHAN_SURROUND_DIRECT_LEFT ] = { "SDL", "surround direct left" },
70 [AV_CHAN_SURROUND_DIRECT_RIGHT] = { "SDR", "surround direct right" },
71 [AV_CHAN_LOW_FREQUENCY_2 ] = { "LFE2", "low frequency 2" },
72 [AV_CHAN_TOP_SIDE_LEFT ] = { "TSL", "top side left" },
73 [AV_CHAN_TOP_SIDE_RIGHT ] = { "TSR", "top side right" },
74 [AV_CHAN_BOTTOM_FRONT_CENTER ] = { "BFC", "bottom front center" },
75 [AV_CHAN_BOTTOM_FRONT_LEFT ] = { "BFL", "bottom front left" },
76 [AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" },
77 };
78
79 static const char *get_channel_name(enum AVChannel channel_id)
80 {
81 if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names) ||
82 !channel_names[channel_id].name)
83 return NULL;
84 return channel_names[channel_id].name;
85 }
86
87 1054 void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
88 {
89
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1048 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
1054 if (channel_id >= AV_CHAN_AMBISONIC_BASE &&
90 channel_id <= AV_CHAN_AMBISONIC_END)
91 6 av_bprintf(bp, "AMBI%d", channel_id - AV_CHAN_AMBISONIC_BASE);
92
2/2
✓ Branch 0 taken 1039 times.
✓ Branch 1 taken 9 times.
1048 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
93
1/2
✓ Branch 0 taken 1039 times.
✗ Branch 1 not taken.
1039 channel_names[channel_id].name)
94 1039 av_bprintf(bp, "%s", channel_names[channel_id].name);
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 else if (channel_id == AV_CHAN_NONE)
96 av_bprintf(bp, "NONE");
97 else
98 9 av_bprintf(bp, "USR%d", channel_id);
99 1054 }
100
101 104 int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
102 {
103 AVBPrint bp;
104
105
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
104 if (!buf && buf_size)
106 return AVERROR(EINVAL);
107
108 104 av_bprint_init_for_buffer(&bp, buf, buf_size);
109 104 av_channel_name_bprint(&bp, channel_id);
110
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
104 if (bp.len >= INT_MAX)
112 return AVERROR(ERANGE);
113 104 return bp.len + 1;
114 }
115
116 15 void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
117 {
118
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 &&
119 channel_id <= AV_CHAN_AMBISONIC_END)
120 6 av_bprintf(bp, "ambisonic ACN %d", channel_id - AV_CHAN_AMBISONIC_BASE);
121
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
122
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 channel_names[channel_id].description)
123 6 av_bprintf(bp, "%s", channel_names[channel_id].description);
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (channel_id == AV_CHAN_NONE)
125 av_bprintf(bp, "none");
126 else
127 3 av_bprintf(bp, "user %d", channel_id);
128 15 }
129
130 10 int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel_id)
131 {
132 AVBPrint bp;
133
134
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)
135 return AVERROR(EINVAL);
136
137 10 av_bprint_init_for_buffer(&bp, buf, buf_size);
138 10 av_channel_description_bprint(&bp, channel_id);
139
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (bp.len >= INT_MAX)
141 return AVERROR(ERANGE);
142 10 return bp.len + 1;
143 }
144
145 79 enum AVChannel av_channel_from_string(const char *str)
146 {
147 int i;
148 79 char *endptr = (char *)str;
149 79 enum AVChannel id = AV_CHAN_NONE;
150
151
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 77 times.
79 if (!strncmp(str, "AMBI", 4)) {
152 2 i = strtol(str + 4, NULL, 0);
153
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (i < 0 || i > AV_CHAN_AMBISONIC_END - AV_CHAN_AMBISONIC_BASE)
154 return AV_CHAN_NONE;
155 2 return AV_CHAN_AMBISONIC_BASE + i;
156 }
157
158
2/2
✓ Branch 0 taken 684 times.
✓ Branch 1 taken 11 times.
695 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
159
4/4
✓ Branch 0 taken 563 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 497 times.
684 if (channel_names[i].name && !strcmp(str, channel_names[i].name))
160 66 return i;
161 }
162
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
11 if (!strncmp(str, "USR", 3)) {
163 5 const char *p = str + 3;
164 5 id = strtol(p, &endptr, 0);
165 }
166
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
11 if (id >= 0 && !*endptr)
167 5 return id;
168
169 6 return AV_CHAN_NONE;
170 }
171
172 struct channel_layout_name {
173 const char *name;
174 AVChannelLayout layout;
175 };
176
177 static const struct channel_layout_name channel_layout_map[] = {
178 { "mono", AV_CHANNEL_LAYOUT_MONO },
179 { "stereo", AV_CHANNEL_LAYOUT_STEREO },
180 { "2.1", AV_CHANNEL_LAYOUT_2POINT1 },
181 { "3.0", AV_CHANNEL_LAYOUT_SURROUND },
182 { "3.0(back)", AV_CHANNEL_LAYOUT_2_1 },
183 { "4.0", AV_CHANNEL_LAYOUT_4POINT0 },
184 { "quad", AV_CHANNEL_LAYOUT_QUAD },
185 { "quad(side)", AV_CHANNEL_LAYOUT_2_2 },
186 { "3.1", AV_CHANNEL_LAYOUT_3POINT1 },
187 { "5.0", AV_CHANNEL_LAYOUT_5POINT0_BACK },
188 { "5.0(side)", AV_CHANNEL_LAYOUT_5POINT0 },
189 { "4.1", AV_CHANNEL_LAYOUT_4POINT1 },
190 { "5.1", AV_CHANNEL_LAYOUT_5POINT1_BACK },
191 { "5.1(side)", AV_CHANNEL_LAYOUT_5POINT1 },
192 { "6.0", AV_CHANNEL_LAYOUT_6POINT0 },
193 { "6.0(front)", AV_CHANNEL_LAYOUT_6POINT0_FRONT },
194 { "3.1.2", AV_CHANNEL_LAYOUT_3POINT1POINT2 },
195 { "hexagonal", AV_CHANNEL_LAYOUT_HEXAGONAL },
196 { "6.1", AV_CHANNEL_LAYOUT_6POINT1 },
197 { "6.1(back)", AV_CHANNEL_LAYOUT_6POINT1_BACK },
198 { "6.1(front)", AV_CHANNEL_LAYOUT_6POINT1_FRONT },
199 { "7.0", AV_CHANNEL_LAYOUT_7POINT0 },
200 { "7.0(front)", AV_CHANNEL_LAYOUT_7POINT0_FRONT },
201 { "7.1", AV_CHANNEL_LAYOUT_7POINT1 },
202 { "7.1(wide)", AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK },
203 { "7.1(wide-side)", AV_CHANNEL_LAYOUT_7POINT1_WIDE },
204 { "5.1.2", AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK },
205 { "octagonal", AV_CHANNEL_LAYOUT_OCTAGONAL },
206 { "cube", AV_CHANNEL_LAYOUT_CUBE },
207 { "5.1.4", AV_CHANNEL_LAYOUT_5POINT1POINT4_BACK },
208 { "7.1.2", AV_CHANNEL_LAYOUT_7POINT1POINT2 },
209 { "7.1.4", AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK },
210 { "7.2.3", AV_CHANNEL_LAYOUT_7POINT2POINT3 },
211 { "9.1.4", AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK },
212 { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL },
213 { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, },
214 { "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
215 };
216
217 #if FF_API_OLD_CHANNEL_LAYOUT
218 FF_DISABLE_DEPRECATION_WARNINGS
219 15 static uint64_t get_channel_layout_single(const char *name, int name_len)
220 {
221 int i;
222 char *end;
223 int64_t layout;
224
225
2/2
✓ Branch 0 taken 555 times.
✓ Branch 1 taken 15 times.
570 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
226
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 518 times.
555 if (strlen(channel_layout_map[i].name) == name_len &&
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 !memcmp(channel_layout_map[i].name, name, name_len))
228 return channel_layout_map[i].layout.u.mask;
229 }
230
2/2
✓ Branch 0 taken 615 times.
✓ Branch 1 taken 15 times.
630 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
231
2/2
✓ Branch 0 taken 450 times.
✓ Branch 1 taken 165 times.
615 if (channel_names[i].name &&
232
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 310 times.
450 strlen(channel_names[i].name) == name_len &&
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
140 !memcmp(channel_names[i].name, name, name_len))
234 return (int64_t)1 << i;
235
236 15 errno = 0;
237 15 i = strtol(name, &end, 10);
238
239
4/6
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
15 if (!errno && (end + 1 - name == name_len && *end == 'c'))
240 9 return av_get_default_channel_layout(i);
241
242 6 errno = 0;
243 6 layout = strtoll(name, &end, 0);
244
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
6 if (!errno && end - name == name_len)
245 5 return FFMAX(layout, 0);
246 1 return 0;
247 }
248
249 8 uint64_t av_get_channel_layout(const char *name)
250 {
251 const char *n, *e;
252 8 const char *name_end = name + strlen(name);
253 8 int64_t layout = 0, layout_single;
254
255
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 for (n = name; n < name_end; n = e + 1) {
256
5/6
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
46 for (e = n; e < name_end && *e != '+' && *e != '|'; e++);
257 15 layout_single = get_channel_layout_single(n, e - n);
258
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 10 times.
15 if (!layout_single)
259 5 return 0;
260 10 layout |= layout_single;
261 }
262 3 return layout;
263 }
264
265 8 int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels)
266 {
267 8 int nb = 0;
268 char *end;
269 8 uint64_t layout = av_get_channel_layout(name);
270
271
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (layout) {
272 3 *channel_layout = layout;
273 3 *nb_channels = av_get_channel_layout_nb_channels(layout);
274 3 return 0;
275 }
276
277 5 nb = strtol(name, &end, 10);
278
2/10
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
5 if (!errno && *end == 'C' && *(end + 1) == '\0' && nb > 0 && nb < 64) {
279 *channel_layout = 0;
280 *nb_channels = nb;
281 return 0;
282 }
283
284 5 return AVERROR(EINVAL);
285 }
286
287 void av_bprint_channel_layout(struct AVBPrint *bp,
288 int nb_channels, uint64_t channel_layout)
289 {
290 int i;
291
292 if (nb_channels <= 0)
293 nb_channels = av_get_channel_layout_nb_channels(channel_layout);
294
295 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
296 if (nb_channels == channel_layout_map[i].layout.nb_channels &&
297 channel_layout == channel_layout_map[i].layout.u.mask) {
298 av_bprintf(bp, "%s", channel_layout_map[i].name);
299 return;
300 }
301
302 av_bprintf(bp, "%d channels", nb_channels);
303 if (channel_layout) {
304 int i, ch;
305 av_bprintf(bp, " (");
306 for (i = 0, ch = 0; i < 64; i++) {
307 if ((channel_layout & (UINT64_C(1) << i))) {
308 const char *name = get_channel_name(i);
309 if (name) {
310 if (ch > 0)
311 av_bprintf(bp, "+");
312 av_bprintf(bp, "%s", name);
313 }
314 ch++;
315 }
316 }
317 av_bprintf(bp, ")");
318 }
319 }
320
321 void av_get_channel_layout_string(char *buf, int buf_size,
322 int nb_channels, uint64_t channel_layout)
323 {
324 AVBPrint bp;
325
326 av_bprint_init_for_buffer(&bp, buf, buf_size);
327 av_bprint_channel_layout(&bp, nb_channels, channel_layout);
328 }
329
330 568917 int av_get_channel_layout_nb_channels(uint64_t channel_layout)
331 {
332 568917 return av_popcount64(channel_layout);
333 }
334
335 9 int64_t av_get_default_channel_layout(int nb_channels) {
336 int i;
337
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 3 times.
121 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
338
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 112 times.
118 if (nb_channels == channel_layout_map[i].layout.nb_channels)
339 6 return channel_layout_map[i].layout.u.mask;
340 3 return 0;
341 }
342
343 int av_get_channel_layout_channel_index(uint64_t channel_layout,
344 uint64_t channel)
345 {
346 if (!(channel_layout & channel) ||
347 av_get_channel_layout_nb_channels(channel) != 1)
348 return AVERROR(EINVAL);
349 channel_layout &= channel - 1;
350 return av_get_channel_layout_nb_channels(channel_layout);
351 }
352
353 const char *av_get_channel_name(uint64_t channel)
354 {
355 int i;
356 if (av_get_channel_layout_nb_channels(channel) != 1)
357 return NULL;
358 for (i = 0; i < 64; i++)
359 if ((1ULL<<i) & channel)
360 return get_channel_name(i);
361 return NULL;
362 }
363
364 const char *av_get_channel_description(uint64_t channel)
365 {
366 int i;
367 if (av_get_channel_layout_nb_channels(channel) != 1)
368 return NULL;
369 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
370 if ((1ULL<<i) & channel)
371 return channel_names[i].description;
372 return NULL;
373 }
374
375 518 uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
376 {
377 int i;
378
379
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 518 times.
518 if (av_get_channel_layout_nb_channels(channel_layout) <= index)
380 return 0;
381
382
1/2
✓ Branch 0 taken 777 times.
✗ Branch 1 not taken.
777 for (i = 0; i < 64; i++) {
383
3/4
✓ Branch 0 taken 777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 518 times.
✓ Branch 3 taken 259 times.
777 if ((1ULL << i) & channel_layout && !index--)
384 518 return 1ULL << i;
385 }
386 return 0;
387 }
388
389 int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
390 const char **name)
391 {
392 if (index >= FF_ARRAY_ELEMS(channel_layout_map))
393 return AVERROR_EOF;
394 if (layout) *layout = channel_layout_map[index].layout.u.mask;
395 if (name) *name = channel_layout_map[index].name;
396 return 0;
397 }
398 FF_ENABLE_DEPRECATION_WARNINGS
399 #endif
400
401 3 int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
402 {
403 AVChannelCustom *map;
404
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (nb_channels <= 0)
406 return AVERROR(EINVAL);
407
408 3 map = av_calloc(nb_channels, sizeof(*channel_layout->u.map));
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!map)
410 return AVERROR(ENOMEM);
411
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int i = 0; i < nb_channels; i++)
412 3 map[i].id = AV_CHAN_UNKNOWN;
413
414 3 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
415 3 channel_layout->nb_channels = nb_channels;
416 3 channel_layout->u.map = map;
417
418 3 return 0;
419 }
420
421 20854 int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
422 uint64_t mask)
423 {
424
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20814 times.
20854 if (!mask)
425 40 return AVERROR(EINVAL);
426
427 20814 channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
428 20814 channel_layout->nb_channels = av_popcount64(mask);
429 20814 channel_layout->u.mask = mask;
430
431 20814 return 0;
432 }
433
434 1847 int av_channel_layout_from_string(AVChannelLayout *channel_layout,
435 const char *str)
436 {
437 int i;
438 1847 int channels = 0, nb_channels = 0, native = 1;
439 1847 enum AVChannel highest_channel = AV_CHAN_NONE;
440 const char *dup;
441 char *chlist, *end;
442 1847 uint64_t mask = 0;
443
444 /* channel layout names */
445
2/2
✓ Branch 0 taken 12335 times.
✓ Branch 1 taken 154 times.
12489 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
446
3/4
✓ Branch 0 taken 12335 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1693 times.
✓ Branch 3 taken 10642 times.
12335 if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
447 1693 *channel_layout = channel_layout_map[i].layout;
448 1693 return 0;
449 }
450 }
451
452 /* ambisonic */
453
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 149 times.
154 if (!strncmp(str, "ambisonic ", 10)) {
454 5 const char *p = str + 10;
455 char *endptr;
456 5 AVChannelLayout extra = {0};
457 int order;
458
459 5 order = strtol(p, &endptr, 0);
460
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (order < 0 || order + 1 > INT_MAX / (order + 1) ||
461
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
5 (*endptr && *endptr != '+'))
462 return AVERROR(EINVAL);
463
464 5 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
465 5 channel_layout->nb_channels = (order + 1) * (order + 1);
466
467
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (*endptr) {
468 3 int ret = av_channel_layout_from_string(&extra, endptr + 1);
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < 0)
470 return ret;
471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) {
472 av_channel_layout_uninit(&extra);
473 return AVERROR(EINVAL);
474 }
475
476
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (extra.order == AV_CHANNEL_ORDER_NATIVE) {
477 1 channel_layout->u.mask = extra.u.mask;
478 } else {
479 2 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
480 2 channel_layout->u.map =
481 2 av_calloc(channel_layout->nb_channels + extra.nb_channels,
482 sizeof(*channel_layout->u.map));
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!channel_layout->u.map) {
484 av_channel_layout_uninit(&extra);
485 return AVERROR(ENOMEM);
486 }
487
488
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (i = 0; i < channel_layout->nb_channels; i++)
489 13 channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i;
490
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < extra.nb_channels; i++) {
491 3 enum AVChannel ch = av_channel_layout_channel_from_index(&extra, i);
492
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)) {
493 av_channel_layout_uninit(&extra);
494 return AVERROR(EINVAL);
495 }
496 3 channel_layout->u.map[channel_layout->nb_channels + i].id = ch;
497
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (extra.order == AV_CHANNEL_ORDER_CUSTOM &&
498
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 extra.u.map[i].name[0])
499 1 av_strlcpy(channel_layout->u.map[channel_layout->nb_channels + i].name,
500 1 extra.u.map[i].name,
501 sizeof(channel_layout->u.map[channel_layout->nb_channels + i].name));
502 }
503 }
504 3 channel_layout->nb_channels += extra.nb_channels;
505 3 av_channel_layout_uninit(&extra);
506 }
507
508 5 return 0;
509 }
510
511 149 chlist = av_strdup(str);
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
149 if (!chlist)
513 return AVERROR(ENOMEM);
514
515 /* channel names */
516 149 av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
517 149 end = strchr(str, ')');
518
519 149 dup = chlist;
520
2/2
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 64 times.
322 while (*dup) {
521 char *channel, *chname;
522 258 int ret = av_opt_get_key_value(&dup, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 258 times.
258 if (ret < 0) {
524 av_free(chlist);
525 return ret;
526 }
527
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 146 times.
258 if (*dup)
528 112 dup++; // skip separator
529
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
258 if (channel && !*channel)
530 av_freep(&channel);
531
2/2
✓ Branch 0 taken 4290 times.
✓ Branch 1 taken 87 times.
4377 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
532
6/6
✓ Branch 0 taken 3289 times.
✓ Branch 1 taken 1001 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 3252 times.
✓ Branch 4 taken 171 times.
✓ Branch 5 taken 3118 times.
4290 if (channel_names[i].name && !strcmp(channel ? channel : chname, channel_names[i].name)) {
533
5/6
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 164 times.
171 if (channel || i < highest_channel || mask & (1ULL << i))
534 7 native = 0; // Not a native layout, use a custom one
535 171 highest_channel = i;
536 171 mask |= 1ULL << i;
537 171 break;
538 }
539 }
540
541
4/4
✓ Branch 0 taken 253 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 167 times.
258 if (!channel && i >= FF_ARRAY_ELEMS(channel_names)) {
542 86 char *endptr = chname;
543 86 enum AVChannel id = AV_CHAN_NONE;
544
545
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 85 times.
86 if (!strncmp(chname, "USR", 3)) {
546 1 const char *p = chname + 3;
547 1 id = strtol(p, &endptr, 0);
548 }
549
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 85 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
86 if (id < 0 || *endptr) {
550 85 native = 0; // Unknown channel name
551 85 channels = 0;
552 85 mask = 0;
553 85 av_free(chname);
554 85 break;
555 }
556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (id > 63)
557 native = 0; // Not a native layout, use a custom one
558 else {
559
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (id < highest_channel || mask & (1ULL << id))
560 native = 0; // Not a native layout, use a custom one
561 1 highest_channel = id;
562 1 mask |= 1ULL << id;
563 }
564 }
565 173 channels++;
566 173 av_free(channel);
567 173 av_free(chname);
568 }
569
570
4/4
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 6 times.
149 if (mask && native) {
571 58 av_free(chlist);
572
5/8
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 26 times.
58 if (nb_channels && ((nb_channels != channels) || (!end || *++end)))
573 return AVERROR(EINVAL);
574 58 av_channel_layout_from_mask(channel_layout, mask);
575 58 return 0;
576 }
577
578 /* custom layout of channel names */
579
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
91 if (channels && !native) {
580 6 int idx = 0;
581
582
5/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
6 if (nb_channels && ((nb_channels != channels) || (!end || *++end))) {
583 av_free(chlist);
584 return AVERROR(EINVAL);
585 }
586
587 6 channel_layout->u.map = av_calloc(channels, sizeof(*channel_layout->u.map));
588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!channel_layout->u.map) {
589 av_free(chlist);
590 return AVERROR(ENOMEM);
591 }
592
593 6 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
594 6 channel_layout->nb_channels = channels;
595
596 6 dup = chlist;
597
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6 times.
22 while (*dup) {
598 char *channel, *chname;
599 16 int ret = av_opt_get_key_value(&dup, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (ret < 0) {
601 av_freep(&channel_layout->u.map);
602 av_free(chlist);
603 return ret;
604 }
605
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if (*dup)
606 10 dup++; // skip separator
607
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 1 times.
78 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
608
6/6
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 51 times.
77 if (channel_names[i].name && !strcmp(channel ? channel : chname, channel_names[i].name)) {
609 15 channel_layout->u.map[idx].id = i;
610
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11 times.
15 if (channel)
611 4 av_strlcpy(channel_layout->u.map[idx].name, chname, sizeof(channel_layout->u.map[idx].name));
612 15 idx++;
613 15 break;
614 }
615 }
616
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (i >= FF_ARRAY_ELEMS(channel_names)) {
617
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 const char *p = (channel ? channel : chname) + 3;
618 1 channel_layout->u.map[idx].id = strtol(p, NULL, 0);
619
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (channel)
620 1 av_strlcpy(channel_layout->u.map[idx].name, chname, sizeof(channel_layout->u.map[idx].name));
621 1 idx++;
622 }
623 16 av_free(channel);
624 16 av_free(chname);
625 }
626 6 av_free(chlist);
627
628 6 return 0;
629 }
630 85 av_freep(&chlist);
631
632 85 errno = 0;
633 85 mask = strtoull(str, &end, 0);
634
635 /* channel layout mask */
636
6/8
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 43 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 43 times.
✗ Branch 7 not taken.
85 if (!errno && !*end && !strchr(str, '-') && mask) {
637 43 av_channel_layout_from_mask(channel_layout, mask);
638 43 return 0;
639 }
640
641 42 errno = 0;
642 42 channels = strtol(str, &end, 10);
643
644 /* number of channels */
645
5/6
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 1 times.
42 if (!errno && !strcmp(end, "c") && channels > 0) {
646 11 av_channel_layout_default(channel_layout, channels);
647
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
648 9 return 0;
649 }
650
651 /* number of unordered channels */
652
5/6
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 9 times.
33 if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels"))
653
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 && channels > 0) {
654 24 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
655 24 channel_layout->nb_channels = channels;
656 24 return 0;
657 }
658
659 9 return AVERROR(EINVAL);
660 }
661
662 10923687 void av_channel_layout_uninit(AVChannelLayout *channel_layout)
663 {
664
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10923674 times.
10923687 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
665 13 av_freep(&channel_layout->u.map);
666 10923687 memset(channel_layout, 0, sizeof(*channel_layout));
667 10923687 }
668
669 2041095 int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
670 {
671 2041095 av_channel_layout_uninit(dst);
672 2041095 *dst = *src;
673
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2041094 times.
2041095 if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
674 1 dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!dst->u.map)
676 return AVERROR(ENOMEM);
677 1 memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
678 }
679 2041095 return 0;
680 }
681
682 /**
683 * If the layout is n-th order standard-order ambisonic, with optional
684 * extra non-diegetic channels at the end, return the order.
685 * Return a negative error code otherwise.
686 */
687 32 static int ambisonic_order(const AVChannelLayout *channel_layout)
688 {
689 int i, highest_ambi, order;
690
691 32 highest_ambi = -1;
692
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 25 times.
32 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC)
693 7 highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1;
694 else {
695 25 const AVChannelCustom *map = channel_layout->u.map;
696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 av_assert0(channel_layout->order == AV_CHANNEL_ORDER_CUSTOM);
697
698
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 25 times.
125 for (i = 0; i < channel_layout->nb_channels; i++) {
699
3/4
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
100 int is_ambi = CHAN_IS_AMBI(map[i].id);
700
701 /* ambisonic following non-ambisonic */
702
6/8
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 39 times.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 36 times.
100 if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id))
703 return AVERROR(EINVAL);
704
705 /* non-default ordering */
706
3/4
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 43 times.
100 if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i)
707 return AVERROR(EINVAL);
708
709
3/4
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 43 times.
✗ Branch 3 not taken.
100 if (CHAN_IS_AMBI(map[i].id))
710 43 highest_ambi = i;
711 }
712 }
713 /* no ambisonic channels*/
714
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 14 times.
32 if (highest_ambi < 0)
715 18 return AVERROR(EINVAL);
716
717 14 order = floor(sqrt(highest_ambi));
718 /* incomplete order - some harmonics are missing */
719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if ((order + 1) * (order + 1) != highest_ambi + 1)
720 return AVERROR(EINVAL);
721
722 14 return order;
723 }
724
725 /**
726 * If the custom layout is n-th order standard-order ambisonic, with optional
727 * extra non-diegetic channels at the end, write its string description in bp.
728 * Return a negative error code otherwise.
729 */
730 32 static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
731 {
732 int nb_ambi_channels;
733 32 int order = ambisonic_order(channel_layout);
734
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 14 times.
32 if (order < 0)
735 18 return order;
736
737 14 av_bprintf(bp, "ambisonic %d", order);
738
739 /* extra channels present */
740 14 nb_ambi_channels = (order + 1) * (order + 1);
741
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
14 if (nb_ambi_channels < channel_layout->nb_channels) {
742 9 AVChannelLayout extra = { 0 };
743
744
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) {
745 3 extra.order = AV_CHANNEL_ORDER_NATIVE;
746 3 extra.nb_channels = av_popcount64(channel_layout->u.mask);
747 3 extra.u.mask = channel_layout->u.mask;
748 } else {
749 6 extra.order = AV_CHANNEL_ORDER_CUSTOM;
750 6 extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
751 6 extra.u.map = channel_layout->u.map + nb_ambi_channels;
752 }
753
754 9 av_bprint_chars(bp, '+', 1);
755 9 av_channel_layout_describe_bprint(&extra, bp);
756 /* Not calling uninit here on extra because we don't own the u.map pointer */
757 }
758
759 14 return 0;
760 }
761
762 15085 int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
763 AVBPrint *bp)
764 {
765 int i;
766
767
4/5
✓ Branch 0 taken 14949 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 104 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
15085 switch (channel_layout->order) {
768 14949 case AV_CHANNEL_ORDER_NATIVE:
769
2/2
✓ Branch 0 taken 45347 times.
✓ Branch 1 taken 177 times.
45524 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
770
2/2
✓ Branch 0 taken 14772 times.
✓ Branch 1 taken 30575 times.
45347 if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
771 14772 av_bprintf(bp, "%s", channel_layout_map[i].name);
772 14772 return 0;
773 }
774 // fall-through
775 case AV_CHANNEL_ORDER_CUSTOM:
776
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 177 times.
202 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
777 25 int res = try_describe_ambisonic(bp, channel_layout);
778
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18 times.
25 if (res >= 0)
779 7 return 0;
780 }
781
1/2
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
195 if (channel_layout->nb_channels)
782 195 av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
783
2/2
✓ Branch 0 taken 683 times.
✓ Branch 1 taken 195 times.
878 for (i = 0; i < channel_layout->nb_channels; i++) {
784 683 enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
785
786
2/2
✓ Branch 0 taken 488 times.
✓ Branch 1 taken 195 times.
683 if (i)
787 488 av_bprintf(bp, "+");
788 683 av_channel_name_bprint(bp, ch);
789
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 635 times.
683 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
790
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 33 times.
48 channel_layout->u.map[i].name[0])
791 15 av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
792 }
793
1/2
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
195 if (channel_layout->nb_channels) {
794 195 av_bprintf(bp, ")");
795 195 return 0;
796 }
797 // fall-through
798 case AV_CHANNEL_ORDER_UNSPEC:
799 104 av_bprintf(bp, "%d channels", channel_layout->nb_channels);
800 104 return 0;
801 7 case AV_CHANNEL_ORDER_AMBISONIC:
802 7 return try_describe_ambisonic(bp, channel_layout);
803 default:
804 return AVERROR(EINVAL);
805 }
806 }
807
808 10203 int av_channel_layout_describe(const AVChannelLayout *channel_layout,
809 char *buf, size_t buf_size)
810 {
811 AVBPrint bp;
812 int ret;
813
814
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10183 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
10203 if (!buf && buf_size)
815 return AVERROR(EINVAL);
816
817 10203 av_bprint_init_for_buffer(&bp, buf, buf_size);
818 10203 ret = av_channel_layout_describe_bprint(channel_layout, &bp);
819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10203 times.
10203 if (ret < 0)
820 return ret;
821
822
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10203 times.
10203 if (bp.len >= INT_MAX)
823 return AVERROR(ERANGE);
824 10203 return bp.len + 1;
825 }
826
827 enum AVChannel
828 1386 av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout,
829 unsigned int idx)
830 {
831 int i;
832
833
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1365 times.
1386 if (idx >= channel_layout->nb_channels)
834 21 return AV_CHAN_NONE;
835
836
3/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1296 times.
✗ Branch 3 not taken.
1365 switch (channel_layout->order) {
837 66 case AV_CHANNEL_ORDER_CUSTOM:
838 66 return channel_layout->u.map[idx].id;
839 3 case AV_CHANNEL_ORDER_AMBISONIC: {
840 3 int ambi_channels = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask);
841
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (idx < ambi_channels)
842 1 return AV_CHAN_AMBISONIC_BASE + idx;
843 2 idx -= ambi_channels;
844 }
845 // fall-through
846 1298 case AV_CHANNEL_ORDER_NATIVE:
847
1/2
✓ Branch 0 taken 6194 times.
✗ Branch 1 not taken.
6194 for (i = 0; i < 64; i++) {
848
4/4
✓ Branch 0 taken 3015 times.
✓ Branch 1 taken 3179 times.
✓ Branch 2 taken 1298 times.
✓ Branch 3 taken 1717 times.
6194 if ((1ULL << i) & channel_layout->u.mask && !idx--)
849 1298 return i;
850 }
851 default:
852 return AV_CHAN_NONE;
853 }
854 }
855
856 enum AVChannel
857 16 av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout,
858 const char *str)
859 {
860 16 int index = av_channel_layout_index_from_string(channel_layout, str);
861
862
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
16 if (index < 0)
863 4 return AV_CHAN_NONE;
864
865 12 return av_channel_layout_channel_from_index(channel_layout, index);
866 }
867
868 10471 int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout,
869 enum AVChannel channel)
870 {
871 int i;
872
873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10471 times.
10471 if (channel == AV_CHAN_NONE)
874 return AVERROR(EINVAL);
875
876
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 10453 times.
✗ Branch 2 not taken.
10471 switch (channel_layout->order) {
877 18 case AV_CHANNEL_ORDER_CUSTOM:
878
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 5 times.
44 for (i = 0; i < channel_layout->nb_channels; i++)
879
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (channel_layout->u.map[i].id == channel)
880 13 return i;
881 5 return AVERROR(EINVAL);
882 10453 case AV_CHANNEL_ORDER_AMBISONIC:
883 case AV_CHANNEL_ORDER_NATIVE: {
884 10453 uint64_t mask = channel_layout->u.mask;
885 10453 int ambi_channels = channel_layout->nb_channels - av_popcount64(mask);
886
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10449 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
10453 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC &&
887 channel >= AV_CHAN_AMBISONIC_BASE) {
888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (channel - AV_CHAN_AMBISONIC_BASE >= ambi_channels)
889 return AVERROR(EINVAL);
890 1 return channel - AV_CHAN_AMBISONIC_BASE;
891 }
892
3/4
✓ Branch 0 taken 10452 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5398 times.
✓ Branch 3 taken 5054 times.
10452 if ((unsigned)channel > 63 || !(mask & (1ULL << channel)))
893 5398 return AVERROR(EINVAL);
894 5054 mask &= (1ULL << channel) - 1;
895 5054 return av_popcount64(mask) + ambi_channels;
896 }
897 default:
898 return AVERROR(EINVAL);
899 }
900 }
901
902 32 int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout,
903 const char *str)
904 {
905 char *chname;
906 32 enum AVChannel ch = AV_CHAN_NONE;
907
908
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
32 switch (channel_layout->order) {
909 18 case AV_CHANNEL_ORDER_CUSTOM:
910 18 chname = strstr(str, "@");
911
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (chname) {
912 char buf[16];
913 8 chname++;
914 8 av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str));
915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!*chname)
916 chname = NULL;
917 8 ch = av_channel_from_string(buf);
918
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)
919 return AVERROR(EINVAL);
920 }
921
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++) {
922
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) &&
923
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id))
924 6 return i;
925 }
926 // fall-through
927 case AV_CHANNEL_ORDER_AMBISONIC:
928 case AV_CHANNEL_ORDER_NATIVE:
929 26 ch = av_channel_from_string(str);
930
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 22 times.
26 if (ch == AV_CHAN_NONE)
931 4 return AVERROR(EINVAL);
932 22 return av_channel_layout_index_from_channel(channel_layout, ch);
933 }
934
935 return AVERROR(EINVAL);
936 }
937
938 2204358 int av_channel_layout_check(const AVChannelLayout *channel_layout)
939 {
940
2/2
✓ Branch 0 taken 1066056 times.
✓ Branch 1 taken 1138302 times.
2204358 if (channel_layout->nb_channels <= 0)
941 1066056 return 0;
942
943
4/5
✓ Branch 0 taken 1128140 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 10151 times.
✗ Branch 4 not taken.
1138302 switch (channel_layout->order) {
944 1128140 case AV_CHANNEL_ORDER_NATIVE:
945 1128140 return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
946 9 case AV_CHANNEL_ORDER_CUSTOM:
947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!channel_layout->u.map)
948 return 0;
949
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 9 times.
41 for (int i = 0; i < channel_layout->nb_channels; i++) {
950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (channel_layout->u.map[i].id == AV_CHAN_NONE)
951 return 0;
952 }
953 9 return 1;
954 2 case AV_CHANNEL_ORDER_AMBISONIC:
955 /* If non-diegetic channels are present, ensure they are taken into account */
956 2 return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels;
957 10151 case AV_CHANNEL_ORDER_UNSPEC:
958 10151 return 1;
959 default:
960 return 0;
961 }
962 }
963
964 1732426 int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
965 {
966 int i;
967
968 /* different channel counts -> not equal */
969
2/2
✓ Branch 0 taken 6859 times.
✓ Branch 1 taken 1725567 times.
1732426 if (chl->nb_channels != chl1->nb_channels)
970 6859 return 1;
971
972 /* if only one is unspecified -> not equal */
973 1725567 if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
974
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1725565 times.
1725567 (chl1->order == AV_CHANNEL_ORDER_UNSPEC))
975 2 return 1;
976 /* both are unspecified -> equal */
977
2/2
✓ Branch 0 taken 13303 times.
✓ Branch 1 taken 1712262 times.
1725565 else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
978 13303 return 0;
979
980 /* can compare masks directly */
981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1712261 times.
1712262 if ((chl->order == AV_CHANNEL_ORDER_NATIVE ||
982
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 chl->order == AV_CHANNEL_ORDER_AMBISONIC) &&
983
1/2
✓ Branch 0 taken 1712261 times.
✗ Branch 1 not taken.
1712261 chl->order == chl1->order)
984 1712261 return chl->u.mask != chl1->u.mask;
985
986 /* compare channel by channel */
987
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 for (i = 0; i < chl->nb_channels; i++)
988
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
6 if (av_channel_layout_channel_from_index(chl, i) !=
989 3 av_channel_layout_channel_from_index(chl1, i))
990 return 1;
991 1 return 0;
992 }
993
994 27400 void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
995 {
996 int i;
997
2/2
✓ Branch 0 taken 44323 times.
✓ Branch 1 taken 13 times.
44336 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
998
2/2
✓ Branch 0 taken 27387 times.
✓ Branch 1 taken 16936 times.
44323 if (nb_channels == channel_layout_map[i].layout.nb_channels) {
999 27387 *ch_layout = channel_layout_map[i].layout;
1000 27387 return;
1001 }
1002
1003 13 ch_layout->order = AV_CHANNEL_ORDER_UNSPEC;
1004 13 ch_layout->nb_channels = nb_channels;
1005 }
1006
1007 38 const AVChannelLayout *av_channel_layout_standard(void **opaque)
1008 {
1009 38 uintptr_t i = (uintptr_t)*opaque;
1010 38 const AVChannelLayout *ch_layout = NULL;
1011
1012
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1 times.
38 if (i < FF_ARRAY_ELEMS(channel_layout_map)) {
1013 37 ch_layout = &channel_layout_map[i].layout;
1014 37 *opaque = (void*)(i + 1);
1015 }
1016
1017 38 return ch_layout;
1018 }
1019
1020 1121 uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
1021 uint64_t mask)
1022 {
1023 1121 uint64_t ret = 0;
1024 int i;
1025
1026
3/3
✓ Branch 0 taken 751 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 368 times.
1121 switch (channel_layout->order) {
1027 751 case AV_CHANNEL_ORDER_NATIVE:
1028 case AV_CHANNEL_ORDER_AMBISONIC:
1029 751 return channel_layout->u.mask & mask;
1030 2 case AV_CHANNEL_ORDER_CUSTOM:
1031
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 2 times.
130 for (i = 0; i < 64; i++)
1032
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)
1033 4 ret |= (1ULL << i);
1034 2 break;
1035 }
1036
1037 370 return ret;
1038 }
1039
1040 3 static int64_t masked_description(AVChannelLayout *channel_layout, int start_channel)
1041 {
1042 3 uint64_t mask = 0;
1043
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int i = start_channel; i < channel_layout->nb_channels; i++) {
1044 3 enum AVChannel ch = channel_layout->u.map[i].id;
1045
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
1046 3 mask |= (1ULL << ch);
1047 else
1048 return AVERROR(EINVAL);
1049 }
1050 3 return mask;
1051 }
1052
1053 3 static int has_channel_names(AVChannelLayout *channel_layout)
1054 {
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
1056 return 0;
1057
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int i = 0; i < channel_layout->nb_channels; i++)
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (channel_layout->u.map[i].name[0])
1059 return 1;
1060 3 return 0;
1061 }
1062
1063 3 int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
1064 {
1065 3 int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
1066 int lossy;
1067
1068
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!av_channel_layout_check(channel_layout))
1069 return AVERROR(EINVAL);
1070
1071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (channel_layout->order == order)
1072 return 0;
1073
1074
1/5
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 switch (order) {
1075 case AV_CHANNEL_ORDER_UNSPEC: {
1076 int nb_channels = channel_layout->nb_channels;
1077 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
1078 lossy = 0;
1079 for (int i = 0; i < nb_channels; i++) {
1080 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
1081 lossy = 1;
1082 break;
1083 }
1084 }
1085 } else {
1086 lossy = 1;
1087 }
1088 if (!lossy || allow_lossy) {
1089 av_channel_layout_uninit(channel_layout);
1090 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
1091 channel_layout->nb_channels = nb_channels;
1092 return lossy;
1093 }
1094 return AVERROR(ENOSYS);
1095 }
1096 3 case AV_CHANNEL_ORDER_NATIVE:
1097
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
1098 3 int64_t mask = masked_description(channel_layout, 0);
1099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mask < 0)
1100 return AVERROR(ENOSYS);
1101 3 lossy = has_channel_names(channel_layout);
1102
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (!lossy || allow_lossy) {
1103 3 av_channel_layout_uninit(channel_layout);
1104 3 av_channel_layout_from_mask(channel_layout, mask);
1105 3 return lossy;
1106 }
1107 }
1108 return AVERROR(ENOSYS);
1109 case AV_CHANNEL_ORDER_CUSTOM: {
1110 AVChannelLayout custom = { 0 };
1111 int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
1112 if (ret < 0)
1113 return ret;
1114 if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
1115 for (int i = 0; i < channel_layout->nb_channels; i++)
1116 custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
1117 av_channel_layout_uninit(channel_layout);
1118 *channel_layout = custom;
1119 return 0;
1120 }
1121 case AV_CHANNEL_ORDER_AMBISONIC:
1122 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
1123 int64_t mask;
1124 int nb_channels = channel_layout->nb_channels;
1125 int order = ambisonic_order(channel_layout);
1126 if (order < 0)
1127 return AVERROR(ENOSYS);
1128 mask = masked_description(channel_layout, (order + 1) * (order + 1));
1129 if (mask < 0)
1130 return AVERROR(ENOSYS);
1131 lossy = has_channel_names(channel_layout);
1132 if (!lossy || allow_lossy) {
1133 av_channel_layout_uninit(channel_layout);
1134 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
1135 channel_layout->nb_channels = nb_channels;
1136 channel_layout->u.mask = mask;
1137 return lossy;
1138 }
1139 }
1140 return AVERROR(ENOSYS);
1141 default:
1142 return AVERROR(EINVAL);
1143 }
1144 }
1145