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 },
227 { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL },
228 { "binaural", AV_CHANNEL_LAYOUT_BINAURAL },
229 { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, },
230 { "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
231};
232
233int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
234{
236
237 if (nb_channels <= 0)
238 return AVERROR(EINVAL);
239
240 map = av_calloc(nb_channels, sizeof(*channel_layout->u.map));
241 if (!map)
242 return AVERROR(ENOMEM);
243 for (int i = 0; i < nb_channels; i++)
244 map[i].id = AV_CHAN_UNKNOWN;
245
246 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
247 channel_layout->nb_channels = nb_channels;
248 channel_layout->u.map = map;
249
250 return 0;
251}
252
254 uint64_t mask)
255{
256 if (!mask)
257 return AVERROR(EINVAL);
258
259 channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
260 channel_layout->nb_channels = av_popcount64(mask);
261 channel_layout->u.mask = mask;
262
263 return 0;
264}
265
266static int parse_channel_list(AVChannelLayout *ch_layout, const char *str)
267{
268 int ret;
269 int nb_channels = 0;
271 AVChannelCustom custom = {0};
272
273 while (*str) {
274 char *channel, *chname;
275 ret = av_opt_get_key_value(&str, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
276 if (ret < 0) {
277 av_freep(&map);
278 return ret;
279 }
280 if (*str)
281 str++; // skip separator
282 if (!channel) {
283 channel = chname;
284 chname = NULL;
285 }
286 av_strlcpy(custom.name, chname ? chname : "", sizeof(custom.name));
289 av_free(chname);
290 if (custom.id == AV_CHAN_NONE) {
291 av_freep(&map);
292 return AVERROR(EINVAL);
293 }
294
295 av_dynarray2_add((void **)&map, &nb_channels, sizeof(custom), (void *)&custom);
296 if (!map)
297 return AVERROR(ENOMEM);
298 }
299
300 if (!nb_channels)
301 return AVERROR(EINVAL);
302
303 ch_layout->order = AV_CHANNEL_ORDER_CUSTOM;
304 ch_layout->u.map = map;
305 ch_layout->nb_channels = nb_channels;
306
308 av_assert0(ret == 0);
309
310 return 0;
311}
312
314 const char *str)
315{
316 int i, matches, ret;
317 int channels = 0, nb_channels = 0;
318 char *chlist, *end;
319 uint64_t mask = 0;
320
321 /* channel layout names */
322 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
323 if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
324 *channel_layout = channel_layout_map[i].layout;
325 return 0;
326 }
327 }
328
329 /* This function is a channel layout initializer, so we have to
330 * zero-initialize before we start setting fields individually. */
331 memset(channel_layout, 0, sizeof(*channel_layout));
332
333 /* ambisonic */
334 if (!strncmp(str, "ambisonic ", 10)) {
335 const char *p = str + 10;
336 char *endptr;
337 AVChannelLayout extra = {0};
338 int order;
339
340 order = strtol(p, &endptr, 0);
341 if (order < 0 || order + 1 > INT_MAX / (order + 1) ||
342 (*endptr && *endptr != '+'))
343 return AVERROR(EINVAL);
344
345 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
346 channel_layout->nb_channels = (order + 1) * (order + 1);
347
348 if (*endptr) {
349 ret = av_channel_layout_from_string(&extra, endptr + 1);
350 if (ret < 0)
351 return ret;
352 if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) {
354 return AVERROR(EINVAL);
355 }
356
357 if (extra.order == AV_CHANNEL_ORDER_NATIVE) {
358 channel_layout->u.mask = extra.u.mask;
359 } else {
360 channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
361 channel_layout->u.map =
362 av_calloc(channel_layout->nb_channels + extra.nb_channels,
363 sizeof(*channel_layout->u.map));
364 if (!channel_layout->u.map) {
366 return AVERROR(ENOMEM);
367 }
368
369 for (i = 0; i < channel_layout->nb_channels; i++)
370 channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i;
371 for (i = 0; i < extra.nb_channels; i++) {
373 if (CHAN_IS_AMBI(ch)) {
374 av_channel_layout_uninit(channel_layout);
376 return AVERROR(EINVAL);
377 }
378 channel_layout->u.map[channel_layout->nb_channels + i].id = ch;
379 if (extra.order == AV_CHANNEL_ORDER_CUSTOM &&
380 extra.u.map[i].name[0])
381 av_strlcpy(channel_layout->u.map[channel_layout->nb_channels + i].name,
382 extra.u.map[i].name,
383 sizeof(channel_layout->u.map[channel_layout->nb_channels + i].name));
384 }
385 }
386 channel_layout->nb_channels += extra.nb_channels;
388 }
389
390 return 0;
391 }
392
393 chlist = av_strdup(str);
394 if (!chlist)
395 return AVERROR(ENOMEM);
396
397 /* channel names */
398 matches = av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
399 ret = parse_channel_list(channel_layout, chlist);
400 av_freep(&chlist);
401 if (ret < 0 && ret != AVERROR(EINVAL))
402 return ret;
403
404 if (ret >= 0) {
405 const char *end_par = strchr(str, ')');
406 if (matches == 2 && (nb_channels != channel_layout->nb_channels || !end_par || *++end_par)) {
407 av_channel_layout_uninit(channel_layout);
408 return AVERROR(EINVAL);
409 }
410 return 0;
411 }
412
413 errno = 0;
414 mask = strtoull(str, &end, 0);
415
416 /* channel layout mask */
417 if (!errno && !*end && !strchr(str, '-') && mask) {
418 av_channel_layout_from_mask(channel_layout, mask);
419 return 0;
420 }
421
422 errno = 0;
423 channels = strtol(str, &end, 10);
424
425 /* number of channels */
426 if (!errno && !strcmp(end, "c") && channels > 0) {
427 av_channel_layout_default(channel_layout, channels);
428 if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
429 return 0;
430 }
431
432 /* number of unordered channels */
433 if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels"))
434 && channels > 0) {
435 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
436 channel_layout->nb_channels = channels;
437 return 0;
438 }
439
440 return AVERROR(EINVAL);
441}
442
444{
445 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
446 av_freep(&channel_layout->u.map);
447 memset(channel_layout, 0, sizeof(*channel_layout));
448}
449
451{
453 *dst = *src;
454 if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
455 dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
456 if (!dst->u.map)
457 return AVERROR(ENOMEM);
458 memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
459 }
460 return 0;
461}
462
463static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel)
464{
465 uint64_t mask = 0;
466 for (int i = start_channel; i < channel_layout->nb_channels; i++) {
467 enum AVChannel ch = channel_layout->u.map[i].id;
468 if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
469 mask |= (1ULL << ch);
470 else
471 return AVERROR(EINVAL);
472 }
473 return mask;
474}
475
476static int has_channel_names(const AVChannelLayout *channel_layout)
477{
478 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
479 return 0;
480 for (int i = 0; i < channel_layout->nb_channels; i++)
481 if (channel_layout->u.map[i].name[0])
482 return 1;
483 return 0;
484}
485
487{
488 int i, highest_ambi, order;
489
490 if (channel_layout->order != AV_CHANNEL_ORDER_AMBISONIC &&
491 channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
492 return AVERROR(EINVAL);
493
494 highest_ambi = -1;
495 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC)
496 highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1;
497 else {
498 const AVChannelCustom *map = channel_layout->u.map;
499 av_assert0(channel_layout->order == AV_CHANNEL_ORDER_CUSTOM);
500
501 for (i = 0; i < channel_layout->nb_channels; i++) {
502 int is_ambi = CHAN_IS_AMBI(map[i].id);
503
504 /* ambisonic following non-ambisonic */
505 if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id))
506 return AVERROR(EINVAL);
507
508 /* non-default ordering */
509 if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i)
510 return AVERROR(EINVAL);
511
512 if (CHAN_IS_AMBI(map[i].id))
513 highest_ambi = i;
514 }
515 }
516 /* no ambisonic channels*/
517 if (highest_ambi < 0)
518 return AVERROR(EINVAL);
519
520 order = floor(sqrt(highest_ambi));
521 /* incomplete order - some harmonics are missing */
522 if ((order + 1) * (order + 1) != highest_ambi + 1)
523 return AVERROR(EINVAL);
524
525 return order;
526}
527
529{
530 int has_known_channel = 0;
531 int order;
532
533 if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
534 return channel_layout->order;
535
536 if (has_channel_names(channel_layout))
538
539 for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++)
540 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN)
541 has_known_channel = 1;
542 if (!has_known_channel)
544
545 if (masked_description(channel_layout, 0) > 0)
547
548 order = av_channel_layout_ambisonic_order(channel_layout);
549 if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0)
551
553}
554
555/**
556 * If the custom layout is n-th order standard-order ambisonic, with optional
557 * extra non-diegetic channels at the end, write its string description in bp.
558 * Return a negative error code otherwise.
559 */
560static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
561{
562 int nb_ambi_channels;
563 int order = av_channel_layout_ambisonic_order(channel_layout);
564 if (order < 0)
565 return order;
566
567 av_bprintf(bp, "ambisonic %d", order);
568
569 /* extra channels present */
570 nb_ambi_channels = (order + 1) * (order + 1);
571 if (nb_ambi_channels < channel_layout->nb_channels) {
572 AVChannelLayout extra = { 0 };
573
574 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) {
576 extra.nb_channels = av_popcount64(channel_layout->u.mask);
577 extra.u.mask = channel_layout->u.mask;
578 } else {
580 if (!has_channel_names(channel_layout) &&
581 (mask = masked_description(channel_layout, nb_ambi_channels)) > 0) {
584 extra.u.mask = mask;
585 } else {
587 extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels;
588 extra.u.map = channel_layout->u.map + nb_ambi_channels;
589 }
590 }
591
592 av_bprint_chars(bp, '+', 1);
594 /* Not calling uninit here on extra because we don't own the u.map pointer */
595 }
596
597 return 0;
598}
599
601 AVBPrint *bp)
602{
603 int i;
604
605 switch (channel_layout->order) {
607 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
608 if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
610 return 0;
611 }
614 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
616 int res = try_describe_ambisonic(bp, channel_layout);
617 if (res >= 0)
618 return 0;
619 if (!has_channel_names(channel_layout) &&
620 (mask = masked_description(channel_layout, 0)) > 0) {
621 AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE,
622 .nb_channels = av_popcount64(mask),
623 .u.mask = mask };
624 return av_channel_layout_describe_bprint(&native, bp);
625 }
626 }
627 if (channel_layout->nb_channels)
628 av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
629 for (i = 0; i < channel_layout->nb_channels; i++) {
630 enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
631
632 if (i)
633 av_bprintf(bp, "+");
635 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
636 channel_layout->u.map[i].name[0])
637 av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
638 }
639 if (channel_layout->nb_channels) {
640 av_bprintf(bp, ")");
641 return 0;
642 }
645 av_bprintf(bp, "%d channels", channel_layout->nb_channels);
646 return 0;
648 return try_describe_ambisonic(bp, channel_layout);
649 default:
650 return AVERROR(EINVAL);
651 }
652}
653
655 char *buf, size_t buf_size)
656{
657 AVBPrint bp;
658 int ret;
659
660 if (!buf && buf_size)
661 return AVERROR(EINVAL);
662
663 av_bprint_init_for_buffer(&bp, buf, buf_size);
664 ret = av_channel_layout_describe_bprint(channel_layout, &bp);
665 if (ret < 0)
666 return ret;
667
668 if (bp.len >= INT_MAX)
669 return AVERROR(ERANGE);
670 return bp.len + 1;
671}
672
673enum AVChannel
675 unsigned int idx)
676{
677 int i;
678
679 if (idx >= channel_layout->nb_channels)
680 return AV_CHAN_NONE;
681
682 switch (channel_layout->order) {
684 return channel_layout->u.map[idx].id;
686 int ambi_channels = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask);
687 if (idx < ambi_channels)
688 return AV_CHAN_AMBISONIC_BASE + idx;
689 idx -= ambi_channels;
690 }
693 for (i = 0; i < 64; i++) {
694 if ((1ULL << i) & channel_layout->u.mask && !idx--)
695 return i;
696 }
698 default:
699 return AV_CHAN_NONE;
700 }
701}
702
703enum AVChannel
705 const char *str)
706{
707 int index = av_channel_layout_index_from_string(channel_layout, str);
708
709 if (index < 0)
710 return AV_CHAN_NONE;
711
712 return av_channel_layout_channel_from_index(channel_layout, index);
713}
714
716 enum AVChannel channel)
717{
718 int i;
719
720 if (channel == AV_CHAN_NONE)
721 return AVERROR(EINVAL);
722
723 switch (channel_layout->order) {
725 for (i = 0; i < channel_layout->nb_channels; i++)
726 if (channel_layout->u.map[i].id == channel)
727 return i;
728 return AVERROR(EINVAL);
731 uint64_t mask = channel_layout->u.mask;
732 int ambi_channels = channel_layout->nb_channels - av_popcount64(mask);
733 if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC &&
735 if (channel - AV_CHAN_AMBISONIC_BASE >= ambi_channels)
736 return AVERROR(EINVAL);
738 }
739 if ((unsigned)channel > 63 || !(mask & (1ULL << channel)))
740 return AVERROR(EINVAL);
741 mask &= (1ULL << channel) - 1;
742 return av_popcount64(mask) + ambi_channels;
743 }
744 default:
745 return AVERROR(EINVAL);
746 }
747}
748
750 const char *str)
751{
752 const char *chname;
753 enum AVChannel ch = AV_CHAN_NONE;
754
755 switch (channel_layout->order) {
757 chname = strstr(str, "@");
758 if (chname) {
759 char buf[16];
760 chname++;
761 av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str));
762 if (!*chname)
763 chname = NULL;
764 ch = av_channel_from_string(buf);
765 if (ch == AV_CHAN_NONE && *buf)
766 return AVERROR(EINVAL);
767 }
768 for (int i = 0; chname && i < channel_layout->nb_channels; i++) {
769 if (!strcmp(chname, channel_layout->u.map[i].name) &&
770 (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id))
771 return i;
772 }
776 ch = av_channel_from_string(str);
777 if (ch == AV_CHAN_NONE)
778 return AVERROR(EINVAL);
779 return av_channel_layout_index_from_channel(channel_layout, ch);
780 }
781
782 return AVERROR(EINVAL);
783}
784
785int av_channel_layout_check(const AVChannelLayout *channel_layout)
786{
787 if (channel_layout->nb_channels <= 0)
788 return 0;
789
790 switch (channel_layout->order) {
792 return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
794 if (!channel_layout->u.map)
795 return 0;
796 for (int i = 0; i < channel_layout->nb_channels; i++) {
797 if (channel_layout->u.map[i].id == AV_CHAN_NONE)
798 return 0;
799 }
800 return 1;
802 /* If non-diegetic channels are present, ensure they are taken into account */
803 return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels;
805 return 1;
806 default:
807 return 0;
808 }
809}
810
812{
813 int i;
814
815 /* different channel counts -> not equal */
816 if (chl->nb_channels != chl1->nb_channels)
817 return 1;
818
819 /* if only one is unspecified -> not equal */
820 if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
822 return 1;
823 /* both are unspecified -> equal */
824 else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
825 return 0;
826
827 /* can compare masks directly */
828 if ((chl->order == AV_CHANNEL_ORDER_NATIVE ||
830 chl->order == chl1->order)
831 return chl->u.mask != chl1->u.mask;
832
833 /* compare channel by channel */
834 for (i = 0; i < chl->nb_channels; i++)
837 return 1;
838 return 0;
839}
840
841void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
842{
843 int i;
844 for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
845 if (nb_channels == channel_layout_map[i].layout.nb_channels) {
846 *ch_layout = channel_layout_map[i].layout;
847 return;
848 }
849
850 ch_layout->order = AV_CHANNEL_ORDER_UNSPEC;
851 ch_layout->nb_channels = nb_channels;
852}
853
855{
856 uintptr_t i = (uintptr_t)*opaque;
857 const AVChannelLayout *ch_layout = NULL;
858
860 ch_layout = &channel_layout_map[i].layout;
861 *opaque = (void*)(i + 1);
862 }
863
864 return ch_layout;
865}
866
867uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
868 uint64_t mask)
869{
870 uint64_t ret = 0;
871 int i;
872
873 switch (channel_layout->order) {
876 return channel_layout->u.mask & mask;
878 for (i = 0; i < 64; i++)
879 if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0)
880 ret |= (1ULL << i);
881 break;
882 }
883
884 return ret;
885}
886
888{
889 int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
890 int lossy;
891
892 if (!av_channel_layout_check(channel_layout))
893 return AVERROR(EINVAL);
894
896 order = canonical_order(channel_layout);
897
898 if (channel_layout->order == order)
899 return 0;
900
901 switch (order) {
903 int nb_channels = channel_layout->nb_channels;
904 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
905 lossy = 0;
906 for (int i = 0; i < nb_channels; i++) {
907 if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
908 lossy = 1;
909 break;
910 }
911 }
912 } else {
913 lossy = 1;
914 }
915 if (!lossy || allow_lossy) {
916 void *opaque = channel_layout->opaque;
917 av_channel_layout_uninit(channel_layout);
918 channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
919 channel_layout->nb_channels = nb_channels;
920 channel_layout->opaque = opaque;
921 return lossy;
922 }
923 return AVERROR(ENOSYS);
924 }
926 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
927 int64_t mask = masked_description(channel_layout, 0);
928 if (mask < 0)
929 return AVERROR(ENOSYS);
930 lossy = has_channel_names(channel_layout);
931 if (!lossy || allow_lossy) {
932 void *opaque = channel_layout->opaque;
933 av_channel_layout_uninit(channel_layout);
934 av_channel_layout_from_mask(channel_layout, mask);
935 channel_layout->opaque = opaque;
936 return lossy;
937 }
938 }
939 return AVERROR(ENOSYS);
941 AVChannelLayout custom = { 0 };
942 int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
943 void *opaque = channel_layout->opaque;
944 if (ret < 0)
945 return ret;
946 if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
947 for (int i = 0; i < channel_layout->nb_channels; i++)
948 custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
949 av_channel_layout_uninit(channel_layout);
950 *channel_layout = custom;
951 channel_layout->opaque = opaque;
952 return 0;
953 }
955 if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
957 int nb_channels = channel_layout->nb_channels;
958 int amb_order = av_channel_layout_ambisonic_order(channel_layout);
959 if (amb_order < 0)
960 return AVERROR(ENOSYS);
961 mask = masked_description(channel_layout, (amb_order + 1) * (amb_order + 1));
962 if (mask < 0)
963 return AVERROR(ENOSYS);
964 lossy = has_channel_names(channel_layout);
965 if (!lossy || allow_lossy) {
966 void *opaque = channel_layout->opaque;
967 av_channel_layout_uninit(channel_layout);
968 channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
969 channel_layout->nb_channels = nb_channels;
970 channel_layout->u.mask = mask;
971 channel_layout->opaque = opaque;
972 return lossy;
973 }
974 }
975 return AVERROR(ENOSYS);
976 default:
977 return AVERROR(EINVAL);
978 }
979}
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:962
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
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
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
#define AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK
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_RETYPE_FLAG_LOSSLESS
The conversion must be lossless.
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.
#define AV_CHANNEL_LAYOUT_5POINT1POINT4_BACK
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_7POINT1POINT4_BACK
#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:130
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition bprint.c:85
#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:341
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:1951
@ 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:264
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