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