From 4ea7f46f818cd7a34601cba488a4c0d2bdcde160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 19 Feb 2025 11:20:41 -0600 Subject: [PATCH] Atrac3+: Try to work around Code Lyoko issue Now we don't generate an error code when the channel configuration doesn't match the packets. See the code comment for what I've been able to figure out so far. See issue #19994 --- Core/HLE/AtracCtx.cpp | 8 ++++++-- Core/HW/Atrac3Standalone.cpp | 2 +- ext/at3_standalone/atrac3plusdec.cpp | 14 ++++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 342fec915431..c9fe5afb91bc 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -576,7 +576,7 @@ void AtracBase::CreateDecoder() { delete decoder_; } - // First, init the standalone decoder. Only used for low-level-decode initially, but simple. + // First, init the standalone decoder. if (track_.codecType == PSP_MODE_AT_3) { // We don't pull this from the RIFF so that we can support OMA also. uint8_t extraData[14]{}; @@ -650,6 +650,10 @@ void Atrac::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int sample) { int Atrac::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, int successCode) { outputChannels_ = outputChannels; + if (outputChannels != track_.channels) { + WARN_LOG(Log::ME, "outputChannels %d doesn't match track_.channels %d", outputChannels, track_.channels); + } + first_.addr = buffer; first_.size = readSize; @@ -696,7 +700,7 @@ int Atrac::SetData(u32 buffer, u32 readSize, u32 bufferSize, int outputChannels, Memory::Memcpy(dataBuf_, buffer, copybytes, "AtracSetData"); } CreateDecoder(); - return hleLogInfo(Log::ME, successCode, "%s %s audio", codecName, channelName); + return hleLogInfo(Log::ME, successCode, "%s %s (%d channels) audio", codecName, channelName, track_.channels); } u32 Atrac::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) { diff --git a/Core/HW/Atrac3Standalone.cpp b/Core/HW/Atrac3Standalone.cpp index cc34a15957a7..82a3f26cb876 100644 --- a/Core/HW/Atrac3Standalone.cpp +++ b/Core/HW/Atrac3Standalone.cpp @@ -82,7 +82,7 @@ class Atrac3Audio : public AudioDecoder { } } if (inbytes != blockAlign_ && blockAlign_ != 0) { - WARN_LOG(Log::ME, "Atrac3Audio::Decode: Unexpected block align %d (expected %d). %s", inbytes, blockAlign_, at3pCtx_ ? "Atrac3+" : "Atrac3"); + WARN_LOG(Log::ME, "Atrac3Audio::Decode: inbytes not matching expected blockalign. Updating blockAlign_. Got %d bytes, expected %d. (%s)", inbytes, blockAlign_, at3pCtx_ ? "Atrac3+" : "Atrac3"); } blockAlign_ = inbytes; diff --git a/ext/at3_standalone/atrac3plusdec.cpp b/ext/at3_standalone/atrac3plusdec.cpp index c57cee7a9794..e5eaae9f1a3f 100644 --- a/ext/at3_standalone/atrac3plusdec.cpp +++ b/ext/at3_standalone/atrac3plusdec.cpp @@ -323,14 +323,20 @@ int atrac3p_decode_frame(ATRAC3PContext *ctx, float *out_data[2], int *nb_sample while (get_bits_left(&ctx->gb) >= 2 && (ch_unit_id = get_bits(&ctx->gb, 2)) != CH_UNIT_TERMINATOR) { if (ch_unit_id == CH_UNIT_EXTENSION) { - avpriv_report_missing_feature("Channel unit extension"); + av_log(AV_LOG_ERROR, "Missing atrac3p feature: Channel unit extension"); return AVERROR_PATCHWELCOME; } if (ch_block >= ctx->num_channel_blocks || ctx->channel_blocks[ch_block] != ch_unit_id) { - av_log(AV_LOG_ERROR, - "Frame data doesn't match channel configuration!"); - return AVERROR_INVALIDDATA; + av_log(AV_LOG_WARNING, "Frame data doesn't match channel configuration! ch_block %d >= num_channel_blocks %d", ch_block, ctx->num_channel_blocks); + // This happens in Code Lyoko, see issue #19994. + // The atrac3+ wav header clearly specifies stereo, so we only have one channel block, but here we try to decode a third (and/or fourth) one. + // Maybe the data chunk is just improperly terminated, but it's reported that when ignoring this error previously, + // it didn't sound right. So I'm really not sure what's going on here. Most likely some unknown feature of the Atrac3+ format that we + // failed to parse previously? + // + // return AVERROR_INVALIDDATA; // This soft-locks the game. + return FFMIN(ctx->block_align, indata_size); // We try to stumble along. } ctx->ch_units[ch_block].unit_type = ch_unit_id;