History

avutil/channel_layout: add av_channel_layout_retype()

Marton Balint committed 2 years ago

Commit 66386bf1 parent 4569b864 files · +150 −1Browse files

Unified · Split

4 files
  1. doc/APIchanges +3 −0
  2. libavutil/channel_layout.c +106 −0
  3. libavutil/channel_layout.h +40 −0
  4. libavutil/version.h +1 −1
doc/APIchanges+3−0
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09 · 1 unmodified line
22
33 API changes, most recent first:
44
5+2024-02-xx - xxxxxxxxxx - lavu 58.38.100 - channel_layout.h
6+ Add av_channel_layout_retype().
7+
58 2024-02-xx - xxxxxxxxxx - lavu 58.37.100 - channel_layout.h
69 Add av_channel_layout_custom_init().
710
libavutil/channel_layout.c+106−0
@@ -1036,3 +1036,109 @@ uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout, · 1035 unmodified lines
10361036
10371037 return ret;
10381038 }
1039+
1040+static int64_t masked_description(AVChannelLayout *channel_layout, int start_channel)
1041+{
1042+ uint64_t mask = 0;
1043+ for (int i = start_channel; i < channel_layout->nb_channels; i++) {
1044+ enum AVChannel ch = channel_layout->u.map[i].id;
1045+ if (ch >= 0 && ch < 63 && mask < (1ULL << ch))
1046+ mask |= (1ULL << ch);
1047+ else
1048+ return AVERROR(EINVAL);
1049+ }
1050+ return mask;
1051+}
1052+
1053+static int has_channel_names(AVChannelLayout *channel_layout)
1054+{
1055+ if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM)
1056+ return 0;
1057+ for (int i = 0; i < channel_layout->nb_channels; i++)
1058+ if (channel_layout->u.map[i].name[0])
1059+ return 1;
1060+ return 0;
1061+}
1062+
1063+int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags)
1064+{
1065+ int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS);
1066+ int lossy;
1067+
1068+ if (!av_channel_layout_check(channel_layout))
1069+ return AVERROR(EINVAL);
1070+
1071+ if (channel_layout->order == order)
1072+ return 0;
1073+
1074+ switch (order) {
1075+ case AV_CHANNEL_ORDER_UNSPEC: {
1076+ int nb_channels = channel_layout->nb_channels;
1077+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
1078+ lossy = 0;
1079+ for (int i = 0; i < nb_channels; i++) {
1080+ if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) {
1081+ lossy = 1;
1082+ break;
1083+ }
1084+ }
1085+ } else {
1086+ lossy = 1;
1087+ }
1088+ if (!lossy || allow_lossy) {
1089+ av_channel_layout_uninit(channel_layout);
1090+ channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
1091+ channel_layout->nb_channels = nb_channels;
1092+ return lossy;
1093+ }
1094+ return AVERROR(ENOSYS);
1095+ }
1096+ case AV_CHANNEL_ORDER_NATIVE:
1097+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
1098+ int64_t mask = masked_description(channel_layout, 0);
1099+ if (mask < 0)
1100+ return AVERROR(ENOSYS);
1101+ lossy = has_channel_names(channel_layout);
1102+ if (!lossy || allow_lossy) {
1103+ av_channel_layout_uninit(channel_layout);
1104+ av_channel_layout_from_mask(channel_layout, mask);
1105+ return lossy;
1106+ }
1107+ }
1108+ return AVERROR(ENOSYS);
1109+ case AV_CHANNEL_ORDER_CUSTOM: {
1110+ AVChannelLayout custom = { 0 };
1111+ int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels);
1112+ if (ret < 0)
1113+ return ret;
1114+ if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC)
1115+ for (int i = 0; i < channel_layout->nb_channels; i++)
1116+ custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i);
1117+ av_channel_layout_uninit(channel_layout);
1118+ *channel_layout = custom;
1119+ return 0;
1120+ }
1121+ case AV_CHANNEL_ORDER_AMBISONIC:
1122+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) {
1123+ int64_t mask;
1124+ int nb_channels = channel_layout->nb_channels;
1125+ int order = ambisonic_order(channel_layout);
1126+ if (order < 0)
1127+ return AVERROR(ENOSYS);
1128+ mask = masked_description(channel_layout, (order + 1) * (order + 1));
1129+ if (mask < 0)
1130+ return AVERROR(ENOSYS);
1131+ lossy = has_channel_names(channel_layout);
1132+ if (!lossy || allow_lossy) {
1133+ av_channel_layout_uninit(channel_layout);
1134+ channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC;
1135+ channel_layout->nb_channels = nb_channels;
1136+ channel_layout->u.mask = mask;
1137+ return lossy;
1138+ }
1139+ }
1140+ return AVERROR(ENOSYS);
1141+ default:
1142+ return AVERROR(EINVAL);
1143+ }
1144+}
libavutil/channel_layout.h+40−0
@@ -821,6 +821,46 @@ int av_channel_layout_check(const AVChannelLayout *channel_layout); · 820 unmodified lines
821821 */
822822 int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1);
823823
824+/**
825+ * The conversion must be lossless.
826+ */
827+#define AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS (1 << 0)
828+
829+/**
830+ * Change the AVChannelOrder of a channel layout.
831+ *
832+ * Change of AVChannelOrder can be either lossless or lossy. In case of a
833+ * lossless conversion all the channel designations and the associated channel
834+ * names (if any) are kept. On a lossy conversion the channel names and channel
835+ * designations might be lost depending on the capabilities of the desired
836+ * AVChannelOrder. Note that some conversions are simply not possible in which
837+ * case this function returns AVERROR(ENOSYS).
838+ *
839+ * The following conversions are supported:
840+ *
841+ * Any -> Custom : Always possible, always lossless.
842+ * Any -> Unspecified: Always possible, lossless if channel designations
843+ * are all unknown and channel names are not used, lossy otherwise.
844+ * Custom -> Ambisonic : Possible if it contains ambisonic channels with
845+ * optional non-diegetic channels in the end. Lossy if the channels have
846+ * custom names, lossless otherwise.
847+ * Custom -> Native : Possible if it contains native channels in native
848+ * order. Lossy if the channels have custom names, lossless otherwise.
849+ *
850+ * On error this function keeps the original channel layout untouched.
851+ *
852+ * @param channel_layout channel layout which will be changed
853+ * @param order the desired channel layout order
854+ * @param flags a combination of AV_CHANNEL_LAYOUT_RETYPE_FLAG_* constants
855+ * @return 0 if the conversion was successful and lossless or if the channel
856+ * layout was already in the desired order
857+ * >0 if the conversion was successful but lossy
858+ * AVERROR(ENOSYS) if the conversion was not possible (or would be
859+ * lossy and AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS was specified)
860+ * AVERROR(EINVAL), AVERROR(ENOMEM) on error
861+ */
862+int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags);
863+
824864 /**
825865 * @}
826866 */
libavutil/version.h+1−1
@@ -79,7 +79,7 @@ · 78 unmodified lines
7979 */
8080
8181 #define LIBAVUTIL_VERSION_MAJOR 58
82−#define LIBAVUTIL_VERSION_MINOR 37
82+#define LIBAVUTIL_VERSION_MINOR 38
8383 #define LIBAVUTIL_VERSION_MICRO 100
8484
8585 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t