FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2026-09-30 17:13:31
Exec Total Coverage
Lines: 483 531 91.0%
Functions: 28 28 100.0%
Branches: 355 434 81.8%

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