audio_core: Clean up AAC decoder infrastructure. (#7310)
This commit is contained in:
165
src/audio_core/hle/aac_decoder.cpp
Normal file
165
src/audio_core/hle/aac_decoder.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <neaacdec.h>
|
||||
#include "audio_core/hle/aac_decoder.h"
|
||||
|
||||
namespace AudioCore::HLE {
|
||||
|
||||
AACDecoder::AACDecoder(Memory::MemorySystem& memory) : memory(memory) {
|
||||
decoder = NeAACDecOpen();
|
||||
if (decoder == nullptr) {
|
||||
LOG_CRITICAL(Audio_DSP, "Could not open FAAD2 decoder.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto config = NeAACDecGetCurrentConfiguration(decoder);
|
||||
config->defObjectType = LC;
|
||||
config->outputFormat = FAAD_FMT_16BIT;
|
||||
if (!NeAACDecSetConfiguration(decoder, config)) {
|
||||
LOG_CRITICAL(Audio_DSP, "Could not configure FAAD2 decoder.");
|
||||
NeAACDecClose(decoder);
|
||||
decoder = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO(Audio_DSP, "Created FAAD2 AAC decoder.");
|
||||
}
|
||||
|
||||
AACDecoder::~AACDecoder() {
|
||||
if (decoder) {
|
||||
NeAACDecClose(decoder);
|
||||
decoder = nullptr;
|
||||
|
||||
LOG_INFO(Audio_DSP, "Destroyed FAAD2 AAC decoder.");
|
||||
}
|
||||
}
|
||||
|
||||
BinaryMessage AACDecoder::ProcessRequest(const BinaryMessage& request) {
|
||||
if (request.header.codec != DecoderCodec::DecodeAAC) {
|
||||
LOG_ERROR(Audio_DSP, "AAC decoder received unsupported codec: {}",
|
||||
static_cast<u16>(request.header.codec));
|
||||
return {
|
||||
.header =
|
||||
{
|
||||
.result = ResultStatus::Error,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
switch (request.header.cmd) {
|
||||
case DecoderCommand::Init: {
|
||||
BinaryMessage response = request;
|
||||
response.header.result = ResultStatus::Success;
|
||||
return response;
|
||||
}
|
||||
case DecoderCommand::EncodeDecode: {
|
||||
return Decode(request);
|
||||
}
|
||||
case DecoderCommand::Shutdown:
|
||||
case DecoderCommand::SaveState:
|
||||
case DecoderCommand::LoadState: {
|
||||
LOG_WARNING(Audio_DSP, "Got unimplemented AAC binary request: {}",
|
||||
static_cast<u16>(request.header.cmd));
|
||||
BinaryMessage response = request;
|
||||
response.header.result = ResultStatus::Success;
|
||||
return response;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Audio_DSP, "Got unknown AAC binary request: {}",
|
||||
static_cast<u16>(request.header.cmd));
|
||||
return {
|
||||
.header =
|
||||
{
|
||||
.result = ResultStatus::Error,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
BinaryMessage AACDecoder::Decode(const BinaryMessage& request) {
|
||||
BinaryMessage response{};
|
||||
response.header.codec = request.header.codec;
|
||||
response.header.cmd = request.header.cmd;
|
||||
response.decode_aac_response.size = request.decode_aac_request.size;
|
||||
// This is a hack to continue games when a failure occurs.
|
||||
response.decode_aac_response.sample_rate = DecoderSampleRate::Rate48000;
|
||||
response.decode_aac_response.num_channels = 2;
|
||||
response.decode_aac_response.num_samples = 1024;
|
||||
|
||||
if (decoder == nullptr) {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (request.decode_aac_request.src_addr < Memory::FCRAM_PADDR ||
|
||||
request.decode_aac_request.src_addr + request.decode_aac_request.size >
|
||||
Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
|
||||
LOG_ERROR(Audio_DSP, "Got out of bounds src_addr {:08x}",
|
||||
request.decode_aac_request.src_addr);
|
||||
return response;
|
||||
}
|
||||
u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
|
||||
u32 data_len = request.decode_aac_request.size;
|
||||
|
||||
unsigned long sample_rate;
|
||||
u8 num_channels;
|
||||
auto init_result = NeAACDecInit(decoder, data, data_len, &sample_rate, &num_channels);
|
||||
if (init_result < 0) {
|
||||
LOG_ERROR(Audio_DSP, "Could not initialize FAAD2 AAC decoder for request: {}", init_result);
|
||||
return response;
|
||||
}
|
||||
|
||||
// Advance past the frame header if needed.
|
||||
data += init_result;
|
||||
data_len -= init_result;
|
||||
|
||||
std::array<std::vector<s16>, 2> out_streams;
|
||||
|
||||
while (data_len > 0) {
|
||||
NeAACDecFrameInfo frame_info;
|
||||
auto curr_sample_buffer =
|
||||
static_cast<s16*>(NeAACDecDecode(decoder, &frame_info, data, data_len));
|
||||
if (curr_sample_buffer == nullptr || frame_info.error != 0) {
|
||||
LOG_ERROR(Audio_DSP, "Failed to decode AAC buffer using FAAD2: {}", frame_info.error);
|
||||
return response;
|
||||
}
|
||||
|
||||
// Split the decode result into channels.
|
||||
u32 num_samples = frame_info.samples / frame_info.channels;
|
||||
for (u32 sample = 0; sample < num_samples; sample++) {
|
||||
for (u32 ch = 0; ch < frame_info.channels; ch++) {
|
||||
out_streams[ch].push_back(curr_sample_buffer[(sample * frame_info.channels) + ch]);
|
||||
}
|
||||
}
|
||||
|
||||
data += frame_info.bytesconsumed;
|
||||
data_len -= frame_info.bytesconsumed;
|
||||
}
|
||||
|
||||
// Transfer the decoded buffer from vector to the FCRAM.
|
||||
for (std::size_t ch = 0; ch < out_streams.size(); ch++) {
|
||||
if (out_streams[ch].empty()) {
|
||||
continue;
|
||||
}
|
||||
auto byte_size = out_streams[ch].size() * sizeof(s16);
|
||||
auto dst = ch == 0 ? request.decode_aac_request.dst_addr_ch0
|
||||
: request.decode_aac_request.dst_addr_ch1;
|
||||
if (dst < Memory::FCRAM_PADDR ||
|
||||
dst + byte_size > Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
|
||||
LOG_ERROR(Audio_DSP, "Got out of bounds dst_addr_ch{} {:08x}", ch, dst);
|
||||
return response;
|
||||
}
|
||||
std::memcpy(memory.GetFCRAMPointer(dst - Memory::FCRAM_PADDR), out_streams[ch].data(),
|
||||
byte_size);
|
||||
}
|
||||
|
||||
// Set the output frame info.
|
||||
response.decode_aac_response.sample_rate = GetSampleRateEnum(sample_rate);
|
||||
response.decode_aac_response.num_channels = num_channels;
|
||||
response.decode_aac_response.num_samples = static_cast<u32_le>(out_streams[0].size());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
} // namespace AudioCore::HLE
|
Reference in New Issue
Block a user