diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f171681cf..8aeefd3044 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1117,10 +1117,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceNp.h
Core/HLE/scePauth.cpp
Core/HLE/scePauth.h
- Core/HW/SimpleAT3Dec.cpp
- Core/HW/SimpleAT3Dec.h
- Core/HW/SimpleMp3Dec.cpp
- Core/HW/SimpleMp3Dec.h
+ Core/HW/SimpleAudioDec.cpp
+ Core/HW/SimpleAudioDec.h
Core/HW/AsyncIOManager.cpp
Core/HW/AsyncIOManager.h
Core/HW/MediaEngine.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 8e063a1849..61d4957453 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -257,13 +257,12 @@
-
-
+
@@ -531,13 +530,12 @@
-
-
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index a7cc163337..fb49932054 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -433,9 +433,6 @@
Core
-
- HW
-
HW
@@ -520,7 +517,7 @@
MIPS\PPC
-
+
HW
@@ -885,9 +882,6 @@
Core
-
- HW
-
HW
@@ -963,7 +957,7 @@
HW
-
+
HW
diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp
index f714e4f03b..062e8484f2 100644
--- a/Core/HLE/sceAudiocodec.cpp
+++ b/Core/HLE/sceAudiocodec.cpp
@@ -20,26 +20,8 @@
#include "Core/HLE/sceAudiocodec.h"
#include "Core/MemMap.h"
#include "Core/Reporting.h"
-#include "Core/HW/SimpleMp3Dec.h"
-
-enum {
- PSP_CODEC_AT3PLUS = 0x00001000,
- PSP_CODEC_AT3 = 0x00001001,
- PSP_CODEC_MP3 = 0x00001002,
- PSP_CODEC_AAC = 0x00001003,
-};
-
-static const char *const codecNames[4] = {
- "AT3+", "AT3", "MP3", "AAC",
-};
-
-static const char *GetCodecName(int codec) {
- if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
- return codecNames[codec - PSP_CODEC_AT3PLUS];
- } else {
- return "(unk)";
- }
-}
+#include "Core/HW/SimpleAudioDec.h"
+#include "Common/ChunkFile.h"
// Following kaien_fr's sample code https://github.com/hrydgard/ppsspp/issues/5620#issuecomment-37086024
// Should probably store the EDRAM get/release status somewhere within here, etc.
@@ -50,18 +32,43 @@ struct AudioCodecContext {
u32_le outDataPtr; // 8
u32_le audioSamplesPerFrame; // 9
u32_le inDataSizeAgain; // 10 ??
-};
+};
+
+// audioList is to store current playing audios.
+std::list audioList;
+
+// find the audio decoder for corresponding ctxPtr in audioList
+SimpleAudio * findDecoder(u32 ctxPtr){
+ for (std::list::iterator it = audioList.begin(); it != audioList.end(); it++){
+ if ((*it)->ctxPtr == ctxPtr){
+ return (*it);
+ }
+ }
+ return NULL;
+}
+
+// remove decoder from audioList
+bool removeDecoder(u32 ctxPtr){
+ for (std::list::iterator it = audioList.begin(); it != audioList.end(); it++){
+ if ((*it)->ctxPtr == ctxPtr){
+ audioList.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
-SimpleMP3* mp3;
int sceAudiocodecInit(u32 ctxPtr, int codec) {
- if (codec == PSP_CODEC_MP3){
- // Initialize MP3 audio decoder.
- mp3 = MP3Create();
- DEBUG_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
+ if (isValidCodec(codec)){
+ // Create audio decoder for given audio codec and push it into AudioList
+ auto decoder = new SimpleAudio(ctxPtr, codec);
+ audioList.push_front(decoder);
+ INFO_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
+ DEBUG_LOG(ME, "Number of playing audios : %d", audioList.size());
return 0;
}
- ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
+ ERROR_LOG_REPORT(ME, "sceAudiocodecInit(%08x, %i (%s)): Unknown audio codec %i", ctxPtr, codec, GetCodecName(codec), codec);
return 0;
}
@@ -70,15 +77,24 @@ int sceAudiocodecDecode(u32 ctxPtr, int codec) {
ERROR_LOG_REPORT(ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(codec));
return -1;
}
- if (codec == PSP_CODEC_MP3){
- //Use SimpleMp3Dec to decode Mp3 audio
+ if (isValidCodec(codec)){
+ // Use SimpleAudioDec to decode audio
// Get AudioCodecContext
- AudioCodecContext* ctx = new AudioCodecContext;
+ auto ctx = new AudioCodecContext;
Memory::ReadStruct(ctxPtr, ctx);
int outbytes = 0;
- // Decode Mp3 audio
- MP3Decode(mp3, Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, &outbytes, Memory::GetPointer(ctx->outDataPtr));
+ // find a decoder in audioList
+ auto decoder = findDecoder(ctxPtr);
+ if (decoder == NULL){
+ // create a decoder, this is possible when loadstate
+ decoder = new SimpleAudio(ctxPtr, codec);
+ audioList.push_front(decoder);
+ }
+ // Decode audio
+ AudioDecode(decoder, Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, &outbytes, Memory::GetPointer(ctx->outDataPtr));
DEBUG_LOG(ME, "sceAudiocodecDec(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
+ // Delete AudioCodecContext
+ delete(ctx);
return 0;
}
ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecDecode(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
@@ -100,22 +116,32 @@ int sceAudiocodecGetEDRAM(u32 ctxPtr, int codec) {
return 0;
}
-int sceAudiocodecReleaseEDRAM(u32 ctxPtr, int codec) {
- WARN_LOG(ME, "UNIMPL sceAudiocodecReleaseEDRAM(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
+int sceAudiocodecReleaseEDRAM(u32 ctxPtr, int id) {
+ //id is not always a codec, so what is should be?
+ if (removeDecoder(ctxPtr)){
+ INFO_LOG(ME, "sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id);
+ return 0;
+ }
+ WARN_LOG(ME, "UNIMPL sceAudiocodecReleaseEDRAM(%08x, %i)", ctxPtr, id);
return 0;
}
const HLEFunction sceAudiocodec[] = {
- {0x70A703F8, WrapI_UI, "sceAudiocodecDecode"},
- {0x5B37EB1D, WrapI_UI, "sceAudiocodecInit"},
- {0x8ACA11D5, WrapI_UI, "sceAudiocodecGetInfo"},
- {0x3A20A200, WrapI_UI, "sceAudiocodecGetEDRAM" },
- {0x29681260, WrapI_UI, "sceAudiocodecReleaseEDRAM" },
- {0x9D3F790C, WrapI_UI, "sceAudiocodecCheckNeedMem" },
- {0x59176a0f, 0, "sceAudiocodec_59176A0F"},
+ { 0x70A703F8, WrapI_UI, "sceAudiocodecDecode" },
+ { 0x5B37EB1D, WrapI_UI, "sceAudiocodecInit" },
+ { 0x8ACA11D5, WrapI_UI, "sceAudiocodecGetInfo" },
+ { 0x3A20A200, WrapI_UI, "sceAudiocodecGetEDRAM" },
+ { 0x29681260, WrapI_UI, "sceAudiocodecReleaseEDRAM" },
+ { 0x9D3F790C, WrapI_UI, "sceAudiocodecCheckNeedMem" },
+ { 0x59176a0f, 0, "sceAudiocodec_59176A0F" },
};
void Register_sceAudiocodec()
{
RegisterModule("sceAudiocodec", ARRAY_SIZE(sceAudiocodec), sceAudiocodec);
-}
\ No newline at end of file
+}
+
+void resetAudioList(){
+ audioList.clear();
+ INFO_LOG(ME, "Audio playing list is reset");
+}
diff --git a/Core/HLE/sceAudiocodec.h b/Core/HLE/sceAudiocodec.h
index 981803a9d2..c2135f8556 100644
--- a/Core/HLE/sceAudiocodec.h
+++ b/Core/HLE/sceAudiocodec.h
@@ -56,4 +56,5 @@ typedef struct
u8 unk[20];
} SceAudiocodecCodec;
-void Register_sceAudiocodec();
\ No newline at end of file
+void Register_sceAudiocodec();
+void resetAudioList();
diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp
index b70e91423d..124bbd2c7c 100644
--- a/Core/HW/MediaEngine.cpp
+++ b/Core/HW/MediaEngine.cpp
@@ -20,7 +20,7 @@
#include "Core/MemMap.h"
#include "Core/Reporting.h"
#include "GPU/GPUInterface.h"
-#include "Core/HW/SimpleAT3Dec.h"
+#include "Core/HW/SimpleAudioDec.h"
#include
@@ -152,6 +152,7 @@ MediaEngine::MediaEngine(): m_pdata(0) {
m_ringbuffersize = 0;
m_mpegheaderReadPos = 0;
+ m_audioType = PSP_CODEC_AT3PLUS; // in movie, we use only AT3+ audio
g_iNumVideos++;
}
@@ -168,7 +169,7 @@ void MediaEngine::closeMedia() {
delete m_demux;
m_pdata = 0;
m_demux = 0;
- AT3Close(&m_audioContext);
+ AudioClose(&m_audioContext);
m_isVideoEnd = false;
m_noAudioData = false;
}
@@ -212,6 +213,9 @@ void MediaEngine::DoState(PointerWrap &p){
p.Do(m_isVideoEnd);
p.Do(m_noAudioData);
+ if (s > 2){
+ p.Do(m_audioType);
+ }
}
int _MpegReadbuffer(void *opaque, uint8_t *buf, int buf_size)
@@ -279,7 +283,7 @@ bool MediaEngine::openContext() {
return false;
setVideoDim();
- m_audioContext = AT3Create();
+ m_audioContext = AudioCreate(m_audioType);
m_isVideoEnd = false;
m_noAudioData = false;
m_mpegheaderReadPos++;
@@ -734,8 +738,8 @@ int MediaEngine::getAudioSamples(u32 bufferPtr) {
int outbytes = 0;
if (m_audioContext != NULL) {
- if (!AT3Decode(m_audioContext, audioFrame, frameSize, &outbytes, buffer)) {
- ERROR_LOG(ME, "AT3 decode failed during video playback");
+ if (!AudioDecode(m_audioContext, audioFrame, frameSize, &outbytes, buffer)) {
+ ERROR_LOG(ME, "Audio (%s) decode failed during video playback", GetCodecName(m_audioType));
}
}
diff --git a/Core/HW/MediaEngine.h b/Core/HW/MediaEngine.h
index ece2a32efc..1597b8ef51 100644
--- a/Core/HW/MediaEngine.h
+++ b/Core/HW/MediaEngine.h
@@ -28,9 +28,10 @@
#include "Common/CommonTypes.h"
#include "Core/HLE/sceMpeg.h"
#include "Core/HW/MpegDemux.h"
+#include "Core/HW/SimpleAudioDec.h"
class PointerWrap;
-struct SimpleAT3;
+struct SimpleAudio;
#ifdef USE_FFMPEG
struct SwsContext;
@@ -119,7 +120,7 @@ public: // TODO: Very little of this below should be public.
BufferQueue *m_pdata;
MpegDemux *m_demux;
- SimpleAT3 *m_audioContext;
+ SimpleAudio *m_audioContext;
s64 m_audiopts;
s64 m_firstTimeStamp;
@@ -131,4 +132,7 @@ public: // TODO: Very little of this below should be public.
int m_ringbuffersize;
u8 m_mpegheader[0x10000]; // TODO: Allocate separately
int m_mpegheaderReadPos;
+
+ // used for audio type
+ int m_audioType;
};
diff --git a/Core/HW/SimpleAT3Dec.cpp b/Core/HW/SimpleAT3Dec.cpp
deleted file mode 100644
index 2ba87ea63b..0000000000
--- a/Core/HW/SimpleAT3Dec.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright (c) 2013- PPSSPP Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official git repository and contact information can be found at
-// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-
-#include "Core/HW/SimpleAT3Dec.h"
-#include "Core/HW/MediaEngine.h"
-#include "Core/HW/BufferQueue.h"
-
-#ifdef USE_FFMPEG
-
-extern "C" {
-#include
-#include
-#include
-}
-
-struct SimpleAT3 {
-public:
- SimpleAT3();
- ~SimpleAT3();
-
- bool Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
- bool IsOK() const { return codec_ != 0; }
-
-private:
- AVFrame *frame_;
- AVCodec *codec_;
- AVCodecContext *codecCtx_;
- SwrContext *swrCtx_;
-};
-
-SimpleAT3::SimpleAT3()
- : codec_(0),
- codecCtx_(0),
- swrCtx_(0) {
- frame_ = av_frame_alloc();
-
- codec_ = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
- if (!codec_) {
- // Eh, we shouldn't even have managed to compile. But meh.
- ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ID_ATRAC3P (Atrac3+). Update your submodule.");
- return;
- }
-
- codecCtx_ = avcodec_alloc_context3(codec_);
- if (!codecCtx_) {
- ERROR_LOG(ME, "Failed to allocate a codec context");
- return;
- }
-
- codecCtx_->channels = 2;
- codecCtx_->channel_layout = AV_CH_LAYOUT_STEREO;
-
- AVDictionary *opts = 0;
- av_dict_set(&opts, "channels", "2", 0);
- av_dict_set(&opts, "sample_rate", "44100", 0);
- if (avcodec_open2(codecCtx_, codec_, &opts) < 0) {
- ERROR_LOG(ME, "Failed to open codec");
- return;
- }
-
- av_dict_free(&opts);
-
- // Initializing the sample rate convert. We only really use it to convert float output
- // into int.
- int wanted_channels = 2;
- int64_t wanted_channel_layout = av_get_default_channel_layout(wanted_channels);
- int64_t dec_channel_layout = av_get_default_channel_layout(2);
-
- swrCtx_ = swr_alloc_set_opts(
- swrCtx_,
- wanted_channel_layout,
- AV_SAMPLE_FMT_S16,
- codecCtx_->sample_rate,
- dec_channel_layout,
- codecCtx_->sample_fmt,
- codecCtx_->sample_rate,
- 0,
- NULL);
-
- if (!swrCtx_ || swr_init(swrCtx_) < 0) {
- ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context");
- avcodec_close(codecCtx_);
- codec_ = 0;
- return;
- }
-}
-
-SimpleAT3::~SimpleAT3() {
- if (frame_)
- av_frame_free(&frame_);
- if (codecCtx_)
- avcodec_close(codecCtx_);
- codecCtx_ = 0;
- codec_ = 0;
- if (swrCtx_)
- swr_free(&swrCtx_);
-}
-
-// Input is a single Atrac3+ packet.
-bool SimpleAT3::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes) {
-#ifdef USE_FFMPEG
- AVPacket packet = {0};
- av_init_packet(&packet);
- packet.data = static_cast(inbuf);
- packet.size = inbytes;
-
- *outbytes = 0;
-
- int got_frame = 0;
- av_frame_unref(frame_);
-
- int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
- if (len < 0) {
- ERROR_LOG(ME, "Error decoding Atrac3+ frame");
- // TODO: cleanup
- return false;
- }
-
- if (got_frame) {
- int data_size = av_samples_get_buffer_size(
- NULL,
- codecCtx_->channels,
- frame_->nb_samples,
- codecCtx_->sample_fmt, 1);
- int numSamples = frame_->nb_samples;
- int swrRet = swr_convert(swrCtx_, &outbuf, numSamples, (const u8 **)frame_->extended_data, numSamples);
- if (swrRet < 0) {
- ERROR_LOG(ME, "swr_convert: Error while converting %d", swrRet);
- return false;
- }
- // We always convert to stereo.
- __AdjustBGMVolume((s16 *)outbuf, numSamples * 2);
- }
-
- return true;
-#else
- // Zero bytes output. No need to memset.
- *outbytes = 0;
- return true;
-#endif // USE_FFMPEG
-}
-
-#endif // USE_FFMPEG
-
-// "C" wrapper
-
-SimpleAT3 *AT3Create() {
-#ifdef USE_FFMPEG
- avcodec_register_all();
- av_register_all();
- InitFFmpeg();
-
- SimpleAT3 *at3 = new SimpleAT3();
- if (!at3->IsOK()) {
- delete at3;
- return 0;
- }
- return at3;
-#else
- return 0;
-#endif // USE_FFMPEG
-}
-
-bool AT3Decode(SimpleAT3 *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t *outbuf) {
-#ifdef USE_FFMPEG
- return ctx->Decode(inbuf, inbytes, outbuf, outbytes);
-#else
- *outbytes = 0;
- return true;
-#endif
-}
-
-void AT3Close(SimpleAT3 **ctx) {
-#ifdef USE_FFMPEG
- delete *ctx;
- *ctx = 0;
-#endif // USE_FFMPEG
-}
diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp
new file mode 100644
index 0000000000..8567641c79
--- /dev/null
+++ b/Core/HW/SimpleAudioDec.cpp
@@ -0,0 +1,269 @@
+// Copyright (c) 2013- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Core/HW/SimpleAudioDec.h"
+#include "Core/HW/MediaEngine.h"
+#include "Core/HW/BufferQueue.h"
+
+#ifdef USE_FFMPEG
+
+extern "C" {
+#include
+#include
+#include
+}
+
+#endif // USE_FFMPEG
+
+bool SimpleAudio::GetAudioCodecID(int audioType){
+#ifdef USE_FFMPEG
+
+ switch (audioType)
+ {
+ case PSP_CODEC_AAC:
+ audioCodecId = AV_CODEC_ID_AAC;
+ break;
+ case PSP_CODEC_AT3:
+ audioCodecId = AV_CODEC_ID_ATRAC3;
+ break;
+ case PSP_CODEC_AT3PLUS:
+ audioCodecId = AV_CODEC_ID_ATRAC3P;
+ break;
+ case PSP_CODEC_MP3:
+ audioCodecId = AV_CODEC_ID_MP3;
+ break;
+ default:
+ audioType = 0;
+ break;
+ }
+ if (audioType != 0){
+ return true;
+ }
+ return false;
+#else
+ return false;
+#endif // USE_FFMPEG
+}
+
+SimpleAudio::SimpleAudio(int audioType)
+: codec_(0),
+codecCtx_(0),
+swrCtx_(0) {
+ SimpleAudio::audioType = audioType;
+#ifdef USE_FFMPEG
+ frame_ = av_frame_alloc();
+
+ // Get Audio Codec ID
+ if (!GetAudioCodecID(audioType)){
+ ERROR_LOG(ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType);
+ return;
+ }
+ // Find decoder
+ codec_ = avcodec_find_decoder(audioCodecId);
+ if (!codec_) {
+ // Eh, we shouldn't even have managed to compile. But meh.
+ ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ID for audio (%s). Update your submodule.", GetCodecName(audioType));
+ return;
+ }
+ // Allocate codec context
+ codecCtx_ = avcodec_alloc_context3(codec_);
+ if (!codecCtx_) {
+ ERROR_LOG(ME, "Failed to allocate a codec context");
+ return;
+ }
+ codecCtx_->channels = 2;
+ codecCtx_->channel_layout = AV_CH_LAYOUT_STEREO;
+ // Open codec
+ AVDictionary *opts = 0;
+ if (avcodec_open2(codecCtx_, codec_, &opts) < 0) {
+ ERROR_LOG(ME, "Failed to open codec");
+ return;
+ }
+
+ av_dict_free(&opts);
+#endif // USE_FFMPEG
+}
+
+
+SimpleAudio::SimpleAudio(u32 ctxPtr, int audioType)
+: codec_(0),
+codecCtx_(0),
+swrCtx_(0) {
+ SimpleAudio::ctxPtr = ctxPtr;
+ SimpleAudio::audioType = audioType;
+#ifdef USE_FFMPEG
+ frame_ = av_frame_alloc();
+
+ // Get Audio Codec ID
+ if (!GetAudioCodecID(audioType)){
+ ERROR_LOG(ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType);
+ return;
+ }
+ // Find decoder
+ codec_ = avcodec_find_decoder(audioCodecId);
+ if (!codec_) {
+ // Eh, we shouldn't even have managed to compile. But meh.
+ ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ID for audio (%s). Update your submodule.",GetCodecName(audioType));
+ return;
+ }
+ // Allocate codec context
+ codecCtx_ = avcodec_alloc_context3(codec_);
+ if (!codecCtx_) {
+ ERROR_LOG(ME, "Failed to allocate a codec context");
+ return;
+ }
+ codecCtx_->channels = 2;
+ codecCtx_->channel_layout = AV_CH_LAYOUT_STEREO;
+ // Open codec
+ AVDictionary *opts = 0;
+ if (avcodec_open2(codecCtx_, codec_, &opts) < 0) {
+ ERROR_LOG(ME, "Failed to open codec");
+ return;
+ }
+
+ av_dict_free(&opts);
+#endif // USE_FFMPEG
+}
+
+SimpleAudio::~SimpleAudio() {
+#ifdef USE_FFMPEG
+ if (frame_)
+ av_frame_free(&frame_);
+ if (codecCtx_)
+ avcodec_close(codecCtx_);
+ codecCtx_ = 0;
+ codec_ = 0;
+ if (swrCtx_)
+ swr_free(&swrCtx_);
+#endif // USE_FFMPEG
+}
+
+// Input is a single Audio packet.
+bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes) {
+#ifdef USE_FFMPEG
+ AVPacket packet = { 0 };
+ av_init_packet(&packet);
+ packet.data = static_cast(inbuf);
+ packet.size = inbytes;
+
+ int got_frame = 0;
+ av_frame_unref(frame_);
+
+ int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
+ if (len < 0) {
+ ERROR_LOG(ME, "Error decoding Audio frame");
+ // TODO: cleanup
+ return false;
+ }
+ if (got_frame) {
+ // Initializing the sample rate convert. We will use it to convert float output into int.
+ int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO; // we want stereo output layout
+ int64_t dec_channel_layout = frame_->channel_layout; // decoded channel layout
+
+ swrCtx_ = swr_alloc_set_opts(
+ swrCtx_,
+ wanted_channel_layout,
+ AV_SAMPLE_FMT_S16,
+ codecCtx_->sample_rate,
+ dec_channel_layout,
+ codecCtx_->sample_fmt,
+ codecCtx_->sample_rate,
+ 0,
+ NULL);
+
+ if (!swrCtx_ || swr_init(swrCtx_) < 0) {
+ ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context");
+ avcodec_close(codecCtx_);
+ codec_ = 0;
+ return false;
+ }
+
+ // convert audio to AV_SAMPLE_FMT_S16
+ int swrRet = swr_convert(swrCtx_, &outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples);
+ if (swrRet < 0) {
+ ERROR_LOG(ME, "swr_convert: Error while converting %d", swrRet);
+ return false;
+ }
+ // We always convert to stereo.
+ __AdjustBGMVolume((s16 *)outbuf, frame_->nb_samples * 2);
+ }
+
+ return true;
+#else
+ // Zero bytes output. No need to memset.
+ *outbytes = 0;
+ return true;
+#endif // USE_FFMPEG
+}
+
+
+SimpleAudio *AudioCreate(int audioType) {
+#ifdef USE_FFMPEG
+ avcodec_register_all();
+ av_register_all();
+ InitFFmpeg();
+
+ SimpleAudio *Audio = new SimpleAudio(audioType);
+ if (!Audio->IsOK()) {
+ delete Audio;
+ return 0;
+ }
+ return Audio;
+#else
+ return 0;
+#endif // USE_FFMPEG
+}
+
+SimpleAudio *AudioCreate(u32 ctxPtr, int audioType) {
+#ifdef USE_FFMPEG
+ avcodec_register_all();
+ av_register_all();
+ InitFFmpeg();
+
+ SimpleAudio *Audio = new SimpleAudio(ctxPtr, audioType);
+ if (!Audio->IsOK()) {
+ delete Audio;
+ return 0;
+ }
+ return Audio;
+#else
+ return 0;
+#endif // USE_FFMPEG
+}
+
+bool AudioDecode(SimpleAudio *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t *outbuf) {
+#ifdef USE_FFMPEG
+ return ctx->Decode(inbuf, inbytes, outbuf, outbytes);
+#else
+ *outbytes = 0;
+ return true;
+#endif // USE_FFMPEG
+}
+
+void AudioClose(SimpleAudio **ctx) {
+#ifdef USE_FFMPEG
+ delete *ctx;
+ *ctx = 0;
+#endif // USE_FFMPEG
+}
+
+bool isValidCodec(int codec){
+ if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
+ return true;
+ }
+ return false;
+}
diff --git a/Core/HW/SimpleAT3Dec.h b/Core/HW/SimpleAudioDec.h
similarity index 51%
rename from Core/HW/SimpleAT3Dec.h
rename to Core/HW/SimpleAudioDec.h
index 2c54889600..535541ac14 100644
--- a/Core/HW/SimpleAT3Dec.h
+++ b/Core/HW/SimpleAudioDec.h
@@ -20,6 +20,17 @@
#include
#include "base/basictypes.h"
+#include "Core/HW/MediaEngine.h"
+
+#ifdef USE_FFMPEG
+
+extern "C" {
+#include
+#include
+#include
+}
+
+#endif // USE_FFMPEG
// Wraps FFMPEG in a nice interface that's drop-in compatible with
// the old one. Decodes packet by packet - does NOT demux. That's done by
@@ -32,8 +43,52 @@
// However, it will be maintained as a part of FFMPEG so that's the way we'll go
// for simplicity and sanity.
-struct SimpleAT3;
+struct SimpleAudio {
+public:
+ SimpleAudio(int);
+ SimpleAudio(u32, int);
+ ~SimpleAudio();
-SimpleAT3 *AT3Create();
-bool AT3Decode(SimpleAT3 *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t* outbuf);
-void AT3Close(SimpleAT3 **ctx);
+ bool Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
+ bool IsOK() const { return codec_ != 0; }
+
+ u32 ctxPtr;
+ int audioType;
+
+private:
+#ifdef USE_FFMPEG
+ AVFrame *frame_;
+ AVCodec *codec_;
+ AVCodecContext *codecCtx_;
+ SwrContext *swrCtx_;
+ AVCodecID audioCodecId; // AV_CODEC_ID_XXX
+
+ bool GetAudioCodecID(int audioType); // Get audioCodecId from audioType
+#endif // USE_FFMPEG
+};
+
+
+enum {
+ PSP_CODEC_AT3PLUS = 0x00001000,
+ PSP_CODEC_AT3 = 0x00001001,
+ PSP_CODEC_MP3 = 0x00001002,
+ PSP_CODEC_AAC = 0x00001003,
+};
+
+static const char *const codecNames[4] = {
+ "AT3+", "AT3", "MP3", "AAC",
+};
+
+
+SimpleAudio *AudioCreate(int audioType);
+bool AudioDecode(SimpleAudio *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t* outbuf);
+void AudioClose(SimpleAudio **ctx);
+static 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(int codec);
diff --git a/Core/HW/SimpleMp3Dec.cpp b/Core/HW/SimpleMp3Dec.cpp
deleted file mode 100644
index a567993bce..0000000000
--- a/Core/HW/SimpleMp3Dec.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright (c) 2013- PPSSPP Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official git repository and contact information can be found at
-// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-
-#include "Core/HW/SimpleMp3Dec.h"
-#include "Core/HW/MediaEngine.h"
-#include "Core/HW/BufferQueue.h"
-
-#ifdef USE_FFMPEG
-
-extern "C" {
-#include
-#include
-#include
-}
-
-struct SimpleMP3 {
-public:
- SimpleMP3();
- ~SimpleMP3();
-
- bool Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
- bool IsOK() const { return codec_ != 0; }
-
-private:
- AVFrame *frame_;
- AVCodec *codec_;
- AVCodecContext *codecCtx_;
- SwrContext *swrCtx_;
-};
-
-SimpleMP3::SimpleMP3()
-: codec_(0),
-codecCtx_(0),
-swrCtx_(0) {
- frame_ = av_frame_alloc();
-
- codec_ = avcodec_find_decoder(AV_CODEC_ID_MP3);
- if (!codec_) {
- // Eh, we shouldn't even have managed to compile. But meh.
- ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ID_MP3 (MP3). Update your submodule.");
- return;
- }
-
- codecCtx_ = avcodec_alloc_context3(codec_);
- if (!codecCtx_) {
- ERROR_LOG(ME, "Failed to allocate a codec context");
- return;
- }
-
- codecCtx_->channels = 2;
- codecCtx_->channel_layout = AV_CH_LAYOUT_STEREO;
-
- AVDictionary *opts = 0;
- av_dict_set(&opts, "channels", "2", 0);
- av_dict_set(&opts, "sample_rate", "44100", 0);
- if (avcodec_open2(codecCtx_, codec_, &opts) < 0) {
- ERROR_LOG(ME, "Failed to open codec");
- return;
- }
-
- av_dict_free(&opts);
-
- // Initializing the sample rate convert. We only really use it to convert float output
- // into int.
- int wanted_channels = 2;
- int64_t wanted_channel_layout = av_get_default_channel_layout(wanted_channels);
- int64_t dec_channel_layout = av_get_default_channel_layout(2);
-
- swrCtx_ = swr_alloc_set_opts(
- swrCtx_,
- wanted_channel_layout,
- AV_SAMPLE_FMT_S16,
- codecCtx_->sample_rate,
- dec_channel_layout,
- codecCtx_->sample_fmt,
- codecCtx_->sample_rate,
- 0,
- NULL);
-
- if (!swrCtx_ || swr_init(swrCtx_) < 0) {
- ERROR_LOG(ME, "swr_init: Failed to initialize the resampling context");
- avcodec_close(codecCtx_);
- codec_ = 0;
- return;
- }
-}
-
-SimpleMP3::~SimpleMP3() {
- if (frame_)
- av_frame_free(&frame_);
- if (codecCtx_)
- avcodec_close(codecCtx_);
- codecCtx_ = 0;
- codec_ = 0;
- if (swrCtx_)
- swr_free(&swrCtx_);
-}
-
-// Input is a single MP3 packet.
-bool SimpleMP3::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes) {
-#ifdef USE_FFMPEG
- AVPacket packet = { 0 };
- av_init_packet(&packet);
- packet.data = static_cast(inbuf);
- packet.size = inbytes;
-
- *outbytes = 0;
-
- int got_frame = 0;
- av_frame_unref(frame_);
-
- int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
- if (len < 0) {
- ERROR_LOG(ME, "Error decoding Mp3 frame");
- // TODO: cleanup
- return false;
- }
-
- if (got_frame) {
- int data_size = av_samples_get_buffer_size(
- NULL,
- codecCtx_->channels,
- frame_->nb_samples,
- codecCtx_->sample_fmt, 1);
- int numSamples = frame_->nb_samples;
- int swrRet = swr_convert(swrCtx_, &outbuf, numSamples, (const u8 **)frame_->extended_data, numSamples);
- if (swrRet < 0) {
- ERROR_LOG(ME, "swr_convert: Error while converting %d", swrRet);
- return false;
- }
- // We always convert to stereo.
- __AdjustBGMVolume((s16 *)outbuf, numSamples * 2);
- }
-
- return true;
-#else
- // Zero bytes output. No need to memset.
- *outbytes = 0;
- return true;
-#endif // USE_FFMPEG
-}
-
-#endif // USE_FFMPEG
-
-// "C" wrapper
-
-SimpleMP3 *MP3Create() {
-#ifdef USE_FFMPEG
- avcodec_register_all();
- av_register_all();
- InitFFmpeg();
-
- SimpleMP3 *MP3 = new SimpleMP3();
- if (!MP3->IsOK()) {
- delete MP3;
- return 0;
- }
- return MP3;
-#else
- return 0;
-#endif // USE_FFMPEG
-}
-
-bool MP3Decode(SimpleMP3 *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t *outbuf) {
-#ifdef USE_FFMPEG
- return ctx->Decode(inbuf, inbytes, outbuf, outbytes);
-#else
- *outbytes = 0;
- return true;
-#endif
-}
-
-void MP3Close(SimpleMP3 **ctx) {
-#ifdef USE_FFMPEG
- delete *ctx;
- *ctx = 0;
-#endif // USE_FFMPEG
-}
diff --git a/Core/HW/SimpleMp3Dec.h b/Core/HW/SimpleMp3Dec.h
deleted file mode 100644
index 7b0aa1022f..0000000000
--- a/Core/HW/SimpleMp3Dec.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2013- PPSSPP Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official git repository and contact information can be found at
-// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-
-#pragma once
-
-#include
-
-#include "base/basictypes.h"
-
-// Wraps FFMPEG in a nice interface that's drop-in compatible with
-// the old one. Decodes packet by packet - does NOT demux. That's done by
-// MpegDemux. Only decodes Atrac3+, not regular Atrac3.
-
-// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13
-
-// Ideally, Maxim's Atrac3+ decoder would be available as a standalone library
-// that we could link, as that would be totally sufficient for the use case here.
-// However, it will be maintained as a part of FFMPEG so that's the way we'll go
-// for simplicity and sanity.
-
-struct SimpleMP3;
-
-SimpleMP3 *MP3Create();
-bool MP3Decode(SimpleMP3 *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t* outbuf);
-void MP3Close(SimpleMP3 **ctx);
diff --git a/Core/System.cpp b/Core/System.cpp
index a2b21d6fdd..31b2c90157 100644
--- a/Core/System.cpp
+++ b/Core/System.cpp
@@ -55,6 +55,7 @@
#include "Core/ELF/ParamSFO.h"
#include "Core/SaveState.h"
#include "Common/LogManager.h"
+#include "Core/HLE/sceAudiocodec.h"
#include "GPU/GPUState.h"
#include "GPU/GPUInterface.h"
@@ -414,6 +415,7 @@ void PSP_Shutdown() {
CPU_Shutdown();
}
GPU_Shutdown();
+ resetAudioList();
host->SetWindowTitle(0);
currentMIPS = 0;
pspIsInited = false;
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 483b31d718..cc3138ae9e 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -160,8 +160,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/ELF/PBPReader.cpp \
$(SRC)/Core/ELF/PrxDecrypter.cpp \
$(SRC)/Core/ELF/ParamSFO.cpp \
- $(SRC)/Core/HW/SimpleAT3Dec.cpp \
- $(SRC)/Core/HW/SimpleMp3Dec.cpp \
+ $(SRC)/Core/HW/SimpleAudioDec.cpp \
$(SRC)/Core/HW/AsyncIOManager.cpp \
$(SRC)/Core/HW/MemoryStick.cpp \
$(SRC)/Core/HW/MpegDemux.cpp.arm \