mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Merge pull request #19024 from hrydgard/audio-decoder-refactor
Audio format decoder: Refactor to enable multiple decoder implementations
This commit is contained in:
commit
c6f5ac0c81
@ -36,12 +36,12 @@ struct AudioCodecContext {
|
||||
};
|
||||
|
||||
// audioList is to store current playing audios.
|
||||
static std::map<u32, SimpleAudio *> audioList;
|
||||
static std::map<u32, AudioDecoder *> audioList;
|
||||
|
||||
static bool oldStateLoaded = false;
|
||||
|
||||
// find the audio decoder for corresponding ctxPtr in audioList
|
||||
static SimpleAudio *findDecoder(u32 ctxPtr) {
|
||||
static AudioDecoder *findDecoder(u32 ctxPtr) {
|
||||
auto it = audioList.find(ctxPtr);
|
||||
if (it != audioList.end()) {
|
||||
return it->second;
|
||||
@ -77,29 +77,31 @@ void __AudioCodecShutdown() {
|
||||
}
|
||||
|
||||
static int sceAudiocodecInit(u32 ctxPtr, int codec) {
|
||||
if (IsValidCodec(codec)) {
|
||||
PSPAudioType audioType = (PSPAudioType)codec;
|
||||
if (IsValidCodec(audioType)) {
|
||||
// Create audio decoder for given audio codec and push it into AudioList
|
||||
if (removeDecoder(ctxPtr)) {
|
||||
WARN_LOG_REPORT(HLE, "sceAudiocodecInit(%08x, %d): replacing existing context", ctxPtr, codec);
|
||||
}
|
||||
auto decoder = new SimpleAudio(codec);
|
||||
AudioDecoder *decoder = CreateAudioDecoder(audioType);
|
||||
decoder->SetCtxPtr(ctxPtr);
|
||||
audioList[ctxPtr] = decoder;
|
||||
INFO_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
|
||||
INFO_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(audioType));
|
||||
DEBUG_LOG(ME, "Number of playing sceAudioCodec audios : %d", (int)audioList.size());
|
||||
return 0;
|
||||
}
|
||||
ERROR_LOG_REPORT(ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(codec), codec);
|
||||
ERROR_LOG_REPORT(ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(audioType), codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceAudiocodecDecode(u32 ctxPtr, int codec) {
|
||||
PSPAudioType audioType = (PSPAudioType)codec;
|
||||
if (!ctxPtr){
|
||||
ERROR_LOG_REPORT(ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(codec));
|
||||
ERROR_LOG_REPORT(ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(audioType));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IsValidCodec(codec)){
|
||||
if (IsValidCodec(audioType)){
|
||||
int outbytes = 0;
|
||||
// find a decoder in audioList
|
||||
auto decoder = findDecoder(ctxPtr);
|
||||
@ -107,7 +109,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) {
|
||||
if (!decoder && oldStateLoaded) {
|
||||
// We must have loaded an old state that did not have sceAudiocodec information.
|
||||
// Fake it by creating the desired context.
|
||||
decoder = new SimpleAudio(codec);
|
||||
decoder = CreateAudioDecoder(audioType);
|
||||
decoder->SetCtxPtr(ctxPtr);
|
||||
audioList[ctxPtr] = decoder;
|
||||
}
|
||||
@ -194,7 +196,7 @@ void __sceAudiocodecDoState(PointerWrap &p){
|
||||
DoArray(p, codec_, s >= 2 ? count : (int)ARRAY_SIZE(codec_));
|
||||
DoArray(p, ctxPtr_, s >= 2 ? count : (int)ARRAY_SIZE(ctxPtr_));
|
||||
for (int i = 0; i < count; i++) {
|
||||
auto decoder = new SimpleAudio(codec_[i]);
|
||||
auto decoder = CreateAudioDecoder((PSPAudioType)codec_[i]);
|
||||
decoder->SetCtxPtr(ctxPtr_[i]);
|
||||
audioList[ctxPtr_[i]] = decoder;
|
||||
}
|
||||
@ -214,7 +216,7 @@ void __sceAudiocodecDoState(PointerWrap &p){
|
||||
auto ctxPtr_ = new u32[count];
|
||||
int i = 0;
|
||||
for (auto it = audioList.begin(), end = audioList.end(); it != end; it++) {
|
||||
const SimpleAudio *decoder = it->second;
|
||||
const AudioDecoder *decoder = it->second;
|
||||
codec_[i] = decoder->GetAudioType();
|
||||
ctxPtr_[i] = decoder->GetCtxPtr();
|
||||
i++;
|
||||
|
@ -124,6 +124,7 @@ void __KernelInit()
|
||||
__IoInit();
|
||||
__JpegInit();
|
||||
__AudioInit();
|
||||
__Mp3Init();
|
||||
__SasInit();
|
||||
__AtracInit();
|
||||
__CccInit();
|
||||
|
@ -15,6 +15,57 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
// Games known to support custom music and almost certainly use sceMp3:
|
||||
//
|
||||
// * ATV Offroad Fury: Blazin' Trails
|
||||
// * Beats (/PSP/MUSIC)
|
||||
// * Crazy Taxi : Fare Wars (/MUSIC)
|
||||
// * Dead or Alive Paradise
|
||||
// * Gran Turismo - You must first clear all driving challenges up to C to unlock this feature, then it will be available through the options menu.
|
||||
// * Grand Theft Auto : Liberty City Stories
|
||||
// * Grand Theft Auto : Vice City Stories
|
||||
// * Heroes' VS (#5866 ?)
|
||||
// * MLB 08 : The Show
|
||||
// * MotorStorm : Artic Edge
|
||||
// * NBA Live 09
|
||||
// * Need for Speed Carbon
|
||||
// * Need for Speed Pro Street
|
||||
// * Pro Evolution Soccer 2014
|
||||
// * SD Gundam G Generation Overworld
|
||||
// * TOCA Race Driver 2
|
||||
// * Untold Legends II
|
||||
// * Wipeout Pulse (/MUSIC/WIPEOUT)
|
||||
//
|
||||
// Games known to use LowLevelDecode:
|
||||
//
|
||||
// * Gundam G (custom BGM)
|
||||
// * Heroes' VS (custom BGM)
|
||||
//
|
||||
// Games that use sceMp3 internally
|
||||
//
|
||||
// * Kirameki School Life SP
|
||||
// * Breakquest (mini)
|
||||
// * Orbit (mini)
|
||||
// * SWAT Target Liberty ULES00927
|
||||
// * Geometry Wars (homebrew)
|
||||
// * Hanayaka Nari Wa ga Ichizoku
|
||||
// * Velocity (mini)
|
||||
// * N+ (mini) (#9379)
|
||||
// * Mighty Flip Champs DX (mini)
|
||||
// * EDGE (mini)
|
||||
// * Stellar Attack (mini)
|
||||
// * Hungry Giraffe (mini)
|
||||
// * OMG - Z (mini)
|
||||
// ...probably lots more minis...
|
||||
//
|
||||
// BUGS
|
||||
//
|
||||
// Custom music plays but starts stuttering:
|
||||
// * Beats
|
||||
//
|
||||
// Custom music just repeats a small section:
|
||||
// * Crazy Taxi
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
@ -44,9 +95,9 @@ static const int AU_BUF_MIN_SIZE = 8192;
|
||||
static const int PCM_BUF_MIN_SIZE = 9216;
|
||||
static const size_t MP3_MAX_HANDLES = 2;
|
||||
|
||||
struct Mp3Context {
|
||||
// This one is only used for save state upgrading.
|
||||
struct Mp3ContextOld {
|
||||
public:
|
||||
|
||||
int mp3StreamStart;
|
||||
int mp3StreamEnd;
|
||||
u32 mp3Buf;
|
||||
@ -106,6 +157,10 @@ static AuCtx *getMp3Ctx(u32 mp3) {
|
||||
return mp3Map[mp3];
|
||||
}
|
||||
|
||||
void __Mp3Init() {
|
||||
resourceInited = false;
|
||||
}
|
||||
|
||||
void __Mp3Shutdown() {
|
||||
for (auto it = mp3Map.begin(), end = mp3Map.end(); it != end; ++it) {
|
||||
delete it->second;
|
||||
@ -121,7 +176,7 @@ void __Mp3DoState(PointerWrap &p) {
|
||||
if (s >= 2) {
|
||||
Do(p, mp3Map);
|
||||
} else {
|
||||
std::map<u32, Mp3Context *> mp3Map_old;
|
||||
std::map<u32, Mp3ContextOld *> mp3Map_old;
|
||||
Do(p, mp3Map_old); // read old map
|
||||
for (auto it = mp3Map_old.begin(), end = mp3Map_old.end(); it != end; ++it) {
|
||||
auto mp3 = new AuCtx;
|
||||
@ -143,8 +198,7 @@ void __Mp3DoState(PointerWrap &p) {
|
||||
mp3->MaxOutputSample = mp3_old->mp3MaxSamples;
|
||||
mp3->SetReadPos(mp3_old->readPosition);
|
||||
|
||||
mp3->audioType = PSP_CODEC_MP3;
|
||||
mp3->decoder = new SimpleAudio(mp3->audioType);
|
||||
mp3->decoder = CreateAudioDecoder(PSP_CODEC_MP3);
|
||||
mp3Map[id] = mp3;
|
||||
}
|
||||
}
|
||||
@ -249,9 +303,8 @@ static u32 sceMp3ReserveMp3Handle(u32 mp3Addr) {
|
||||
Au->PCMBufSize = 0;
|
||||
}
|
||||
|
||||
Au->audioType = PSP_CODEC_MP3;
|
||||
Au->SetReadPos(Au->startPos);
|
||||
Au->decoder = new SimpleAudio(Au->audioType);
|
||||
Au->decoder = CreateAudioDecoder(PSP_CODEC_MP3);
|
||||
|
||||
int handle = (int)mp3Map.size();
|
||||
mp3Map[handle] = Au;
|
||||
@ -445,9 +498,6 @@ static int sceMp3Init(u32 mp3) {
|
||||
|
||||
ctx->Version = versionBits;
|
||||
|
||||
// This tells us to resample to the same frequency it decodes to.
|
||||
ctx->decoder->SetResampleFrequency(ctx->freq);
|
||||
|
||||
return hleDelayResult(hleLogSuccessI(ME, 0), "mp3 init", PARSE_DELAY_MS);
|
||||
}
|
||||
|
||||
@ -476,7 +526,7 @@ static int sceMp3GetMaxOutputSample(u32 mp3) {
|
||||
return hleLogWarning(ME, 0, "no channel available for low level");
|
||||
}
|
||||
|
||||
return hleLogSuccessI(ME, ctx->AuGetMaxOutputSample());
|
||||
return hleLogSuccessI(ME, ctx->MaxOutputSample);
|
||||
}
|
||||
|
||||
static int sceMp3GetSumDecodedSample(u32 mp3) {
|
||||
@ -489,7 +539,7 @@ static int sceMp3GetSumDecodedSample(u32 mp3) {
|
||||
return hleLogError(ME, ERROR_MP3_UNRESERVED_HANDLE, "incorrect handle type");
|
||||
}
|
||||
|
||||
return hleLogSuccessI(ME, ctx->AuGetSumDecodedSample());
|
||||
return hleLogSuccessI(ME, ctx->SumDecodedSamples);
|
||||
}
|
||||
|
||||
static int sceMp3SetLoopNum(u32 mp3, int loop) {
|
||||
@ -520,7 +570,7 @@ static int sceMp3GetMp3ChannelNum(u32 mp3) {
|
||||
return hleLogWarning(ME, 0, "no channel available for low level");
|
||||
}
|
||||
|
||||
return hleLogSuccessI(ME, ctx->AuGetChannelNum());
|
||||
return hleLogSuccessI(ME, ctx->Channels);
|
||||
}
|
||||
|
||||
static int sceMp3GetBitRate(u32 mp3) {
|
||||
@ -535,7 +585,7 @@ static int sceMp3GetBitRate(u32 mp3) {
|
||||
return hleLogWarning(ME, 0, "no bitrate available for low level");
|
||||
}
|
||||
|
||||
return hleLogSuccessI(ME, ctx->AuGetBitRate());
|
||||
return hleLogSuccessI(ME, ctx->BitRate);
|
||||
}
|
||||
|
||||
static int sceMp3GetSamplingRate(u32 mp3) {
|
||||
@ -550,7 +600,7 @@ static int sceMp3GetSamplingRate(u32 mp3) {
|
||||
return hleLogWarning(ME, 0, "no sample rate available for low level");
|
||||
}
|
||||
|
||||
return hleLogSuccessI(ME, ctx->AuGetSamplingRate());
|
||||
return hleLogSuccessI(ME, ctx->SamplingRate);
|
||||
}
|
||||
|
||||
static int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) {
|
||||
@ -613,7 +663,7 @@ static u32 sceMp3GetFrameNum(u32 mp3) {
|
||||
return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
|
||||
}
|
||||
|
||||
return hleLogSuccessI(ME, ctx->AuGetFrameNum());
|
||||
return hleLogSuccessI(ME, ctx->FrameNum);
|
||||
}
|
||||
|
||||
static u32 sceMp3GetMPEGVersion(u32 mp3) {
|
||||
@ -630,7 +680,7 @@ static u32 sceMp3GetMPEGVersion(u32 mp3) {
|
||||
}
|
||||
|
||||
// Tests have not revealed how to expose more than "3" here as a result.
|
||||
return hleReportDebug(ME, ctx->AuGetVersion());
|
||||
return hleReportDebug(ME, ctx->Version);
|
||||
}
|
||||
|
||||
static u32 sceMp3ResetPlayPositionByFrame(u32 mp3, u32 frame) {
|
||||
@ -643,7 +693,7 @@ static u32 sceMp3ResetPlayPositionByFrame(u32 mp3, u32 frame) {
|
||||
return hleLogError(ME, ERROR_MP3_NOT_YET_INIT_HANDLE, "not yet init");
|
||||
}
|
||||
|
||||
if (frame >= (u32)ctx->AuGetFrameNum()) {
|
||||
if (frame >= (u32)ctx->FrameNum) {
|
||||
return hleLogError(ME, ERROR_MP3_BAD_RESET_FRAME, "bad frame position");
|
||||
}
|
||||
|
||||
@ -651,11 +701,10 @@ static u32 sceMp3ResetPlayPositionByFrame(u32 mp3, u32 frame) {
|
||||
}
|
||||
|
||||
static u32 sceMp3LowLevelInit(u32 mp3, u32 unk) {
|
||||
auto ctx = new AuCtx;
|
||||
auto ctx = new AuCtx();
|
||||
|
||||
ctx->audioType = PSP_CODEC_MP3;
|
||||
// create mp3 decoder
|
||||
ctx->decoder = new SimpleAudio(ctx->audioType);
|
||||
ctx->decoder = CreateAudioDecoder(PSP_CODEC_MP3);
|
||||
|
||||
// close the audio if mp3 already exists.
|
||||
if (mp3Map.find(mp3) != mp3Map.end()) {
|
||||
|
@ -21,5 +21,6 @@ class PointerWrap;
|
||||
|
||||
void Register_sceMp3();
|
||||
|
||||
void __Mp3Init();
|
||||
void __Mp3Shutdown();
|
||||
void __Mp3DoState(PointerWrap &p);
|
||||
void __Mp3DoState(PointerWrap &p);
|
||||
|
@ -253,10 +253,9 @@ static u32 sceAacInit(u32 id)
|
||||
aac->Channels = 2;
|
||||
aac->MaxOutputSample = aac->PCMBufSize / 4;
|
||||
aac->SetReadPos((int)aac->startPos);
|
||||
aac->audioType = PSP_CODEC_AAC;
|
||||
|
||||
// create aac decoder
|
||||
aac->decoder = new SimpleAudio(aac->audioType);
|
||||
aac->decoder = CreateAudioDecoder(PSP_CODEC_AAC);
|
||||
|
||||
// close the audio if id already exist.
|
||||
if (aacMap.find(id) != aacMap.end()) {
|
||||
@ -368,7 +367,7 @@ static u32 sceAacGetMaxOutputSample(u32 id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ctx->AuGetMaxOutputSample();
|
||||
return ctx->MaxOutputSample;
|
||||
}
|
||||
|
||||
static u32 sceAacGetSumDecodedSample(u32 id)
|
||||
@ -380,7 +379,7 @@ static u32 sceAacGetSumDecodedSample(u32 id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ctx->AuGetSumDecodedSample();
|
||||
return ctx->SumDecodedSamples;
|
||||
}
|
||||
|
||||
static u32 sceAacResetPlayPosition(u32 id)
|
||||
|
@ -340,7 +340,7 @@ bool MediaEngine::openContext(bool keepReadPos) {
|
||||
return false;
|
||||
|
||||
setVideoDim();
|
||||
m_audioContext = new SimpleAudio(m_audioType, 44100, 2);
|
||||
m_audioContext = CreateAudioDecoder((PSPAudioType)m_audioType);
|
||||
m_isVideoEnd = false;
|
||||
#endif // USE_FFMPEG
|
||||
return true;
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "Core/HW/SimpleAudioDec.h"
|
||||
|
||||
class PointerWrap;
|
||||
class SimpleAudio;
|
||||
class AudioDecoder;
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
struct SwsContext;
|
||||
@ -50,8 +50,7 @@ inline s64 getMpegTimeStamp(const u8 *buf) {
|
||||
bool InitFFmpeg();
|
||||
#endif
|
||||
|
||||
class MediaEngine
|
||||
{
|
||||
class MediaEngine {
|
||||
public:
|
||||
MediaEngine();
|
||||
~MediaEngine();
|
||||
@ -144,7 +143,7 @@ private:
|
||||
s64 m_lastPts = -1;
|
||||
|
||||
MpegDemux *m_demux = nullptr;
|
||||
SimpleAudio *m_audioContext = nullptr;
|
||||
AudioDecoder *m_audioContext = nullptr;
|
||||
s64 m_audiopts = 0;
|
||||
|
||||
// used for audio type
|
||||
|
@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Core/Config.h"
|
||||
@ -32,12 +33,63 @@ extern "C" {
|
||||
#include "libswresample/swresample.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
#include "libavcodec/avcodec.h"
|
||||
}
|
||||
#include "libavutil/version.h"
|
||||
|
||||
#include "Core/FFMPEGCompat.h"
|
||||
}
|
||||
|
||||
#endif // USE_FFMPEG
|
||||
|
||||
int SimpleAudio::GetAudioCodecID(int audioType) {
|
||||
// FFMPEG-based decoder. TODO: Replace with individual codecs.
|
||||
class SimpleAudio : public AudioDecoder {
|
||||
public:
|
||||
SimpleAudio(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2);
|
||||
~SimpleAudio();
|
||||
|
||||
bool Decode(const uint8_t* inbuf, int inbytes, uint8_t *outbuf, int *outbytes) override;
|
||||
bool IsOK() const override;
|
||||
|
||||
int GetOutSamples() const override {
|
||||
return outSamples;
|
||||
}
|
||||
int GetSourcePos() const override {
|
||||
return srcPos;
|
||||
}
|
||||
|
||||
// Not save stated, only used by UI. Used for ATRAC3 (non+) files.
|
||||
void SetExtraData(const uint8_t *data, int size, int wav_bytes_per_packet) override;
|
||||
|
||||
void SetChannels(int channels) override;
|
||||
|
||||
// These two are only here because of save states.
|
||||
PSPAudioType GetAudioType() const { return audioType; }
|
||||
|
||||
private:
|
||||
bool OpenCodec(int block_align);
|
||||
|
||||
PSPAudioType audioType;
|
||||
int sample_rate_;
|
||||
int channels_;
|
||||
int outSamples; // output samples per frame
|
||||
int srcPos; // bytes consumed in source during the last decoding
|
||||
|
||||
AVFrame *frame_;
|
||||
#if HAVE_LIBAVCODEC_CONST_AVCODEC // USE_FFMPEG is implied
|
||||
const
|
||||
#endif
|
||||
AVCodec *codec_;
|
||||
AVCodecContext *codecCtx_;
|
||||
SwrContext *swrCtx_;
|
||||
|
||||
bool codecOpen_;
|
||||
};
|
||||
|
||||
// TODO: This should also be able to create other types of decoders.
|
||||
AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels) {
|
||||
return new SimpleAudio(audioType, sampleRateHz, channels);
|
||||
}
|
||||
|
||||
static int GetAudioCodecID(int audioType) {
|
||||
#ifdef USE_FFMPEG
|
||||
switch (audioType) {
|
||||
case PSP_CODEC_AAC:
|
||||
@ -56,14 +108,12 @@ int SimpleAudio::GetAudioCodecID(int audioType) {
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
SimpleAudio::SimpleAudio(int audioType, int sample_rate, int channels)
|
||||
: ctxPtr(0xFFFFFFFF), audioType(audioType), sample_rate_(sample_rate), channels_(channels),
|
||||
outSamples(0), srcPos(0), wanted_resample_freq(44100), frame_(0), codec_(0), codecCtx_(0), swrCtx_(0),
|
||||
codecOpen_(false) {
|
||||
Init();
|
||||
}
|
||||
SimpleAudio::SimpleAudio(PSPAudioType audioType, int sampleRateHz, int channels)
|
||||
: audioType(audioType), sample_rate_(sampleRateHz), channels_(channels),
|
||||
outSamples(0), srcPos(0),
|
||||
frame_(0), codec_(0), codecCtx_(0), swrCtx_(0),
|
||||
codecOpen_(false) {
|
||||
|
||||
void SimpleAudio::Init() {
|
||||
#ifdef USE_FFMPEG
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100)
|
||||
avcodec_register_all();
|
||||
@ -122,7 +172,7 @@ bool SimpleAudio::OpenCodec(int block_align) {
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
void SimpleAudio::SetExtraData(const u8 *data, int size, int wav_bytes_per_packet) {
|
||||
void SimpleAudio::SetExtraData(const uint8_t *data, int size, int wav_bytes_per_packet) {
|
||||
#ifdef USE_FFMPEG
|
||||
if (codecCtx_) {
|
||||
codecCtx_->extradata = (uint8_t *)av_mallocz(size);
|
||||
@ -179,6 +229,7 @@ bool SimpleAudio::IsOK() const {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Decodes a single input frame.
|
||||
bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int *outbytes) {
|
||||
#ifdef USE_FFMPEG
|
||||
if (!codecOpen_) {
|
||||
@ -238,7 +289,7 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int
|
||||
swrCtx_,
|
||||
wanted_channel_layout,
|
||||
AV_SAMPLE_FMT_S16,
|
||||
wanted_resample_freq,
|
||||
codecCtx_->sample_rate,
|
||||
dec_channel_layout,
|
||||
codecCtx_->sample_fmt,
|
||||
codecCtx_->sample_rate,
|
||||
@ -279,12 +330,11 @@ bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, uint8_t *outbuf, int
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
int SimpleAudio::GetOutSamples() {
|
||||
return outSamples;
|
||||
}
|
||||
|
||||
int SimpleAudio::GetSourcePos() {
|
||||
return srcPos;
|
||||
void AudioClose(AudioDecoder **ctx) {
|
||||
#ifdef USE_FFMPEG
|
||||
delete *ctx;
|
||||
*ctx = 0;
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
void AudioClose(SimpleAudio **ctx) {
|
||||
@ -294,7 +344,6 @@ void AudioClose(SimpleAudio **ctx) {
|
||||
#endif // USE_FFMPEG
|
||||
}
|
||||
|
||||
|
||||
static const char *const codecNames[4] = {
|
||||
"AT3+", "AT3", "MP3", "AAC",
|
||||
};
|
||||
@ -307,7 +356,7 @@ const char *GetCodecName(int codec) {
|
||||
}
|
||||
};
|
||||
|
||||
bool IsValidCodec(int codec){
|
||||
bool IsValidCodec(PSPAudioType codec){
|
||||
if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
|
||||
return true;
|
||||
}
|
||||
@ -328,7 +377,7 @@ AuCtx::~AuCtx() {
|
||||
}
|
||||
|
||||
size_t AuCtx::FindNextMp3Sync() {
|
||||
if (audioType != PSP_CODEC_MP3) {
|
||||
if (decoder->GetAudioType() != PSP_CODEC_MP3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -421,7 +470,7 @@ int AuCtx::AuCheckStreamDataNeeded() {
|
||||
}
|
||||
|
||||
int AuCtx::AuStreamBytesNeeded() {
|
||||
if (audioType == PSP_CODEC_MP3) {
|
||||
if (decoder->GetAudioType() == PSP_CODEC_MP3) {
|
||||
// The endPos and readPos are not considered, except when you've read to the end.
|
||||
if (readPos >= endPos)
|
||||
return 0;
|
||||
@ -436,7 +485,7 @@ int AuCtx::AuStreamBytesNeeded() {
|
||||
|
||||
int AuCtx::AuStreamWorkareaSize() {
|
||||
// Note that this is 31 bytes more than the max layer 3 frame size.
|
||||
if (audioType == PSP_CODEC_MP3)
|
||||
if (decoder->GetAudioType() == PSP_CODEC_MP3)
|
||||
return 0x05c0;
|
||||
return 0;
|
||||
}
|
||||
@ -533,6 +582,7 @@ void AuCtx::DoState(PointerWrap &p) {
|
||||
Do(p, Channels);
|
||||
Do(p, MaxOutputSample);
|
||||
Do(p, readPos);
|
||||
int audioType = (int)decoder->GetAudioType();
|
||||
Do(p, audioType);
|
||||
Do(p, BitRate);
|
||||
Do(p, SamplingRate);
|
||||
@ -552,6 +602,6 @@ void AuCtx::DoState(PointerWrap &p) {
|
||||
}
|
||||
|
||||
if (p.mode == p.MODE_READ) {
|
||||
decoder = new SimpleAudio(audioType);
|
||||
decoder = CreateAudioDecoder((PSPAudioType)audioType);
|
||||
}
|
||||
}
|
||||
|
@ -17,88 +17,48 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
#include "Core/HLE/sceAudio.h"
|
||||
|
||||
struct AVFrame;
|
||||
struct AVCodec;
|
||||
struct AVCodecContext;
|
||||
struct SwrContext;
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
|
||||
extern "C" {
|
||||
#include "libavutil/version.h"
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// Wraps FFMPEG for audio decoding in a nice interface.
|
||||
// Decodes packet by packet - does NOT demux.
|
||||
|
||||
// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13
|
||||
|
||||
// audioType
|
||||
enum {
|
||||
enum PSPAudioType {
|
||||
PSP_CODEC_AT3PLUS = 0x00001000,
|
||||
PSP_CODEC_AT3 = 0x00001001,
|
||||
PSP_CODEC_MP3 = 0x00001002,
|
||||
PSP_CODEC_AAC = 0x00001003,
|
||||
};
|
||||
|
||||
class SimpleAudio {
|
||||
class AudioDecoder {
|
||||
public:
|
||||
SimpleAudio(int audioType, int sample_rate = 44100, int channels = 2);
|
||||
~SimpleAudio();
|
||||
virtual ~AudioDecoder() {}
|
||||
|
||||
bool Decode(const uint8_t* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
|
||||
bool IsOK() const;
|
||||
virtual bool Decode(const uint8_t* inbuf, int inbytes, uint8_t *outbuf, int *outbytes) = 0;
|
||||
virtual bool IsOK() const = 0;
|
||||
|
||||
int GetOutSamples();
|
||||
int GetSourcePos();
|
||||
int GetAudioCodecID(int audioType); // Get audioCodecId from audioType
|
||||
virtual int GetOutSamples() const = 0;
|
||||
virtual int GetSourcePos() const = 0;
|
||||
virtual PSPAudioType GetAudioType() const = 0;
|
||||
|
||||
// Not save stated, only used by UI. Used for ATRAC3 (non+) files.
|
||||
void SetExtraData(const u8 *data, int size, int wav_bytes_per_packet);
|
||||
|
||||
void SetChannels(int channels);
|
||||
|
||||
// These two are only here because of save states.
|
||||
int GetAudioType() const { return audioType; }
|
||||
void SetResampleFrequency(int freq) { wanted_resample_freq = freq; }
|
||||
virtual void SetChannels(int channels) = 0;
|
||||
virtual void SetExtraData(const uint8_t *data, int size, int wav_bytes_per_packet) = 0;
|
||||
|
||||
// Just metadata.
|
||||
void SetCtxPtr(u32 ptr) { ctxPtr = ptr; }
|
||||
u32 GetCtxPtr() const { return ctxPtr; }
|
||||
void SetCtxPtr(uint32_t ptr) { ctxPtr = ptr; }
|
||||
uint32_t GetCtxPtr() const { return ctxPtr; }
|
||||
|
||||
private:
|
||||
void Init();
|
||||
bool OpenCodec(int block_align);
|
||||
|
||||
u32 ctxPtr;
|
||||
int audioType;
|
||||
int sample_rate_;
|
||||
int channels_;
|
||||
int outSamples; // output samples per frame
|
||||
int srcPos; // bytes consumed in source during the last decoding
|
||||
int wanted_resample_freq; // wanted resampling rate/frequency
|
||||
|
||||
AVFrame *frame_;
|
||||
#if HAVE_LIBAVCODEC_CONST_AVCODEC // USE_FFMPEG is implied
|
||||
const
|
||||
#endif
|
||||
AVCodec *codec_;
|
||||
AVCodecContext *codecCtx_;
|
||||
SwrContext *swrCtx_;
|
||||
|
||||
bool codecOpen_;
|
||||
uint32_t ctxPtr = 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
void AudioClose(SimpleAudio **ctx);
|
||||
void AudioClose(AudioDecoder **ctx);
|
||||
const char *GetCodecName(int codec); // audioType
|
||||
bool IsValidCodec(int codec);
|
||||
bool IsValidCodec(PSPAudioType codec);
|
||||
AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2);
|
||||
|
||||
class AuCtx {
|
||||
public:
|
||||
@ -118,13 +78,6 @@ public:
|
||||
u32 AuGetLoopNum();
|
||||
|
||||
u32 AuGetInfoToAddStreamData(u32 bufPtr, u32 sizePtr, u32 srcPosPtr);
|
||||
u32 AuGetMaxOutputSample() const { return MaxOutputSample; }
|
||||
u32 AuGetSumDecodedSample() const { return SumDecodedSamples; }
|
||||
int AuGetChannelNum() const { return Channels; }
|
||||
int AuGetBitRate() const { return BitRate; }
|
||||
int AuGetSamplingRate() const { return SamplingRate; }
|
||||
int AuGetVersion() const { return Version; }
|
||||
int AuGetFrameNum() const { return FrameNum; }
|
||||
|
||||
void SetReadPos(int pos) { readPos = pos; }
|
||||
int ReadPos() { return readPos; }
|
||||
@ -146,7 +99,8 @@ public:
|
||||
u32 AuBufSize = 0;
|
||||
u32 PCMBuf = 0;
|
||||
u32 PCMBufSize = 0;
|
||||
int freq = -1;
|
||||
|
||||
int freq = -1; // used by AAC only?
|
||||
int BitRate = 0;
|
||||
int SamplingRate = -1;
|
||||
int Channels = 0;
|
||||
@ -159,10 +113,7 @@ public:
|
||||
int FrameNum = 0;
|
||||
|
||||
// Au decoder
|
||||
SimpleAudio *decoder = nullptr;
|
||||
|
||||
// Au type
|
||||
int audioType = 0;
|
||||
AudioDecoder *decoder = nullptr;
|
||||
|
||||
private:
|
||||
size_t FindNextMp3Sync();
|
||||
@ -171,7 +122,7 @@ private:
|
||||
|
||||
// buffers informations
|
||||
int AuBufAvailable = 0; // the available buffer of AuBuf to be able to recharge data
|
||||
int readPos; // read position in audio source file
|
||||
int readPos = 0; // read position in audio source file
|
||||
int askedReadSize = 0; // the size of data requied to be read from file by the game
|
||||
int nextOutputHalf = 0;
|
||||
};
|
||||
|
@ -189,7 +189,7 @@ public:
|
||||
|
||||
wave_.Read(file_);
|
||||
|
||||
decoder_ = new SimpleAudio(wave_.codec, wave_.sample_rate, wave_.num_channels);
|
||||
decoder_ = CreateAudioDecoder((PSPAudioType)wave_.codec, wave_.sample_rate, wave_.num_channels);
|
||||
if (wave_.codec == PSP_CODEC_AT3) {
|
||||
decoder_->SetExtraData(&wave_.at3_extradata[2], 14, wave_.raw_bytes_per_frame);
|
||||
}
|
||||
@ -256,7 +256,7 @@ private:
|
||||
int skip_next_samples_ = 0;
|
||||
FixedSizeQueue<s16, 128 * 1024> bgQueue;
|
||||
short *buffer_ = nullptr;
|
||||
SimpleAudio *decoder_ = nullptr;
|
||||
AudioDecoder *decoder_ = nullptr;
|
||||
};
|
||||
|
||||
BackgroundAudio g_BackgroundAudio;
|
||||
@ -433,7 +433,7 @@ Sample *Sample::Load(const std::string &path) {
|
||||
// mp3_info contains the decoded data.
|
||||
int16_t *sample_data = new int16_t[mp3_info.samples];
|
||||
memcpy(sample_data, mp3_info.buffer, mp3_info.samples * sizeof(int16_t));
|
||||
Sample *sample = new Sample(sample_data, mp3_info.channels, mp3_info.samples, mp3_info.hz);
|
||||
Sample *sample = new Sample(sample_data, mp3_info.channels, (int)mp3_info.samples, mp3_info.hz);
|
||||
free(mp3_info.buffer);
|
||||
delete[] data;
|
||||
return sample;
|
||||
|
Loading…
Reference in New Issue
Block a user