blob: fb798d1eefaeaac702862f33f5670571cc1d6f56 [file] [log] [blame]
/*
* 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/audio_frame.h"
#include <cstdint>
#include <vector>
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/types/span.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_base.h"
#include "iamf/obu/obu_header.h"
#include "iamf/obu/types.h"
namespace iamf_tools {
namespace {
ObuType GetObuType(uint32_t substream_id) {
constexpr int kMaxImplicitAudioFrameID =
kObuIaAudioFrameId17 - kObuIaAudioFrameId0;
if (substream_id > kMaxImplicitAudioFrameID) {
return kObuIaAudioFrame;
}
return static_cast<ObuType>(static_cast<uint32_t>(kObuIaAudioFrameId0) +
substream_id);
}
} // namespace
AudioFrameObu::AudioFrameObu(const ObuHeader& header,
DecodedUleb128 substream_id,
absl::Span<const uint8_t> audio_frame)
: ObuBase(header, GetObuType(substream_id)),
audio_frame_(audio_frame.begin(), audio_frame.end()),
audio_substream_id_(substream_id) {}
absl::StatusOr<AudioFrameObu> AudioFrameObu::CreateFromBuffer(
const ObuHeader& header, int64_t payload_size, ReadBitBuffer& rb) {
AudioFrameObu audio_frame_obu(header);
RETURN_IF_NOT_OK(audio_frame_obu.ReadAndValidatePayload(payload_size, rb));
return audio_frame_obu;
}
absl::Status AudioFrameObu::ValidateAndWritePayload(WriteBitBuffer& wb) const {
if (header_.obu_type == kObuIaAudioFrame) {
// The ID is explicitly in the bitstream when `kObuIaAudioFrame`. Otherwise
// it is implied by `obu_type`.
RETURN_IF_NOT_OK(wb.WriteUleb128(audio_substream_id_));
}
RETURN_IF_NOT_OK(wb.WriteUint8Span(absl::MakeConstSpan(audio_frame_)));
return absl::OkStatus();
}
absl::Status AudioFrameObu::ReadAndValidatePayloadDerived(int64_t payload_size,
ReadBitBuffer& rb) {
int8_t encoded_uleb128_size = 0;
if (header_.obu_type == kObuIaAudioFrame) {
// The ID is explicitly in the bitstream when `kObuIaAudioFrame`. Otherwise
// it is implied by `obu_type`.
RETURN_IF_NOT_OK(rb.ReadULeb128(audio_substream_id_, encoded_uleb128_size));
} else {
audio_substream_id_ = header_.obu_type - kObuIaAudioFrameId0;
}
if (payload_size < 0 || payload_size < encoded_uleb128_size) {
return absl::InvalidArgumentError(absl::StrCat(
"Less than zero bytes remaining in payload. payload_size=",
payload_size, " encoded_uleb128_size=", encoded_uleb128_size));
}
audio_frame_.resize(payload_size - encoded_uleb128_size);
return rb.ReadUint8Span(absl::MakeSpan(audio_frame_));
}
void AudioFrameObu::PrintObu() const {
LOG(INFO) << " audio_substream_id= " << GetSubstreamId();
LOG(INFO) << " // obu_trimming_status_flag= "
<< header_.obu_trimming_status_flag;
LOG(INFO) << " // samples_to_trim_at_end= "
<< header_.num_samples_to_trim_at_end;
LOG(INFO) << " // samples_to_trim_at_start= "
<< header_.num_samples_to_trim_at_start;
LOG(INFO) << " // size_of(audio_frame)= " << audio_frame_.size();
}
} // namespace iamf_tools