1 /* 2 * Copyright (c) 2024, Alliance for Open Media. All rights reserved 3 * 4 * This source code is subject to the terms of the BSD 3-Clause Clear License 5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear 6 * License was not distributed with this source code in the LICENSE file, you 7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the 8 * Alliance for Open Media Patent License 1.0 was not distributed with this 9 * source code in the PATENTS file, you can obtain it at 10 * www.aomedia.org/license/patent. 11 */ 12 13 #ifndef CLI_PROTO_CONVERSION_CHANNEL_LABEL_UTILS_H_ 14 #define CLI_PROTO_CONVERSION_CHANNEL_LABEL_UTILS_H_ 15 16 #include <algorithm> 17 18 #include "absl/status/status.h" 19 #include "absl/status/statusor.h" 20 #include "absl/strings/str_cat.h" 21 #include "absl/strings/string_view.h" 22 #include "iamf/cli/channel_label.h" 23 #include "iamf/cli/proto/audio_frame.pb.h" 24 25 namespace iamf_tools { 26 27 class ChannelLabelUtils { 28 public: 29 /*!\brief Converts the input proto enum to a `Label`. 30 * 31 * \param proto_label Label to convert. 32 * \return Converted label on success. A specific status on failure. 33 */ 34 static absl::StatusOr<ChannelLabel::Label> ProtoToLabel( 35 iamf_tools_cli_proto::ChannelLabel proto_label); 36 37 /*!\brief Converts the input `ChanelLabel` to a proto enum 38 * 39 * \param label Label to convert. 40 * \return Converted label on success. A specific status on failure. 41 */ 42 static absl::StatusOr<iamf_tools_cli_proto::ChannelLabel> LabelToProto( 43 ChannelLabel::Label label); 44 45 /*!\brief Converts labels and fill the output container. 46 * 47 * Useful to convert containers of `std::string`, `absl::string_view`, or 48 * `iamf_tools_cli_proto::ChannelLabel` proto enums to the 49 * canonical internal representation. 50 * 51 * \param input_labels Container to convert. 52 * \param output_labels Container to fill with the converted labels. The 53 * labels are inserted using the end iterator as a "hint"; when both 54 * containers are ordered the input and output order will agree. 55 * \return `absl::OkStatus()` on success. An error if any labels fail to be 56 * converted. An error if any output labels are duplicate. 57 */ 58 template <class InputContainer, class OutputContainer> ConvertAndFillLabels(const InputContainer & input_labels,OutputContainer & output_labels)59 static absl::Status ConvertAndFillLabels(const InputContainer& input_labels, 60 OutputContainer& output_labels) { 61 for (const auto& input_label : input_labels) { 62 const absl::StatusOr<ChannelLabel::Label> label = [&]() -> auto { 63 using iamf_tools_cli_proto::ChannelMetadata; 64 if constexpr (std::is_convertible_v<decltype(input_label), 65 absl::string_view>) { 66 return ChannelLabel::DeprecatedStringBasedLabelToLabel(input_label); 67 } else if constexpr (std::is_convertible_v<decltype(input_label), 68 ChannelMetadata>) { 69 return ProtoToLabel(input_label.channel_label()); 70 } else { 71 return ProtoToLabel(input_label); 72 } 73 }(); 74 if (!label.ok()) { 75 return label.status(); 76 } 77 78 if (std::find(output_labels.begin(), output_labels.end(), *label) != 79 output_labels.end()) { 80 return absl::InvalidArgumentError( 81 absl::StrCat("Duplicate output_label: ", *label, 82 " when inserting from input_label= ", input_label)); 83 } 84 output_labels.insert(output_labels.end(), *label); 85 } 86 87 return absl::OkStatus(); 88 } 89 90 /*!\brief Select the labels and forward to `ConvertAndFillLabels`. 91 * 92 * Acts as a shim to allow common handling of `channel_metadatas` and 93 * the deprecated `channel_labels` fields. This function will change behavior 94 * as the deprecation process moves forward. 95 * 96 * Prefers selecting labels based on the `channel_metadatas` field if it is 97 * present. Warns, but permits the deprecated `channel_labels`. Forbids 98 * partial upgrades, which would result in a confusing state with multiple 99 * sources of labels. 100 * 101 * \param audio_frame_metadata Metadata to select labels from and convert. 102 * \param output_labels Container to fill with the converted labels. The 103 * labels are inserted using the end iterator as a "hint"; when both 104 * containers are ordered the input and output order will agree. 105 * \return `absl::OkStatus()` on success. An error if the `channel_metadatas` 106 * is present, but `channel_labels` or `channel_ids` is not empty. An 107 * error if any labels fail to be converted. An error if any output 108 * labels are duplicate. 109 */ 110 template <class OutputContainer> SelectConvertAndFillLabels(const iamf_tools_cli_proto::AudioFrameObuMetadata & audio_frame_metadata,OutputContainer & output_labels)111 static absl::Status SelectConvertAndFillLabels( 112 const iamf_tools_cli_proto::AudioFrameObuMetadata& audio_frame_metadata, 113 OutputContainer& output_labels) { 114 if (!audio_frame_metadata.channel_metadatas().empty()) { 115 if (!audio_frame_metadata.channel_labels().empty()) { 116 return absl::InvalidArgumentError( 117 "Please fully upgrade to `channel_metadatas`. Leave " 118 "`channel_labels` empty"); 119 } 120 return ConvertAndFillLabels(audio_frame_metadata.channel_metadatas(), 121 output_labels); 122 } else { 123 return ConvertAndFillLabels(audio_frame_metadata.channel_labels(), 124 output_labels); 125 } 126 } 127 }; 128 } // namespace iamf_tools 129 130 #endif // CLI_PROTO_CONVERSION_CHANNEL_LABEL_UTILS_H_ 131