blob: 17b34474acf7f5bea76cbf74e284cf62427208c5 [file] [log] [blame]
/*
* 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 <algorithm>
#include <cstddef>
#include <cstdint>
#include <vector>
#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<FlacDecoder*>(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<FlacDecoder*>(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<std::vector<int32_t>> decoded_samples(
num_samples_per_channel, std::vector<int32_t>(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<void*>(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<uint8_t>& 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