• 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 
13 #include "iamf/common/leb_generator.h"
14 
15 #include <cstdint>
16 #include <memory>
17 #include <variant>
18 #include <vector>
19 
20 #include "absl/log/log.h"
21 #include "absl/memory/memory.h"
22 #include "absl/status/status.h"
23 #include "absl/strings/str_cat.h"
24 #include "iamf/obu/types.h"
25 
26 namespace iamf_tools {
27 
28 namespace {
29 
30 /*!\brief A general struct to represent an LEB128.
31  *
32  * When `is_signed` is false this represents a ULEB128. Otherwise this
33  * represents an SLEB128. An LEB128 can be encoded in up to 8 bytes.
34  *
35  * A ULEB128 may have values from 0 to (1 << 32) - 1.
36  * An SLEB128 may have values from -(1 << 31) to (1 << 31) - 1.
37  * These bounds imply the decoded value can be stored in 32 bits.
38  */
39 struct Leb128 {
40   std::variant<DecodedUleb128, DecodedSleb128> decoded_val;
41   int8_t coded_size;
42   bool is_signed;
43 };
44 
45 /*!\brief Serializes the LEB128 and returns a status based on the result.
46  *
47  * Serializes a leb128 and returns a status based on the result. Each byte of a
48  * leb128 encodes 7 bits, the upper bit encodes whether it is the last byte in
49  * the sequence. Writes the number of written to the output argument.
50  *
51  * \param val Leb128 to serialize.
52  * \param min_size_encoding Controls whether the function writes the
53  *        smallest possible representation of a LEB128. When false codes the
54  *        LEB128 in `coded_size` bytes.
55  * \param buffer Buffer to serialize to.
56  * \return `absl::OkStatus()` if successful. `absl::InvalidArgumentError()`
57  *         if the initial `coded_size` was invalid. `absl::UnknownError()` if
58  *         the `coded_size` was insufficient to encode the value.
59  */
Leb128ToUint8Vector(const Leb128 & val,bool min_size_encoding,std::vector<uint8_t> & buffer)60 absl::Status Leb128ToUint8Vector(const Leb128& val, bool min_size_encoding,
61                                  std::vector<uint8_t>& buffer) {
62   // Reject LEB128s with invalid size.
63   if (val.coded_size < 1 || kMaxLeb128Size < val.coded_size) {
64     return absl::InvalidArgumentError("Invalid `coded_size`");
65   }
66 
67   buffer.clear();
68   buffer.reserve(val.coded_size);
69 
70   const bool decoded_is_negative =
71       val.is_signed && std::get<DecodedSleb128>(val.decoded_val) < 0;
72 
73   uint32_t temp_val = val.is_signed
74                           ? static_cast<DecodedUleb128>(
75                                 std::get<DecodedSleb128>(val.decoded_val))
76                           : std::get<DecodedUleb128>(val.decoded_val);
77   absl::Status status = absl::UnknownError("Unknown error");
78 
79   for (int i = 0; i < val.coded_size; i++) {
80     // Encode the next 7 bits.
81     buffer.push_back(0x80 | (temp_val & 0x7f));
82     temp_val >>= 7;  // Logical shift clears the upper 7 bits.
83 
84     if (decoded_is_negative) {
85       // For a negative SLEB128 set upper 7 bits (arithmetic shift).
86       temp_val |= 0xfe000000;
87     }
88 
89     // The encoding could end when it is negative and is all 1s (-1) or positive
90     // and all 0s.
91     uint32_t end_value = 0;
92     if (val.is_signed && (buffer.back() & 0x40))
93       end_value = static_cast<uint32_t>(-1);
94 
95     if (temp_val == end_value) {
96       status = absl::OkStatus();
97 
98       // Exit early if the `min_size_encoding` flag is set. Otherwise continue
99       // until the encoding is `val->coded_size` bytes long.
100       if (min_size_encoding) {
101         break;
102       }
103     }
104   }
105 
106   // Clear the final MSB to 0 to signal the end of the encoding.
107   buffer.back() &= 0x7f;
108 
109   if (!status.ok() && !min_size_encoding) {
110     auto error_message = absl::StrCat(
111         (val.is_signed ? std::get<DecodedSleb128>(val.decoded_val)
112                        : std::get<DecodedUleb128>(val.decoded_val)),
113         " requires at least ", buffer.size(), " bytes. The caller requested it",
114         " have a fixed size of ", val.coded_size);
115     status = absl::InvalidArgumentError(error_message);
116   }
117 
118   return status;
119 }
120 
121 }  // namespace
122 
123 // A trusted private constructor. The `Create()` functions ensure it is only
124 // called with expected arguments.
LebGenerator(GenerationMode generation_mode,int8_t fixed_size)125 LebGenerator::LebGenerator(GenerationMode generation_mode, int8_t fixed_size)
126     : generation_mode_(generation_mode), fixed_size_(fixed_size) {}
127 
Create(GenerationMode generation_mode,int8_t fixed_size)128 std::unique_ptr<LebGenerator> LebGenerator::Create(
129     GenerationMode generation_mode, int8_t fixed_size) {
130   switch (generation_mode) {
131     case GenerationMode::kMinimum:
132       return absl::WrapUnique(new LebGenerator(generation_mode, 0));
133     case GenerationMode::kFixedSize:
134       if (1 <= fixed_size && fixed_size <= kMaxLeb128Size) {
135         return absl::WrapUnique(new LebGenerator(generation_mode, fixed_size));
136       } else {
137         LOG(ERROR) << "Invalid fixed size: " << fixed_size;
138         return nullptr;
139       }
140     default:
141       LOG(ERROR) << "Invalid generation mode: "
142                  << absl::StrCat(generation_mode);
143       return nullptr;
144   }
145 }
146 
Uleb128ToUint8Vector(DecodedUleb128 input,std::vector<uint8_t> & buffer) const147 absl::Status LebGenerator::Uleb128ToUint8Vector(
148     DecodedUleb128 input, std::vector<uint8_t>& buffer) const {
149   switch (generation_mode_) {
150     case GenerationMode::kMinimum:
151       return Leb128ToUint8Vector({input, kMaxLeb128Size, false},
152                                  /*min_size_encoding=*/true, buffer);
153     case GenerationMode::kFixedSize:
154       return Leb128ToUint8Vector({input, fixed_size_, false},
155                                  /*min_size_encoding=*/false, buffer);
156     default:
157       return absl::UnknownError("Unknown `generation_mode_`.");
158   }
159 }
160 
Sleb128ToUint8Vector(DecodedSleb128 input,std::vector<uint8_t> & buffer) const161 absl::Status LebGenerator::Sleb128ToUint8Vector(
162     DecodedSleb128 input, std::vector<uint8_t>& buffer) const {
163   switch (generation_mode_) {
164     case GenerationMode::kMinimum:
165       return Leb128ToUint8Vector({input, kMaxLeb128Size, true},
166                                  /*min_size_encoding=*/true, buffer);
167     case GenerationMode::kFixedSize:
168       return Leb128ToUint8Vector({input, fixed_size_, true},
169                                  /*min_size_encoding=*/false, buffer);
170     default:
171       return absl::UnknownError("Unknown `generation_mode_`.");
172   }
173 }
174 
175 }  // namespace iamf_tools
176