Skip to content

Commit

Permalink
Implements reading of AmbisonicsConfig in AudioElementObu.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 633689304
  • Loading branch information
trevorknight authored and jwcullen committed May 16, 2024
1 parent 6358d42 commit 98b4b63
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 5 deletions.
65 changes: 60 additions & 5 deletions iamf/obu/audio_element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

namespace iamf_tools {

using absl::OkStatus;

namespace {

// Returns the number of elements in the demixing_matrix.
Expand Down Expand Up @@ -150,6 +152,7 @@ absl::Status ValidateUniqueParamDefinitionType(
collected_param_definition_types.end(),
"audio_element_params");
}

absl::Status ValidateOutputChannelCount(const uint8_t channel_count) {
uint8_t next_valid_output_channel_count;
RETURN_IF_NOT_OK(AmbisonicsConfig ::GetNextValidOutputChannelCount(
Expand Down Expand Up @@ -323,12 +326,63 @@ absl::Status ValidateAndWriteAmbisonicsConfig(const AmbisonicsConfig& config,
}
}

absl::Status ReadAndValidateAmbisonicsProjection(
AmbisonicsProjectionConfig& projection_config,
DecodedUleb128 num_substreams, ReadBitBuffer& rb) {
RETURN_IF_NOT_OK(
rb.ReadUnsignedLiteral(8, projection_config.output_channel_count));
RETURN_IF_NOT_OK(
rb.ReadUnsignedLiteral(8, projection_config.substream_count));
RETURN_IF_NOT_OK(
rb.ReadUnsignedLiteral(8, projection_config.coupled_substream_count));
const size_t demixing_matrix_size =
GetNumDemixingMatrixElements(projection_config);
for (size_t i = 0; i < demixing_matrix_size; ++i) {
int16_t demixing_matrix_value;
RETURN_IF_NOT_OK(rb.ReadSigned16(demixing_matrix_value));
projection_config.demixing_matrix.push_back(demixing_matrix_value);
}
RETURN_IF_NOT_OK(projection_config.Validate(num_substreams));
return OkStatus();
}

absl::Status ReadAndValidateAmbisonicsMonoConfig(
AmbisonicsMonoConfig& mono_config, DecodedUleb128 num_substreams,
ReadBitBuffer& rb) {
RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(8, mono_config.output_channel_count));
RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(8, mono_config.substream_count));
const size_t channel_mapping_size = mono_config.output_channel_count;
RETURN_IF_NOT_OK(
rb.ReadUint8Vector(channel_mapping_size, mono_config.channel_mapping));
RETURN_IF_NOT_OK(mono_config.Validate(num_substreams));
return OkStatus();
}

// Reads the `AmbisonicsConfig` of an ambisonics `AudioElementObu`.
absl::Status ValidateAndReadAmbisonicsConfig(AmbisonicsConfig& config,
absl::Status ReadAndValidateAmbisonicsConfig(AmbisonicsConfig& config,
DecodedUleb128 num_substreams,
ReadBitBuffer& rb) {
return absl::UnimplementedError(
"Reading ambisonics config is not implemented.");
DecodedUleb128 ambisonics_mode;
RETURN_IF_NOT_OK(rb.ReadULeb128(ambisonics_mode));
config.ambisonics_mode =
static_cast<AmbisonicsConfig::AmbisonicsMode>(ambisonics_mode);
switch (config.ambisonics_mode) {
using enum AmbisonicsConfig::AmbisonicsMode;
case kAmbisonicsModeMono: {
config.ambisonics_config = AmbisonicsMonoConfig();
return ReadAndValidateAmbisonicsMonoConfig(
std::get<AmbisonicsMonoConfig>(config.ambisonics_config),
num_substreams, rb);
}
case kAmbisonicsModeProjection: {
config.ambisonics_config = AmbisonicsProjectionConfig();
return ReadAndValidateAmbisonicsProjection(
std::get<AmbisonicsProjectionConfig>(config.ambisonics_config),
num_substreams, rb);
}
default:
return OkStatus();
}
}

} // namespace
Expand Down Expand Up @@ -691,7 +745,7 @@ absl::Status AudioElementObu::ValidateAndReadPayload(ReadBitBuffer& rb) {

RETURN_IF_NOT_OK(rb.ReadULeb128(num_parameters_));

// Loop to write the parameter portion of the obu.
// Loop to read the parameter portion of the obu.
for (int i = 0; i < num_parameters_; ++i) {
AudioElementParam audio_element_param;
RETURN_IF_NOT_OK(ValidateAndReadAudioElementParam(audio_element_param, rb));
Expand All @@ -707,7 +761,8 @@ absl::Status AudioElementObu::ValidateAndReadPayload(ReadBitBuffer& rb) {
return ValidateAndReadScalableChannelLayout(
std::get<ScalableChannelLayoutConfig>(config_), num_substreams_, rb);
case kAudioElementSceneBased:
return ValidateAndReadAmbisonicsConfig(
config_ = AmbisonicsConfig();
return ReadAndValidateAmbisonicsConfig(
std::get<AmbisonicsConfig>(config_), num_substreams_, rb);
default: {
ExtensionConfig extension_config;
Expand Down
94 changes: 94 additions & 0 deletions iamf/obu/tests/audio_element_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1432,5 +1432,99 @@ TEST(CreateFromBuffer, InvalidMultipleChannelConfigWithBinauralLayout) {
EXPECT_FALSE(obu.ok());
}

TEST(CreateFromBuffer, ValidAmbisonicsMonoConfig) {
std::vector<uint8_t> source = {
// `audio_element_id`.
1, // Arbitrary. Doesn't matter for this test.
// `audio_element_type (3), reserved (5).
AudioElementObu::kAudioElementSceneBased << 5, // Req. for Ambisonics.
// `codec_config_id`.
2, // Arbitrary. Doesn't matter for this test.
// `num_substreams`.
4, // Matters for validating the AmbisonicsMonoConfig.
// `audio_substream_ids`
3, 4, 5, 6, // Arbitrary IDs, need one per substream.
// `num_parameters`.
0, // Skip parameters, not part of the tested AmbisonicsMonoConfig.

// Now we're into the fields of the AmbisonicsMonoConfig.
static_cast<uint8_t>(
AmbisonicsConfig::AmbisonicsMode::kAmbisonicsModeMono),
4, // `output_channel_count`
4, // `substream_count`
0, 1, 2, 3 // `channel_mapping`, one per `output_channel_count`.
};
ReadBitBuffer buffer(1024, &source);
ObuHeader header;
auto obu = AudioElementObu::CreateFromBuffer(header, buffer);

// Validate
EXPECT_TRUE(obu.ok());
EXPECT_EQ(obu.value().GetAudioElementType(),
AudioElementObu::kAudioElementSceneBased);
EXPECT_EQ(obu.value().num_substreams_, 4);

AmbisonicsMonoConfig expected_ambisonics_mono_config = {
.output_channel_count = 4,
.substream_count = 4,
.channel_mapping = {0, 1, 2, 3}};
AmbisonicsConfig expected_ambisonics_config = {
.ambisonics_mode = AmbisonicsConfig::kAmbisonicsModeMono,
.ambisonics_config = expected_ambisonics_mono_config};
EXPECT_EQ(std::get<AmbisonicsConfig>(obu.value().config_),
expected_ambisonics_config);
}

TEST(CreateFromBuffer, ValidAmbisonicsProjectionConfig) {
std::vector<uint8_t> source = {
// `audio_element_id`.
1, // Arbitrary. Doesn't matter for this test.
// `audio_element_type (3), reserved (5).
AudioElementObu::kAudioElementSceneBased << 5, // Req. for Ambisonics.
// `codec_config_id`.
2, // Arbitrary. Doesn't matter for this test.
// `num_substreams`.
4, // Matters for validating the AmbisonicsMonoConfig.
// `audio_substream_ids`. Arbitrary IDs, need one per substream.
3, 4, 5, 6,
// `num_parameters`.
0, // Skip parameters, not part of the tested AmbisonicsMonoConfig.

// Now we're into the fields of the AmbisonicsMonoConfig.
static_cast<uint8_t>(
AmbisonicsConfig::AmbisonicsMode::kAmbisonicsModeProjection),
4, // `output_channel_count`
4, // `substream_count`
0, // `coupled_substream_count`
// We need (`substream_count` + `coupled_substream_count`) *
// `output_channel_count` values for `demixing matrix`.
0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06,
0x00, 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c,
0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10};
ReadBitBuffer buffer(1024, &source);
ObuHeader header;
auto obu = AudioElementObu::CreateFromBuffer(header, buffer);

// Validate
EXPECT_TRUE(obu.ok());
EXPECT_EQ(obu.value().GetAudioElementType(),
AudioElementObu::kAudioElementSceneBased);
EXPECT_EQ(obu.value().num_substreams_, 4);

AmbisonicsProjectionConfig expected_ambisonics_projection_config = {
.output_channel_count = 4,
.substream_count = 4,
.coupled_substream_count = 0,
.demixing_matrix = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16}};
AmbisonicsConfig expected_ambisonics_config = {
.ambisonics_mode = AmbisonicsConfig::kAmbisonicsModeProjection,
.ambisonics_config = expected_ambisonics_projection_config};
AmbisonicsConfig actual_ambisonics_config =
std::get<AmbisonicsConfig>(obu.value().config_);
EXPECT_EQ(std::get<AmbisonicsConfig>(obu.value().config_),
expected_ambisonics_config);
}

} // namespace
} // namespace iamf_tools

0 comments on commit 98b4b63

Please sign in to comment.