| @@ -1036,3 +1036,109 @@ uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout, · 1035 unmodified lines |
| 1036 | 1036 | |
| 1037 | 1037 | return ret; |
| 1038 | 1038 | } |
| 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 | +} |