Skip to content

Commit

Permalink
AudioFrameDecoder: Process a single frame at a time.
Browse files Browse the repository at this point in the history
  - Instead of outputting by appending to a list, directly process one frame at a time.
    - The new interface is more generic and convenient if any call sites have their input in a different form or a different output arrangement.
    - Removes the thin loop which had to perform lookups each iteration anyway.
  - Directly return `abls::StatusOr`. Instead of leaving the reference in unknown state.
  - Simplify some tests. Empty list input, or append are no longer possible.

PiperOrigin-RevId: 691387035
  • Loading branch information
jwcullen committed Nov 1, 2024
1 parent 67c6cf2 commit 399bd5c
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 143 deletions.
1 change: 1 addition & 0 deletions iamf/cli/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ cc_library(
"@com_google_absl//absl/container:node_hash_map",
"@com_google_absl//absl/log",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
Expand Down
73 changes: 29 additions & 44 deletions iamf/cli/audio_frame_decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/
#include "iamf/cli/audio_frame_decoder.h"

#include <list>
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
Expand All @@ -20,7 +20,6 @@
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "iamf/cli/audio_element_with_data.h"
#include "iamf/cli/audio_frame_with_data.h"
#include "iamf/cli/codec/aac_decoder.h"
Expand Down Expand Up @@ -63,29 +62,6 @@ absl::Status InitializeDecoder(const CodecConfigObu& codec_config,
return absl::OkStatus();
}

absl::Status DecodeAudioFrame(const AudioFrameWithData& encoded_frame,
DecoderBase* decoder,
DecodedAudioFrame& decoded_audio_frame) {
// Copy over some fields from the encoded frame.
decoded_audio_frame.substream_id = encoded_frame.obu.GetSubstreamId();
decoded_audio_frame.start_timestamp = encoded_frame.start_timestamp;
decoded_audio_frame.end_timestamp = encoded_frame.end_timestamp;
decoded_audio_frame.samples_to_trim_at_end =
encoded_frame.obu.header_.num_samples_to_trim_at_end;
decoded_audio_frame.samples_to_trim_at_start =
encoded_frame.obu.header_.num_samples_to_trim_at_start;
decoded_audio_frame.down_mixing_params = encoded_frame.down_mixing_params;
decoded_audio_frame.audio_element_with_data =
encoded_frame.audio_element_with_data;

// Decode the samples with the specific decoder associated with this
// substream.
RETURN_IF_NOT_OK(decoder->DecodeAudioFrame(
encoded_frame.obu.audio_frame_, decoded_audio_frame.decoded_samples));

return absl::OkStatus();
}

} // namespace

// Initializes all decoders and wav writers based on the corresponding Audio
Expand All @@ -111,26 +87,35 @@ absl::Status AudioFrameDecoder::InitDecodersForSubstreams(
return absl::OkStatus();
}

absl::Status AudioFrameDecoder::Decode(
const std::list<AudioFrameWithData>& encoded_audio_frames,
std::list<DecodedAudioFrame>& decoded_audio_frames) {
// Decode all frames in all substreams.
for (const auto& audio_frame : encoded_audio_frames) {
auto decoder_iter =
substream_id_to_decoder_.find(audio_frame.obu.GetSubstreamId());
if (decoder_iter == substream_id_to_decoder_.end()) {
return absl::InvalidArgumentError(
absl::StrCat("No decoder found for substream ID: ",
audio_frame.obu.GetSubstreamId()));
}

DecodedAudioFrame decoded_audio_frame;
RETURN_IF_NOT_OK(DecodeAudioFrame(audio_frame, decoder_iter->second.get(),
decoded_audio_frame));
decoded_audio_frames.push_back(std::move(decoded_audio_frame));
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()));
}

return absl::OkStatus();
// Decode the samples with the specific decoder associated with this
// substream.
std::vector<std::vector<int32_t>> decoded_samples;
RETURN_IF_NOT_OK(decoder_iter->second->DecodeAudioFrame(
audio_frame.obu.audio_frame_, decoded_samples));

// 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 = decoded_samples,
.down_mixing_params = audio_frame.down_mixing_params,
.audio_element_with_data = audio_frame.audio_element_with_data,
};
}

} // namespace iamf_tools
13 changes: 6 additions & 7 deletions iamf/cli/audio_frame_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
#define CLI_AUDIO_FRAME_DECODER_H_

#include <cstdint>
#include <list>
#include <memory>
#include <vector>

#include "absl/container/node_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "iamf/cli/audio_element_with_data.h"
#include "iamf/cli/audio_frame_with_data.h"
#include "iamf/cli/codec/decoder_base.h"
Expand Down Expand Up @@ -85,14 +85,13 @@ class AudioFrameDecoder {
const SubstreamIdLabelsMap& substream_id_to_labels,
const CodecConfigObu& codec_config);

/*!\brief Decodes a list of Audio Frame OBUs.
/*!\brief Decodes an Audio Frame OBU.
*
* \param encoded_audio_frames Input Audio Frame OBUs.
* \param decoded_audio_frames Output decoded audio frames.
* \return `absl::OkStatus()` on success. A specific status on failure.
* \param encoded_audio_frame Input Audio Frame OBU.
* \return Decoded audio frame on success. A specific status on failure.
*/
absl::Status Decode(const std::list<AudioFrameWithData>& encoded_audio_frames,
std::list<DecodedAudioFrame>& decoded_audio_frames);
absl::StatusOr<DecodedAudioFrame> Decode(
const AudioFrameWithData& encoded_audio_frame);

private:
// A map of substream IDs to the relevant decoder and codec config. This is
Expand Down
10 changes: 8 additions & 2 deletions iamf/cli/iamf_encoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <list>
#include <memory>
#include <optional>
#include <utility>
#include <vector>

#include "absl/container/flat_hash_map.h"
Expand Down Expand Up @@ -233,8 +234,13 @@ absl::Status IamfEncoder::OutputTemporalUnit(
// Decode the audio frames. They are required to determine the demixed
// frames.
std::list<DecodedAudioFrame> decoded_audio_frames;
RETURN_IF_NOT_OK(
audio_frame_decoder_->Decode(audio_frames, decoded_audio_frames));
for (const auto& audio_frame : audio_frames) {
auto decoded_audio_frame = audio_frame_decoder_->Decode(audio_frame);
if (!decoded_audio_frame.ok()) {
return decoded_audio_frame.status();
}
decoded_audio_frames.emplace_back(*decoded_audio_frame);
}

// Demix the audio frames.
IdLabeledFrameMap id_to_labeled_decoded_frame;
Expand Down
Loading

0 comments on commit 399bd5c

Please sign in to comment.