Skip to content

Commit

Permalink
Add LabelToProto using the new "invertible lookup table" pattern.
Browse files Browse the repository at this point in the history
  - Rename `LabelToString` to `LabelToStringForDebugging`.
    - We can prefer the proto form for non-debugging use-cases.
    - Debugging use cases can typically go through `absl::Stringify`
  - Deprecate `StringToLabel` which should only be used to support the deprecation plan for `ChannelMetadata`.

PiperOrigin-RevId: 690595272
  • Loading branch information
jwcullen committed Oct 28, 2024
1 parent 15bb509 commit b30adbc
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 154 deletions.
197 changes: 57 additions & 140 deletions iamf/cli/channel_label.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
*/
#include "iamf/cli/channel_label.h"

#include <array>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "absl/base/no_destructor.h"
Expand All @@ -32,6 +34,46 @@ namespace iamf_tools {

namespace {

using enum iamf_tools_cli_proto::ChannelLabel;
using enum ChannelLabel::Label;

constexpr auto kProtoAndInternalLabel = std::to_array<
std::pair<iamf_tools_cli_proto::ChannelLabel, ChannelLabel::Label>>({
{CHANNEL_LABEL_MONO, kMono}, {CHANNEL_LABEL_L_2, kL2},
{CHANNEL_LABEL_R_2, kR2}, {CHANNEL_LABEL_CENTRE, kCentre},
{CHANNEL_LABEL_LFE, kLFE}, {CHANNEL_LABEL_L_3, kL3},
{CHANNEL_LABEL_R_3, kR3}, {CHANNEL_LABEL_LTF_3, kLtf3},
{CHANNEL_LABEL_RTF_3, kRtf3}, {CHANNEL_LABEL_L_5, kL5},
{CHANNEL_LABEL_R_5, kR5}, {CHANNEL_LABEL_LS_5, kLs5},
{CHANNEL_LABEL_RS_5, kRs5}, {CHANNEL_LABEL_LTF_2, kLtf2},
{CHANNEL_LABEL_RTF_2, kRtf2}, {CHANNEL_LABEL_LTF_4, kLtf4},
{CHANNEL_LABEL_RTF_4, kRtf4}, {CHANNEL_LABEL_LTB_4, kLtb4},
{CHANNEL_LABEL_RTB_4, kRtb4}, {CHANNEL_LABEL_L_7, kL7},
{CHANNEL_LABEL_R_7, kR7}, {CHANNEL_LABEL_LSS_7, kLss7},
{CHANNEL_LABEL_RSS_7, kRss7}, {CHANNEL_LABEL_LRS_7, kLrs7},
{CHANNEL_LABEL_RRS_7, kRrs7}, {CHANNEL_LABEL_FLC, kFLc},
{CHANNEL_LABEL_FC, kFC}, {CHANNEL_LABEL_FRC, kFRc},
{CHANNEL_LABEL_FL, kFL}, {CHANNEL_LABEL_FR, kFR},
{CHANNEL_LABEL_SI_L, kSiL}, {CHANNEL_LABEL_SI_R, kSiR},
{CHANNEL_LABEL_BL, kBL}, {CHANNEL_LABEL_BR, kBR},
{CHANNEL_LABEL_TP_FL, kTpFL}, {CHANNEL_LABEL_TP_FR, kTpFR},
{CHANNEL_LABEL_TP_SI_L, kTpSiL}, {CHANNEL_LABEL_TP_SI_R, kTpSiR},
{CHANNEL_LABEL_TP_BL, kTpBL}, {CHANNEL_LABEL_TP_BR, kTpBR},
{CHANNEL_LABEL_A_0, kA0}, {CHANNEL_LABEL_A_1, kA1},
{CHANNEL_LABEL_A_2, kA2}, {CHANNEL_LABEL_A_3, kA3},
{CHANNEL_LABEL_A_4, kA4}, {CHANNEL_LABEL_A_5, kA5},
{CHANNEL_LABEL_A_6, kA6}, {CHANNEL_LABEL_A_7, kA7},
{CHANNEL_LABEL_A_8, kA8}, {CHANNEL_LABEL_A_9, kA9},
{CHANNEL_LABEL_A_10, kA10}, {CHANNEL_LABEL_A_11, kA11},
{CHANNEL_LABEL_A_12, kA12}, {CHANNEL_LABEL_A_13, kA13},
{CHANNEL_LABEL_A_14, kA14}, {CHANNEL_LABEL_A_15, kA15},
{CHANNEL_LABEL_A_16, kA16}, {CHANNEL_LABEL_A_17, kA17},
{CHANNEL_LABEL_A_18, kA18}, {CHANNEL_LABEL_A_19, kA19},
{CHANNEL_LABEL_A_20, kA20}, {CHANNEL_LABEL_A_21, kA21},
{CHANNEL_LABEL_A_22, kA22}, {CHANNEL_LABEL_A_23, kA23},
{CHANNEL_LABEL_A_24, kA24},
});

absl::StatusOr<std::vector<ChannelLabel::Label>>
LookupEarChannelOrderFromNonExpandedLoudspeakerLayout(
const ChannelAudioLayerConfig::LoudspeakerLayout& loudspeaker_layout) {
Expand Down Expand Up @@ -265,149 +307,24 @@ absl::StatusOr<ChannelLabel::Label> ChannelLabel::StringToLabel(
}

absl::StatusOr<ChannelLabel::Label> ChannelLabel::ProtoToLabel(
iamf_tools_cli_proto::ChannelLabel label) {
using enum iamf_tools_cli_proto::ChannelLabel;
using enum ChannelLabel::Label;
switch (label) {
case CHANNEL_LABEL_INVALID:
return absl::InvalidArgumentError("Invalid channel label.");
case CHANNEL_LABEL_MONO:
return kMono;
case CHANNEL_LABEL_L_2:
return kL2;
case CHANNEL_LABEL_R_2:
return kR2;
case CHANNEL_LABEL_CENTRE:
return kCentre;
case CHANNEL_LABEL_LFE:
return kLFE;
case CHANNEL_LABEL_L_3:
return kL3;
case CHANNEL_LABEL_R_3:
return kR3;
case CHANNEL_LABEL_LTF_3:
return kLtf3;
case CHANNEL_LABEL_RTF_3:
return kRtf3;
case CHANNEL_LABEL_L_5:
return kL5;
case CHANNEL_LABEL_R_5:
return kR5;
case CHANNEL_LABEL_LS_5:
return kLs5;
case CHANNEL_LABEL_RS_5:
return kRs5;
case CHANNEL_LABEL_LTF_2:
return kLtf2;
case CHANNEL_LABEL_RTF_2:
return kRtf2;
case CHANNEL_LABEL_LTF_4:
return kLtf4;
case CHANNEL_LABEL_RTF_4:
return kRtf4;
case CHANNEL_LABEL_LTB_4:
return kLtb4;
case CHANNEL_LABEL_RTB_4:
return kRtb4;
case CHANNEL_LABEL_L_7:
return kL7;
case CHANNEL_LABEL_R_7:
return kR7;
case CHANNEL_LABEL_LSS_7:
return kLss7;
case CHANNEL_LABEL_RSS_7:
return kRss7;
case CHANNEL_LABEL_LRS_7:
return kLrs7;
case CHANNEL_LABEL_RRS_7:
return kRrs7;
case CHANNEL_LABEL_FLC:
return kFLc;
case CHANNEL_LABEL_FC:
return kFC;
case CHANNEL_LABEL_FRC:
return kFRc;
case CHANNEL_LABEL_FL:
return kFL;
case CHANNEL_LABEL_FR:
return kFR;
case CHANNEL_LABEL_SI_L:
return kSiL;
case CHANNEL_LABEL_SI_R:
return kSiR;
case CHANNEL_LABEL_BL:
return kBL;
case CHANNEL_LABEL_BR:
return kBR;
case CHANNEL_LABEL_TP_FL:
return kTpFL;
case CHANNEL_LABEL_TP_FR:
return kTpFR;
case CHANNEL_LABEL_TP_SI_L:
return kTpSiL;
case CHANNEL_LABEL_TP_SI_R:
return kTpSiR;
case CHANNEL_LABEL_TP_BL:
return kTpBL;
case CHANNEL_LABEL_TP_BR:
return kTpBR;
case CHANNEL_LABEL_A_0:
return kA0;
case CHANNEL_LABEL_A_1:
return kA1;
case CHANNEL_LABEL_A_2:
return kA2;
case CHANNEL_LABEL_A_3:
return kA3;
case CHANNEL_LABEL_A_4:
return kA4;
case CHANNEL_LABEL_A_5:
return kA5;
case CHANNEL_LABEL_A_6:
return kA6;
case CHANNEL_LABEL_A_7:
return kA7;
case CHANNEL_LABEL_A_8:
return kA8;
case CHANNEL_LABEL_A_9:
return kA9;
case CHANNEL_LABEL_A_10:
return kA10;
case CHANNEL_LABEL_A_11:
return kA11;
case CHANNEL_LABEL_A_12:
return kA12;
case CHANNEL_LABEL_A_13:
return kA13;
case CHANNEL_LABEL_A_14:
return kA14;
case CHANNEL_LABEL_A_15:
return kA15;
case CHANNEL_LABEL_A_16:
return kA16;
case CHANNEL_LABEL_A_17:
return kA17;
case CHANNEL_LABEL_A_18:
return kA18;
case CHANNEL_LABEL_A_19:
return kA19;
case CHANNEL_LABEL_A_20:
return kA20;
case CHANNEL_LABEL_A_21:
return kA21;
case CHANNEL_LABEL_A_22:
return kA22;
case CHANNEL_LABEL_A_23:
return kA23;
case CHANNEL_LABEL_A_24:
return kA24;
}
iamf_tools_cli_proto::ChannelLabel proto_label) {
static const auto kProtoToLabel =
BuildStaticMapFromPairs(kProtoAndInternalLabel);

// The above switch statement is exhaustive.
LOG(FATAL) << "Enum out of range.";
return LookupInMap(*kProtoToLabel, proto_label,
"Internal version of proto `ChannelLabel`");
}

absl::StatusOr<iamf_tools_cli_proto::ChannelLabel> ChannelLabel::LabelToProto(
ChannelLabel::Label label) {
static const auto kLabelToProto =
BuildStaticMapFromInvertedPairs(kProtoAndInternalLabel);

return LookupInMap(*kLabelToProto, label,
"Proto version of internal `ChannelLabel`");
}

std::string ChannelLabel::LabelToString(Label label) {
std::string ChannelLabel::LabelToStringForDebugging(Label label) {
using enum ChannelLabel::Label;
switch (label) {
case kOmitted:
Expand Down
20 changes: 15 additions & 5 deletions iamf/cli/channel_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class ChannelLabel {

template <typename Sink>
friend void AbslStringify(Sink& sink, Label e) {
sink.Append(LabelToString(e));
sink.Append(LabelToStringForDebugging(e));
}

/*!\brief Converts the input string to a `Label`.
Expand All @@ -148,15 +148,25 @@ class ChannelLabel {
* \param label Label to convert.
* \return Converted label on success. A specific status on failure.
*/
[[deprecated(
"Remove when `AudioFrameObuMetadata.channel_labels` is removed.")]]
static absl::StatusOr<Label> StringToLabel(absl::string_view label);

/*!\brief Converts the input proto enum to a `Label`.
*
* \param label Label to convert.
* \param proto_label Label to convert.
* \return Converted label on success. A specific status on failure.
*/
static absl::StatusOr<Label> ProtoToLabel(
iamf_tools_cli_proto::ChannelLabel label);
iamf_tools_cli_proto::ChannelLabel proto_label);

/*!\brief Converts the input `ChanelLabel` to a proto enum
*
* \param label Label to convert.
* \return Converted label on success. A specific status on failure.
*/
static absl::StatusOr<iamf_tools_cli_proto::ChannelLabel> LabelToProto(
Label label);

/*!\brief Converts labels and fill the output container.
*
Expand Down Expand Up @@ -241,12 +251,12 @@ class ChannelLabel {
}
}

/*!\brief Converts the `Label` to an output string.
/*!\brief Converts the `Label` to a debugging string.
*
* \param label Label to convert.
* \return Converted label.
*/
static std::string LabelToString(Label label);
static std::string LabelToStringForDebugging(Label label);

/*!\brief Gets the channel label for an ambisonics channel number.
*
Expand Down
12 changes: 6 additions & 6 deletions iamf/cli/proto_to_obu/audio_element_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -534,13 +534,13 @@ absl::Status AddSubstreamLabels(
substream_index < substream_ids.size();) {
const auto substream_id = substream_ids[substream_index++];
auto& labels_for_substream_id = substream_id_to_labels[substream_id];
labels_for_substream_id.push_back(*iter++);
std::string concatenated_labels =
ChannelLabel::LabelToString(labels_for_substream_id.back());
labels_for_substream_id.push_back(*iter++);
absl::StrAppend(&concatenated_labels, "/", labels_for_substream_id.back());
const auto first_label = *iter++;
const auto second_label = *iter++;

labels_for_substream_id.push_back(first_label);
labels_for_substream_id.push_back(second_label);
LOG(INFO) << " substream_id_to_labels[" << substream_id
<< "]: " << concatenated_labels;
<< "]: " << first_label << "/" << second_label;
}

// Then add non-coupled substream labels.
Expand Down
60 changes: 57 additions & 3 deletions iamf/cli/tests/channel_label_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,13 @@ TEST(StringToLabel, InvalidForFourteenthOrderAmbisonicsInput) {
}

using LabelTestCase = ::testing::TestWithParam<ChannelLabel::Label>;
TEST_P(LabelTestCase, StringToLabelAndLabelToStringAreSymmetric) {
TEST_P(LabelTestCase, StringToLabelAndLabelToStringForDebuggingAreSymmetric) {
const ChannelLabel::Label label = GetParam();
const std::string label_string = ChannelLabel::LabelToString(label);
const std::string label_string_for_debugging =
ChannelLabel::LabelToStringForDebugging(label);

EXPECT_THAT(ChannelLabel::StringToLabel(label_string), IsOkAndHolds(label));
EXPECT_THAT(ChannelLabel::StringToLabel(label_string_for_debugging),
IsOkAndHolds(label));
}

INSTANTIATE_TEST_SUITE_P(
Expand Down Expand Up @@ -161,6 +163,58 @@ INSTANTIATE_TEST_SUITE_P(
kA13, kA14, kA15, kA16, kA17, kA18, kA19, kA20, kA21, kA22, kA23,
kA24}));

using ProtoLabelTestCase =
::testing::TestWithParam<iamf_tools_cli_proto::ChannelLabel>;
TEST_P(ProtoLabelTestCase, ProtoToLabelAndLabelToProtoAreSymmetric) {
const iamf_tools_cli_proto::ChannelLabel proto_label = GetParam();
const auto channel_label = ChannelLabel::ProtoToLabel(proto_label);
EXPECT_THAT(channel_label, IsOk());

EXPECT_THAT(ChannelLabel::LabelToProto(*channel_label),
IsOkAndHolds(proto_label));
}

INSTANTIATE_TEST_SUITE_P(
ProtoToLabelAndLabelToProtoAreSymmetric, ProtoLabelTestCase,
::testing::ValuesIn<iamf_tools_cli_proto::ChannelLabel>(
{CHANNEL_LABEL_MONO,
// Stereo or binaural channels.
CHANNEL_LABEL_L_2, CHANNEL_LABEL_R_2,
// Centre channel common to several layouts (e.g. 3.1.2, 5.x.y, 7.x.y).
CHANNEL_LABEL_CENTRE,
// LFE channel common to several layouts
// (e.g. 3.1.2, 5.1.y, 7.1.y, 9.1.6).
CHANNEL_LABEL_LFE,
// 3.1.2 surround channels.
CHANNEL_LABEL_L_3, CHANNEL_LABEL_R_3, CHANNEL_LABEL_LTF_3,
CHANNEL_LABEL_RTF_3,
// 5.x.y surround channels.
CHANNEL_LABEL_L_5, CHANNEL_LABEL_R_5, CHANNEL_LABEL_LS_5,
CHANNEL_LABEL_RS_5,
// Common channels between 5.1.2 and 7.1.2.
CHANNEL_LABEL_LTF_2, CHANNEL_LABEL_RTF_2,
// Common channels between 5.1.4 and 7.1.4.
CHANNEL_LABEL_LTF_4, CHANNEL_LABEL_RTF_4, CHANNEL_LABEL_LTB_4,
CHANNEL_LABEL_RTB_4,
// 7.x.y surround channels.
CHANNEL_LABEL_L_7, CHANNEL_LABEL_R_7, CHANNEL_LABEL_LSS_7,
CHANNEL_LABEL_RSS_7, CHANNEL_LABEL_LRS_7, CHANNEL_LABEL_RRS_7,
// 9.1.6 surround channels.
CHANNEL_LABEL_FLC, CHANNEL_LABEL_FC, CHANNEL_LABEL_FRC,
CHANNEL_LABEL_FL, CHANNEL_LABEL_FR, CHANNEL_LABEL_SI_L,
CHANNEL_LABEL_SI_R, CHANNEL_LABEL_BL, CHANNEL_LABEL_BR,
CHANNEL_LABEL_TP_FL, CHANNEL_LABEL_TP_FR, CHANNEL_LABEL_TP_SI_L,
CHANNEL_LABEL_TP_SI_R, CHANNEL_LABEL_TP_BL, CHANNEL_LABEL_TP_BR,
CHANNEL_LABEL_A_0, CHANNEL_LABEL_A_1, CHANNEL_LABEL_A_2,
CHANNEL_LABEL_A_3, CHANNEL_LABEL_A_4, CHANNEL_LABEL_A_5,
CHANNEL_LABEL_A_6, CHANNEL_LABEL_A_7, CHANNEL_LABEL_A_8,
CHANNEL_LABEL_A_9, CHANNEL_LABEL_A_10, CHANNEL_LABEL_A_11,
CHANNEL_LABEL_A_12, CHANNEL_LABEL_A_13, CHANNEL_LABEL_A_14,
CHANNEL_LABEL_A_15, CHANNEL_LABEL_A_16, CHANNEL_LABEL_A_17,
CHANNEL_LABEL_A_18, CHANNEL_LABEL_A_19, CHANNEL_LABEL_A_20,
CHANNEL_LABEL_A_21, CHANNEL_LABEL_A_22, CHANNEL_LABEL_A_23,
CHANNEL_LABEL_A_24}));

template <class InputContainer, class OutputContainer>
void ExpectConvertAndFillLabelsHasExpectedOutput(
const InputContainer& input_labels,
Expand Down

0 comments on commit b30adbc

Please sign in to comment.