FFmpeg
Loading...
Searching...
No Matches
channel_layout.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * audio channel layout utility functions
24 */
25
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "avassert.h"
31#include "channel_layout.h"
32#include "bprint.h"
33#include "common.h"
34#include "error.h"
35#include "attributes.h"
36#include "macros.h"
37#include "mem.h"
38#include "opt.h"
39
40#define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\
41 (x) <= AV_CHAN_AMBISONIC_END)
42
44 const char *name;
45 const char *description;
46};
47
48static const struct channel_name channel_names[] = {
49 [AV_CHAN_FRONT_LEFT ] = { "FL", "front left" },
50 [AV_CHAN_FRONT_RIGHT ] = { "FR", "front right" },
51 [AV_CHAN_FRONT_CENTER ] = { "FC", "front center" },
52 [AV_CHAN_LOW_FREQUENCY ] = { "LFE", "low frequency" },
53 [AV_CHAN_BACK_LEFT ] = { "BL", "back left" },
54 [AV_CHAN_BACK_RIGHT ] = { "BR", "back right" },
55 [AV_CHAN_FRONT_LEFT_OF_CENTER ] = { "FLC", "front left-of-center" },
56 [AV_CHAN_FRONT_RIGHT_OF_CENTER] = { "FRC", "front right-of-center" },
57 [AV_CHAN_BACK_CENTER ] = { "BC", "back center" },
58 [AV_CHAN_SIDE_LEFT ] = { "SL", "side left" },
59 [AV_CHAN_SIDE_RIGHT ] = { "SR", "side right" },
60 [AV_CHAN_TOP_CENTER ] = { "TC", "top center" },
61 [AV_CHAN_TOP_FRONT_LEFT ] = { "TFL", "top front left" },
62 [AV_CHAN_TOP_FRONT_CENTER ] = { "TFC", "top front center" },
63 [AV_CHAN_TOP_FRONT_RIGHT ] = { "TFR", "top front right" },
64 [AV_CHAN_TOP_BACK_LEFT ] = { "TBL", "top back left" },
65 [AV_CHAN_TOP_BACK_CENTER ] = { "TBC", "top back center" },
66 [AV_CHAN_TOP_BACK_RIGHT ] = { "TBR", "top back right" },
67 [AV_CHAN_STEREO_LEFT ] = { "DL", "downmix left" },
68 [AV_CHAN_STEREO_RIGHT ] = { "DR", "downmix right" },
69 [AV_CHAN_WIDE_LEFT ] = { "WL", "wide left" },
70 [AV_CHAN_WIDE_RIGHT ] = { "WR", "wide right" },
71 [AV_CHAN_SURROUND_DIRECT_LEFT ] = { "SDL", "surround direct left" },
72 [AV_CHAN_SURROUND_DIRECT_RIGHT] = { "SDR", "surround direct right" },
73 [AV_CHAN_LOW_FREQUENCY_2 ] = { "LFE2", "low frequency 2" },
74 [AV_CHAN_TOP_SIDE_LEFT ] = { "TSL", "top side left" },
75 [AV_CHAN_TOP_SIDE_RIGHT ] = { "TSR", "top side right" },
76 [AV_CHAN_BOTTOM_FRONT_CENTER ] = { "BFC", "bottom front center" },
77 [AV_CHAN_BOTTOM_FRONT_LEFT ] = { "BFL", "bottom front left" },
78 [AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" },
79 [AV_CHAN_SIDE_SURROUND_LEFT ] = { "SSL", "side surround left" },
80 [AV_CHAN_SIDE_SURROUND_RIGHT ] = { "SSR", "side surround right" },
81 [AV_CHAN_TOP_SURROUND_LEFT ] = { "TTL", "top surround left" },
82 [AV_CHAN_TOP_SURROUND_RIGHT ] = { "TTR", "top surround right" },
83 [AV_CHAN_BINAURAL_LEFT ] = { "BIL", "binaural left" },
84 [AV_CHAN_BINAURAL_RIGHT ] = { "BIR", "binaural right" },
85};
86
87void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
88{
89 if (channel_id >= AV_CHAN_AMBISONIC_BASE &&
90 channel_id <= AV_CHAN_AMBISONIC_END)
91 av_bprintf(bp, "AMBI%d", channel_id - AV_CHAN_AMBISONIC_BASE);
92 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
93 channel_names[channel_id].name)
94 av_bprintf(bp, "%s", channel_names[channel_id].name);
95 else if (channel_id == AV_CHAN_NONE)
96 av_bprintf(bp, "NONE");
97 else if (channel_id == AV_CHAN_UNKNOWN)
98 av_bprintf(bp, "UNK");
99 else if (channel_id == AV_CHAN_UNUSED)
100 av_bprintf(bp, "UNSD");
101 else
102 av_bprintf(bp, "USR%d", channel_id);
103}
104
105int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
106{
107 AVBPrint bp;
108
109 if (!buf && buf_size)
110 return AVERROR(EINVAL);
111
112 av_bprint_init_for_buffer(&bp, buf, buf_size);
113 av_channel_name_bprint(&bp, channel_id);
114
115 if (bp.len >= INT_MAX)
116 return AVERROR(ERANGE);
117 return bp.len + 1;
118}
119
120void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
121{
122 if (channel_id >= AV_CHAN_AMBISONIC_BASE &&
123 channel_id <= AV_CHAN_AMBISONIC_END)
124 av_bprintf(bp, "ambisonic ACN %d", channel_id - AV_CHAN_AMBISONIC_BASE);
125 else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) &&
126 channel_names[channel_id].description)
127 av_bprintf(bp, "%s", channel_names[channel_id].description);
128 else if (channel_id == AV_CHAN_NONE)
129 av_bprintf(bp, "none");
130 else if (channel_id == AV_CHAN_UNKNOWN)
131 av_bprintf(bp, "unknown");
132 else if (channel_id == AV_CHAN_UNUSED)
133 av_bprintf(bp, "unused");
134 else
135 av_bprintf(bp, "user %d", channel_id);
136}
137
138int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel_id)
139{
140 AVBPrint bp;
141
142 if (!buf && buf_size)
143 return AVERROR(EINVAL);
144
145 av_bprint_init_for_buffer(&bp, buf, buf_size);
146 av_channel_description_bprint(&bp, channel_id);
147
148 if (bp.len >= INT_MAX)
149 return AVERROR(ERANGE);
150 return bp.len + 1;
151}
152
154{
155 int i;
156 char *endptr = (char *)str;
157 enum AVChannel id = AV_CHAN_NONE;
158
159 if (!strncmp(str, "AMBI", 4)) {
160 i = strtol(str + 4, NULL, 0);
162 return AV_CHAN_NONE;
163 return AV_CHAN_AMBISONIC_BASE + i;
164 }
165
166 for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
167 if (channel_names[i].name && !strcmp(str, channel_names[i].name))
168 return i;
169 }
170 if (!strcmp(str, "UNK"))
171 return AV_CHAN_UNKNOWN;
172 if (!strcmp(str, "UNSD"))
173 return AV_CHAN_UNUSED;
174
175 if (!strncmp(str, "USR", 3)) {
176 const char *p = str + 3;
177 id = strtol(p, &endptr, 0);
178 }
179 if (id >= 0 && !*endptr)
180 return id;
181
182 return AV_CHAN_NONE;
183}
184
189
191 { "mono", AV_CHANNEL_LAYOUT_MONO },
192 { "stereo", AV_CHANNEL_LAYOUT_STEREO },
193 { "2.1", AV_CHANNEL_LAYOUT_2POINT1 },
195 { "3.0(back)", AV_CHANNEL_LAYOUT_2_1 },
196 { "4.0", AV_CHANNEL_LAYOUT_4POINT0 },
197 { "quad", AV_CHANNEL_LAYOUT_QUAD },
198 { "quad(side)", AV_CHANNEL_LAYOUT_2_2 },
199 { "3.1", AV_CHANNEL_LAYOUT_3POINT1 },
201 { "5.0(side)", AV_CHANNEL_LAYOUT_5POINT0 },
202 { "4.1", AV_CHANNEL_LAYOUT_4POINT1 },
204 { "5.1(side)", AV_CHANNEL_LAYOUT_5POINT1 },
205 { "6.0", AV_CHANNEL_LAYOUT_6POINT0 },
206 { "6.0(front)", AV_CHANNEL_LAYOUT_6POINT0_FRONT },
208 { "hexagonal", AV_CHANNEL_LAYOUT_HEXAGONAL },
209 { "6.1", AV_CHANNEL_LAYOUT_6POINT1 },
210 { "6.1(back)", AV_CHANNEL_LAYOUT_6POINT1_BACK },
211 { "6.1(front)", AV_CHANNEL_LAYOUT_6POINT1_FRONT },
212 { "7.0", AV_CHANNEL_LAYOUT_7POINT0 },
213 { "7.0(front)", AV_CHANNEL_LAYOUT_7POINT0_FRONT },
214 { "7.1", AV_CHANNEL_LAYOUT_7POINT1 },
216 { "7.1(wide-side)", AV_CHANNEL_LAYOUT_7POINT1_WIDE },
218 { "5.1.2(back)", AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK },
219 { "octagonal", AV_CHANNEL_LAYOUT_OCTAGONAL },
220 { "cube", AV_CHANNEL_LAYOUT_CUBE },
229 { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL },
230 { "binaural", AV_CHANNEL_LAYOUT_BINAURAL },
231 { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, },
232 { "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
233};
234
235int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
236{
238
239 if (nb_channels <= 0)
240 return AVERROR(EINVAL);
241
242 map = av_calloc(nb_channels, sizeof(*channel_layout->u.map));
243 if (!map)
244 return AVERROR(ENOMEM);
245 for (int i = 0; i < nb_channels; i++)
246 map[i].id = AV_CHAN_UNKNOWN;
247
248 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
249 channel_layout->nb_channels = nb_channels;
250 channel_layout->u.map = map;
251
252 return 0;
253}
254
256 uint64_t mask)
257{
258 if (!mask)
259 return AVERROR(EINVAL);
260
261 channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
262 channel_layout->nb_channels = av_popcount64(mask);
263 channel_layout->u.mask = mask;
264
265 return 0;
266}
267
268static int parse_channel_list(AVChannelLayout *ch_layout, const char *str)
269{
270 int ret;
271 int nb_channels = 0;
273 AVChannelCustom custom = {0};
274
275 while (*str) {
276 char *channel, *chname;
277 ret = av_opt_get_key_value(&str, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
278 if (ret < 0) {
279 av_freep(&map);
280 return ret;
281 }
282 if (*str)
283 str++; // skip separator
284 if (!channel) {
285 channel = chname;
286 chname = NULL;
287 }
288 av_strlcpy(custom.name, chname ? chname : "", sizeof(custom.name));
291 av_free(chname);
292 if (custom.id == AV_CHAN_NONE) {
293 av_freep(&map);
294 return AVERROR(EINVAL);
295 }
296
297 av_dynarray2_add((void **)&map, &nb_channels, sizeof(custom), (void *)&custom);
298 if (!map)
299 return AVERROR(ENOMEM);
300 }
301
302 if (!nb_channels)
303 return AVERROR(EINVAL);
304
305 ch_layout->order = AV_CHANNEL_ORDER_CUSTOM;
306 ch_layout->u.map = map;
307 ch_layout->nb_channels = nb_channels;
308
310 av_assert0(ret == 0);
311
312 return 0;
313}
314
316 const char *str)
317{
318 int i, matches, ret;
319 int channels = 0, nb_channels = 0;
320 char *chlist, *end;
321 uint64_t mask = 0;
322
323 /* channel layout names */
324 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
325 if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
326 *channel_layout = channel_layout_map[i].layout;
327 return 0;
328 }
329 }
330
331 /* This function is a channel layout initializer, so we have to
332 * zero-initialize before we start setting fields individually. */
333 memset(channel_layout, 0, sizeof(*channel_layout));
334
335 /* ambisonic */
336 if (!strncmp(str, "ambisonic ", 10)) {
337 const char *p = str + 10;
338 char *endptr;
339 AVChannelLayout extra = {0};
340 int order;
341
342 order = strtol(p, &endptr, 0);
343 if (order < 0 || order + 1 > INT_MAX / (order + 1) ||
344 (*endptr && *endptr != '+'))
345 return AVERROR(EINVAL);
346
347 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
348 channel_layout->nb_channels = (order + 1) * (order + 1);
349
350 if (*endptr) {
351 ret = av_channel_layout_from_string(&extra, endptr + 1);
352 if (ret < 0)
353 return ret;
354 if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) {
356 return AVERROR(EINVAL);
357 }
358
359 if (extra.order == AV_CHANNEL_ORDER_NATIVE) {
360 channel_layout->u.mask = extra.u.mask;
361 } else {
362 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
363 channel_layout->u.map =
364 av_calloc(channel_layout->nb_channels + extra.nb_channels,
365 sizeof(*channel_layout->u.map));
366 if (!channel_layout->u.map) {
368 return AVERROR(ENOMEM);
369 }
370
371 for (i = 0; i < channel_layout->nb_channels; i++)
372 channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i;
373 for (i = 0; i < extra.nb_channels; i++) {
375 if (CHAN_IS_AMBI(ch)) {
376 av_channel_layout_uninit(channel_layout);
378 return AVERROR(EINVAL);
379 }
380 channel_layout->u.map[channel_layout->nb_channels + i].id = ch;
381 if (extra.order == AV_CHANNEL_ORDER_CUSTOM &&
382 extra.u.map[i].name[0])
383 av_strlcpy(channel_layout->u.map[channel_layout->nb_channels + i].name,
384 extra.u.map[i].name,
385 sizeof(channel_layout->u.map[channel_layout->nb_channels + i].name));
386 }
387 }
388 channel_layout->nb_channels += extra.nb_channels;
390 }
391
392 return 0;
393 }
394
395 chlist = av_strdup(str);
396 if (!chlist)
397 return AVERROR(ENOMEM);
398
399 /* channel names */
400 matches = av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
401 ret = parse_channel_list(channel_layout, chlist);
402 av_freep(&chlist);
403 if (ret < 0 && ret != AVERROR(EINVAL))
404 return ret;
405
406 if (ret >= 0) {
407 const char *end_par = strchr(str, ')');
408 if (matches == 2 && (nb_channels != channel_layout->nb_channels || !end_par || *++end_par)) {
409 av_channel_layout_uninit(channel_layout);
410 return AVERROR(EINVAL);
411 }
412 return 0;
413 }
414
415 errno = 0;
416 mask = strtoull(str, &end, 0);
417
418 /* channel layout mask */
419 if (!errno && !*end && !strchr(str, '-') && mask) {
420 av_channel_layout_from_mask(channel_layout, mask);
421 return 0;
422 }
423
424 errno = 0;
425 channels = strtol(str, &end, 10);
426
427 /* number of channels */
428 if (!errno && !strcmp(end, "c") && channels > 0) {
429 av_channel_layout_default(channel_layout, channels);
430 if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
431 return 0;
432 }
433
434 /* number of unordered channels */
435 if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels"))
436 && channels > 0) {
437 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
438 channel_layout->nb_channels = channels;
439 return 0;
440 }
441
442 return AVERROR(EINVAL);
443}
444
446{
447 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
448 av_freep(&channel_layout->u.map);
449 memset(channel_layout, 0, sizeof(*channel_layout));
450}
451
453{
455 *dst = *src;
456 if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
457 dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
458 if (!dst->u.map)
459 return AVERROR(ENOMEM);
460 memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
461 }
462 return 0;
463}
464
465static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel)
466{
467 uint64_t mask = 0;
468 for (int i = start_channel; i < channel_layout->nb_channels; i++) {
469 enum AVChannel ch = channel_layout->u.map[i].id;
470 if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
471 mask |= (1ULL << ch);
472 else
473 return AVERROR(EINVAL);
474 }
475 return mask;
476}
477
478static int has_channel_names(const AVChannelLayout *channel_layout)
479{
480 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
481 return 0;
482 for (int i = 0; i < channel_layout->nb_channels; i++)
483 if (channel_layout->u.map[i].name[0])
484 return 1;
485 return 0;
486}
487
489{
490 int i, highest_ambi, order;
491
492 if (channel_layout->order != AV_CHANNEL_ORDER_AMBISONIC &&
493 channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
494 return AVERROR(EINVAL);
495
496 highest_ambi = -1;
497 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC)
498 highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1;
499 else {
500 const AVChannelCustom *map = channel_layout->u.map;
501 av_assert0(channel_layout->order == AV_CHANNEL_ORDER_CUSTOM);
502
503 for (i = 0; i < channel_layout->nb_channels; i++) {
504 int is_ambi = CHAN_IS_AMBI(map[i].id);
505
506 /* ambisonic following non-ambisonic */
507 if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id))
508 return AVERROR(EINVAL);
509
510 /* non-default ordering */
511 if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i)
512 return AVERROR(EINVAL);
513
514 if (CHAN_IS_AMBI(map[i].id))
515 highest_ambi = i;
516 }
517 }
518 /* no ambisonic channels*/
519 if (highest_ambi < 0)
520 return AVERROR(EINVAL);
521
522 order = floor(sqrt(highest_ambi));
523 /* incomplete order - some harmonics are missing */
524 if ((order + 1) * (order + 1) != highest_ambi + 1)
525 return AVERROR(EINVAL);
526
527 return order;
528}
529
531{
532 int has_known_channel = 0;
533 int order;
534
535 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
536 return channel_layout->order;
537
538 if (has_channel_names(channel_layout))
540
541 for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++)
542 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN)
543 has_known_channel = 1;
544 if (!has_known_channel)
546
547 if (masked_description(channel_layout, 0) > 0)
549
550 order = av_channel_layout_ambisonic_order(channel_layout);
551 if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0)
553
555}
556
557/**
558 * If the custom layout is n-th order standard-order ambisonic, with optional
559 * extra non-diegetic channels at the end, write its string description in bp.
560 * Return a negative error code otherwise.
561 */
562static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
563{
564 int nb_ambi_channels;
565 int order = av_channel_layout_ambisonic_order(channel_layout);
566 if (order < 0)
567 return order;
568
569 av_bprintf(bp, "ambisonic %d", order);
570
571 /* extra channels present */
572 nb_ambi_channels = (order + 1) * (order + 1);
573 if (nb_ambi_channels < channel_layout->nb_channels) {
574 AVChannelLayout extra = { 0 };
575
576 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) {
578 extra.nb_channels = av_popcount64(channel_layout->u.mask);
579 extra.u.mask = channel_layout->u.mask;
580 } else {
582 if (!has_channel_names(channel_layout) &&
583 (mask = masked_description(channel_layout, nb_ambi_channels)) > 0) {
586 extra.u.mask = mask;
587 } else {
589 extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
590 extra.u.map = channel_layout->u.map + nb_ambi_channels;
591 }
592 }
593
594 av_bprint_chars(bp, '+', 1);
596 /* Not calling uninit here on extra because we don't own the u.map pointer */
597 }
598
599 return 0;
600}
601
603 AVBPrint *bp)
604{
605 int i;
606
607 switch (channel_layout->order) {
609 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
610 if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
612 return 0;
613 }
616 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
618 int res = try_describe_ambisonic(bp, channel_layout);
619 if (res >= 0)
620 return 0;
621 if (!has_channel_names(channel_layout) &&
622 (mask = masked_description(channel_layout, 0)) > 0) {
623 AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE,
624 .nb_channels = av_popcount64(mask),
625 .u.mask = mask };
626 return av_channel_layout_describe_bprint(&native, bp);
627 }
628 }
629 if (channel_layout->nb_channels)
630 av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
631 for (i = 0; i < channel_layout->nb_channels; i++) {
632 enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
633
634 if (i)
635 av_bprintf(bp, "+");
637 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
638 channel_layout->u.map[i].name[0])
639 av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
640 }
641 if (channel_layout->nb_channels) {
642 av_bprintf(bp, ")");
643 return 0;
644 }
647 av_bprintf(bp, "%d channels", channel_layout->nb_channels);
648 return 0;
650 return try_describe_ambisonic(bp, channel_layout);
651 default:
652 return AVERROR(EINVAL);
653 }
654}
655
657 char *buf, size_t buf_size)
658{
659 AVBPrint bp;
660 int ret;
661
662 if (!buf && buf_size)
663 return AVERROR(EINVAL);
664
665 av_bprint_init_for_buffer(&bp, buf, buf_size);
666 ret = av_channel_layout_describe_bprint(channel_layout, &bp);
667 if (ret < 0)
668 return ret;
669
670 if (bp.len >= INT_MAX)
671 return AVERROR(ERANGE);
672 return bp.len + 1;
673}
674
675enum AVChannel
677 unsigned int idx)
678{
679 int i;
680
681 if (idx >= channel_layout->nb_channels)
682 return AV_CHAN_NONE;
683
684 switch (channel_layout->order) {
686 return channel_layout->u.map[idx].id;
688 int ambi_channels = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask);
689 if (idx < ambi_channels)
690 return AV_CHAN_AMBISONIC_BASE + idx;
691 idx -= ambi_channels;
692 }
695 for (i = 0; i < 64; i++) {
696 if ((1ULL << i) & channel_layout->u.mask && !idx--)
697 return i;
698 }
700 default:
701 return AV_CHAN_NONE;
702 }
703}
704
705enum AVChannel
707 const char *str)
708{
709 int index = av_channel_layout_index_from_string(channel_layout, str);
710
711 if (index < 0)
712 return AV_CHAN_NONE;
713
714 return av_channel_layout_channel_from_index(channel_layout, index);
715}
716
718 enum AVChannel channel)
719{
720 int i;
721
722 if (channel == AV_CHAN_NONE)
723 return AVERROR(EINVAL);
724
725 switch (channel_layout->order) {
727 for (i = 0; i < channel_layout->nb_channels; i++)
728 if (channel_layout->u.map[i].id == channel)
729 return i;
730 return AVERROR(EINVAL);
733 uint64_t mask = channel_layout->u.mask;
734 int ambi_channels = channel_layout->nb_channels - av_popcount64(mask);
735 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC &&
737 if (channel - AV_CHAN_AMBISONIC_BASE >= ambi_channels)
738 return AVERROR(EINVAL);
740 }
741 if ((unsigned)channel > 63 || !(mask & (1ULL << channel)))
742 return AVERROR(EINVAL);
743 mask &= (1ULL << channel) - 1;
744 return av_popcount64(mask) + ambi_channels;
745 }
746 default:
747 return AVERROR(EINVAL);
748 }
749}
750
752 const char *str)
753{
754 const char *chname;
755 enum AVChannel ch = AV_CHAN_NONE;
756
757 switch (channel_layout->order) {
759 chname = strstr(str, "@");
760 if (chname) {
761 char buf[16];
762 chname++;
763 av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str));
764 if (!*chname)
765 chname = NULL;
766 ch = av_channel_from_string(buf);
767 if (ch == AV_CHAN_NONE && *buf)
768 return AVERROR(EINVAL);
769 }
770 for (int i = 0; chname && i < channel_layout->nb_channels; i++) {
771 if (!strcmp(chname, channel_layout->u.map[i].name) &&
772 (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id))
773 return i;
774 }
778 ch = av_channel_from_string(str);
779 if (ch == AV_CHAN_NONE)
780 return AVERROR(EINVAL);
781 return av_channel_layout_index_from_channel(channel_layout, ch);
782 }
783
784 return AVERROR(EINVAL);
785}
786
787int av_channel_layout_check(const AVChannelLayout *channel_layout)
788{
789 if (channel_layout->nb_channels <= 0)
790 return 0;
791
792 switch (channel_layout->order) {
794 return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
796 if (!channel_layout->u.map)
797 return 0;
798 for (int i = 0; i < channel_layout->nb_channels; i++) {
799 if (channel_layout->u.map[i].id == AV_CHAN_NONE)
800 return 0;
801 }
802 return 1;
804 /* If non-diegetic channels are present, ensure they are taken into account */
805 return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels;
807 return 1;
808 default:
809 return 0;
810 }
811}
812
814{
815 int i;
816
817 /* different channel counts -> not equal */
818 if (chl->nb_channels != chl1->nb_channels)
819 return 1;
820
821 /* if only one is unspecified -> not equal */
822 if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
824 return 1;
825 /* both are unspecified -> equal */
826 else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
827 return 0;
828
829 /* can compare masks directly */
830 if ((chl->order == AV_CHANNEL_ORDER_NATIVE ||
832 chl->order == chl1->order)
833 return chl->u.mask != chl1->u.mask;
834
835 /* compare channel by channel */
836 for (i = 0; i < chl->nb_channels; i++)
839 return 1;
840 return 0;
841}
842
843void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
844{
845 int i;
846 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
847 if (nb_channels == channel_layout_map[i].layout.nb_channels) {
848 *ch_layout = channel_layout_map[i].layout;
849 return;
850 }
851
852 ch_layout->order = AV_CHANNEL_ORDER_UNSPEC;
853 ch_layout->nb_channels = nb_channels;
854}
855
857{
858 uintptr_t i = (uintptr_t)*opaque;
859 const AVChannelLayout *ch_layout = NULL;
860
862 ch_layout = &channel_layout_map[i].layout;
863 *opaque = (void*)(i + 1);
864 }
865
866 return ch_layout;
867}
868
869uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
870 uint64_t mask)
871{
872 uint64_t ret = 0;
873 int i;
874
875 switch (channel_layout->order) {
878 return channel_layout->u.mask & mask;
880 for (i = 0; i < 64; i++)
881 if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0)
882 ret |= (1ULL << i);
883 break;
884 }
885
886 return ret;
887}
888
890{
891 int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
892 int lossy;
893
894 if (!av_channel_layout_check(channel_layout))
895 return AVERROR(EINVAL);
896
898 order = canonical_order(channel_layout);
899
900 if (channel_layout->order == order)
901 return 0;
902
903 switch (order) {
905 int nb_channels = channel_layout->nb_channels;
906 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
907 lossy = 0;
908 for (int i = 0; i < nb_channels; i++) {
909 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
910 lossy = 1;
911 break;
912 }
913 }
914 } else {
915 lossy = 1;
916 }
917 if (!lossy || allow_lossy) {
918 void *opaque = channel_layout->opaque;
919 av_channel_layout_uninit(channel_layout);
920 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
921 channel_layout->nb_channels = nb_channels;
922 channel_layout->opaque = opaque;
923 return lossy;
924 }
925 return AVERROR(ENOSYS);
926 }
928 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
929 int64_t mask = masked_description(channel_layout, 0);
930 if (mask < 0)
931 return AVERROR(ENOSYS);
932 lossy = has_channel_names(channel_layout);
933 if (!lossy || allow_lossy) {
934 void *opaque = channel_layout->opaque;
935 av_channel_layout_uninit(channel_layout);
936 av_channel_layout_from_mask(channel_layout, mask);
937 channel_layout->opaque = opaque;
938 return lossy;
939 }
940 }
941 return AVERROR(ENOSYS);
943 AVChannelLayout custom = { 0 };
944 int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
945 void *opaque = channel_layout->opaque;
946 if (ret < 0)
947 return ret;
948 if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
949 for (int i = 0; i < channel_layout->nb_channels; i++)
950 custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
951 av_channel_layout_uninit(channel_layout);
952 *channel_layout = custom;
953 channel_layout->opaque = opaque;
954 return 0;
955 }
957 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
959 int nb_channels = channel_layout->nb_channels;
960 int amb_order = av_channel_layout_ambisonic_order(channel_layout);
961 if (amb_order < 0)
962 return AVERROR(ENOSYS);
963 mask = masked_description(channel_layout, (amb_order + 1) * (amb_order + 1));
964 if (mask < 0)
965 return AVERROR(ENOSYS);
966 lossy = has_channel_names(channel_layout);
967 if (!lossy || allow_lossy) {
968 void *opaque = channel_layout->opaque;
969 av_channel_layout_uninit(channel_layout);
970 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
971 channel_layout->nb_channels = nb_channels;
972 channel_layout->u.mask = mask;
973 channel_layout->opaque = opaque;
974 return lossy;
975 }
976 }
977 return AVERROR(ENOSYS);
978 default:
979 return AVERROR(EINVAL);
980 }
981}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
channels
Definition aptx.h:31
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
int av_sscanf(const char *string, const char *format,...)
Definition avsscanf.c:961
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:121
AVBPrint public header.
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel)
static const struct channel_layout_name channel_layout_map[]
static const struct channel_name channel_names[]
static int has_channel_names(const AVChannelLayout *channel_layout)
static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
If the custom layout is n-th order standard-order ambisonic, with optional extra non-diegetic channel...
static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout)
#define CHAN_IS_AMBI(x)
static int parse_channel_list(AVChannelLayout *ch_layout, const char *str)
Public libavutil channel layout APIs header.
common internal and external API header
#define av_popcount64
Definition common.h:157
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static __device__ float floor(float a)
enum AVCodecID id
Definition dts2pts.c:607
channel
Use these values when setting the channel map with ebur128_set_channel().
Definition ebur128.h:39
error code definitions
#define AV_CHANNEL_LAYOUT_4POINT0
#define AV_CHANNEL_LAYOUT_9POINT1POINT4
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
enum AVChannel av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout, const char *str)
Get a channel described by the given string.
#define AV_CHANNEL_LAYOUT_HEXADECAGONAL
#define AV_CHANNEL_LAYOUT_7POINT2POINT3
#define AV_CHANNEL_LAYOUT_5POINT1POINT2
#define AV_CHANNEL_LAYOUT_HEXAGONAL
int av_channel_layout_from_string(AVChannelLayout *channel_layout, const char *str)
Initialize a channel layout from a given string description.
#define AV_CHANNEL_LAYOUT_4POINT1
int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, enum AVChannel channel)
Get the index of a given channel in a channel layout.
#define AV_CHANNEL_LAYOUT_3POINT1
#define AV_CHANNEL_LAYOUT_BINAURAL
AVChannelOrder
int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout, const char *str)
Get the index in a channel layout of a channel described by the given string.
#define AV_CHANNEL_LAYOUT_7POINT0_FRONT
int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
Change the AVChannelOrder of a channel layout.
int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout, AVBPrint *bp)
bprint variant of av_channel_layout_describe().
#define AV_CHANNEL_LAYOUT_5POINT1_BACK
#define AV_CHANNEL_LAYOUT_7POINT1_WIDE
#define AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL
The specified retype target order is ignored and the simplest possible (canonical) order is used for ...
#define AV_CHANNEL_LAYOUT_7POINT1POINT2
#define AV_CHANNEL_LAYOUT_6POINT1_FRONT
#define AV_CHANNEL_LAYOUT_5POINT0
#define AV_CHANNEL_LAYOUT_7POINT1POINT4
#define AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS
The conversion must be lossless.
#define AV_CHANNEL_LAYOUT_5POINT1POINT6
void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
bprint variant of av_channel_description().
#define AV_CHANNEL_LAYOUT_CUBE
int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout)
Return the order if the layout is n-th order standard-order ambisonic.
#define AV_CHANNEL_LAYOUT_STEREO
int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
Check whether two channel layouts are semantically the same, i.e.
int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
Get a human readable string in an abbreviated form describing a given channel.
#define AV_CHANNEL_LAYOUT_6POINT0
#define AV_CHANNEL_LAYOUT_2_2
int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel_id)
Get a human readable string describing a given channel.
#define AV_CHANNEL_LAYOUT_6POINT1_BACK
#define AV_CHANNEL_LAYOUT_5POINT0_BACK
#define AV_CHANNEL_LAYOUT_5POINT1
#define AV_CHANNEL_LAYOUT_MONO
int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
Initialize a custom channel layout with the specified number of channels.
enum AVChannel av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx)
Get the channel with the given index in a channel layout.
#define AV_CHANNEL_LAYOUT_7POINT0
void av_channel_layout_uninit(AVChannelLayout *channel_layout)
Free any allocated data in the channel layout and reset the channel count to 0.
AVChannel
#define AV_CHANNEL_LAYOUT_SURROUND
#define AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK
#define AV_CHANNEL_LAYOUT_2_1
#define AV_CHANNEL_LAYOUT_OCTAGONAL
void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
bprint variant of av_channel_name().
#define AV_CHANNEL_LAYOUT_22POINT2
int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask)
Initialize a native channel layout from a bitmask indicating which channels are present.
int av_channel_layout_describe(const AVChannelLayout *channel_layout, char *buf, size_t buf_size)
Get a human-readable string describing the channel layout properties.
#define AV_CHANNEL_LAYOUT_7POINT1
int av_channel_layout_check(const AVChannelLayout *channel_layout)
Check whether a channel layout is valid, i.e.
int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
Make a copy of a channel layout.
#define AV_CHANNEL_LAYOUT_5POINT1POINT4
#define AV_CHANNEL_LAYOUT_7POINT1POINT6
#define AV_CHANNEL_LAYOUT_STEREO_DOWNMIX
uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout, uint64_t mask)
Find out what channels from a given set are present in a channel layout, without regard for their pos...
#define AV_CHANNEL_LAYOUT_9POINT1POINT6
const AVChannelLayout * av_channel_layout_standard(void **opaque)
Iterate over all standard channel layouts.
#define AV_CHANNEL_LAYOUT_QUAD
#define AV_CHANNEL_LAYOUT_6POINT0_FRONT
#define AV_CHANNEL_LAYOUT_3POINT1POINT2
#define AV_CHANNEL_LAYOUT_2POINT1
enum AVChannel av_channel_from_string(const char *str)
This is the inverse function of av_channel_name().
#define AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK
#define AV_CHANNEL_LAYOUT_6POINT1
@ AV_CHANNEL_ORDER_NATIVE
The native channel order, i.e.
@ AV_CHANNEL_ORDER_CUSTOM
The channel order does not correspond to any other predefined order and is stored as an explicit map.
@ AV_CHANNEL_ORDER_UNSPEC
Only the channel count is specified, without any further information about the channel order.
@ AV_CHANNEL_ORDER_AMBISONIC
The audio is represented as the decomposition of the sound field into spherical harmonics.
@ AV_CHAN_LOW_FREQUENCY
@ AV_CHAN_BACK_RIGHT
@ AV_CHAN_UNUSED
Channel is empty can be safely skipped.
@ AV_CHAN_TOP_SURROUND_RIGHT
-110 degrees, Rvs, TpRS
@ AV_CHAN_FRONT_RIGHT_OF_CENTER
@ AV_CHAN_FRONT_LEFT
@ AV_CHAN_SIDE_SURROUND_RIGHT
-90 degrees, Rss, SiR
@ AV_CHAN_TOP_BACK_LEFT
@ AV_CHAN_TOP_FRONT_RIGHT
@ AV_CHAN_FRONT_RIGHT
@ AV_CHAN_AMBISONIC_BASE
Range of channels between AV_CHAN_AMBISONIC_BASE and AV_CHAN_AMBISONIC_END represent Ambisonic compon...
@ AV_CHAN_BACK_CENTER
@ AV_CHAN_TOP_SIDE_RIGHT
@ AV_CHAN_FRONT_CENTER
@ AV_CHAN_TOP_SURROUND_LEFT
+110 degrees, Lvs, TpLS
@ AV_CHAN_SIDE_RIGHT
@ AV_CHAN_SIDE_SURROUND_LEFT
+90 degrees, Lss, SiL
@ AV_CHAN_WIDE_LEFT
@ AV_CHAN_FRONT_LEFT_OF_CENTER
@ AV_CHAN_NONE
Invalid channel index.
@ AV_CHAN_LOW_FREQUENCY_2
@ AV_CHAN_TOP_BACK_CENTER
@ AV_CHAN_BACK_LEFT
@ AV_CHAN_UNKNOWN
Channel contains data, but its position is unknown.
@ AV_CHAN_SIDE_LEFT
@ AV_CHAN_SURROUND_DIRECT_RIGHT
@ AV_CHAN_BOTTOM_FRONT_CENTER
@ AV_CHAN_TOP_FRONT_LEFT
@ AV_CHAN_TOP_BACK_RIGHT
@ AV_CHAN_BOTTOM_FRONT_RIGHT
@ AV_CHAN_STEREO_RIGHT
See above.
@ AV_CHAN_AMBISONIC_END
@ AV_CHAN_TOP_SIDE_LEFT
@ AV_CHAN_BINAURAL_LEFT
@ AV_CHAN_WIDE_RIGHT
@ AV_CHAN_BOTTOM_FRONT_LEFT
@ AV_CHAN_SURROUND_DIRECT_LEFT
@ AV_CHAN_TOP_CENTER
@ AV_CHAN_BINAURAL_RIGHT
@ AV_CHAN_STEREO_LEFT
Stereo downmix.
@ AV_CHAN_TOP_FRONT_CENTER
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition bprint.c:129
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition bprint.c:84
#define AVERROR(e)
Definition error.h:45
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
Definition mem.c:447
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition avstring.c:85
int av_opt_get_key_value(const char **ropts, const char *key_val_sep, const char *pairs_sep, unsigned flags, char **rkey, char **rval)
Extract a key-value pair from the beginning of a string.
Definition opt.c:1955
@ AV_OPT_FLAG_IMPLICIT_KEY
Accept to parse a value without a key; the key will then be returned as NULL.
Definition opt.h:723
int index
Definition gxfenc.c:90
const VDPAUPixFmtMap * map
Macro definitions for various function/variable attributes.
#define av_fallthrough
Definition attributes.h:67
static const uint16_t mask[17]
Definition lzw.c:38
Utility Preprocessor macros.
#define FFMIN(a, b)
Definition macros.h:49
uint64_t layout
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:370
Memory handling functions.
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
const char * name
Definition qsvenc.c:142
#define FF_ARRAY_ELEMS(a)
An AVChannelCustom defines a single channel within a custom order layout.
enum AVChannel id
An AVChannelLayout holds information about the channel layout of audio data.
enum AVChannelOrder order
Channel order used in this layout.
uint64_t mask
This member must be used for AV_CHANNEL_ORDER_NATIVE, and may be used for AV_CHANNEL_ORDER_AMBISONIC ...
union AVChannelLayout::@162063043056170047076125117143030261346263330336 u
Details about which channels are present in this layout.
int nb_channels
Number of channels in this layout.
void * opaque
For some private data of the user.
AVChannelCustom * map
This member must be used when the channel order is AV_CHANNEL_ORDER_CUSTOM.
AVChannelLayout layout
const char * description
const char * name
#define av_free(p)
#define av_malloc_array(a, b)
#define av_freep(p)
#define src
Definition vp8dsp.c:248