1 /*
2 * Copyright (c) 2024, 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/bit_buffer_util.h"
13
14 #include <cstdint>
15 #include <vector>
16
17 #include "absl/status/status.h"
18
19 namespace iamf_tools {
20
21 // Checks to see if `bit_buffer` is writeable. If not, will resize the buffer
22 // accordingly, so long as `allow_resizing` is set to true.
CanWriteBits(const bool allow_resizing,const int num_bits,const int64_t bit_offset,std::vector<uint8_t> & bit_buffer)23 absl::Status CanWriteBits(const bool allow_resizing, const int num_bits,
24 const int64_t bit_offset,
25 std::vector<uint8_t>& bit_buffer) {
26 const int64_t size = static_cast<int64_t>(bit_buffer.size());
27 if (bit_offset + num_bits <= size * 8) {
28 return absl::OkStatus();
29 }
30
31 if (!allow_resizing) {
32 return absl::ResourceExhaustedError(
33 "The buffer does not have enough capacity to write and cannot be "
34 "resized.");
35 }
36
37 const int64_t required_bytes = ((bit_offset + num_bits) / 8) +
38 ((bit_offset + num_bits) % 8 == 0 ? 0 : 1);
39
40 // Adjust the size of the buffer.
41 bit_buffer.resize(required_bytes, 0);
42
43 return absl::OkStatus();
44 }
45
CanWriteBytes(const bool allow_resizing,const int num_bytes,const int64_t bit_offset,std::vector<uint8_t> & bit_buffer)46 absl::Status CanWriteBytes(const bool allow_resizing, const int num_bytes,
47 const int64_t bit_offset,
48 std::vector<uint8_t>& bit_buffer) {
49 return CanWriteBits(allow_resizing, num_bytes * 8, bit_offset, bit_buffer);
50 }
51
52 // Write one bit `bit` to `bit_buffer` using an AND or OR mask. All unwritten
53 // bits are unchanged. This function is designed to work even if the buffer has
54 // uninitialized data - this is done by calling CanWriteBit first. Has the side
55 // effect of incrementing bit_offset if successful.
WriteBit(int bit,int64_t & bit_offset,std::vector<uint8_t> & bit_buffer)56 absl::Status WriteBit(int bit, int64_t& bit_offset,
57 std::vector<uint8_t>& bit_buffer) {
58 if (bit_offset < 0) {
59 return absl::InvalidArgumentError("The bit offset should not be negative.");
60 }
61 const int64_t off = bit_offset;
62 const int64_t p = off >> 3;
63 const int q = 7 - static_cast<int>(off & 0x7);
64
65 if (bit == 0) {
66 // AND mask to set the target bit to 0 and leave others unchanged.
67 bit_buffer[p] &= ~(1 << q);
68 } else {
69 // OR mask to set the target bit to 1 and leave others unchanged.
70 bit_buffer[p] |= (1 << q);
71 }
72 bit_offset = off + 1;
73
74 return absl::OkStatus();
75 }
76 } // namespace iamf_tools
77