#include <algorithm>
#include <cmath>
#include "Common/Serialize/SerializeFuncs.h"
#include "Core/Debugger/MemBlockInfo.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HW/SimpleAudioDec.h"
#include "Core/HW/MediaEngine.h"
#include "Core/HW/BufferQueue.h"
#include "Core/HW/Atrac3Standalone.h"
#include "ext/minimp3/minimp3.h"
#ifdef USE_FFMPEG
extern "C" {
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
#include "libavutil/samplefmt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/version.h"
#include "Core/FFMPEGCompat.h"
}
#include "Core/Config.h"
#else
extern "C" {
struct AVCodec;
struct AVCodecContext;
struct SwrContext;
struct AVFrame;
}
#endif
class MiniMp3Audio : public AudioDecoder {
public:
MiniMp3Audio() {
mp3dec_init(&mp3_);
}
~MiniMp3Audio() {}
bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override {
_dbg_assert_(outputChannels == 2);
mp3dec_frame_info_t info{};
int samplesWritten = mp3dec_decode_frame(&mp3_, inbuf, inbytes, (mp3d_sample_t *)temp_, &info);
_dbg_assert_(samplesWritten <= MINIMP3_MAX_SAMPLES_PER_FRAME);
_dbg_assert_(info.channels <= 2);
if (info.channels == 1) {
for (int i = 0; i < samplesWritten; i++) {
outbuf[i * 2] = temp_[i];
outbuf[i * 2 + 1] = temp_[i];
}
} else {
memcpy(outbuf, temp_, 4 * samplesWritten);
}
*inbytesConsumed = info.frame_bytes;
*outSamples = samplesWritten;
return true;
}
bool IsOK() const override { return true; }
void SetChannels(int channels) override {
}
PSPAudioType GetAudioType() const override { return PSP_CODEC_MP3; }
private:
mp3dec_t mp3_{};
int16_t temp_[MINIMP3_MAX_SAMPLES_PER_FRAME]{};
};
class FFmpegAudioDecoder : public AudioDecoder {
public:
FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2);
~FFmpegAudioDecoder();
bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override;
bool IsOK() const override {
#ifdef USE_FFMPEG
return codec_ != 0;
#else
return 0;
#endif
}
void SetChannels(int channels) override;
PSPAudioType GetAudioType() const override { return audioType; }
private:
bool OpenCodec(int block_align);
PSPAudioType audioType;
int sample_rate_;
int channels_;
AVFrame *frame_ = nullptr;
AVCodec *codec_ = nullptr;
AVCodecContext *codecCtx_ = nullptr;
SwrContext *swrCtx_ = nullptr;
bool codecOpen_ = false;
};
AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) {
bool forceFfmpeg = false;
#ifdef USE_FFMPEG
forceFfmpeg = g_Config.bForceFfmpegForAudioDec;
#endif
if (forceFfmpeg) {
return new FFmpegAudioDecoder(audioType, sampleRateHz, channels);
}
switch (audioType) {
case PSP_CODEC_AT3:
return CreateAtrac3Audio(channels, blockAlign, extraData, extraDataSize);
case PSP_CODEC_AT3PLUS:
return CreateAtrac3PlusAudio(channels, blockAlign);
default:
return new FFmpegAudioDecoder(audioType, sampleRateHz, channels);
}
}
static int GetAudioCodecID(int audioType) {
#ifdef USE_FFMPEG
switch (audioType) {
case PSP_CODEC_AAC:
return AV_CODEC_ID_AAC;
case PSP_CODEC_AT3:
return AV_CODEC_ID_ATRAC3;
case PSP_CODEC_AT3PLUS:
return AV_CODEC_ID_ATRAC3P;
case PSP_CODEC_MP3:
return AV_CODEC_ID_MP3;
default:
return AV_CODEC_ID_NONE;
}
#else
return 0;
#endif
}
FFmpegAudioDecoder::FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels)
: audioType(audioType), sample_rate_(sampleRateHz), channels_(channels) {
#ifdef USE_FFMPEG
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100)
avcodec_register_all();
#endif
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100)
av_register_all();
#endif
InitFFmpeg();
frame_ = av_frame_alloc();
int audioCodecId = GetAudioCodecID(audioType);
if (!audioCodecId) {
ERROR_LOG(Log::ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType);
return;
}
codec_ = avcodec_find_decoder((AVCodecID)audioCodecId);
if (!codec_) {
ERROR_LOG(Log::ME, "This version of FFMPEG does not support AV_CODEC_ctx for audio (%s). Update your submodule.", GetCodecName(audioType));
return;
}
codecCtx_ = avcodec_alloc_context3(codec_);
if (!codecCtx_) {
ERROR_LOG(Log::ME, "Failed to allocate a codec context");
return;
}
#if LIBAVUTIL_VERSION_MAJOR >= 59
if (channels_ == 2)
codecCtx_->ch_layout = AV_CHANNEL_LAYOUT_STEREO;
else
codecCtx_->ch_layout = AV_CHANNEL_LAYOUT_MONO;
#else
codecCtx_->channels = channels_;
codecCtx_->channel_layout = channels_ == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
#endif
codecCtx_->sample_rate = sample_rate_;
codecOpen_ = false;
#endif
}
bool FFmpegAudioDecoder::OpenCodec(int block_align) {
#ifdef USE_FFMPEG
if (codecCtx_->block_align == 0) {
codecCtx_->block_align = block_align;
}
AVDictionary *opts = 0;
int retval = avcodec_open2(codecCtx_, codec_, &opts);
if (retval < 0) {
ERROR_LOG(Log::ME, "Failed to open codec: retval = %i", retval);
}
av_dict_free(&opts);
codecOpen_ = true;
return retval >= 0;
#else
return false;
#endif
}
void FFmpegAudioDecoder::SetChannels(int channels) {
if (channels_ == channels) {
return;
}
#ifdef USE_FFMPEG
if (codecOpen_) {
ERROR_LOG(Log::ME, "Codec already open, cannot change channels");
} else {
channels_ = channels;
#if LIBAVUTIL_VERSION_MAJOR >= 59
if (channels_ == 2)
codecCtx_->ch_layout = AV_CHANNEL_LAYOUT_STEREO;
else
codecCtx_->ch_layout = AV_CHANNEL_LAYOUT_MONO;
#else
codecCtx_->channels = channels_;
codecCtx_->channel_layout = channels_ == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
#endif
}
#endif
}
FFmpegAudioDecoder::~FFmpegAudioDecoder() {
#ifdef USE_FFMPEG
swr_free(&swrCtx_);
av_frame_free(&frame_);
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0)
avcodec_free_context(&codecCtx_);
#else
avcodec_close(codecCtx_);
av_freep(&codecCtx_->extradata);
av_freep(&codecCtx_->subtitle_header);
av_freep(&codecCtx_);
#endif
codec_ = 0;
#endif
}
bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) {
#ifdef USE_FFMPEG
if (!codecOpen_) {
OpenCodec(inbytes);
}
AVPacket packet;
av_init_packet(&packet);
packet.data = (uint8_t *)(inbuf);
packet.size = inbytes;
int got_frame = 0;
av_frame_unref(frame_);
if (outSamples) {
*outSamples = 0;
}
if (inbytesConsumed) {
*inbytesConsumed = 0;
}
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
if (inbytes != 0) {
int err = avcodec_send_packet(codecCtx_, &packet);
if (err < 0) {
ERROR_LOG(Log::ME, "Error sending audio frame to decoder (%d bytes): %d (%08x)", inbytes, err, err);
return false;
}
}
int err = avcodec_receive_frame(codecCtx_, frame_);
int len = 0;
if (err >= 0) {
len = frame_->pkt_size;
got_frame = 1;
} else if (err != AVERROR(EAGAIN)) {
len = err;
}
#else
int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
#endif
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
av_packet_unref(&packet);
#else
av_free_packet(&packet);
#endif
if (len < 0) {
ERROR_LOG(Log::ME, "Error decoding Audio frame (%i bytes): %i (%08x)", inbytes, len, len);
return false;
}
if (inbytesConsumed) {
*inbytesConsumed = len;
}
if (got_frame) {
_dbg_assert_(outputChannels == 2);
#if LIBAVUTIL_VERSION_MAJOR >= 59
AVChannelLayout wanted_channel_layout = AV_CHANNEL_LAYOUT_STEREO;
const AVChannelLayout& dec_channel_layout = frame_->ch_layout;
#else
int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO;
int64_t dec_channel_layout = frame_->channel_layout;
#endif
if (!swrCtx_) {
const int inputSampleRate = codecCtx_->sample_rate;
const int outputSampleRate = codecCtx_->sample_rate;
#if LIBAVUTIL_VERSION_MAJOR >= 59
swr_alloc_set_opts2(
&swrCtx_,
&wanted_channel_layout,
AV_SAMPLE_FMT_S16,
outputSampleRate,
&dec_channel_layout,
codecCtx_->sample_fmt,
inputSampleRate,
0,
NULL);
#else
swrCtx_ = swr_alloc_set_opts(
swrCtx_,
wanted_channel_layout,
AV_SAMPLE_FMT_S16,
outputSampleRate,
dec_channel_layout,
codecCtx_->sample_fmt,
inputSampleRate,
0,
NULL);
#endif
if (!swrCtx_ || swr_init(swrCtx_) < 0) {
ERROR_LOG(Log::ME, "swr_init: Failed to initialize the resampling context");
avcodec_close(codecCtx_);
codec_ = 0;
return false;
}
}
int swrRet = 0;
if (outbuf != nullptr) {
swrRet = swr_convert(swrCtx_, (uint8_t **)&outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples);
}
if (swrRet < 0) {
ERROR_LOG(Log::ME, "swr_convert: Error while converting: %d", swrRet);
return false;
}
if (outSamples) {
*outSamples = swrRet;
}
}
return true;
#else
*outSamples = 0;
return true;
#endif
}
void AudioClose(AudioDecoder **ctx) {
#ifdef USE_FFMPEG
delete *ctx;
*ctx = 0;
#endif
}
void AudioClose(FFmpegAudioDecoder **ctx) {
#ifdef USE_FFMPEG
delete *ctx;
*ctx = 0;
#endif
}
static const char *const codecNames[4] = {
"AT3+", "AT3", "MP3", "AAC",
};
const char *GetCodecName(int codec) {
if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
return codecNames[codec - PSP_CODEC_AT3PLUS];
} else {
return "(unk)";
}
};
bool IsValidCodec(PSPAudioType codec){
if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
return true;
}
return false;
}
AuCtx::AuCtx() {
}
AuCtx::~AuCtx() {
if (decoder) {
AudioClose(&decoder);
decoder = nullptr;
}
}
size_t AuCtx::FindNextMp3Sync() {
for (size_t i = 0; i < sourcebuff.size() - 2; ++i) {
if ((sourcebuff[i] & 0xFF) == 0xFF && (sourcebuff[i + 1] & 0xC0) == 0xC0) {
return i;
}
}
return 0;
}
u32 AuCtx::AuDecode(u32 pcmAddr) {
u32 outptr = PCMBuf + nextOutputHalf * PCMBufSize / 2;
auto outbuf = Memory::GetPointerWriteRange(outptr, PCMBufSize / 2);
int outpcmbufsize = 0;
if (pcmAddr)
Memory::Write_U32(outptr, pcmAddr);
if (!sourcebuff.empty()) {
int nextSync = 0;
if (decoder->GetAudioType() == PSP_CODEC_MP3) {
nextSync = (int)FindNextMp3Sync();
}
int inbytesConsumed = 0;
int outSamples = 0;
decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, &inbytesConsumed, 2, (int16_t *)outbuf, &outSamples);
outpcmbufsize = outSamples * 2 * sizeof(int16_t);
if (outpcmbufsize == 0) {
AuBufAvailable = 0;
sourcebuff.clear();
} else {
SumDecodedSamples += outSamples;
int srcPos = inbytesConsumed + nextSync;
if (srcPos > 0)
sourcebuff.erase(sourcebuff.begin(), sourcebuff.begin() + srcPos);
AuBufAvailable -= srcPos;
}
}
bool end = readPos - AuBufAvailable >= (int64_t)endPos;
if (end && LoopNum != 0) {
SumDecodedSamples = 0;
readPos = startPos;
if (LoopNum > 0)
LoopNum--;
}
if (outpcmbufsize == 0 && !end) {
outpcmbufsize = PCMBufSize / 2;
if (outbuf != nullptr)
memset(outbuf, 0, outpcmbufsize);
} else if ((u32)outpcmbufsize < PCMBufSize) {
if (outbuf != nullptr)
memset(outbuf + outpcmbufsize, 0, PCMBufSize / 2 - outpcmbufsize);
}
if (outpcmbufsize != 0)
NotifyMemInfo(MemBlockFlags::WRITE, outptr, outpcmbufsize, "AuDecode");
nextOutputHalf ^= 1;
return outpcmbufsize;
}
int AuCtx::AuCheckStreamDataNeeded() {
if (AuStreamBytesNeeded() > 0) {
return 1;
}
return 0;
}
int AuCtx::AuStreamBytesNeeded() {
if (decoder->GetAudioType() == PSP_CODEC_MP3) {
if (readPos >= endPos)
return 0;
int offset = AuStreamWorkareaSize();
return (int)AuBufSize - AuBufAvailable - offset;
}
return std::min((int)AuBufSize - AuBufAvailable, (int)endPos - readPos);
}
int AuCtx::AuStreamWorkareaSize() {
if (decoder->GetAudioType() == PSP_CODEC_MP3)
return 0x05c0;
return 0;
}
u32 AuCtx::AuNotifyAddStreamData(int size) {
int offset = AuStreamWorkareaSize();
if (askedReadSize != 0) {
int diffsize = size - askedReadSize;
if (diffsize != 0) {
readPos += diffsize;
AuBufAvailable += diffsize;
}
askedReadSize = 0;
} else {
readPos += size;
AuBufAvailable += size;
}
if (Memory::IsValidRange(AuBuf, size)) {
sourcebuff.resize(sourcebuff.size() + size);
Memory::MemcpyUnchecked(&sourcebuff[sourcebuff.size() - size], AuBuf + offset, size);
}
return 0;
}
u32 AuCtx::AuGetInfoToAddStreamData(u32 bufPtr, u32 sizePtr, u32 srcPosPtr) {
int readsize = AuStreamBytesNeeded();
int offset = AuStreamWorkareaSize();
if (readsize != 0) {
if (Memory::IsValidAddress(bufPtr))
Memory::WriteUnchecked_U32(AuBuf + offset, bufPtr);
if (Memory::IsValidAddress(sizePtr))
Memory::WriteUnchecked_U32(readsize, sizePtr);
if (Memory::IsValidAddress(srcPosPtr))
Memory::WriteUnchecked_U32(readPos, srcPosPtr);
} else {
if (Memory::IsValidAddress(bufPtr))
Memory::WriteUnchecked_U32(0, bufPtr);
if (Memory::IsValidAddress(sizePtr))
Memory::WriteUnchecked_U32(0, sizePtr);
if (Memory::IsValidAddress(srcPosPtr))
Memory::WriteUnchecked_U32(0, srcPosPtr);
}
askedReadSize = 0;
return 0;
}
u32 AuCtx::AuResetPlayPositionByFrame(int frame) {
uint32_t bytesPerSecond = (MaxOutputSample / 8) * BitRate * 1000;
readPos = startPos + (frame * bytesPerSecond) / SamplingRate;
if (frame != 0)
readPos -= 1;
SumDecodedSamples = frame * MaxOutputSample;
AuBufAvailable = 0;
sourcebuff.clear();
return 0;
}
u32 AuCtx::AuResetPlayPosition() {
readPos = startPos;
SumDecodedSamples = 0;
AuBufAvailable = 0;
sourcebuff.clear();
return 0;
}
void AuCtx::DoState(PointerWrap &p) {
auto s = p.Section("AuContext", 0, 2);
if (!s)
return;
Do(p, startPos);
Do(p, endPos);
Do(p, AuBuf);
Do(p, AuBufSize);
Do(p, PCMBuf);
Do(p, PCMBufSize);
Do(p, freq);
Do(p, SumDecodedSamples);
Do(p, LoopNum);
Do(p, Channels);
Do(p, MaxOutputSample);
Do(p, readPos);
int audioType = decoder ? (int)decoder->GetAudioType() : 0;
Do(p, audioType);
Do(p, BitRate);
Do(p, SamplingRate);
Do(p, askedReadSize);
int dummy = 0;
Do(p, dummy);
Do(p, FrameNum);
if (s < 2) {
AuBufAvailable = 0;
Version = 3;
} else {
Do(p, Version);
Do(p, AuBufAvailable);
Do(p, sourcebuff);
Do(p, nextOutputHalf);
}
if (p.mode == p.MODE_READ) {
decoder = CreateAudioDecoder((PSPAudioType)audioType);
}
}