1 /*
2 * Copyright (c) 2023, 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 #include "iamf/obu/decoder_config/opus_decoder_config.h"
13
14 #include <cstdint>
15
16 #include "absl/log/log.h"
17 #include "absl/status/status.h"
18 #include "absl/strings/str_cat.h"
19 #include "iamf/common/read_bit_buffer.h"
20 #include "iamf/common/utils/macros.h"
21 #include "iamf/common/utils/validation_utils.h"
22 #include "iamf/common/write_bit_buffer.h"
23
24 namespace iamf_tools {
25
26 /*!\brief The major version of Opus that is supported. */
27 const uint8_t kOpusMajorVersion = 0;
28
29 namespace {
30
ValidateOpusMajorVersion(uint8_t opus_major_version)31 absl::Status ValidateOpusMajorVersion(uint8_t opus_major_version) {
32 // Opus Major version is in upper 4 bits. Higher versions may break backwards
33 // compatibility and require software updates.
34 if (opus_major_version > kOpusMajorVersion) {
35 return absl::UnimplementedError("Unsupported Opus major version");
36 }
37 return absl::OkStatus();
38 }
39
40 // Validates the `OpusDecoderConfig`.
ValidatePayload(const OpusDecoderConfig & decoder_config)41 absl::Status ValidatePayload(const OpusDecoderConfig& decoder_config) {
42 // Version 0 is invalid in the OPUS spec.
43 if (decoder_config.version_ == 0) {
44 return absl::InvalidArgumentError(
45 absl::StrCat("Invalid version= ", decoder_config.version_));
46 }
47
48 // OPUS Major version is in upper 4 bits. Higher versions may break backwards
49 // compatibility and require software updates.
50 const uint8_t decoder_config_major_version =
51 (decoder_config.version_ & 0xf0) >> 4;
52 MAYBE_RETURN_IF_NOT_OK(
53 ValidateOpusMajorVersion(decoder_config_major_version));
54
55 // Various below fields are fixed. The real value is determined from the Audio
56 // Element OBU.
57 MAYBE_RETURN_IF_NOT_OK(ValidateEqual(decoder_config.output_channel_count_,
58 OpusDecoderConfig::kOutputChannelCount,
59 "output_channel_count"));
60 MAYBE_RETURN_IF_NOT_OK(ValidateEqual(decoder_config.output_gain_,
61 OpusDecoderConfig::kOutputGain,
62 "output_gain"));
63 MAYBE_RETURN_IF_NOT_OK(ValidateEqual(decoder_config.mapping_family_,
64 OpusDecoderConfig::kMappingFamily,
65 "mapping_family"));
66
67 return absl::OkStatus();
68 }
69
ValidateAudioRollDistance(uint32_t num_samples_per_frame,int16_t audio_roll_distance)70 absl::Status ValidateAudioRollDistance(uint32_t num_samples_per_frame,
71 int16_t audio_roll_distance) {
72 const auto expected_roll_distance =
73 OpusDecoderConfig::GetRequiredAudioRollDistance(num_samples_per_frame);
74 if (!expected_roll_distance.ok()) {
75 return expected_roll_distance.status();
76 }
77
78 return ValidateEqual(audio_roll_distance, *expected_roll_distance,
79 absl::StrCat("actual `audio_roll_distance` vs expected "
80 "when `num_samples_per_frame= ",
81 num_samples_per_frame));
82 }
83
84 } // namespace
85
GetRequiredAudioRollDistance(uint32_t num_samples_per_frame)86 absl::StatusOr<int16_t> OpusDecoderConfig::GetRequiredAudioRollDistance(
87 uint32_t num_samples_per_frame) {
88 // Constant used to calculate legal audio roll distance for Opus.
89 static constexpr int kOpusAudioRollDividend = 3840;
90
91 // Prevent divide by 0. This is redundant as the spec ensures that
92 // `num_samples_per_frame` SHALL NOT be 0.
93 if (num_samples_per_frame == 0) {
94 return absl::InvalidArgumentError(
95 absl::StrCat("Invalid num_samples_per_frame= ", num_samples_per_frame));
96 }
97
98 // Let R be the smallest integer greater than or equal to 3840 divided by the
99 // frame size. The audio roll distance must be -R.
100 int16_t expected_r =
101 static_cast<int16_t>(kOpusAudioRollDividend / num_samples_per_frame);
102 if (kOpusAudioRollDividend % num_samples_per_frame != 0) {
103 expected_r += 1;
104 }
105
106 return -1 * expected_r;
107 }
108
ValidateAndWrite(uint32_t num_samples_per_frame,int16_t audio_roll_distance,WriteBitBuffer & wb) const109 absl::Status OpusDecoderConfig::ValidateAndWrite(uint32_t num_samples_per_frame,
110 int16_t audio_roll_distance,
111 WriteBitBuffer& wb) const {
112 MAYBE_RETURN_IF_NOT_OK(
113 ValidateAudioRollDistance(num_samples_per_frame, audio_roll_distance));
114 RETURN_IF_NOT_OK(ValidatePayload(*this));
115 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(version_, 8));
116 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(output_channel_count_, 8));
117 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(pre_skip_, 16));
118 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(input_sample_rate_, 32));
119 RETURN_IF_NOT_OK(wb.WriteSigned16(output_gain_));
120 RETURN_IF_NOT_OK(wb.WriteUnsignedLiteral(mapping_family_, 8));
121
122 return absl::OkStatus();
123 }
124
ReadAndValidate(uint32_t num_samples_per_frame,int16_t audio_roll_distance,ReadBitBuffer & rb)125 absl::Status OpusDecoderConfig::ReadAndValidate(uint32_t num_samples_per_frame,
126 int16_t audio_roll_distance,
127 ReadBitBuffer& rb) {
128 RETURN_IF_NOT_OK(
129 ValidateAudioRollDistance(num_samples_per_frame, audio_roll_distance));
130
131 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(8, version_));
132 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(8, output_channel_count_));
133 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(16, pre_skip_));
134 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(32, input_sample_rate_));
135 RETURN_IF_NOT_OK(rb.ReadSigned16(output_gain_));
136 RETURN_IF_NOT_OK(rb.ReadUnsignedLiteral(8, mapping_family_));
137
138 RETURN_IF_NOT_OK(ValidatePayload(*this));
139 return absl::OkStatus();
140 }
141
Print() const142 void OpusDecoderConfig::Print() const {
143 LOG(INFO) << " decoder_config(opus):";
144 LOG(INFO) << " version= " << absl::StrCat(version_);
145 LOG(INFO) << " output_channel_count= "
146 << absl::StrCat(output_channel_count_);
147 LOG(INFO) << " pre_skip= " << pre_skip_;
148 LOG(INFO) << " input_sample_rate= " << input_sample_rate_;
149 LOG(INFO) << " output_gain= " << output_gain_;
150 LOG(INFO) << " mapping_family= " << absl::StrCat(mapping_family_);
151 }
152
153 } // namespace iamf_tools
154