From b18252b2b5e91c20a320fb2c339b5fc5f60f76d6 Mon Sep 17 00:00:00 2001 From: kaienfr Date: Sun, 23 Mar 2014 19:45:08 +0100 Subject: [PATCH] Support audio playing (AT3, AT3+, Mp3, AAC) --- CMakeLists.txt | 6 +- Core/Core.vcxproj | 6 +- Core/Core.vcxproj.filters | 10 +- Core/HLE/sceAudiocodec.cpp | 110 +++++--- Core/HLE/sceAudiocodec.h | 3 +- Core/HW/MediaEngine.cpp | 14 +- Core/HW/MediaEngine.h | 8 +- Core/HW/SimpleAT3Dec.cpp | 192 ------------- Core/HW/SimpleAudioDec.cpp | 269 +++++++++++++++++++ Core/HW/{SimpleAT3Dec.h => SimpleAudioDec.h} | 63 ++++- Core/HW/SimpleMp3Dec.cpp | 192 ------------- Core/HW/SimpleMp3Dec.h | 39 --- Core/System.cpp | 2 + android/jni/Android.mk | 3 +- 14 files changed, 422 insertions(+), 495 deletions(-) delete mode 100644 Core/HW/SimpleAT3Dec.cpp create mode 100644 Core/HW/SimpleAudioDec.cpp rename Core/HW/{SimpleAT3Dec.h => SimpleAudioDec.h} (51%) delete mode 100644 Core/HW/SimpleMp3Dec.cpp delete mode 100644 Core/HW/SimpleMp3Dec.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f171681c..8aeefd304 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 8e063a184..61d495745 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 a7cc16333..fb4993205 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 f714e4f03..062e8484f 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 981803a9d..c2135f855 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 b70e91423..124bbd2c7 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 ece2a32ef..1597b8ef5 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 2ba87ea63..000000000 --- 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 000000000..8567641c7 --- /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 2c5488960..535541ac1 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 a567993bc..000000000 --- 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 7b0aa1022..000000000 --- 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 a2b21d6fd..31b2c9015 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 483b31d71..cc3138ae9 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 \