FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2026-05-02 03:33:10
Exec Total Coverage
Lines: 482 531 90.8%
Functions: 28 28 100.0%
Branches: 354 434 81.6%

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 2468 void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
88 {
89
3/4
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 1889 times.
✓ Branch 2 taken 579 times.
✗ Branch 3 not taken.
2468 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 1866 times.
✓ Branch 1 taken 23 times.
1889 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
93
1/2
✓ Branch 0 taken 1866 times.
✗ Branch 1 not taken.
1866 channel_names[channel_id].name)
94 1866 av_bprintf(bp, "%s", channel_names[channel_id].name);
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 else if (channel_id == AV_CHAN_NONE)
96 av_bprintf(bp, "NONE");
97
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 12 times.
23 else if (channel_id == AV_CHAN_UNKNOWN)
98 11 av_bprintf(bp, "UNK");
99
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 else if (channel_id == AV_CHAN_UNUSED)
100 3 av_bprintf(bp, "UNSD");
101 else
102 9 av_bprintf(bp, "USR%d", channel_id);
103 2468 }
104
105 479 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 474 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
479 if (!buf && buf_size)
110 return AVERROR(EINVAL);
111
112 479 av_bprint_init_for_buffer(&bp, buf, buf_size);
113 479 av_channel_name_bprint(&bp, channel_id);
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 479 times.
479 if (bp.len >= INT_MAX)
116 return AVERROR(ERANGE);
117 479 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 728 enum AVChannel av_channel_from_string(const char *str)
154 {
155 int i;
156 728 char *endptr = (char *)str;
157 728 enum AVChannel id = AV_CHAN_NONE;
158
159
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 468 times.
728 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 9190 times.
✓ Branch 1 taken 124 times.
9314 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
167
4/4
✓ Branch 0 taken 5798 times.
✓ Branch 1 taken 3392 times.
✓ Branch 2 taken 344 times.
✓ Branch 3 taken 5454 times.
9190 if (channel_names[i].name && !strcmp(str, channel_names[i].name))
168 344 return i;
169 }
170
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 123 times.
124 if (!strcmp(str, "UNK"))
171 1 return AV_CHAN_UNKNOWN;
172
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 122 times.
123 if (!strcmp(str, "UNSD"))
173 1 return AV_CHAN_UNUSED;
174
175
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 115 times.
122 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 115 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
122 if (id >= 0 && !*endptr)
180 7 return id;
181
182 115 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_BACK },
222 { "7.1.2", AV_CHANNEL_LAYOUT_7POINT1POINT2 },
223 { "7.1.4", AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK },
224 { "7.2.3", AV_CHANNEL_LAYOUT_7POINT2POINT3 },
225 { "9.1.4", AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK },
226 { "9.1.6", AV_CHANNEL_LAYOUT_9POINT1POINT6 },
227 { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL },
228 { "binaural", AV_CHANNEL_LAYOUT_BINAURAL },
229 { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, },
230 { "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
231 };
232
233 131 int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
234 {
235 AVChannelCustom *map;
236
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (nb_channels <= 0)
238 return AVERROR(EINVAL);
239
240 131 map = av_calloc(nb_channels, sizeof(*channel_layout->u.map));
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 if (!map)
242 return AVERROR(ENOMEM);
243
2/2
✓ Branch 0 taken 578 times.
✓ Branch 1 taken 131 times.
709 for (int i = 0; i < nb_channels; i++)
244 578 map[i].id = AV_CHAN_UNKNOWN;
245
246 131 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
247 131 channel_layout->nb_channels = nb_channels;
248 131 channel_layout->u.map = map;
249
250 131 return 0;
251 }
252
253 24050 int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
254 uint64_t mask)
255 {
256
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 24009 times.
24050 if (!mask)
257 41 return AVERROR(EINVAL);
258
259 24009 channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
260 24009 channel_layout->nb_channels = av_popcount64(mask);
261 24009 channel_layout->u.mask = mask;
262
263 24009 return 0;
264 }
265
266 183 static int parse_channel_list(AVChannelLayout *ch_layout, const char *str)
267 {
268 int ret;
269 183 int nb_channels = 0;
270 183 AVChannelCustom *map = NULL;
271 183 AVChannelCustom custom = {0};
272
273
2/2
✓ Branch 0 taken 325 times.
✓ Branch 1 taken 81 times.
406 while (*str) {
274 char *channel, *chname;
275 325 ret = av_opt_get_key_value(&str, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
325 if (ret < 0) {
277 av_freep(&map);
278 102 return ret;
279 }
280
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 181 times.
325 if (*str)
281 144 str++; // skip separator
282
2/2
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 14 times.
325 if (!channel) {
283 311 channel = chname;
284 311 chname = NULL;
285 }
286
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 311 times.
325 av_strlcpy(custom.name, chname ? chname : "", sizeof(custom.name));
287 325 custom.id = av_channel_from_string(channel);
288 325 av_free(channel);
289 325 av_free(chname);
290
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 223 times.
325 if (custom.id == AV_CHAN_NONE) {
291 102 av_freep(&map);
292 102 return AVERROR(EINVAL);
293 }
294
295 223 av_dynarray2_add((void **)&map, &nb_channels, sizeof(custom), (void *)&custom);
296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 if (!map)
297 return AVERROR(ENOMEM);
298 }
299
300
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 80 times.
81 if (!nb_channels)
301 1 return AVERROR(EINVAL);
302
303 80 ch_layout->order = AV_CHANNEL_ORDER_CUSTOM;
304 80 ch_layout->u.map = map;
305 80 ch_layout->nb_channels = nb_channels;
306
307 80 ret = av_channel_layout_retype(ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 av_assert0(ret == 0);
309
310 80 return 0;
311 }
312
313 2248 int av_channel_layout_from_string(AVChannelLayout *channel_layout,
314 const char *str)
315 {
316 int i, matches, ret;
317 2248 int channels = 0, nb_channels = 0;
318 char *chlist, *end;
319 2248 uint64_t mask = 0;
320
321 /* channel layout names */
322
2/2
✓ Branch 0 taken 17322 times.
✓ Branch 1 taken 198 times.
17520 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
323
3/4
✓ Branch 0 taken 17322 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2050 times.
✓ Branch 3 taken 15272 times.
17322 if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
324 2050 *channel_layout = channel_layout_map[i].layout;
325 2050 return 0;
326 }
327 }
328
329 /* This function is a channel layout initializer, so we have to
330 * zero-initialize before we start setting fields individually. */
331 198 memset(channel_layout, 0, sizeof(*channel_layout));
332
333 /* ambisonic */
334
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 183 times.
198 if (!strncmp(str, "ambisonic ", 10)) {
335 15 const char *p = str + 10;
336 char *endptr;
337 15 AVChannelLayout extra = {0};
338 int order;
339
340 15 order = strtol(p, &endptr, 0);
341
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (order < 0 || order + 1 > INT_MAX / (order + 1) ||
342
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
15 (*endptr && *endptr != '+'))
343 return AVERROR(EINVAL);
344
345 15 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
346 15 channel_layout->nb_channels = (order + 1) * (order + 1);
347
348
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 if (*endptr) {
349 10 ret = av_channel_layout_from_string(&extra, endptr + 1);
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
351 return ret;
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) {
353 av_channel_layout_uninit(&extra);
354 return AVERROR(EINVAL);
355 }
356
357
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (extra.order == AV_CHANNEL_ORDER_NATIVE) {
358 8 channel_layout->u.mask = extra.u.mask;
359 } else {
360 2 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
361 2 channel_layout->u.map =
362 2 av_calloc(channel_layout->nb_channels + extra.nb_channels,
363 sizeof(*channel_layout->u.map));
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!channel_layout->u.map) {
365 av_channel_layout_uninit(&extra);
366 return AVERROR(ENOMEM);
367 }
368
369
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (i = 0; i < channel_layout->nb_channels; i++)
370 13 channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i;
371
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (i = 0; i < extra.nb_channels; i++) {
372 3 enum AVChannel ch = av_channel_layout_channel_from_index(&extra, i);
373
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)) {
374 av_channel_layout_uninit(channel_layout);
375 av_channel_layout_uninit(&extra);
376 return AVERROR(EINVAL);
377 }
378 3 channel_layout->u.map[channel_layout->nb_channels + i].id = ch;
379
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (extra.order == AV_CHANNEL_ORDER_CUSTOM &&
380
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 extra.u.map[i].name[0])
381 1 av_strlcpy(channel_layout->u.map[channel_layout->nb_channels + i].name,
382 1 extra.u.map[i].name,
383 sizeof(channel_layout->u.map[channel_layout->nb_channels + i].name));
384 }
385 }
386 10 channel_layout->nb_channels += extra.nb_channels;
387 10 av_channel_layout_uninit(&extra);
388 }
389
390 15 return 0;
391 }
392
393 183 chlist = av_strdup(str);
394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
183 if (!chlist)
395 return AVERROR(ENOMEM);
396
397 /* channel names */
398 183 matches = av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
399 183 ret = parse_channel_list(channel_layout, chlist);
400 183 av_freep(&chlist);
401
3/4
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 103 times.
183 if (ret < 0 && ret != AVERROR(EINVAL))
402 return ret;
403
404
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 103 times.
183 if (ret >= 0) {
405 80 end = strchr(str, ')');
406
7/8
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 35 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 35 times.
80 if (matches == 2 && (nb_channels != channel_layout->nb_channels || !end || *++end)) {
407 3 av_channel_layout_uninit(channel_layout);
408 3 return AVERROR(EINVAL);
409 }
410 77 return 0;
411 }
412
413 103 errno = 0;
414 103 mask = strtoull(str, &end, 0);
415
416 /* channel layout mask */
417
7/8
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 47 times.
✓ Branch 7 taken 1 times.
103 if (!errno && !*end && !strchr(str, '-') && mask) {
418 47 av_channel_layout_from_mask(channel_layout, mask);
419 47 return 0;
420 }
421
422 56 errno = 0;
423 56 channels = strtol(str, &end, 10);
424
425 /* number of channels */
426
5/6
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 44 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 1 times.
56 if (!errno && !strcmp(end, "c") && channels > 0) {
427 11 av_channel_layout_default(channel_layout, channels);
428
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
429 9 return 0;
430 }
431
432 /* number of unordered channels */
433
5/6
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 21 times.
47 if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels"))
434
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 && channels > 0) {
435 26 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
436 26 channel_layout->nb_channels = channels;
437 26 return 0;
438 }
439
440 21 return AVERROR(EINVAL);
441 }
442
443 11708696 void av_channel_layout_uninit(AVChannelLayout *channel_layout)
444 {
445
2/2
✓ Branch 0 taken 1972 times.
✓ Branch 1 taken 11706724 times.
11708696 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
446 1972 av_freep(&channel_layout->u.map);
447 11708696 memset(channel_layout, 0, sizeof(*channel_layout));
448 11708696 }
449
450 2648186 int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
451 {
452 2648186 av_channel_layout_uninit(dst);
453 2648186 *dst = *src;
454
2/2
✓ Branch 0 taken 1691 times.
✓ Branch 1 taken 2646495 times.
2648186 if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
455 1691 dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1691 times.
1691 if (!dst->u.map)
457 return AVERROR(ENOMEM);
458 1691 memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
459 }
460 2648186 return 0;
461 }
462
463 867 static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel)
464 {
465 867 uint64_t mask = 0;
466
2/2
✓ Branch 0 taken 1697 times.
✓ Branch 1 taken 266 times.
1963 for (int i = start_channel; i < channel_layout->nb_channels; i++) {
467 1697 enum AVChannel ch = channel_layout->u.map[i].id;
468
5/6
✓ Branch 0 taken 1697 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1238 times.
✓ Branch 3 taken 459 times.
✓ Branch 4 taken 1096 times.
✓ Branch 5 taken 142 times.
1697 if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
469 1096 mask |= (1ULL << ch);
470 else
471 601 return AVERROR(EINVAL);
472 }
473 266 return mask;
474 }
475
476 840 static int has_channel_names(const AVChannelLayout *channel_layout)
477 {
478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 840 times.
840 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
479 return 0;
480
2/2
✓ Branch 0 taken 1835 times.
✓ Branch 1 taken 821 times.
2656 for (int i = 0; i < channel_layout->nb_channels; i++)
481
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1816 times.
1835 if (channel_layout->u.map[i].name[0])
482 19 return 1;
483 821 return 0;
484 }
485
486 615 int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout)
487 {
488 int i, highest_ambi, order;
489
490
2/2
✓ Branch 0 taken 580 times.
✓ Branch 1 taken 35 times.
615 if (channel_layout->order != AV_CHANNEL_ORDER_AMBISONIC &&
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 580 times.
580 channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
492 return AVERROR(EINVAL);
493
494 615 highest_ambi = -1;
495
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 580 times.
615 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC)
496 35 highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1;
497 else {
498 580 const AVChannelCustom *map = channel_layout->u.map;
499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 580 times.
580 av_assert0(channel_layout->order == AV_CHANNEL_ORDER_CUSTOM);
500
501
2/2
✓ Branch 0 taken 1268 times.
✓ Branch 1 taken 135 times.
1403 for (i = 0; i < channel_layout->nb_channels; i++) {
502
3/4
✓ Branch 0 taken 511 times.
✓ Branch 1 taken 757 times.
✓ Branch 2 taken 511 times.
✗ Branch 3 not taken.
1268 int is_ambi = CHAN_IS_AMBI(map[i].id);
503
504 /* ambisonic following non-ambisonic */
505
6/8
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 580 times.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 635 times.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 53 times.
1268 if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id))
506 return AVERROR(EINVAL);
507
508 /* non-default ordering */
509
4/4
✓ Branch 0 taken 511 times.
✓ Branch 1 taken 757 times.
✓ Branch 2 taken 445 times.
✓ Branch 3 taken 66 times.
1268 if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i)
510 445 return AVERROR(EINVAL);
511
512
3/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 757 times.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
823 if (CHAN_IS_AMBI(map[i].id))
513 66 highest_ambi = i;
514 }
515 }
516 /* no ambisonic channels*/
517
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 48 times.
170 if (highest_ambi < 0)
518 122 return AVERROR(EINVAL);
519
520 48 order = floor(sqrt(highest_ambi));
521 /* incomplete order - some harmonics are missing */
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if ((order + 1) * (order + 1) != highest_ambi + 1)
523 return AVERROR(EINVAL);
524
525 48 return order;
526 }
527
528 318 static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout)
529 {
530 318 int has_known_channel = 0;
531 int order;
532
533
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 201 times.
318 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
534 117 return channel_layout->order;
535
536
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 197 times.
201 if (has_channel_names(channel_layout))
537 4 return AV_CHANNEL_ORDER_CUSTOM;
538
539
4/4
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 89 times.
395 for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++)
540
2/2
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 1 times.
198 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN)
541 197 has_known_channel = 1;
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (!has_known_channel)
543 return AV_CHANNEL_ORDER_UNSPEC;
544
545
2/2
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 81 times.
197 if (masked_description(channel_layout, 0) > 0)
546 116 return AV_CHANNEL_ORDER_NATIVE;
547
548 81 order = av_channel_layout_ambisonic_order(channel_layout);
549
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 80 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
81 if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0)
550 1 return AV_CHANNEL_ORDER_AMBISONIC;
551
552 80 return AV_CHANNEL_ORDER_CUSTOM;
553 }
554
555 /**
556 * If the custom layout is n-th order standard-order ambisonic, with optional
557 * extra non-diegetic channels at the end, write its string description in bp.
558 * Return a negative error code otherwise.
559 */
560 527 static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
561 {
562 int nb_ambi_channels;
563 527 int order = av_channel_layout_ambisonic_order(channel_layout);
564
2/2
✓ Branch 0 taken 485 times.
✓ Branch 1 taken 42 times.
527 if (order < 0)
565 485 return order;
566
567 42 av_bprintf(bp, "ambisonic %d", order);
568
569 /* extra channels present */
570 42 nb_ambi_channels = (order + 1) * (order + 1);
571
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
42 if (nb_ambi_channels < channel_layout->nb_channels) {
572 12 AVChannelLayout extra = { 0 };
573
574
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) {
575 5 extra.order = AV_CHANNEL_ORDER_NATIVE;
576 5 extra.nb_channels = av_popcount64(channel_layout->u.mask);
577 5 extra.u.mask = channel_layout->u.mask;
578 } else {
579 int64_t mask;
580
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) &&
581 4 (mask = masked_description(channel_layout, nb_ambi_channels)) > 0) {
582 1 extra.order = AV_CHANNEL_ORDER_NATIVE;
583 1 extra.nb_channels = av_popcount64(mask);
584 1 extra.u.mask = mask;
585 } else {
586 6 extra.order = AV_CHANNEL_ORDER_CUSTOM;
587 6 extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
588 6 extra.u.map = channel_layout->u.map + nb_ambi_channels;
589 }
590 }
591
592 12 av_bprint_chars(bp, '+', 1);
593 12 av_channel_layout_describe_bprint(&extra, bp);
594 /* Not calling uninit here on extra because we don't own the u.map pointer */
595 }
596
597 42 return 0;
598 }
599
600 17478 int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
601 AVBPrint *bp)
602 {
603 int i;
604
605
4/5
✓ Branch 0 taken 16802 times.
✓ Branch 1 taken 492 times.
✓ Branch 2 taken 149 times.
✓ Branch 3 taken 35 times.
✗ Branch 4 not taken.
17478 switch (channel_layout->order) {
606 16802 case AV_CHANNEL_ORDER_NATIVE:
607
2/2
✓ Branch 0 taken 60151 times.
✓ Branch 1 taken 191 times.
60342 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
608
2/2
✓ Branch 0 taken 16611 times.
✓ Branch 1 taken 43540 times.
60151 if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
609 16611 av_bprintf(bp, "%s", channel_layout_map[i].name);
610 16611 return 0;
611 }
612 av_fallthrough;
613 case AV_CHANNEL_ORDER_CUSTOM:
614
2/2
✓ Branch 0 taken 492 times.
✓ Branch 1 taken 191 times.
683 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
615 int64_t mask;
616 492 int res = try_describe_ambisonic(bp, channel_layout);
617
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 485 times.
492 if (res >= 0)
618 7 return 0;
619
4/4
✓ Branch 1 taken 474 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 473 times.
959 if (!has_channel_names(channel_layout) &&
620 474 (mask = masked_description(channel_layout, 0)) > 0) {
621 1 AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE,
622 1 .nb_channels = av_popcount64(mask),
623 .u.mask = mask };
624 1 return av_channel_layout_describe_bprint(&native, bp);
625 }
626 }
627
1/2
✓ Branch 0 taken 675 times.
✗ Branch 1 not taken.
675 if (channel_layout->nb_channels)
628 675 av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
629
2/2
✓ Branch 0 taken 1696 times.
✓ Branch 1 taken 675 times.
2371 for (i = 0; i < channel_layout->nb_channels; i++) {
630 1696 enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
631
632
2/2
✓ Branch 0 taken 1021 times.
✓ Branch 1 taken 675 times.
1696 if (i)
633 1021 av_bprintf(bp, "+");
634 1696 av_channel_name_bprint(bp, ch);
635
2/2
✓ Branch 0 taken 1061 times.
✓ Branch 1 taken 635 times.
1696 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
636
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1044 times.
1061 channel_layout->u.map[i].name[0])
637 17 av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
638 }
639
1/2
✓ Branch 0 taken 675 times.
✗ Branch 1 not taken.
675 if (channel_layout->nb_channels) {
640 675 av_bprintf(bp, ")");
641 675 return 0;
642 }
643 av_fallthrough;
644 case AV_CHANNEL_ORDER_UNSPEC:
645 149 av_bprintf(bp, "%d channels", channel_layout->nb_channels);
646 149 return 0;
647 35 case AV_CHANNEL_ORDER_AMBISONIC:
648 35 return try_describe_ambisonic(bp, channel_layout);
649 default:
650 return AVERROR(EINVAL);
651 }
652 }
653
654 11763 int av_channel_layout_describe(const AVChannelLayout *channel_layout,
655 char *buf, size_t buf_size)
656 {
657 AVBPrint bp;
658 int ret;
659
660
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11741 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
11763 if (!buf && buf_size)
661 return AVERROR(EINVAL);
662
663 11763 av_bprint_init_for_buffer(&bp, buf, buf_size);
664 11763 ret = av_channel_layout_describe_bprint(channel_layout, &bp);
665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11763 times.
11763 if (ret < 0)
666 return ret;
667
668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11763 times.
11763 if (bp.len >= INT_MAX)
669 return AVERROR(ERANGE);
670 11763 return bp.len + 1;
671 }
672
673 enum AVChannel
674 6812 av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout,
675 unsigned int idx)
676 {
677 int i;
678
679
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6809 times.
6812 if (idx >= channel_layout->nb_channels)
680 3 return AV_CHAN_NONE;
681
682
4/4
✓ Branch 0 taken 5327 times.
✓ Branch 1 taken 344 times.
✓ Branch 2 taken 1136 times.
✓ Branch 3 taken 2 times.
6809 switch (channel_layout->order) {
683 5327 case AV_CHANNEL_ORDER_CUSTOM:
684 5327 return channel_layout->u.map[idx].id;
685 344 case AV_CHANNEL_ORDER_AMBISONIC: {
686 344 int ambi_channels = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask);
687
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 14 times.
344 if (idx < ambi_channels)
688 330 return AV_CHAN_AMBISONIC_BASE + idx;
689 14 idx -= ambi_channels;
690 }
691 av_fallthrough;
692 1150 case AV_CHANNEL_ORDER_NATIVE:
693
1/2
✓ Branch 0 taken 6400 times.
✗ Branch 1 not taken.
6400 for (i = 0; i < 64; i++) {
694
4/4
✓ Branch 0 taken 2989 times.
✓ Branch 1 taken 3411 times.
✓ Branch 2 taken 1150 times.
✓ Branch 3 taken 1839 times.
6400 if ((1ULL << i) & channel_layout->u.mask && !idx--)
695 1150 return i;
696 }
697 av_fallthrough;
698 default:
699 2 return AV_CHAN_NONE;
700 }
701 }
702
703 enum AVChannel
704 19 av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout,
705 const char *str)
706 {
707 19 int index = av_channel_layout_index_from_string(channel_layout, str);
708
709
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 12 times.
19 if (index < 0)
710 7 return AV_CHAN_NONE;
711
712 12 return av_channel_layout_channel_from_index(channel_layout, index);
713 }
714
715 14165 int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout,
716 enum AVChannel channel)
717 {
718 int i;
719
720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14165 times.
14165 if (channel == AV_CHAN_NONE)
721 return AVERROR(EINVAL);
722
723
3/3
✓ Branch 0 taken 2166 times.
✓ Branch 1 taken 11983 times.
✓ Branch 2 taken 16 times.
14165 switch (channel_layout->order) {
724 2166 case AV_CHANNEL_ORDER_CUSTOM:
725
2/2
✓ Branch 0 taken 15021 times.
✓ Branch 1 taken 1887 times.
16908 for (i = 0; i < channel_layout->nb_channels; i++)
726
2/2
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 14742 times.
15021 if (channel_layout->u.map[i].id == channel)
727 279 return i;
728 1887 return AVERROR(EINVAL);
729 11983 case AV_CHANNEL_ORDER_AMBISONIC:
730 case AV_CHANNEL_ORDER_NATIVE: {
731 11983 uint64_t mask = channel_layout->u.mask;
732 11983 int ambi_channels = channel_layout->nb_channels - av_popcount64(mask);
733
4/4
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 11781 times.
✓ Branch 2 taken 193 times.
✓ Branch 3 taken 9 times.
11983 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC &&
734 channel >= AV_CHAN_AMBISONIC_BASE) {
735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
193 if (channel - AV_CHAN_AMBISONIC_BASE >= ambi_channels)
736 return AVERROR(EINVAL);
737 193 return channel - AV_CHAN_AMBISONIC_BASE;
738 }
739
3/4
✓ Branch 0 taken 11790 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6444 times.
✓ Branch 3 taken 5346 times.
11790 if ((unsigned)channel > 63 || !(mask & (1ULL << channel)))
740 6444 return AVERROR(EINVAL);
741 5346 mask &= (1ULL << channel) - 1;
742 5346 return av_popcount64(mask) + ambi_channels;
743 }
744 16 default:
745 16 return AVERROR(EINVAL);
746 }
747 }
748
749 35 int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout,
750 const char *str)
751 {
752 char *chname;
753 35 enum AVChannel ch = AV_CHAN_NONE;
754
755
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
35 switch (channel_layout->order) {
756 18 case AV_CHANNEL_ORDER_CUSTOM:
757 18 chname = strstr(str, "@");
758
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (chname) {
759 char buf[16];
760 8 chname++;
761 8 av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str));
762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!*chname)
763 chname = NULL;
764 8 ch = av_channel_from_string(buf);
765
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)
766 return AVERROR(EINVAL);
767 }
768
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++) {
769
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) &&
770
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id))
771 6 return i;
772 }
773 av_fallthrough;
774 case AV_CHANNEL_ORDER_AMBISONIC:
775 case AV_CHANNEL_ORDER_NATIVE:
776 29 ch = av_channel_from_string(str);
777
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
29 if (ch == AV_CHAN_NONE)
778 7 return AVERROR(EINVAL);
779 22 return av_channel_layout_index_from_channel(channel_layout, ch);
780 }
781
782 return AVERROR(EINVAL);
783 }
784
785 347135 int av_channel_layout_check(const AVChannelLayout *channel_layout)
786 {
787
2/2
✓ Branch 0 taken 6702 times.
✓ Branch 1 taken 340433 times.
347135 if (channel_layout->nb_channels <= 0)
788 6702 return 0;
789
790
4/5
✓ Branch 0 taken 301738 times.
✓ Branch 1 taken 619 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 38064 times.
✗ Branch 4 not taken.
340433 switch (channel_layout->order) {
791 301738 case AV_CHANNEL_ORDER_NATIVE:
792 301738 return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
793 619 case AV_CHANNEL_ORDER_CUSTOM:
794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 619 times.
619 if (!channel_layout->u.map)
795 return 0;
796
2/2
✓ Branch 0 taken 1266 times.
✓ Branch 1 taken 619 times.
1885 for (int i = 0; i < channel_layout->nb_channels; i++) {
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1266 times.
1266 if (channel_layout->u.map[i].id == AV_CHAN_NONE)
798 return 0;
799 }
800 619 return 1;
801 12 case AV_CHANNEL_ORDER_AMBISONIC:
802 /* If non-diegetic channels are present, ensure they are taken into account */
803 12 return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels;
804 38064 case AV_CHANNEL_ORDER_UNSPEC:
805 38064 return 1;
806 default:
807 return 0;
808 }
809 }
810
811 1969627 int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
812 {
813 int i;
814
815 /* different channel counts -> not equal */
816
2/2
✓ Branch 0 taken 8528 times.
✓ Branch 1 taken 1961099 times.
1969627 if (chl->nb_channels != chl1->nb_channels)
817 8528 return 1;
818
819 /* if only one is unspecified -> not equal */
820 1961099 if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
821
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 1961032 times.
1961099 (chl1->order == AV_CHANNEL_ORDER_UNSPEC))
822 67 return 1;
823 /* both are unspecified -> equal */
824
2/2
✓ Branch 0 taken 244729 times.
✓ Branch 1 taken 1716303 times.
1961032 else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
825 244729 return 0;
826
827 /* can compare masks directly */
828
2/2
✓ Branch 0 taken 714 times.
✓ Branch 1 taken 1715589 times.
1716303 if ((chl->order == AV_CHANNEL_ORDER_NATIVE ||
829
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 701 times.
714 chl->order == AV_CHANNEL_ORDER_AMBISONIC) &&
830
1/2
✓ Branch 0 taken 1715602 times.
✗ Branch 1 not taken.
1715602 chl->order == chl1->order)
831 1715602 return chl->u.mask != chl1->u.mask;
832
833 /* compare channel by channel */
834
2/2
✓ Branch 0 taken 2030 times.
✓ Branch 1 taken 698 times.
2728 for (i = 0; i < chl->nb_channels; i++)
835
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2027 times.
4060 if (av_channel_layout_channel_from_index(chl, i) !=
836 2030 av_channel_layout_channel_from_index(chl1, i))
837 3 return 1;
838 698 return 0;
839 }
840
841 28057 void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
842 {
843 int i;
844
2/2
✓ Branch 0 taken 46627 times.
✓ Branch 1 taken 15 times.
46642 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
845
2/2
✓ Branch 0 taken 28042 times.
✓ Branch 1 taken 18585 times.
46627 if (nb_channels == channel_layout_map[i].layout.nb_channels) {
846 28042 *ch_layout = channel_layout_map[i].layout;
847 28042 return;
848 }
849
850 15 ch_layout->order = AV_CHANNEL_ORDER_UNSPEC;
851 15 ch_layout->nb_channels = nb_channels;
852 }
853
854 41 const AVChannelLayout *av_channel_layout_standard(void **opaque)
855 {
856 41 uintptr_t i = (uintptr_t)*opaque;
857 41 const AVChannelLayout *ch_layout = NULL;
858
859
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1 times.
41 if (i < FF_ARRAY_ELEMS(channel_layout_map)) {
860 40 ch_layout = &channel_layout_map[i].layout;
861 40 *opaque = (void*)(i + 1);
862 }
863
864 41 return ch_layout;
865 }
866
867 2321 uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
868 uint64_t mask)
869 {
870 2321 uint64_t ret = 0;
871 int i;
872
873
3/3
✓ Branch 0 taken 1912 times.
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 368 times.
2321 switch (channel_layout->order) {
874 1912 case AV_CHANNEL_ORDER_NATIVE:
875 case AV_CHANNEL_ORDER_AMBISONIC:
876 1912 return channel_layout->u.mask & mask;
877 41 case AV_CHANNEL_ORDER_CUSTOM:
878
2/2
✓ Branch 0 taken 2624 times.
✓ Branch 1 taken 41 times.
2665 for (i = 0; i < 64; i++)
879
4/4
✓ Branch 0 taken 2007 times.
✓ Branch 1 taken 617 times.
✓ Branch 3 taken 245 times.
✓ Branch 4 taken 1762 times.
2624 if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0)
880 245 ret |= (1ULL << i);
881 41 break;
882 }
883
884 409 return ret;
885 }
886
887 410 int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
888 {
889 410 int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
890 int lossy;
891
892
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 410 times.
410 if (!av_channel_layout_check(channel_layout))
893 return AVERROR(EINVAL);
894
895
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 92 times.
410 if (flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL)
896 318 order = canonical_order(channel_layout);
897
898
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 204 times.
410 if (channel_layout->order == order)
899 206 return 0;
900
901
4/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
204 switch (order) {
902 4 case AV_CHANNEL_ORDER_UNSPEC: {
903 4 int nb_channels = channel_layout->nb_channels;
904
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
905 2 lossy = 0;
906
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 for (int i = 0; i < nb_channels; i++) {
907
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]) {
908 2 lossy = 1;
909 2 break;
910 }
911 }
912 } else {
913 2 lossy = 1;
914 }
915
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) {
916 4 void *opaque = channel_layout->opaque;
917 4 av_channel_layout_uninit(channel_layout);
918 4 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
919 4 channel_layout->nb_channels = nb_channels;
920 4 channel_layout->opaque = opaque;
921 4 return lossy;
922 }
923 return AVERROR(ENOSYS);
924 }
925 188 case AV_CHANNEL_ORDER_NATIVE:
926
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 2 times.
188 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
927 186 int64_t mask = masked_description(channel_layout, 0);
928
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 142 times.
186 if (mask < 0)
929 44 return AVERROR(ENOSYS);
930 142 lossy = has_channel_names(channel_layout);
931
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
142 if (!lossy || allow_lossy) {
932 142 void *opaque = channel_layout->opaque;
933 142 av_channel_layout_uninit(channel_layout);
934 142 av_channel_layout_from_mask(channel_layout, mask);
935 142 channel_layout->opaque = opaque;
936 142 return lossy;
937 }
938 }
939 2 return AVERROR(ENOSYS);
940 3 case AV_CHANNEL_ORDER_CUSTOM: {
941 3 AVChannelLayout custom = { 0 };
942 3 int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
943 3 void *opaque = channel_layout->opaque;
944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < 0)
945 return ret;
946
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
947
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
15 for (int i = 0; i < channel_layout->nb_channels; i++)
948 13 custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
949 3 av_channel_layout_uninit(channel_layout);
950 3 *channel_layout = custom;
951 3 channel_layout->opaque = opaque;
952 3 return 0;
953 }
954 9 case AV_CHANNEL_ORDER_AMBISONIC:
955
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
956 int64_t mask;
957 7 int nb_channels = channel_layout->nb_channels;
958 7 int amb_order = av_channel_layout_ambisonic_order(channel_layout);
959
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (amb_order < 0)
960 2 return AVERROR(ENOSYS);
961 5 mask = masked_description(channel_layout, (amb_order + 1) * (amb_order + 1));
962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (mask < 0)
963 return AVERROR(ENOSYS);
964 5 lossy = has_channel_names(channel_layout);
965
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5 if (!lossy || allow_lossy) {
966 5 void *opaque = channel_layout->opaque;
967 5 av_channel_layout_uninit(channel_layout);
968 5 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
969 5 channel_layout->nb_channels = nb_channels;
970 5 channel_layout->u.mask = mask;
971 5 channel_layout->opaque = opaque;
972 5 return lossy;
973 }
974 }
975 2 return AVERROR(ENOSYS);
976 default:
977 return AVERROR(EINVAL);
978 }
979 }
980