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/obu/obu_base.h"
14
15 #include <cstdint>
16 #include <memory>
17
18 #include "absl/status/status.h"
19 #include "absl/strings/str_cat.h"
20 #include "absl/types/span.h"
21 #include "iamf/common/leb_generator.h"
22 #include "iamf/common/read_bit_buffer.h"
23 #include "iamf/common/utils/macros.h"
24 #include "iamf/common/write_bit_buffer.h"
25 #include "iamf/obu/obu_header.h"
26
27 namespace iamf_tools {
28
~ObuBase()29 ObuBase::~ObuBase() {}
30
ValidateAndWriteObu(WriteBitBuffer & final_wb) const31 absl::Status ObuBase::ValidateAndWriteObu(WriteBitBuffer& final_wb) const {
32 // Allocate a temporary buffer big enough for most OBUs to assist writing, but
33 // make it resizable so it can be expanded for large OBUs.
34 static const int64_t kBufferSize = 1024;
35 WriteBitBuffer temp_wb(kBufferSize, final_wb.leb_generator_);
36
37 // Write the payload to a temporary buffer using the virtual function.
38 RETURN_IF_NOT_OK(ValidateAndWritePayload(temp_wb));
39 // Write the footer to the temporary buffer.
40 RETURN_IF_NOT_OK(temp_wb.WriteUint8Span(absl::MakeConstSpan(footer_)));
41 if (!temp_wb.IsByteAligned()) {
42 // The header stores the size of the OBU in bytes.
43 return absl::InvalidArgumentError(absl::StrCat(
44 "Expected the OBU payload to be byte-aligned: ", temp_wb.bit_offset()));
45 }
46
47 // Write the header now that the payload size is known.
48 const int64_t payload_size_bytes = temp_wb.bit_buffer().size();
49
50 RETURN_IF_NOT_OK(header_.ValidateAndWrite(payload_size_bytes, final_wb));
51
52 const int64_t expected_end_payload =
53 final_wb.bit_offset() + payload_size_bytes * 8;
54
55 // Copy over the payload into the final write buffer.
56 RETURN_IF_NOT_OK(
57 final_wb.WriteUint8Span(absl::MakeConstSpan(temp_wb.bit_buffer())));
58
59 // Validate the write buffer is at the expected location expected after
60 // writing the payload.
61 if (expected_end_payload != final_wb.bit_offset()) {
62 return absl::InvalidArgumentError(absl::StrCat(
63 "Expected end_payload: ", expected_end_payload,
64 " to be equal to write buffer bit offset: ", final_wb.bit_offset()));
65 }
66
67 return absl::OkStatus();
68 }
69
ReadAndValidatePayload(int64_t payload_size_bytes,ReadBitBuffer & rb)70 absl::Status ObuBase::ReadAndValidatePayload(int64_t payload_size_bytes,
71 ReadBitBuffer& rb) {
72 const int64_t expected_final_position = rb.Tell() + (payload_size_bytes * 8);
73
74 // Read the known portion of the payload.
75 RETURN_IF_NOT_OK(ReadAndValidatePayloadDerived(payload_size_bytes, rb));
76 const int64_t final_position = rb.Tell();
77
78 // Read the remaining of the payload (if any) into the footer.
79 if (expected_final_position == final_position) {
80 return absl::OkStatus();
81 } else if (expected_final_position > final_position) {
82 if ((expected_final_position - final_position) % 8 != 0) {
83 return absl::InvalidArgumentError(
84 absl::StrCat("Expected `ReadAndValidatePayloadDerived` to write a "
85 "multiple of 8 bits for obu_type=",
86 header_.obu_type));
87 }
88 const int64_t num_bytes_to_read =
89 (expected_final_position - final_position) / 8;
90 footer_.resize(num_bytes_to_read);
91 return rb.ReadUint8Span(absl::MakeSpan(footer_));
92 } else {
93 // The dispatched function read past the end of the payload. Something could
94 // be inconsistent between the parsing logic and the claimed OBU size.
95 return absl::InvalidArgumentError(absl::StrCat(
96 "Read beyond the end of the OBU for obu_type=", header_.obu_type));
97 }
98 }
99
PrintHeader(int64_t payload_size_bytes) const100 void ObuBase::PrintHeader(int64_t payload_size_bytes) const {
101 // TODO(b/299480731): Use the correct `LebGenerator` when printing OBU
102 // headers.
103 header_.Print(*LebGenerator::Create(), payload_size_bytes);
104 }
105
106 } // namespace iamf_tools
107