/* * Copyright (c) 2022, Alliance for Open Media. All rights reserved * * This source code is subject to the terms of the BSD 3-Clause Clear License * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear * License was not distributed with this source code in the LICENSE file, you * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the * Alliance for Open Media Patent License 1.0 was not distributed with this * source code in the PATENTS file, you can obtain it at * www.aomedia.org/license/patent. */ #include "iamf/common/utils/numeric_utils.h" #include #include #include #include #include #include #include "absl/log/check.h" #include "absl/log/log.h" #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" namespace iamf_tools { absl::Status AddUint32CheckOverflow(uint32_t x_1, uint32_t x_2, uint32_t& result) { // Add in the payload size. const uint64_t sum = static_cast(x_1) + static_cast(x_2); // Check if this would overflow as a `uint32_t`. if (sum > std::numeric_limits::max()) { return absl::InvalidArgumentError( "Result of AddUint32CheckOverflow would overflow a uint32_t."); } result = static_cast(sum); return absl::OkStatus(); } absl::Status FloatToQ7_8(float value, int16_t& result) { // Q7.8 format can represent values in the range [-2^7, 2^7 - 2^-8]. if (std::isnan(value) || value < -128 || (128.0 - 1.0 / 256.0) < value) { return absl::UnknownError(absl::StrCat( "Value, ", value, " cannot be represented in Q7.8 format.")); } result = static_cast(value * (1 << 8)); return absl::OkStatus(); } float Q7_8ToFloat(int16_t value) { return static_cast(value) * 1.0f / 256.0f; } absl::Status FloatToQ0_8(float value, uint8_t& result) { // Q0.8 format can represent values in the range [0, 1 - 2^-8]. if (std::isnan(value) || value < 0 || 1 <= value) { return absl::UnknownError(absl::StrCat( "Value, ", value, " cannot be represented in Q0.8 format.")); } result = static_cast(value * (1 << 8)); return absl::OkStatus(); } float Q0_8ToFloat(uint8_t value) { return static_cast(value) * 1.0f / 256.0f; } absl::Status LittleEndianBytesToInt32(absl::Span bytes, int32_t& output) { // If we have bytes A, B, C, D, then we need to read them as: // (D << 24) | (C << 16) | (B << 8) | A // If we have less than four bytes, e.g. two bytes, we would read them as: // (B << 8) | A // with the upper bits filled with the sign bit. const size_t num_bytes = bytes.size(); if (num_bytes > 4 || num_bytes < 1) { return absl::InvalidArgumentError("Need [1, 4] bytes to make an int32_t"); } int32_t result = 0; for (int i = 0; i < bytes.size(); ++i) { const auto shift = 8 * ((4 - num_bytes) + i); result |= static_cast(bytes[i]) << shift; } output = result; return absl::OkStatus(); } absl::Status BigEndianBytesToInt32(absl::Span bytes, int32_t& output) { // If we have bytes A, B, C, D, then we need to read them as: // (A << 24) | (B << 16) | (C << 8) | D // If we have less than four bytes, e.g. two bytes, we would read them as: // (A << 8) | B // with the upper bits filled with the sign bit. auto reversed_bytes = std::vector(bytes.rbegin(), bytes.rend()); return LittleEndianBytesToInt32(reversed_bytes, output); } absl::Status ClipDoubleToInt32(double input, int32_t& output) { if (std::isnan(input)) { return absl::InvalidArgumentError("Input is NaN."); } if (input > std::numeric_limits::max()) { output = std::numeric_limits::max(); } else if (input < std::numeric_limits::min()) { output = std::numeric_limits::min(); } else { output = static_cast(input); } return absl::OkStatus(); } bool IsNativeBigEndian() { if (std::endian::native == std::endian::big) { return true; } else if (std::endian::native == std::endian::little) { return false; } else { CHECK(false) << "Mixed-endian systems are not supported."; } } } // namespace iamf_tools