From patchwork Thu Jan 13 02:09:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 33539 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:cd86:0:0:0:0:0 with SMTP id d128csp47458iog; Wed, 12 Jan 2022 18:53:39 -0800 (PST) X-Google-Smtp-Source: ABdhPJwFvkhrVfibxh0ZK42Dd6cg+Db+zVMnsaNpUuM5+NKJdSOq01vrj5tWpzWJr3xB9pqg4sCo X-Received: by 2002:a17:906:9f06:: with SMTP id fy6mr2103944ejc.38.1642042419176; Wed, 12 Jan 2022 18:53:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1642042419; cv=none; d=google.com; s=arc-20160816; b=CgI9HJ26yLn4jgVvyq/9HldDt9mmNyi/KqwevH5cvOO6om51pk/K4rxLTQWLjl0zLi ext/QCj63ZK8DIpkkqVlA7jv0/sw8Er6JDvtw/tqWcWv3iGwEzwpU/hOPs8s7x6hcJT5 navVzcb+JFJ8gnKOQ5h1jBdZhH5H5HnOwxgb1hCLOCo5XmX86MaTEnMLDdI0MIKsaXpD ol2WuCPjLAVAyv2K58DNO2WsmJ7sz4laGUgJiPKM3YhIXN9StvgrRgRnmyOIBtwv2wS1 88tFBpX+lk99fLo0sxb+SfNJKVxjiHviIHDIZrGYcV+yQFEcLHxXIg/9tWPp29eyL2je ogJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:dkim-signature:delivered-to; bh=ord/U3ZbKt837qj8fDXNA3ND8qGTSkstJjrnVTfHDi4=; b=ZUYA0QKI0MMdvzAKwqGFae49QUmSsY+tkp7AuILibxctk0sxV+1hyrcPx7qOClJ5C+ Ql53xlEcH9gpI3vnvrD+WkxPKvobbzIS1Zkge0k3MWfI7SHUDXdf34OwBu6a7Yk+WjY2 3icZjtFkkdhbyyyL2YbytFXP41ibGTuBIPQMg0ZcTlPp1tmv3l5oI7RjV+HawqUobDf+ C8/DFvhAFzm2AezttdN8ZGmkYZHxnVDEkdB1JZAiTo/CjC7pD87s/WE/rlZTGdGin1uN Cs/X88ikFok0k5LsKI2p2nWGX2d/DoEhdqj0wE/DO5vffu0sCRVHWBaRqLBxsMxVu/hn CRew== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="f5sL/Lkj"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id l11si811917ejo.781.2022.01.12.18.53.38; Wed, 12 Jan 2022 18:53:39 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="f5sL/Lkj"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 176D568BABF; Thu, 13 Jan 2022 04:09:45 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qv1-f41.google.com (mail-qv1-f41.google.com [209.85.219.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1213768BA9D for ; Thu, 13 Jan 2022 04:09:41 +0200 (EET) Received: by mail-qv1-f41.google.com with SMTP id q4so5118857qvh.9 for ; Wed, 12 Jan 2022 18:09:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=pIBA3Ij9WLJk57ezskvmsK9fP1jppFTM7c4FU6ARa/4=; b=f5sL/LkjkRkde0zA8dmFH13DF0pReaQeo1k2uAcGtBpuB6ijcLthfzs845u8xXAKy7 ZI9vkaOB6dcRW9TBDY/Ab6JhYFQUejBjbvA1qaCM/OoWns3/oEHKlKTtw9wTXZ5XoCAe N5Wm+tBqur0clNbFu+z6JMtNDAFcHo8P7tRjTACdN8g1CEjTiYTKRqII6bwFtRo3ZMHZ 5LA4tmybwsFvKs4D8I6+O7UaxYfJKUVDXugbEySryic6HhJ8azD8pbn/0/lJhAbzK+fZ qf1PRkWayOqk30M29476zNSZBn4c54Om2RW2Eg61VZTYjnlgkdrrRNpUUiypYzumTV3s vR1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=pIBA3Ij9WLJk57ezskvmsK9fP1jppFTM7c4FU6ARa/4=; b=ELQv86gujS1PP/09PGn3dfvhKect5osGfB0a6+0WGsCOnE9HWan6IyfQgrQ8/dSEKN bIgXsiowHzQuVljUU4lNQyFgOn46Dt4JFc1ay8UwTJajNXKNRUi7zAPue5Cs01jGgXO5 6zw8fBV2sCHgnzE6GGe8VWgAGT7f+uT3kUQpGCOuynHArrY0YRv/pVCXIV5UJqsmAw0k NPcjhEQTTIC8t44Qsbcg3GTY3zucpHLrqQknRw5YdyQJrC36DDPQrfUhNyLjdzhaAY6y ixfWlT92yPmuRz7UpSLG/xPXCJov1Xbpw1DX5rELR+P2doZ0pl4HXGa+vgHRdus2SKIF xN/g== X-Gm-Message-State: AOAM530vgpOrsWSCAbKRl3sZJCU28QXgP+cFzl4vBckIS/YYKElyThCO QjENQKZVLYLXLGtlgl/GaOYlo/H7EXo= X-Received: by 2002:a05:6214:767:: with SMTP id f7mr2421834qvz.129.1642039780438; Wed, 12 Jan 2022 18:09:40 -0800 (PST) Received: from localhost.localdomain ([186.136.131.95]) by smtp.gmail.com with ESMTPSA id u6sm1068031qko.83.2022.01.12.18.09.39 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 12 Jan 2022 18:09:40 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Wed, 12 Jan 2022 23:09:11 -0300 Message-Id: <20220113020913.870-10-jamrial@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220113015101.4-1-jamrial@gmail.com> References: <20220113015101.4-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 279/281] channel_layout: add support for Ambisonic X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: tZaVU7PmTmb2 From: Vittorio Giovara Signed-off-by: James Almer --- libavutil/channel_layout.c | 166 ++++++++++++++++++++++++++++++- libavutil/channel_layout.h | 52 +++++++++- libavutil/tests/channel_layout.c | 20 ++++ tests/ref/fate/channel_layout | 13 +++ 4 files changed, 247 insertions(+), 4 deletions(-) diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c index 68b40cc37c..3863e50e91 100644 --- a/libavutil/channel_layout.c +++ b/libavutil/channel_layout.c @@ -31,6 +31,9 @@ #include "bprint.h" #include "common.h" +#define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\ + (x) <= AV_CHAN_AMBISONIC_END) + struct channel_name { const char *name; const char *description; @@ -81,7 +84,10 @@ void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id) { av_bprint_clear(bp); - if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names)) + if (channel_id >= AV_CHAN_AMBISONIC_BASE && + channel_id <= AV_CHAN_AMBISONIC_END) + av_bprintf(bp, "AMBI%d", channel_id - AV_CHAN_AMBISONIC_BASE); + else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names)) av_bprintf(bp, "%s", channel_names[channel_id].name); else av_bprintf(bp, "USR%d", channel_id); @@ -104,7 +110,10 @@ void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id) { av_bprint_clear(bp); - if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names)) + if (channel_id >= AV_CHAN_AMBISONIC_BASE && + channel_id <= AV_CHAN_AMBISONIC_END) + av_bprintf(bp, "ambisonic ACN %d", channel_id - AV_CHAN_AMBISONIC_BASE); + else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names)) av_bprintf(bp, "%s", channel_names[channel_id].description); else av_bprintf(bp, "user %d", channel_id); @@ -128,6 +137,14 @@ enum AVChannel av_channel_from_string(const char *str) int i; char *endptr = (char *)str; enum AVChannel id = AV_CHAN_NONE; + + if (!strncmp(str, "AMBI", 4)) { + i = strtol(str + 4, NULL, 0); + if (i < 0 || i > AV_CHAN_AMBISONIC_END - AV_CHAN_AMBISONIC_BASE) + return AV_CHAN_NONE; + return AV_CHAN_AMBISONIC_BASE + i; + } + for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) { if (channel_names[i].name && !strcmp(str, channel_names[i].name)) return i; @@ -395,6 +412,60 @@ int av_channel_layout_from_string(AVChannelLayout *channel_layout, } } + /* ambisonic */ + if (!strncmp(str, "ambisonic ", 10)) { + const char *p = str + 10; + char *endptr; + AVChannelLayout extra = {0}; + int order; + + order = strtol(p, &endptr, 0); + if (order < 0 || order + 1 > INT_MAX / (order + 1) || + (*endptr && *endptr != '+')) + return AVERROR(EINVAL); + + channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC; + channel_layout->nb_channels = (order + 1) * (order + 1); + + if (*endptr) { + int ret = av_channel_layout_from_string(&extra, endptr + 1); + if (ret < 0) + return ret; + if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) { + av_channel_layout_uninit(&extra); + return AVERROR(EINVAL); + } + + if (extra.order == AV_CHANNEL_ORDER_NATIVE) { + channel_layout->u.mask = extra.u.mask; + } else { + channel_layout->order = AV_CHANNEL_ORDER_CUSTOM; + channel_layout->u.map = + av_calloc(channel_layout->nb_channels + extra.nb_channels, + sizeof(*channel_layout->u.map)); + if (!channel_layout->u.map) { + av_channel_layout_uninit(&extra); + return AVERROR(ENOMEM); + } + + for (i = 0; i < channel_layout->nb_channels; i++) + channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i; + for (i = 0; i < extra.nb_channels; i++) { + enum AVChannel ch = av_channel_layout_channel_from_index(&extra, i); + if (CHAN_IS_AMBI(ch)) { + av_channel_layout_uninit(&extra); + return AVERROR(EINVAL); + } + channel_layout->u.map[channel_layout->nb_channels + i].id = ch; + } + } + channel_layout->nb_channels += extra.nb_channels; + av_channel_layout_uninit(&extra); + } + + return 0; + } + /* channel names */ while (*dup) { char *chname = av_get_token(&dup, "+"); @@ -526,6 +597,77 @@ int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src) return 0; } +/** + * If the custom layout is n-th order standard-order ambisonic, with optional + * extra non-diegetic channels at the end, write its string description in bp. + * Return a negative error code on error. + */ +static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout) +{ + int i, highest_ambi, order; + + highest_ambi = -1; + if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) + highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1; + else { + const AVChannelCustom *map = channel_layout->u.map; + for (i = 0; i < channel_layout->nb_channels; i++) { + int is_ambi = CHAN_IS_AMBI(map[i].id); + + /* ambisonic following non-ambisonic */ + if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id)) + return 0; + + /* non-default ordering */ + if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i) + return 0; + + if (CHAN_IS_AMBI(map[i].id)) + highest_ambi = i; + } + } + /* no ambisonic channels*/ + if (highest_ambi < 0) + return 0; + + order = floor(sqrt(highest_ambi)); + /* incomplete order - some harmonics are missing */ + if ((order + 1) * (order + 1) != highest_ambi + 1) + return 0; + + av_bprintf(bp, "ambisonic %d", order); + + /* extra channels present */ + if (highest_ambi < channel_layout->nb_channels - 1) { + AVChannelLayout extra = { 0 }; + char buf[128]; + + if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) { + extra.order = AV_CHANNEL_ORDER_NATIVE; + extra.nb_channels = av_popcount64(channel_layout->u.mask); + extra.u.mask = channel_layout->u.mask; + } else { + const AVChannelCustom *map = channel_layout->u.map; + + extra.order = AV_CHANNEL_ORDER_CUSTOM; + extra.nb_channels = channel_layout->nb_channels - highest_ambi - 1; + extra.u.map = av_calloc(extra.nb_channels, sizeof(*extra.u.map)); + if (!extra.u.map) + return AVERROR(ENOMEM); + + memcpy(extra.u.map, &map[highest_ambi + 1], + sizeof(*extra.u.map) * extra.nb_channels); + } + + av_channel_layout_describe(&extra, buf, sizeof(buf)); + av_channel_layout_uninit(&extra); + + av_bprintf(bp, "+%s", buf); + } + + return 0; +} + int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout, AVBPrint *bp) { @@ -542,6 +684,11 @@ int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout, } // fall-through case AV_CHANNEL_ORDER_CUSTOM: + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + int res = try_describe_ambisonic(bp, channel_layout); + if (res < 0 || bp->len) + return res; + } for (i = 0; i < channel_layout->nb_channels; i++) { const char *ch_name = NULL; enum AVChannel ch = AV_CHAN_NONE; @@ -567,6 +714,8 @@ int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout, case AV_CHANNEL_ORDER_UNSPEC: av_bprintf(bp, "%d channels", channel_layout->nb_channels); return 0; + case AV_CHANNEL_ORDER_AMBISONIC: + return try_describe_ambisonic(bp, channel_layout); default: return AVERROR(EINVAL); } @@ -601,6 +750,8 @@ av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, switch (channel_layout->order) { case AV_CHANNEL_ORDER_CUSTOM: return channel_layout->u.map[idx].id; + case AV_CHANNEL_ORDER_AMBISONIC: + return AV_CHAN_AMBISONIC_BASE + idx; case AV_CHANNEL_ORDER_NATIVE: for (i = 0; i < 64; i++) { if ((1ULL << i) & channel_layout->u.mask && !idx--) @@ -651,6 +802,11 @@ int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, if (channel_layout->u.map[i].id == channel) return i; return AVERROR(EINVAL); + case AV_CHANNEL_ORDER_AMBISONIC: + if (!CHAN_IS_AMBI(channel) || + channel - AV_CHAN_AMBISONIC_BASE >= channel_layout->nb_channels) + return AVERROR(EINVAL); + return channel - AV_CHAN_AMBISONIC_BASE; case AV_CHANNEL_ORDER_NATIVE: { uint64_t mask = channel_layout->u.mask; if (!(mask & (1ULL << channel))) @@ -701,6 +857,9 @@ int av_channel_layout_check(const AVChannelLayout *channel_layout) return 0; } return 1; + case AV_CHANNEL_ORDER_AMBISONIC: + /* If non-diegetic channels are present, ensure they are taken into account */ + return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels; case AV_CHANNEL_ORDER_UNSPEC: return 1; default: @@ -725,7 +884,8 @@ int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout return 0; /* can compare masks directly */ - if (chl->order != AV_CHANNEL_ORDER_CUSTOM && + if ((chl->order == AV_CHANNEL_ORDER_NATIVE || + chl->order == AV_CHANNEL_ORDER_AMBISONIC) && chl->order == chl1->order) return chl->u.mask != chl1->u.mask; diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h index 6356a9a38a..b7e709a022 100644 --- a/libavutil/channel_layout.h +++ b/libavutil/channel_layout.h @@ -79,6 +79,23 @@ enum AVChannel { /** Channel contains data, but its position is unknown. */ AV_CHAN_UNKWNOWN = 128, + + /** + * Range of channels between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END represent Ambisonic components using the ACN system. + * + * Given a channel id between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END (inclusive), the ACN index of the channel is + * = - AV_CHAN_AMBISONIC_BASE. + * + * @note these values are only used for AV_CHANNEL_ORDER_CUSTOM channel + * orderings, the AV_CHANNEL_ORDER_AMBISONIC ordering orders the channels + * implicitly by their position in the stream. + */ + AV_CHAN_AMBISONIC_BASE = 0x400, + // leave space for 1024 ids, which correspond to maximum order-32 harmonics, + // which should be enough for the foreseeable use cases + AV_CHAN_AMBISONIC_END = 0x7ff, }; enum AVChannelOrder { @@ -100,6 +117,29 @@ enum AVChannelOrder { * channels at arbitrary positions. */ AV_CHANNEL_ORDER_CUSTOM, + /** + * The audio is represented as the decomposition of the sound field into + * spherical harmonics. Each channel corresponds to a single expansion + * component. Channels are ordered according to ACN (Ambisonic Channel + * Number). + * + * The channel with the index n in the stream contains the spherical + * harmonic of degree l and order m given by + * @code{.unparsed} + * l = floor(sqrt(n)), + * m = n - l * (l + 1). + * @endcode + * + * Conversely given a spherical harmonic of degree l and order m, the + * corresponding channel index n is given by + * @code{.unparsed} + * n = l * (l + 1) + m. + * @endcode + * + * Normalization is assumed to be SN3D (Schmidt Semi-Normalization) + * as defined in AmbiX format $ 2.1. + */ + AV_CHANNEL_ORDER_AMBISONIC, }; @@ -266,7 +306,8 @@ typedef struct AVChannelLayout { */ union { /** - * This member must be used for AV_CHANNEL_ORDER_NATIVE. + * This member must be used for AV_CHANNEL_ORDER_NATIVE, and may be used + * for AV_CHANNEL_ORDER_AMBISONIC to signal non-diegetic channels. * It is a bitmask, where the position of each set bit means that the * AVChannel with the corresponding value is present. * @@ -288,6 +329,11 @@ typedef struct AVChannelLayout { * I.e. when map[i].id is equal to AV_CHAN_FOO, then AV_CH_FOO is the * i-th channel in the audio data. * + * When map[i].id is in the range between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END (inclusive), the channel contains an ambisonic + * component with ACN index (as defined above) + * n = map[i].id - AV_CHAN_AMBISONIC_BASE. + * * map[i].name may be filled with a 0-terminated string, in which case * it will be used for the purpose of identifying the channel with the * convenience functions below. Otherise it must be zeroed. @@ -359,6 +405,8 @@ typedef struct AVChannelLayout { { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2, .u = { .mask = AV_CH_LAYOUT_STEREO_DOWNMIX }} #define AV_CHANNEL_LAYOUT_22POINT2 \ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 24, .u = { .mask = AV_CH_LAYOUT_22POINT2 }} +#define AV_CHANNEL_LAYOUT_AMBISONIC_FIRST_ORDER \ + { .order = AV_CHANNEL_ORDER_AMBISONIC, .nb_channels = 4, .u = { .mask = 0 }} struct AVBPrint; @@ -554,6 +602,8 @@ int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask); * - a hexadecimal value of a channel layout (eg. "0x4") * - the number of channels with default layout (eg. "5c") * - the number of unordered channels (eg. "4", "4C", or "4 channels") + * - the ambisonic order followed by optional non-diegetic channels (eg. + * "ambisonic 2+stereo") * * @param channel_layout input channel layout * @param str string describing the channel layout diff --git a/libavutil/tests/channel_layout.c b/libavutil/tests/channel_layout.c index 7e6be0be17..b3318aed27 100644 --- a/libavutil/tests/channel_layout.c +++ b/libavutil/tests/channel_layout.c @@ -66,6 +66,10 @@ int main(void) printf("With AV_CHAN_FRONT_RIGHT: %26s\n", bp.str); av_channel_name_bprint(&bp, 63); printf("With 63: %43s\n", bp.str); + av_channel_name_bprint(&bp, AV_CHAN_AMBISONIC_BASE); + printf("With AV_CHAN_AMBISONIC_BASE: %23s\n", bp.str); + av_channel_name_bprint(&bp, AV_CHAN_AMBISONIC_END); + printf("With AV_CHAN_AMBISONIC_END: %24s\n", bp.str); printf("Testing av_channel_description\n"); av_channel_description_bprint(&bp, AV_CHAN_FRONT_LEFT); @@ -74,11 +78,17 @@ int main(void) printf("With AV_CHAN_FRONT_RIGHT: %26s\n", bp.str); av_channel_description_bprint(&bp, 63); printf("With 63: %43s\n", bp.str); + av_channel_description_bprint(&bp, AV_CHAN_AMBISONIC_BASE); + printf("With AV_CHAN_AMBISONIC_BASE: %23s\n", bp.str); + av_channel_description_bprint(&bp, AV_CHAN_AMBISONIC_END); + printf("With AV_CHAN_AMBISONIC_END: %24s\n", bp.str); printf("\nTesting av_channel_from_string\n"); printf("With \"FL\": %41d\n", av_channel_from_string("FL")); printf("With \"FR\": %41d\n", av_channel_from_string("FR")); printf("With \"USR63\": %38d\n", av_channel_from_string("USR63")); + printf("With \"AMBI0\": %38d\n", av_channel_from_string("AMBI0")); + printf("With \"AMBI1023\": %35d\n", av_channel_from_string("AMBI1023")); printf("\n==Native layouts==\n"); @@ -177,6 +187,8 @@ int main(void) printf("\nTesting av_channel_layout_from_string\n"); CHANNEL_LAYOUT_FROM_STRING(custom, "FL+FR+FC+BL+BR+LFE"); printf("With \"FL+FR+FC+BL+BR+LFE\": %25s\n", bp.str); + CHANNEL_LAYOUT_FROM_STRING(custom, "ambisonic 1+FR+FL"); + printf("With \"ambisonic 1+FR+FL\": %26s\n", bp.str); CHANNEL_LAYOUT_FROM_STRING(custom, "FR+FL+USR63"); printf("With \"FR+FL+USR63\" layout: %25s\n", bp.str); @@ -225,6 +237,14 @@ int main(void) CHANNEL_LAYOUT_CHANNEL_FROM_INDEX(custom, 3); printf("On \"FR+FL+USR63\" layout with 3: %20d\n", ret); + printf("\n==Ambisonic layouts==\n"); + + printf("\nTesting av_channel_layout_from_string\n"); + CHANNEL_LAYOUT_FROM_STRING(custom, "ambisonic 1"); + printf("With \"ambisonic 1\": %32s\n", bp.str); + CHANNEL_LAYOUT_FROM_STRING(custom, "ambisonic 2+stereo"); + printf("With \"ambisonic 2+stereo\": %25s\n", bp.str); + av_channel_layout_uninit(&surround); av_channel_layout_uninit(&custom); av_bprint_finalize(&bp, NULL); diff --git a/tests/ref/fate/channel_layout b/tests/ref/fate/channel_layout index bac00086d6..4614934028 100644 --- a/tests/ref/fate/channel_layout +++ b/tests/ref/fate/channel_layout @@ -2,15 +2,21 @@ Testing av_channel_name With AV_CHAN_FRONT_LEFT: FL With AV_CHAN_FRONT_RIGHT: FR With 63: USR63 +With AV_CHAN_AMBISONIC_BASE: AMBI0 +With AV_CHAN_AMBISONIC_END: AMBI1023 Testing av_channel_description With AV_CHAN_FRONT_LEFT: front left With AV_CHAN_FRONT_RIGHT: front right With 63: user 63 +With AV_CHAN_AMBISONIC_BASE: ambisonic ACN 0 +With AV_CHAN_AMBISONIC_END: ambisonic ACN 1023 Testing av_channel_from_string With "FL": 0 With "FR": 1 With "USR63": 63 +With "AMBI0": 1024 +With "AMBI1023": 2047 ==Native layouts== @@ -69,6 +75,7 @@ On 5.1(side) layout with "BC": -1 Testing av_channel_layout_from_string With "FL+FR+FC+BL+BR+LFE": FL+FR+FC+BL+BR+LFE +With "ambisonic 1+FR+FL": ambisonic 1+FR+FL With "FR+FL+USR63" layout: FR+FL+USR63 Testing av_channel_layout_index_from_string @@ -96,3 +103,9 @@ On "FR+FL+USR63" layout with 0: 1 On "FR+FL+USR63" layout with 1: 0 On "FR+FL+USR63" layout with 2: 63 On "FR+FL+USR63" layout with 3: -1 + +==Ambisonic layouts== + +Testing av_channel_layout_from_string +With "ambisonic 1": ambisonic 1 +With "ambisonic 2+stereo": ambisonic 2+stereo