/* * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
enum AVChannel av_channel_from_string(constchar *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;
} if (!strcmp(str, "UNK")) return AV_CHAN_UNKNOWN; if (!strcmp(str, "UNSD")) return AV_CHAN_UNUSED;
if (!strncmp(str, "USR", 3)) { constchar *p = str + 3;
id = strtol(p, &endptr, 0);
} if (id >= 0 && !*endptr) return id;
int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels)
{
AVChannelCustom *map;
if (nb_channels <= 0) return AVERROR(EINVAL);
map = av_calloc(nb_channels, sizeof(*channel_layout->u.map)); if (!map) return AVERROR(ENOMEM); for (int i = 0; i < nb_channels; i++)
map[i].id = AV_CHAN_UNKNOWN;
ret = av_channel_layout_retype(ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL);
av_assert0(ret == 0);
return 0;
}
int av_channel_layout_from_string(AVChannelLayout *channel_layout, constchar *str)
{ int i, matches, ret; int channels = 0, nb_channels = 0; char *chlist, *end;
uint64_t mask = 0;
/* channel layout names */ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) { if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
*channel_layout = channel_layout_map[i].layout; return 0;
}
}
/* This function is a channel layout initializer, so we have to
* zero-initialize before we start setting fields individually. */
memset(channel_layout, 0, sizeof(*channel_layout));
/* ambisonic */ if (!strncmp(str, "ambisonic ", 10)) { constchar *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);
if (CHAN_IS_AMBI(map[i].id))
highest_ambi = i;
}
} /* no ambisonic channels*/ if (highest_ambi < 0) return AVERROR(EINVAL);
order = floor(sqrt(highest_ambi)); /* incomplete order - some harmonics are missing */ if ((order + 1) * (order + 1) != highest_ambi + 1) return AVERROR(EINVAL);
return order;
}
staticenum AVChannelOrder canonical_order(AVChannelLayout *channel_layout)
{ int has_known_channel = 0; int order;
if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM) return channel_layout->order;
if (has_channel_names(channel_layout)) return AV_CHANNEL_ORDER_CUSTOM;
for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++) if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN)
has_known_channel = 1; if (!has_known_channel) return AV_CHANNEL_ORDER_UNSPEC;
if (masked_description(channel_layout, 0) > 0) return AV_CHANNEL_ORDER_NATIVE;
order = av_channel_layout_ambisonic_order(channel_layout); if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0) return AV_CHANNEL_ORDER_AMBISONIC;
return AV_CHANNEL_ORDER_CUSTOM;
}
/** * 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 otherwise.
*/ staticint try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout)
{ int nb_ambi_channels; int order = av_channel_layout_ambisonic_order(channel_layout); if (order < 0) return order;
av_bprintf(bp, "ambisonic %d", order);
/* extra channels present */
nb_ambi_channels = (order + 1) * (order + 1); if (nb_ambi_channels < channel_layout->nb_channels) {
AVChannelLayout extra = { 0 };
av_bprint_chars(bp, '+', 1);
av_channel_layout_describe_bprint(&extra, bp); /* Not calling uninit here on extra because we don't own the u.map pointer */
}
return 0;
}
int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
AVBPrint *bp)
{ int i;
switch (channel_layout->order) { case AV_CHANNEL_ORDER_NATIVE: for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
av_bprintf(bp, "%s", channel_layout_map[i].name); return 0;
} // fall-through case AV_CHANNEL_ORDER_CUSTOM: if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
int64_t mask; int res = try_describe_ambisonic(bp, channel_layout); if (res >= 0) return 0; if (!has_channel_names(channel_layout) &&
(mask = masked_description(channel_layout, 0)) > 0) {
AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE,
.nb_channels = av_popcount64(mask),
.u.mask = mask }; return av_channel_layout_describe_bprint(&native, bp);
}
} if (channel_layout->nb_channels)
av_bprintf(bp, "%d channels (", channel_layout->nb_channels); for (i = 0; i < channel_layout->nb_channels; i++) { enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
if (i)
av_bprintf(bp, "+");
av_channel_name_bprint(bp, ch); if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
channel_layout->u.map[i].name[0])
av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
} if (channel_layout->nb_channels) {
av_bprintf(bp, ")"); return 0;
} // fall-through 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);
}
}
int av_channel_layout_describe(const AVChannelLayout *channel_layout, char *buf, size_t buf_size)
{
AVBPrint bp; int ret;
if (!buf && buf_size) return AVERROR(EINVAL);
av_bprint_init_for_buffer(&bp, buf, buf_size);
ret = av_channel_layout_describe_bprint(channel_layout, &bp); if (ret < 0) return ret;
switch (channel_layout->order) { case AV_CHANNEL_ORDER_CUSTOM:
chname = strstr(str, "@"); if (chname) { char buf[16];
chname++;
av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str)); if (!*chname)
chname = NULL;
ch = av_channel_from_string(buf); if (ch == AV_CHAN_NONE && *buf) return AVERROR(EINVAL);
} for (int i = 0; chname && i < channel_layout->nb_channels; i++) { if (!strcmp(chname, channel_layout->u.map[i].name) &&
(ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id)) return i;
} // fall-through case AV_CHANNEL_ORDER_AMBISONIC: case AV_CHANNEL_ORDER_NATIVE:
ch = av_channel_from_string(str); if (ch == AV_CHAN_NONE) return AVERROR(EINVAL); return av_channel_layout_index_from_channel(channel_layout, ch);
}
return AVERROR(EINVAL);
}
int av_channel_layout_check(const AVChannelLayout *channel_layout)
{ if (channel_layout->nb_channels <= 0) return 0;
switch (channel_layout->order) { case AV_CHANNEL_ORDER_NATIVE: return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels; case AV_CHANNEL_ORDER_CUSTOM: if (!channel_layout->u.map) return 0; for (int i = 0; i < channel_layout->nb_channels; i++) { if (channel_layout->u.map[i].id == AV_CHAN_NONE) 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: return 0;
}
}
int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
{ int i;
/* different channel counts -> not equal */ if (chl->nb_channels != chl1->nb_channels) return 1;
/* if only one is unspecified -> not equal */ if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
(chl1->order == AV_CHANNEL_ORDER_UNSPEC)) return 1; /* both are unspecified -> equal */ elseif (chl->order == AV_CHANNEL_ORDER_UNSPEC) return 0;
/* compare channel by channel */ for (i = 0; i < chl->nb_channels; i++) if (av_channel_layout_channel_from_index(chl, i) !=
av_channel_layout_channel_from_index(chl1, i)) return 1; return 0;
}
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
{ int i; for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) if (nb_channels == channel_layout_map[i].layout.nb_channels) {
*ch_layout = channel_layout_map[i].layout; return;
}
if (i < FF_ARRAY_ELEMS(channel_layout_map)) {
ch_layout = &channel_layout_map[i].layout;
*opaque = (void*)(i + 1);
}
return ch_layout;
}
uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
uint64_t mask)
{
uint64_t ret = 0; int i;
switch (channel_layout->order) { case AV_CHANNEL_ORDER_NATIVE: case AV_CHANNEL_ORDER_AMBISONIC: return channel_layout->u.mask & mask; case AV_CHANNEL_ORDER_CUSTOM: for (i = 0; i < 64; i++) if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0)
ret |= (1ULL << i); break;
}
return ret;
}
int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
{ int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS); int lossy;
if (!av_channel_layout_check(channel_layout)) return AVERROR(EINVAL);
if (flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL)
order = canonical_order(channel_layout);
if (channel_layout->order == order) return 0;
switch (order) { case AV_CHANNEL_ORDER_UNSPEC: { int nb_channels = channel_layout->nb_channels; if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
lossy = 0; for (int i = 0; i < nb_channels; i++) { if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
lossy = 1; break;
}
}
} else {
lossy = 1;
} if (!lossy || allow_lossy) { void *opaque = channel_layout->opaque;
av_channel_layout_uninit(channel_layout);
channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
channel_layout->nb_channels = nb_channels;
channel_layout->opaque = opaque; return lossy;
} return AVERROR(ENOSYS);
} case AV_CHANNEL_ORDER_NATIVE: if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
int64_t mask = masked_description(channel_layout, 0); if (mask < 0) return AVERROR(ENOSYS);
lossy = has_channel_names(channel_layout); if (!lossy || allow_lossy) { void *opaque = channel_layout->opaque;
av_channel_layout_uninit(channel_layout);
av_channel_layout_from_mask(channel_layout, mask);
channel_layout->opaque = opaque; return lossy;
}
} return AVERROR(ENOSYS); case AV_CHANNEL_ORDER_CUSTOM: {
AVChannelLayout custom = { 0 }; int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels); void *opaque = channel_layout->opaque; if (ret < 0) return ret; if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC) for (int i = 0; i < channel_layout->nb_channels; i++)
custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
av_channel_layout_uninit(channel_layout);
*channel_layout = custom;
channel_layout->opaque = opaque; return 0;
} case AV_CHANNEL_ORDER_AMBISONIC: if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
int64_t mask; int nb_channels = channel_layout->nb_channels; int order = av_channel_layout_ambisonic_order(channel_layout); if (order < 0) return AVERROR(ENOSYS);
mask = masked_description(channel_layout, (order + 1) * (order + 1)); if (mask < 0) return AVERROR(ENOSYS);
lossy = has_channel_names(channel_layout); if (!lossy || allow_lossy) { void *opaque = channel_layout->opaque;
av_channel_layout_uninit(channel_layout);
channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
channel_layout->nb_channels = nb_channels;
channel_layout->u.mask = mask;
channel_layout->opaque = opaque; return lossy;
}
} return AVERROR(ENOSYS); default: return AVERROR(EINVAL);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.