• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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