• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022, 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/common/utils/numeric_utils.h"
13 
14 #include <bit>
15 #include <cmath>
16 #include <cstddef>
17 #include <cstdint>
18 #include <limits>
19 #include <vector>
20 
21 #include "absl/log/check.h"
22 #include "absl/log/log.h"
23 #include "absl/status/status.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/string_view.h"
26 #include "absl/types/span.h"
27 
28 namespace iamf_tools {
29 
AddUint32CheckOverflow(uint32_t x_1,uint32_t x_2,uint32_t & result)30 absl::Status AddUint32CheckOverflow(uint32_t x_1, uint32_t x_2,
31                                     uint32_t& result) {
32   // Add in the payload size.
33   const uint64_t sum = static_cast<uint64_t>(x_1) + static_cast<uint64_t>(x_2);
34   // Check if this would overflow as a `uint32_t`.
35   if (sum > std::numeric_limits<uint32_t>::max()) {
36     return absl::InvalidArgumentError(
37         "Result of AddUint32CheckOverflow would overflow a uint32_t.");
38   }
39   result = static_cast<uint32_t>(sum);
40   return absl::OkStatus();
41 }
42 
FloatToQ7_8(float value,int16_t & result)43 absl::Status FloatToQ7_8(float value, int16_t& result) {
44   // Q7.8 format can represent values in the range [-2^7, 2^7 - 2^-8].
45   if (std::isnan(value) || value < -128 || (128.0 - 1.0 / 256.0) < value) {
46     return absl::UnknownError(absl::StrCat(
47         "Value, ", value, " cannot be represented in Q7.8 format."));
48   }
49   result = static_cast<int16_t>(value * (1 << 8));
50   return absl::OkStatus();
51 }
52 
Q7_8ToFloat(int16_t value)53 float Q7_8ToFloat(int16_t value) {
54   return static_cast<float>(value) * 1.0f / 256.0f;
55 }
56 
FloatToQ0_8(float value,uint8_t & result)57 absl::Status FloatToQ0_8(float value, uint8_t& result) {
58   // Q0.8 format can represent values in the range [0, 1 - 2^-8].
59   if (std::isnan(value) || value < 0 || 1 <= value) {
60     return absl::UnknownError(absl::StrCat(
61         "Value, ", value, " cannot be represented in Q0.8 format."));
62   }
63 
64   result = static_cast<uint8_t>(value * (1 << 8));
65   return absl::OkStatus();
66 }
67 
Q0_8ToFloat(uint8_t value)68 float Q0_8ToFloat(uint8_t value) {
69   return static_cast<float>(value) * 1.0f / 256.0f;
70 }
71 
LittleEndianBytesToInt32(absl::Span<const uint8_t> bytes,int32_t & output)72 absl::Status LittleEndianBytesToInt32(absl::Span<const uint8_t> bytes,
73                                       int32_t& output) {
74   // If we have bytes A, B, C, D, then we need to read them as:
75   //   (D << 24) | (C << 16) | (B << 8) | A
76   // If we have less than four bytes, e.g. two bytes, we would read them as:
77   //   (B << 8) | A
78   // with the upper bits filled with the sign bit.
79   const size_t num_bytes = bytes.size();
80   if (num_bytes > 4 || num_bytes < 1) {
81     return absl::InvalidArgumentError("Need [1, 4] bytes to make an int32_t");
82   }
83   int32_t result = 0;
84   for (int i = 0; i < bytes.size(); ++i) {
85     const auto shift = 8 * ((4 - num_bytes) + i);
86     result |= static_cast<int32_t>(bytes[i]) << shift;
87   }
88   output = result;
89   return absl::OkStatus();
90 }
91 
BigEndianBytesToInt32(absl::Span<const uint8_t> bytes,int32_t & output)92 absl::Status BigEndianBytesToInt32(absl::Span<const uint8_t> bytes,
93                                    int32_t& output) {
94   // If we have bytes A, B, C, D, then we need to read them as:
95   //   (A << 24) | (B << 16) | (C << 8) | D
96   // If we have less than four bytes, e.g. two bytes, we would read them as:
97   //   (A << 8) | B
98   // with the upper bits filled with the sign bit.
99   auto reversed_bytes = std::vector<uint8_t>(bytes.rbegin(), bytes.rend());
100   return LittleEndianBytesToInt32(reversed_bytes, output);
101 }
102 
ClipDoubleToInt32(double input,int32_t & output)103 absl::Status ClipDoubleToInt32(double input, int32_t& output) {
104   if (std::isnan(input)) {
105     return absl::InvalidArgumentError("Input is NaN.");
106   }
107 
108   if (input > std::numeric_limits<int32_t>::max()) {
109     output = std::numeric_limits<int32_t>::max();
110   } else if (input < std::numeric_limits<int32_t>::min()) {
111     output = std::numeric_limits<int32_t>::min();
112   } else {
113     output = static_cast<int32_t>(input);
114   }
115 
116   return absl::OkStatus();
117 }
118 
IsNativeBigEndian()119 bool IsNativeBigEndian() {
120   if (std::endian::native == std::endian::big) {
121     return true;
122   } else if (std::endian::native == std::endian::little) {
123     return false;
124   } else {
125     CHECK(false) << "Mixed-endian systems are not supported.";
126   }
127 }
128 
129 }  // namespace iamf_tools
130