FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/channel_layout.c
Date: 2024-04-24 18:52:15
Exec Total Coverage
Lines: 464 528 87.9%
Functions: 28 28 100.0%
Branches: 343 430 79.8%

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