fix(audiodec): take the M4AAC raw channel layout from the stream
For a raw M4AAC stream the maximum channel count was written into the AudioSpecificConfig as the channel configuration. The maximum only bounds the stream: The Smurfs Dreams creates its decoder with 8 channels at most and sends stereo, so FFmpeg refused configuration 8 (reserved) and a stereo stream under configuration 6 or 7 decodes no frame. The decoder now starts from the mono/stereo configuration and on the first access unit that it cannot decode moves on to the configurations with more channels, up to the maximum, keeping the first one that decodes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4b005b229e
commit
7b722253a4
|
|
@ -82,6 +82,12 @@ protected:
|
|||
return result;
|
||||
}
|
||||
|
||||
void reopen(std::vector<std::uint8_t> replacement) {
|
||||
avcodec_free_context(&context);
|
||||
extradata = std::move(replacement);
|
||||
open();
|
||||
}
|
||||
|
||||
private:
|
||||
void open() {
|
||||
const AVCodec* codec = avcodec_find_decoder(id);
|
||||
|
|
@ -118,7 +124,8 @@ public:
|
|||
|
||||
class AacDecoder final : public FfmpegDecoder {
|
||||
public:
|
||||
AacDecoder(std::int32_t wordSize, bool adts, std::vector<std::uint8_t> extradata) : FfmpegDecoder(AV_CODEC_ID_AAC, wordSize, std::move(extradata)), adts(adts) {}
|
||||
AacDecoder(std::int32_t wordSize, bool adts, std::vector<std::vector<std::uint8_t>> configs)
|
||||
: FfmpegDecoder(AV_CODEC_ID_AAC, wordSize, configs.empty() ? std::vector<std::uint8_t>{} : configs.front()), adts(adts), configs(std::move(configs)) {}
|
||||
|
||||
DecodeResult Decode(const std::uint8_t* data, std::size_t size, std::uint8_t* pcm, std::size_t pcmSize) override {
|
||||
std::size_t frameBytes = size;
|
||||
|
|
@ -128,11 +135,22 @@ public:
|
|||
if (frameBytes < 7) return {DecodeStatus::InvalidData};
|
||||
if (frameBytes > size) return {DecodeStatus::PartialInput};
|
||||
}
|
||||
return decodePacket(data, frameBytes, pcm, pcmSize);
|
||||
if (configs.size() <= 1) return decodePacket(data, frameBytes, pcm, pcmSize);
|
||||
for (std::size_t index = 0; index < configs.size(); ++index) {
|
||||
if (index != 0) reopen(configs[index]);
|
||||
const DecodeResult result = decodePacket(data, frameBytes, pcm, pcmSize);
|
||||
if (result.status != DecodeStatus::InvalidData) {
|
||||
configs = {configs[index]};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
reopen(configs.front());
|
||||
return {DecodeStatus::InvalidData};
|
||||
}
|
||||
|
||||
private:
|
||||
bool adts;
|
||||
std::vector<std::vector<std::uint8_t>> configs;
|
||||
};
|
||||
|
||||
class At9Decoder final : public Decoder {
|
||||
|
|
@ -222,13 +240,19 @@ std::unique_ptr<Decoder> CreateMp3(std::int32_t wordSize) {
|
|||
}
|
||||
|
||||
std::unique_ptr<Decoder> CreateAac(std::int32_t wordSize, bool adts, std::uint32_t samplingFreqIndex, std::uint32_t channels) {
|
||||
std::vector<std::uint8_t> config;
|
||||
std::vector<std::vector<std::uint8_t>> configs;
|
||||
if (!adts) {
|
||||
const std::uint32_t lowComplexity = 2;
|
||||
config = {static_cast<std::uint8_t>(lowComplexity << 3 | samplingFreqIndex >> 1),
|
||||
static_cast<std::uint8_t>((samplingFreqIndex & 1) << 7 | channels << 3)};
|
||||
const auto config = [&](std::uint32_t channelConfiguration) {
|
||||
return std::vector<std::uint8_t>{static_cast<std::uint8_t>(lowComplexity << 3 | samplingFreqIndex >> 1),
|
||||
static_cast<std::uint8_t>((samplingFreqIndex & 1) << 7 | channelConfiguration << 3)};
|
||||
};
|
||||
configs.push_back(config(channels < 2 ? 1 : 2));
|
||||
for (std::uint32_t channelConfiguration = 3; channelConfiguration <= 7; ++channelConfiguration) {
|
||||
if ((channelConfiguration == 7 ? 8 : channelConfiguration) <= channels) configs.push_back(config(channelConfiguration));
|
||||
}
|
||||
}
|
||||
return std::make_unique<AacDecoder>(wordSize, adts, std::move(config));
|
||||
return std::make_unique<AacDecoder>(wordSize, adts, std::move(configs));
|
||||
}
|
||||
|
||||
std::unique_ptr<Decoder> CreateAt9(std::int32_t wordSize, const std::uint8_t (&config)[4], At9Format& format) {
|
||||
|
|
|
|||
|
|
@ -115,12 +115,12 @@ std::size_t AdtsLength(const std::uint8_t* frame) {
|
|||
return static_cast<std::size_t>((frame[3] & 3) << 11 | frame[4] << 3 | frame[5] >> 5);
|
||||
}
|
||||
|
||||
void TestAac(bool adts) {
|
||||
AudiodecParamM4aac param{sizeof(param), 1, adts ? 1u : 2u, 3, 2, 0};
|
||||
void TestAac(bool adts, std::uint32_t maxChannels = 2) {
|
||||
AudiodecParamM4aac param{sizeof(param), 1, adts ? 1u : 2u, 3, maxChannels, 0};
|
||||
AudiodecM4aacInfo info{sizeof(info), 0, 0, 0, 0};
|
||||
AudiodecCtrl ctrl{¶m, &info, nullptr, nullptr};
|
||||
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 3);
|
||||
Require(handle > 0 && info.ui_sampling_freq == 48000 && info.ui_number_of_channels == 2);
|
||||
Require(handle > 0 && info.ui_sampling_freq == 48000 && info.ui_number_of_channels == maxChannels);
|
||||
Streams streams;
|
||||
int crossings = 0;
|
||||
for (std::size_t offset = 0, frame = 0; offset < sizeof(AAC_ADTS); offset += AdtsLength(AAC_ADTS + offset), ++frame) {
|
||||
|
|
@ -229,6 +229,8 @@ int main() {
|
|||
|
||||
TestAac(true);
|
||||
TestAac(false);
|
||||
TestAac(false, 6);
|
||||
TestAac(false, 8);
|
||||
TestMp3();
|
||||
TestAt9();
|
||||
for (std::uint32_t type = 1; type <= 3; ++type) Require(sceAudiodecTermLibrary(type) == 0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue