FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 478 531 90.0%
Functions: 28 28 100.0%
Branches: 351 434 80.9%

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