/* * Copyright (c) 2024, 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/codec/flac_decoder.h" #include #include #include #include #include "absl/log/log.h" #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "iamf/cli/codec/decoder_base.h" #include "include/FLAC/format.h" #include "include/FLAC/ordinals.h" #include "include/FLAC/stream_decoder.h" namespace iamf_tools { FLAC__StreamDecoderReadStatus FlacDecoder::LibFlacReadCallback( const FLAC__StreamDecoder* /*decoder*/, FLAC__byte buffer[], size_t* bytes, void* client_data) { auto flac_decoder = static_cast(client_data); auto encoded_frame = flac_decoder->GetEncodedFrame(); if (encoded_frame.empty()) { // No more data to read. *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } if (encoded_frame.size() > *bytes) { LOG(ERROR) << "Encoded frame size " << encoded_frame.size() << " is larger than the libflac buffer size " << *bytes; *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } for (int i = 0; i < encoded_frame.size(); ++i) { buffer[i] = encoded_frame[i]; } *bytes = encoded_frame.size(); return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } FLAC__StreamDecoderWriteStatus FlacDecoder::LibFlacWriteCallback( const FLAC__StreamDecoder* /*decoder*/, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* client_data) { auto* flac_decoder = static_cast(client_data); const auto num_samples_per_channel = frame->header.blocksize; if (flac_decoder->GetNumSamplesPerChannel() != frame->header.blocksize) { LOG(ERROR) << "Frame blocksize " << frame->header.blocksize << " does not match expected number of samples per channel " << flac_decoder->GetNumSamplesPerChannel(); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } std::vector> decoded_samples( num_samples_per_channel, std::vector(frame->header.channels)); // Note: libFLAC represents data in a planar fashion, so each channel is // stored in a separate array, and the elements within those arrays represent // time ticks. However, we store samples in an interleaved fashion, which // means that each outer entry in decoded_samples represents a time tick, and // each element within represents a channel. So we need to transpose the data // from libFLAC's planar format into our interleaved format. for (int c = 0; c < frame->header.channels; ++c) { const FLAC__int32* const channel_buffer = buffer[c]; for (int t = 0; t < num_samples_per_channel; ++t) { decoded_samples[t][c] = channel_buffer[t] << (32 - frame->header.bits_per_sample); } } flac_decoder->SetDecodedFrame(decoded_samples); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } void FlacDecoder::LibFlacErrorCallback(const FLAC__StreamDecoder* /*decoder*/, FLAC__StreamDecoderErrorStatus status, void* /*client_data*/) { switch (status) { case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC: LOG(ERROR) << "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC"; break; case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: LOG(ERROR) << "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER"; break; case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH: LOG(ERROR) << "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH"; break; case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM: LOG(ERROR) << "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"; break; default: LOG(ERROR) << "Unknown FLAC__StreamDecoderErrorStatus= " << status; break; } } FlacDecoder::FlacDecoder(int num_channels, uint32_t num_samples_per_frame) : DecoderBase(num_channels, num_samples_per_frame) {} FlacDecoder::~FlacDecoder() { if (decoder_ != nullptr) { FLAC__stream_decoder_delete(decoder_); } } absl::Status FlacDecoder::Initialize() { decoder_ = FLAC__stream_decoder_new(); if (decoder_ == nullptr) { return absl::InternalError("Failed to create FLAC stream decoder."); } FLAC__StreamDecoderInitStatus status = FLAC__stream_decoder_init_stream( decoder_, LibFlacReadCallback, /*seek_callback=*/nullptr, /*tell_callback=*/nullptr, /*length_callback=*/nullptr, /*eof_callback=*/nullptr, LibFlacWriteCallback, /*metadata_callback=*/nullptr, LibFlacErrorCallback, static_cast(this)); if (status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { return absl::InternalError( absl::StrCat("Failed to initialize FLAC stream decoder: ", status)); } return absl::OkStatus(); } absl::Status FlacDecoder::Finalize() { // Signal to `libflac` the decoder is finished. if (!FLAC__stream_decoder_finish(decoder_)) { return absl::InternalError("Failed to finalize Flac stream decoder."); } return absl::OkStatus(); } absl::Status FlacDecoder::DecodeAudioFrame( const std::vector& encoded_frame) { num_valid_ticks_ = 0; // Set the encoded frame to be decoded; the libflac decoder will copy the // data using LibFlacReadCallback. encoded_frame_ = encoded_frame; if (!FLAC__stream_decoder_process_single(decoder_)) { // More specific error information is logged in LibFlacErrorCallback. return absl::InternalError("Failed to decode FLAC frame."); } // Get the decoded frame, which will have been set by LibFlacWriteCallback. // Copy the first `num_valid_ticks_` time samples to `decoded_samples_`. num_valid_ticks_ = decoded_frame_.size(); std::copy(decoded_frame_.begin(), decoded_frame_.begin() + num_valid_ticks_, decoded_samples_.begin()); return absl::OkStatus(); } } // namespace iamf_tools