blob: a941132b2c994e4414907edb7c6a0729ee335c69 [file]
/*
* 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/cli/audio_frame_decoder.h"
#include <memory>
#include <utility>
#include <variant>
#include "absl/log/check.h"
#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/cli/audio_element_with_data.h"
#include "iamf/cli/audio_frame_with_data.h"
#include "iamf/cli/codec/decoder_base.h"
#include "iamf/cli/codec/lpcm_decoder.h"
#include "iamf/common/utils/macros.h"
#include "iamf/obu/codec_config.h"
#include "iamf/obu/decoder_config/aac_decoder_config.h"
#include "iamf/obu/decoder_config/lpcm_decoder_config.h"
#include "iamf/obu/decoder_config/opus_decoder_config.h"
// These defines are not part of an official API and are likely to change or be
// removed. Please do not depend on them.
// TODO(b/401063570): Remove these statements when no longer disabling FLAC/AAC.
#ifndef IAMF_TOOLS_DISABLE_AAC_DECODER
#include "iamf/cli/codec/aac_decoder.h"
#endif
#ifndef IAMF_TOOLS_DISABLE_FLAC_DECODER
#include "iamf/cli/codec/flac_decoder.h"
#endif
#ifndef IAMF_TOOLS_DISABLE_OPUS_DECODER
#include "iamf/cli/codec/opus_decoder.h"
#endif
namespace iamf_tools {
namespace {
absl::StatusOr<std::unique_ptr<DecoderBase>> CreateDecoder(
const CodecConfigObu& codec_config, int num_channels) {
const auto* decoder_config = &codec_config.GetCodecConfig().decoder_config;
switch (codec_config.GetCodecConfig().codec_id) {
using enum CodecConfig::CodecId;
case kCodecIdLpcm: {
auto* lpcm_decoder_config =
std::get_if<LpcmDecoderConfig>(decoder_config);
if (lpcm_decoder_config == nullptr) {
return absl::InvalidArgumentError(
"CodecConfigObu does not contain an `LpcmDecoderConfig`.");
}
return LpcmDecoder::Create(*lpcm_decoder_config, num_channels,
codec_config.GetNumSamplesPerFrame());
}
#ifndef IAMF_TOOLS_DISABLE_OPUS_DECODER
case kCodecIdOpus: {
auto* opus_decoder_config =
std::get_if<OpusDecoderConfig>(decoder_config);
if (opus_decoder_config == nullptr) {
return absl::InvalidArgumentError(
"CodecConfigObu does not contain an `OpusDecoderConfig`.");
}
return OpusDecoder::Create(*opus_decoder_config, num_channels,
codec_config.GetNumSamplesPerFrame());
}
#endif
#ifndef IAMF_TOOLS_DISABLE_AAC_DECODER
case kCodecIdAacLc: {
auto* aac_decoder_config = std::get_if<AacDecoderConfig>(decoder_config);
if (aac_decoder_config == nullptr) {
return absl::InvalidArgumentError(
"CodecConfigObu does not contain an `AacDecoderConfig`.");
}
return AacDecoder::Create(*aac_decoder_config, num_channels,
codec_config.GetNumSamplesPerFrame());
}
#endif
#ifndef IAMF_TOOLS_DISABLE_FLAC_DECODER
case kCodecIdFlac:
return FlacDecoder::Create(num_channels,
codec_config.GetNumSamplesPerFrame());
#endif
default:
return absl::InvalidArgumentError(
absl::StrCat("Unrecognized or disabled codec_id= ",
codec_config.GetCodecConfig().codec_id));
}
}
} // namespace
// Initializes all decoders based on the corresponding Audio Element and Codec
// Config OBUs.
absl::Status AudioFrameDecoder::InitDecodersForSubstreams(
const SubstreamIdLabelsMap& substream_id_to_labels,
const CodecConfigObu& codec_config) {
for (const auto& [substream_id, labels] : substream_id_to_labels) {
auto& decoder_for_substream = substream_id_to_decoder_[substream_id];
if (decoder_for_substream != nullptr) {
return absl::InvalidArgumentError(absl::StrCat(
"Already initialized decoder for substream ID: ", substream_id,
". Maybe multiple Audio Element OBUs have the same substream ID?"));
}
const int num_channels = static_cast<int>(labels.size());
// Create the decoder, unwrap it and move it into the map, if it is valid.
absl::StatusOr<std::unique_ptr<DecoderBase>> new_decoder =
CreateDecoder(codec_config, num_channels);
if (!new_decoder.ok()) {
return new_decoder.status();
}
// The factories are not supposed to return an OK and `nullptr` decoder.
// For defensive programming, check for that case.
CHECK_NE(*new_decoder, nullptr);
decoder_for_substream = std::move(*new_decoder);
}
return absl::OkStatus();
}
absl::StatusOr<DecodedAudioFrame> AudioFrameDecoder::Decode(
const AudioFrameWithData& audio_frame) {
auto decoder_iter =
substream_id_to_decoder_.find(audio_frame.obu.GetSubstreamId());
if (decoder_iter == substream_id_to_decoder_.end() ||
decoder_iter->second == nullptr) {
return absl::InvalidArgumentError(
absl::StrCat("No decoder found for substream ID: ",
audio_frame.obu.GetSubstreamId()));
}
// Decode the samples with the specific decoder associated with this
// substream.
auto& decoder = *decoder_iter->second;
RETURN_IF_NOT_OK(decoder.DecodeAudioFrame(
absl::MakeConstSpan(audio_frame.obu.audio_frame_)));
// Return a frame. Most fields are copied from the encoded frame.
return DecodedAudioFrame{
.substream_id = audio_frame.obu.GetSubstreamId(),
.start_timestamp = audio_frame.start_timestamp,
.end_timestamp = audio_frame.end_timestamp,
.samples_to_trim_at_end =
audio_frame.obu.header_.num_samples_to_trim_at_end,
.samples_to_trim_at_start =
audio_frame.obu.header_.num_samples_to_trim_at_start,
.decoded_samples = decoder.ValidDecodedSamples(),
.down_mixing_params = audio_frame.down_mixing_params,
.recon_gain_info_parameter_data =
audio_frame.recon_gain_info_parameter_data,
.audio_element_with_data = audio_frame.audio_element_with_data,
};
}
} // namespace iamf_tools