FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2024-07-26 21:54:09
Exec Total Coverage
Lines: 466 531 87.8%
Functions: 28 28 100.0%
Branches: 346 434 79.7%

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