| /* |
| * Copyright (c) 2023, 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/obu/obu_base.h" |
| |
| #include <cstdint> |
| #include <memory> |
| |
| #include "absl/status/status.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/types/span.h" |
| #include "iamf/common/leb_generator.h" |
| #include "iamf/common/read_bit_buffer.h" |
| #include "iamf/common/utils/macros.h" |
| #include "iamf/common/write_bit_buffer.h" |
| #include "iamf/obu/obu_header.h" |
| |
| namespace iamf_tools { |
| |
| ObuBase::~ObuBase() {} |
| |
| absl::Status ObuBase::ValidateAndWriteObu(WriteBitBuffer& final_wb) const { |
| // Allocate a temporary buffer big enough for most OBUs to assist writing, but |
| // make it resizable so it can be expanded for large OBUs. |
| static const int64_t kBufferSize = 1024; |
| WriteBitBuffer temp_wb(kBufferSize, final_wb.leb_generator_); |
| |
| // Write the payload to a temporary buffer using the virtual function. |
| RETURN_IF_NOT_OK(ValidateAndWritePayload(temp_wb)); |
| // Write the footer to the temporary buffer. |
| RETURN_IF_NOT_OK(temp_wb.WriteUint8Span(absl::MakeConstSpan(footer_))); |
| if (!temp_wb.IsByteAligned()) { |
| // The header stores the size of the OBU in bytes. |
| return absl::InvalidArgumentError(absl::StrCat( |
| "Expected the OBU payload to be byte-aligned: ", temp_wb.bit_offset())); |
| } |
| |
| // Write the header now that the payload size is known. |
| const int64_t payload_size_bytes = temp_wb.bit_buffer().size(); |
| |
| RETURN_IF_NOT_OK(header_.ValidateAndWrite(payload_size_bytes, final_wb)); |
| |
| const int64_t expected_end_payload = |
| final_wb.bit_offset() + payload_size_bytes * 8; |
| |
| // Copy over the payload into the final write buffer. |
| RETURN_IF_NOT_OK( |
| final_wb.WriteUint8Span(absl::MakeConstSpan(temp_wb.bit_buffer()))); |
| |
| // Validate the write buffer is at the expected location expected after |
| // writing the payload. |
| if (expected_end_payload != final_wb.bit_offset()) { |
| return absl::InvalidArgumentError(absl::StrCat( |
| "Expected end_payload: ", expected_end_payload, |
| " to be equal to write buffer bit offset: ", final_wb.bit_offset())); |
| } |
| |
| return absl::OkStatus(); |
| } |
| |
| absl::Status ObuBase::ReadAndValidatePayload(int64_t payload_size_bytes, |
| ReadBitBuffer& rb) { |
| const int64_t expected_final_position = rb.Tell() + (payload_size_bytes * 8); |
| |
| // Read the known portion of the payload. |
| RETURN_IF_NOT_OK(ReadAndValidatePayloadDerived(payload_size_bytes, rb)); |
| const int64_t final_position = rb.Tell(); |
| |
| // Read the remaining of the payload (if any) into the footer. |
| if (expected_final_position == final_position) { |
| return absl::OkStatus(); |
| } else if (expected_final_position > final_position) { |
| if ((expected_final_position - final_position) % 8 != 0) { |
| return absl::InvalidArgumentError( |
| absl::StrCat("Expected `ReadAndValidatePayloadDerived` to write a " |
| "multiple of 8 bits for obu_type=", |
| header_.obu_type)); |
| } |
| const int64_t num_bytes_to_read = |
| (expected_final_position - final_position) / 8; |
| footer_.resize(num_bytes_to_read); |
| return rb.ReadUint8Span(absl::MakeSpan(footer_)); |
| } else { |
| // The dispatched function read past the end of the payload. Something could |
| // be inconsistent between the parsing logic and the claimed OBU size. |
| return absl::InvalidArgumentError(absl::StrCat( |
| "Read beyond the end of the OBU for obu_type=", header_.obu_type)); |
| } |
| } |
| |
| void ObuBase::PrintHeader(int64_t payload_size_bytes) const { |
| // TODO(b/299480731): Use the correct `LebGenerator` when printing OBU |
| // headers. |
| header_.Print(*LebGenerator::Create(), payload_size_bytes); |
| } |
| |
| } // namespace iamf_tools |