mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Support audio playing (AT3, AT3+, Mp3, AAC)
This commit is contained in:
parent
b174996c1c
commit
b18252b2b5
14 changed files with 422 additions and 495 deletions
|
@ -1117,10 +1117,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||||
Core/HLE/sceNp.h
|
Core/HLE/sceNp.h
|
||||||
Core/HLE/scePauth.cpp
|
Core/HLE/scePauth.cpp
|
||||||
Core/HLE/scePauth.h
|
Core/HLE/scePauth.h
|
||||||
Core/HW/SimpleAT3Dec.cpp
|
Core/HW/SimpleAudioDec.cpp
|
||||||
Core/HW/SimpleAT3Dec.h
|
Core/HW/SimpleAudioDec.h
|
||||||
Core/HW/SimpleMp3Dec.cpp
|
|
||||||
Core/HW/SimpleMp3Dec.h
|
|
||||||
Core/HW/AsyncIOManager.cpp
|
Core/HW/AsyncIOManager.cpp
|
||||||
Core/HW/AsyncIOManager.h
|
Core/HW/AsyncIOManager.h
|
||||||
Core/HW/MediaEngine.cpp
|
Core/HW/MediaEngine.cpp
|
||||||
|
|
|
@ -257,13 +257,12 @@
|
||||||
<ClCompile Include="HLE\sceVaudio.cpp" />
|
<ClCompile Include="HLE\sceVaudio.cpp" />
|
||||||
<ClCompile Include="HLE\__sceAudio.cpp" />
|
<ClCompile Include="HLE\__sceAudio.cpp" />
|
||||||
<ClCompile Include="Host.cpp" />
|
<ClCompile Include="Host.cpp" />
|
||||||
<ClCompile Include="HW\SimpleAT3Dec.cpp" />
|
|
||||||
<ClCompile Include="HW\MediaEngine.cpp" />
|
<ClCompile Include="HW\MediaEngine.cpp" />
|
||||||
<ClCompile Include="HW\MemoryStick.cpp" />
|
<ClCompile Include="HW\MemoryStick.cpp" />
|
||||||
<ClCompile Include="HW\MpegDemux.cpp" />
|
<ClCompile Include="HW\MpegDemux.cpp" />
|
||||||
<ClCompile Include="HW\SasAudio.cpp" />
|
<ClCompile Include="HW\SasAudio.cpp" />
|
||||||
<ClCompile Include="HW\AsyncIOManager.cpp" />
|
<ClCompile Include="HW\AsyncIOManager.cpp" />
|
||||||
<ClCompile Include="HW\SimpleMp3Dec.cpp" />
|
<ClCompile Include="HW\SimpleAudioDec.cpp" />
|
||||||
<ClCompile Include="Loaders.cpp" />
|
<ClCompile Include="Loaders.cpp" />
|
||||||
<ClCompile Include="MemMap.cpp" />
|
<ClCompile Include="MemMap.cpp" />
|
||||||
<ClCompile Include="MemmapFunctions.cpp" />
|
<ClCompile Include="MemmapFunctions.cpp" />
|
||||||
|
@ -531,13 +530,12 @@
|
||||||
<ClInclude Include="HLE\__sceAudio.h" />
|
<ClInclude Include="HLE\__sceAudio.h" />
|
||||||
<ClInclude Include="Host.h" />
|
<ClInclude Include="Host.h" />
|
||||||
<ClInclude Include="HW\BufferQueue.h" />
|
<ClInclude Include="HW\BufferQueue.h" />
|
||||||
<ClInclude Include="HW\SimpleAT3Dec.h" />
|
|
||||||
<ClInclude Include="HW\MediaEngine.h" />
|
<ClInclude Include="HW\MediaEngine.h" />
|
||||||
<ClInclude Include="HW\MpegDemux.h" />
|
<ClInclude Include="HW\MpegDemux.h" />
|
||||||
<ClInclude Include="HW\SasAudio.h" />
|
<ClInclude Include="HW\SasAudio.h" />
|
||||||
<ClInclude Include="HW\MemoryStick.h" />
|
<ClInclude Include="HW\MemoryStick.h" />
|
||||||
<ClInclude Include="HW\AsyncIOManager.h" />
|
<ClInclude Include="HW\AsyncIOManager.h" />
|
||||||
<ClInclude Include="HW\SimpleMp3Dec.h" />
|
<ClInclude Include="HW\SimpleAudioDec.h" />
|
||||||
<ClInclude Include="Loaders.h" />
|
<ClInclude Include="Loaders.h" />
|
||||||
<ClInclude Include="MemMap.h" />
|
<ClInclude Include="MemMap.h" />
|
||||||
<ClInclude Include="MIPS\ARM\ArmAsm.h">
|
<ClInclude Include="MIPS\ARM\ArmAsm.h">
|
||||||
|
|
|
@ -433,9 +433,6 @@
|
||||||
<ClCompile Include="Cwcheat.cpp">
|
<ClCompile Include="Cwcheat.cpp">
|
||||||
<Filter>Core</Filter>
|
<Filter>Core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\SimpleAT3Dec.cpp">
|
|
||||||
<Filter>HW</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="HW\MpegDemux.cpp">
|
<ClCompile Include="HW\MpegDemux.cpp">
|
||||||
<Filter>HW</Filter>
|
<Filter>HW</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -520,7 +517,7 @@
|
||||||
<ClCompile Include="MIPS\PPC\PpcCompReplace.cpp">
|
<ClCompile Include="MIPS\PPC\PpcCompReplace.cpp">
|
||||||
<Filter>MIPS\PPC</Filter>
|
<Filter>MIPS\PPC</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\SimpleMp3Dec.cpp">
|
<ClCompile Include="HW\SimpleAudioDec.cpp">
|
||||||
<Filter>HW</Filter>
|
<Filter>HW</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -885,9 +882,6 @@
|
||||||
<ClInclude Include="Cwcheat.h">
|
<ClInclude Include="Cwcheat.h">
|
||||||
<Filter>Core</Filter>
|
<Filter>Core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\SimpleAT3Dec.h">
|
|
||||||
<Filter>HW</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="HW\MpegDemux.h">
|
<ClInclude Include="HW\MpegDemux.h">
|
||||||
<Filter>HW</Filter>
|
<Filter>HW</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -963,7 +957,7 @@
|
||||||
<ClInclude Include="HW\BufferQueue.h">
|
<ClInclude Include="HW\BufferQueue.h">
|
||||||
<Filter>HW</Filter>
|
<Filter>HW</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\SimpleMp3Dec.h">
|
<ClInclude Include="HW\SimpleAudioDec.h">
|
||||||
<Filter>HW</Filter>
|
<Filter>HW</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -20,26 +20,8 @@
|
||||||
#include "Core/HLE/sceAudiocodec.h"
|
#include "Core/HLE/sceAudiocodec.h"
|
||||||
#include "Core/MemMap.h"
|
#include "Core/MemMap.h"
|
||||||
#include "Core/Reporting.h"
|
#include "Core/Reporting.h"
|
||||||
#include "Core/HW/SimpleMp3Dec.h"
|
#include "Core/HW/SimpleAudioDec.h"
|
||||||
|
#include "Common/ChunkFile.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)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Following kaien_fr's sample code https://github.com/hrydgard/ppsspp/issues/5620#issuecomment-37086024
|
// 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.
|
// Should probably store the EDRAM get/release status somewhere within here, etc.
|
||||||
|
@ -52,16 +34,41 @@ struct AudioCodecContext {
|
||||||
u32_le inDataSizeAgain; // 10 ??
|
u32_le inDataSizeAgain; // 10 ??
|
||||||
};
|
};
|
||||||
|
|
||||||
SimpleMP3* mp3;
|
// audioList is to store current playing audios.
|
||||||
|
std::list<SimpleAudio *> audioList;
|
||||||
|
|
||||||
|
// find the audio decoder for corresponding ctxPtr in audioList
|
||||||
|
SimpleAudio * findDecoder(u32 ctxPtr){
|
||||||
|
for (std::list<SimpleAudio *>::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<SimpleAudio *>::iterator it = audioList.begin(); it != audioList.end(); it++){
|
||||||
|
if ((*it)->ctxPtr == ctxPtr){
|
||||||
|
audioList.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int sceAudiocodecInit(u32 ctxPtr, int codec) {
|
int sceAudiocodecInit(u32 ctxPtr, int codec) {
|
||||||
if (codec == PSP_CODEC_MP3){
|
if (isValidCodec(codec)){
|
||||||
// Initialize MP3 audio decoder.
|
// Create audio decoder for given audio codec and push it into AudioList
|
||||||
mp3 = MP3Create();
|
auto decoder = new SimpleAudio(ctxPtr, codec);
|
||||||
DEBUG_LOG(ME, "sceAudiocodecInit(%08x, %i (%s))", ctxPtr, codec, GetCodecName(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;
|
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;
|
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));
|
ERROR_LOG_REPORT(ME, "sceAudiocodecDecode(%08x, %i (%s)) got NULL pointer", ctxPtr, codec, GetCodecName(codec));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (codec == PSP_CODEC_MP3){
|
if (isValidCodec(codec)){
|
||||||
//Use SimpleMp3Dec to decode Mp3 audio
|
// Use SimpleAudioDec to decode audio
|
||||||
// Get AudioCodecContext
|
// Get AudioCodecContext
|
||||||
AudioCodecContext* ctx = new AudioCodecContext;
|
auto ctx = new AudioCodecContext;
|
||||||
Memory::ReadStruct(ctxPtr, ctx);
|
Memory::ReadStruct(ctxPtr, ctx);
|
||||||
int outbytes = 0;
|
int outbytes = 0;
|
||||||
// Decode Mp3 audio
|
// find a decoder in audioList
|
||||||
MP3Decode(mp3, Memory::GetPointer(ctx->inDataPtr), ctx->inDataSize, &outbytes, Memory::GetPointer(ctx->outDataPtr));
|
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));
|
DEBUG_LOG(ME, "sceAudiocodecDec(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
|
||||||
|
// Delete AudioCodecContext
|
||||||
|
delete(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ERROR_LOG_REPORT(ME, "UNIMPL sceAudiocodecDecode(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sceAudiocodecReleaseEDRAM(u32 ctxPtr, int codec) {
|
int sceAudiocodecReleaseEDRAM(u32 ctxPtr, int id) {
|
||||||
WARN_LOG(ME, "UNIMPL sceAudiocodecReleaseEDRAM(%08x, %i (%s))", ctxPtr, codec, GetCodecName(codec));
|
//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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HLEFunction sceAudiocodec[] = {
|
const HLEFunction sceAudiocodec[] = {
|
||||||
{0x70A703F8, WrapI_UI<sceAudiocodecDecode>, "sceAudiocodecDecode"},
|
{ 0x70A703F8, WrapI_UI<sceAudiocodecDecode>, "sceAudiocodecDecode" },
|
||||||
{0x5B37EB1D, WrapI_UI<sceAudiocodecInit>, "sceAudiocodecInit"},
|
{ 0x5B37EB1D, WrapI_UI<sceAudiocodecInit>, "sceAudiocodecInit" },
|
||||||
{0x8ACA11D5, WrapI_UI<sceAudiocodecGetInfo>, "sceAudiocodecGetInfo"},
|
{ 0x8ACA11D5, WrapI_UI<sceAudiocodecGetInfo>, "sceAudiocodecGetInfo" },
|
||||||
{0x3A20A200, WrapI_UI<sceAudiocodecGetEDRAM>, "sceAudiocodecGetEDRAM" },
|
{ 0x3A20A200, WrapI_UI<sceAudiocodecGetEDRAM>, "sceAudiocodecGetEDRAM" },
|
||||||
{0x29681260, WrapI_UI<sceAudiocodecReleaseEDRAM>, "sceAudiocodecReleaseEDRAM" },
|
{ 0x29681260, WrapI_UI<sceAudiocodecReleaseEDRAM>, "sceAudiocodecReleaseEDRAM" },
|
||||||
{0x9D3F790C, WrapI_UI<sceAudiocodecCheckNeedMem>, "sceAudiocodecCheckNeedMem" },
|
{ 0x9D3F790C, WrapI_UI<sceAudiocodecCheckNeedMem>, "sceAudiocodecCheckNeedMem" },
|
||||||
{0x59176a0f, 0, "sceAudiocodec_59176A0F"},
|
{ 0x59176a0f, 0, "sceAudiocodec_59176A0F" },
|
||||||
};
|
};
|
||||||
|
|
||||||
void Register_sceAudiocodec()
|
void Register_sceAudiocodec()
|
||||||
{
|
{
|
||||||
RegisterModule("sceAudiocodec", ARRAY_SIZE(sceAudiocodec), sceAudiocodec);
|
RegisterModule("sceAudiocodec", ARRAY_SIZE(sceAudiocodec), sceAudiocodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetAudioList(){
|
||||||
|
audioList.clear();
|
||||||
|
INFO_LOG(ME, "Audio playing list is reset");
|
||||||
|
}
|
||||||
|
|
|
@ -57,3 +57,4 @@ typedef struct
|
||||||
} SceAudiocodecCodec;
|
} SceAudiocodecCodec;
|
||||||
|
|
||||||
void Register_sceAudiocodec();
|
void Register_sceAudiocodec();
|
||||||
|
void resetAudioList();
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "Core/MemMap.h"
|
#include "Core/MemMap.h"
|
||||||
#include "Core/Reporting.h"
|
#include "Core/Reporting.h"
|
||||||
#include "GPU/GPUInterface.h"
|
#include "GPU/GPUInterface.h"
|
||||||
#include "Core/HW/SimpleAT3Dec.h"
|
#include "Core/HW/SimpleAudioDec.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ MediaEngine::MediaEngine(): m_pdata(0) {
|
||||||
|
|
||||||
m_ringbuffersize = 0;
|
m_ringbuffersize = 0;
|
||||||
m_mpegheaderReadPos = 0;
|
m_mpegheaderReadPos = 0;
|
||||||
|
m_audioType = PSP_CODEC_AT3PLUS; // in movie, we use only AT3+ audio
|
||||||
g_iNumVideos++;
|
g_iNumVideos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +169,7 @@ void MediaEngine::closeMedia() {
|
||||||
delete m_demux;
|
delete m_demux;
|
||||||
m_pdata = 0;
|
m_pdata = 0;
|
||||||
m_demux = 0;
|
m_demux = 0;
|
||||||
AT3Close(&m_audioContext);
|
AudioClose(&m_audioContext);
|
||||||
m_isVideoEnd = false;
|
m_isVideoEnd = false;
|
||||||
m_noAudioData = false;
|
m_noAudioData = false;
|
||||||
}
|
}
|
||||||
|
@ -212,6 +213,9 @@ void MediaEngine::DoState(PointerWrap &p){
|
||||||
|
|
||||||
p.Do(m_isVideoEnd);
|
p.Do(m_isVideoEnd);
|
||||||
p.Do(m_noAudioData);
|
p.Do(m_noAudioData);
|
||||||
|
if (s > 2){
|
||||||
|
p.Do(m_audioType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _MpegReadbuffer(void *opaque, uint8_t *buf, int buf_size)
|
int _MpegReadbuffer(void *opaque, uint8_t *buf, int buf_size)
|
||||||
|
@ -279,7 +283,7 @@ bool MediaEngine::openContext() {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
setVideoDim();
|
setVideoDim();
|
||||||
m_audioContext = AT3Create();
|
m_audioContext = AudioCreate(m_audioType);
|
||||||
m_isVideoEnd = false;
|
m_isVideoEnd = false;
|
||||||
m_noAudioData = false;
|
m_noAudioData = false;
|
||||||
m_mpegheaderReadPos++;
|
m_mpegheaderReadPos++;
|
||||||
|
@ -734,8 +738,8 @@ int MediaEngine::getAudioSamples(u32 bufferPtr) {
|
||||||
int outbytes = 0;
|
int outbytes = 0;
|
||||||
|
|
||||||
if (m_audioContext != NULL) {
|
if (m_audioContext != NULL) {
|
||||||
if (!AT3Decode(m_audioContext, audioFrame, frameSize, &outbytes, buffer)) {
|
if (!AudioDecode(m_audioContext, audioFrame, frameSize, &outbytes, buffer)) {
|
||||||
ERROR_LOG(ME, "AT3 decode failed during video playback");
|
ERROR_LOG(ME, "Audio (%s) decode failed during video playback", GetCodecName(m_audioType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,10 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/HLE/sceMpeg.h"
|
#include "Core/HLE/sceMpeg.h"
|
||||||
#include "Core/HW/MpegDemux.h"
|
#include "Core/HW/MpegDemux.h"
|
||||||
|
#include "Core/HW/SimpleAudioDec.h"
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
struct SimpleAT3;
|
struct SimpleAudio;
|
||||||
|
|
||||||
#ifdef USE_FFMPEG
|
#ifdef USE_FFMPEG
|
||||||
struct SwsContext;
|
struct SwsContext;
|
||||||
|
@ -119,7 +120,7 @@ public: // TODO: Very little of this below should be public.
|
||||||
BufferQueue *m_pdata;
|
BufferQueue *m_pdata;
|
||||||
|
|
||||||
MpegDemux *m_demux;
|
MpegDemux *m_demux;
|
||||||
SimpleAT3 *m_audioContext;
|
SimpleAudio *m_audioContext;
|
||||||
s64 m_audiopts;
|
s64 m_audiopts;
|
||||||
|
|
||||||
s64 m_firstTimeStamp;
|
s64 m_firstTimeStamp;
|
||||||
|
@ -131,4 +132,7 @@ public: // TODO: Very little of this below should be public.
|
||||||
int m_ringbuffersize;
|
int m_ringbuffersize;
|
||||||
u8 m_mpegheader[0x10000]; // TODO: Allocate separately
|
u8 m_mpegheader[0x10000]; // TODO: Allocate separately
|
||||||
int m_mpegheaderReadPos;
|
int m_mpegheaderReadPos;
|
||||||
|
|
||||||
|
// used for audio type
|
||||||
|
int m_audioType;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 <libavformat/avformat.h>
|
|
||||||
#include <libswresample/swresample.h>
|
|
||||||
#include <libavutil/samplefmt.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
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<uint8_t *>(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
|
|
||||||
}
|
|
269
Core/HW/SimpleAudioDec.cpp
Normal file
269
Core/HW/SimpleAudioDec.cpp
Normal file
|
@ -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 <libavformat/avformat.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#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<uint8_t *>(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;
|
||||||
|
}
|
|
@ -20,6 +20,17 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
|
#include "Core/HW/MediaEngine.h"
|
||||||
|
|
||||||
|
#ifdef USE_FFMPEG
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_FFMPEG
|
||||||
|
|
||||||
// Wraps FFMPEG in a nice interface that's drop-in compatible with
|
// 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
|
// 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
|
// However, it will be maintained as a part of FFMPEG so that's the way we'll go
|
||||||
// for simplicity and sanity.
|
// for simplicity and sanity.
|
||||||
|
|
||||||
struct SimpleAT3;
|
struct SimpleAudio {
|
||||||
|
public:
|
||||||
|
SimpleAudio(int);
|
||||||
|
SimpleAudio(u32, int);
|
||||||
|
~SimpleAudio();
|
||||||
|
|
||||||
SimpleAT3 *AT3Create();
|
bool Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
|
||||||
bool AT3Decode(SimpleAT3 *ctx, void* inbuf, int inbytes, int *outbytes, uint8_t* outbuf);
|
bool IsOK() const { return codec_ != 0; }
|
||||||
void AT3Close(SimpleAT3 **ctx);
|
|
||||||
|
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);
|
|
@ -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 <libavformat/avformat.h>
|
|
||||||
#include <libswresample/swresample.h>
|
|
||||||
#include <libavutil/samplefmt.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
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<uint8_t *>(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
|
|
||||||
}
|
|
|
@ -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 <cmath>
|
|
||||||
|
|
||||||
#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);
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "Core/ELF/ParamSFO.h"
|
#include "Core/ELF/ParamSFO.h"
|
||||||
#include "Core/SaveState.h"
|
#include "Core/SaveState.h"
|
||||||
#include "Common/LogManager.h"
|
#include "Common/LogManager.h"
|
||||||
|
#include "Core/HLE/sceAudiocodec.h"
|
||||||
|
|
||||||
#include "GPU/GPUState.h"
|
#include "GPU/GPUState.h"
|
||||||
#include "GPU/GPUInterface.h"
|
#include "GPU/GPUInterface.h"
|
||||||
|
@ -414,6 +415,7 @@ void PSP_Shutdown() {
|
||||||
CPU_Shutdown();
|
CPU_Shutdown();
|
||||||
}
|
}
|
||||||
GPU_Shutdown();
|
GPU_Shutdown();
|
||||||
|
resetAudioList();
|
||||||
host->SetWindowTitle(0);
|
host->SetWindowTitle(0);
|
||||||
currentMIPS = 0;
|
currentMIPS = 0;
|
||||||
pspIsInited = false;
|
pspIsInited = false;
|
||||||
|
|
|
@ -160,8 +160,7 @@ EXEC_AND_LIB_FILES := \
|
||||||
$(SRC)/Core/ELF/PBPReader.cpp \
|
$(SRC)/Core/ELF/PBPReader.cpp \
|
||||||
$(SRC)/Core/ELF/PrxDecrypter.cpp \
|
$(SRC)/Core/ELF/PrxDecrypter.cpp \
|
||||||
$(SRC)/Core/ELF/ParamSFO.cpp \
|
$(SRC)/Core/ELF/ParamSFO.cpp \
|
||||||
$(SRC)/Core/HW/SimpleAT3Dec.cpp \
|
$(SRC)/Core/HW/SimpleAudioDec.cpp \
|
||||||
$(SRC)/Core/HW/SimpleMp3Dec.cpp \
|
|
||||||
$(SRC)/Core/HW/AsyncIOManager.cpp \
|
$(SRC)/Core/HW/AsyncIOManager.cpp \
|
||||||
$(SRC)/Core/HW/MemoryStick.cpp \
|
$(SRC)/Core/HW/MemoryStick.cpp \
|
||||||
$(SRC)/Core/HW/MpegDemux.cpp.arm \
|
$(SRC)/Core/HW/MpegDemux.cpp.arm \
|
||||||
|
|
Loading…
Add table
Reference in a new issue