Save current changes

This commit is contained in:
kaienfr 2014-04-11 15:09:31 +02:00
parent b262794a35
commit c216b535ee
3 changed files with 382 additions and 458 deletions

View File

@ -25,6 +25,7 @@
#include "Core/HW/MediaEngine.h"
#include "Core/MemMap.h"
#include "Core/Reporting.h"
#include "Core/HW/SimpleAudioDec.h"
static const int ID3 = 0x49443300;
@ -42,94 +43,9 @@ extern "C" {
}
#endif
struct Mp3Context;
int __Mp3InitContext(Mp3Context *ctx);
static std::map<u32, AuCtx *> mp3Map;
struct Mp3Context {
Mp3Context()
#ifdef USE_FFMPEG
: avformat_context(NULL), avio_context(NULL), resampler_context(NULL) {
#else
{
#endif
}
~Mp3Context() {
#ifdef USE_FFMPEG
if (avio_context != NULL) {
av_free(avio_context->buffer);
av_free(avio_context);
}
if (avformat_context != NULL) {
avformat_free_context(avformat_context);
}
if (resampler_context != NULL) {
swr_free(&resampler_context);
}
#endif
}
void DoState(PointerWrap &p) {
auto s = p.Section("Mp3Context", 1);
if (!s)
return;
p.Do(mp3StreamStart);
p.Do(mp3StreamEnd);
p.Do(mp3Buf);
p.Do(mp3BufSize);
p.Do(mp3PcmBuf);
p.Do(mp3PcmBufSize);
p.Do(readPosition);
p.Do(bufferRead);
p.Do(bufferWrite);
p.Do(bufferAvailable);
p.Do(mp3DecodedBytes);
p.Do(mp3LoopNum);
p.Do(mp3MaxSamples);
p.Do(mp3SumDecodedSamples);
p.Do(mp3Channels);
p.Do(mp3Bitrate);
p.Do(mp3SamplingRate);
p.Do(mp3Version);
__Mp3InitContext(this);
}
int mp3StreamStart;
int mp3StreamEnd;
u32 mp3Buf;
int mp3BufSize;
u32 mp3PcmBuf;
int mp3PcmBufSize;
int readPosition;
int bufferRead;
int bufferWrite;
int bufferAvailable;
int mp3DecodedBytes;
int mp3LoopNum;
int mp3MaxSamples;
int mp3SumDecodedSamples;
int mp3Channels;
int mp3Bitrate;
int mp3SamplingRate;
int mp3Version;
#ifdef USE_FFMPEG
AVFormatContext *avformat_context;
AVIOContext *avio_context;
AVCodecContext *decoder_context;
SwrContext *resampler_context;
int audio_stream_index;
#endif
};
static std::map<u32, Mp3Context *> mp3Map;
Mp3Context *getMp3Ctx(u32 mp3) {
AuCtx *getMp3Ctx(u32 mp3) {
if (mp3Map.find(mp3) == mp3Map.end())
return NULL;
return mp3Map[mp3];
@ -153,197 +69,77 @@ void __Mp3DoState(PointerWrap &p) {
int sceMp3Decode(u32 mp3, u32 outPcmPtr) {
DEBUG_LOG(ME, "sceMp3Decode(%08x,%08x)", mp3, outPcmPtr);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
// Nothing to decode
if (ctx->bufferAvailable == 0 || ctx->readPosition >= ctx->mp3StreamEnd) {
return 0;
}
int bytesdecoded = 0;
#ifndef USE_FFMPEG
Memory::Memset(ctx->mp3PcmBuf, 0, ctx->mp3PcmBufSize);
Memory::Write_U32(ctx->mp3PcmBuf, outPcmPtr);
#else
AVFrame frame;
memset(&frame, 0, sizeof(frame));
AVPacket packet;
av_init_packet(&packet);
int got_frame = 0, ret;
static int audio_frame_count = 0;
while (!got_frame) {
if ((ret = av_read_frame(ctx->avformat_context, &packet)) < 0)
break;
if (packet.stream_index == ctx->audio_stream_index) {
av_frame_unref(&frame);
got_frame = 0;
ret = avcodec_decode_audio4(ctx->decoder_context, &frame, &got_frame, &packet);
if (ret < 0) {
ERROR_LOG(ME, "avcodec_decode_audio4: Error decoding audio %d", ret);
continue;
}
if (got_frame) {
//char buf[1024] = "";
//av_ts_make_time_string(buf, frame.pts, &ctx->decoder_context->time_base);
//DEBUG_LOG(ME, "audio_frame n:%d nb_samples:%d pts:%s", audio_frame_count++, frame.nb_samples, buf);
/*
u8 *audio_dst_data;
int audio_dst_linesize;
ret = av_samples_alloc(&audio_dst_data, &audio_dst_linesize, frame.channels, frame.nb_samples, (AVSampleFormat)frame.format, 1);
if (ret < 0) {
ERROR_LOG(ME, "av_samples_alloc: Could not allocate audio buffer %d", ret);
return -1;
}
*/
int decoded = av_samples_get_buffer_size(NULL, frame.channels, frame.nb_samples, (AVSampleFormat)frame.format, 1);
u8* out = Memory::GetPointer(ctx->mp3PcmBuf + bytesdecoded);
ret = swr_convert(ctx->resampler_context, &out, frame.nb_samples, (const u8**)frame.extended_data, frame.nb_samples);
if (ret < 0) {
ERROR_LOG(ME, "swr_convert: Error while converting %d", ret);
return -1;
}
__AdjustBGMVolume((s16 *)out, frame.nb_samples * frame.channels);
//av_samples_copy(&audio_dst_data, frame.data, 0, 0, frame.nb_samples, frame.channels, (AVSampleFormat)frame.format);
//memcpy(Memory::GetPointer(ctx->mp3PcmBuf + bytesdecoded), audio_dst_data, decoded);
bytesdecoded += decoded;
// av_freep(&audio_dst_data[0]);
}
}
av_free_packet(&packet);
}
Memory::Write_U32(ctx->mp3PcmBuf, outPcmPtr);
#endif
#if 0 && defined(_DEBUG)
char fileName[256];
sprintf(fileName, "out.wav", mp3);
FILE * file = fopen(fileName, "a+b");
if (file) {
if (!Memory::IsValidAddress(ctx->mp3Buf)) {
ERROR_LOG(ME, "sceMp3Decode mp3Buf %08X is not a valid address!", ctx->mp3Buf);
}
//u8 * ptr = Memory::GetPointer(ctx->mp3Buf);
fwrite(Memory::GetPointer(ctx->mp3PcmBuf), 1, bytesdecoded, file);
fclose(file);
}
#endif
// 2 bytes per channel and we use ctx->mp3Channels here
ctx->mp3SumDecodedSamples += bytesdecoded / (2 * ctx->mp3Channels);
return bytesdecoded;
return ctx->sceAuDecode(outPcmPtr);
}
int sceMp3ResetPlayPosition(u32 mp3) {
DEBUG_LOG(ME, "SceMp3ResetPlayPosition(%08x)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
ctx->readPosition = ctx->mp3StreamStart;
return 0;
return ctx->sceAuResetPlayPosition();
}
int sceMp3CheckStreamDataNeeded(u32 mp3) {
DEBUG_LOG(ME, "sceMp3CheckStreamDataNeeded(%08x)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->bufferAvailable != ctx->mp3BufSize && ctx->readPosition < ctx->mp3StreamEnd;
return ctx->sceAuCheckStreamDataNeeded();
}
static int readFunc(void *opaque, uint8_t *buf, int buf_size) {
Mp3Context *ctx = static_cast<Mp3Context*>(opaque);
int res = 0;
while (ctx->bufferAvailable && buf_size) {
// Maximum bytes we can read
int to_read = std::min(ctx->bufferAvailable, buf_size);
// Don't read past the end if the buffer loops
to_read = std::min(ctx->mp3BufSize - ctx->bufferRead, to_read);
memcpy(buf + res, Memory::GetCharPointer(ctx->mp3Buf + ctx->bufferRead), to_read);
ctx->bufferRead += to_read;
if (ctx->bufferRead == ctx->mp3BufSize)
ctx->bufferRead = 0;
ctx->bufferAvailable -= to_read;
buf_size -= to_read;
res += to_read;
}
if (ctx->bufferAvailable == 0) {
ctx->bufferRead = 0;
ctx->bufferWrite = 0;
}
#if 0 && defined(_DEBUG)
char fileName[256];
sprintf(fileName, "out.mp3");
FILE * file = fopen(fileName, "a+b");
if (file) {
if (!Memory::IsValidAddress(ctx->mp3Buf)) {
ERROR_LOG(ME, "sceMp3Decode mp3Buf %08X is not a valid address!", ctx->mp3Buf);
}
fwrite(buf, 1, res, file);
fclose(file);
}
#endif
return res;
}
u32 sceMp3ReserveMp3Handle(u32 mp3Addr) {
DEBUG_LOG(ME, "sceMp3ReserveMp3Handle(%08x)", mp3Addr);
Mp3Context *ctx = new Mp3Context;
AuCtx *Au = new AuCtx;
memset(ctx, 0, sizeof(Mp3Context));
if (!Memory::IsValidAddress(mp3Addr)) {
WARN_LOG_REPORT(ME, "sceMp3ReserveMp3Handle(%08x): invalid address", mp3Addr)
} else {
ctx->mp3StreamStart = Memory::Read_U64(mp3Addr);
ctx->mp3StreamEnd = Memory::Read_U64(mp3Addr + 8);
ctx->mp3Buf = Memory::Read_U32(mp3Addr + 16);
ctx->mp3BufSize = Memory::Read_U32(mp3Addr + 20);
ctx->mp3PcmBuf = Memory::Read_U32(mp3Addr + 24);
ctx->mp3PcmBufSize = Memory::Read_U32(mp3Addr + 28);
if (!Memory::IsValidAddress(mp3Addr)){
ERROR_LOG(ME, "sceMp3ReserveMp3Handle(%08x) invalid address %08x", mp3Addr);
return -1;
}
ctx->readPosition = ctx->mp3StreamStart;
ctx->mp3MaxSamples = ctx->mp3PcmBufSize / 4 ;
ctx->mp3DecodedBytes = 0;
ctx->mp3SumDecodedSamples = 0;
ctx->mp3LoopNum = -1;
Au->startPos = Memory::Read_U64(mp3Addr); // Audio stream start position.
Au->endPos = Memory::Read_U32(mp3Addr + 8); // Audio stream end position.
Au->AuBuf = Memory::Read_U32(mp3Addr + 16); // Input Au data buffer.
Au->AuBufSize = Memory::Read_U32(mp3Addr + 20); // Input Au data buffer size.
Au->PCMBuf = Memory::Read_U32(mp3Addr + 24); // Output PCM data buffer.
Au->PCMBufSize = Memory::Read_U32(mp3Addr + 28); // Output PCM data buffer size.
DEBUG_LOG(ME, "startPos %x endPos %x mp3buf %08x mp3bufSize %08x PCMbuf %08x PCMbufSize %08x",
Au->startPos, Au->endPos, Au->AuBuf, Au->AuBufSize, Au->PCMBuf, Au->PCMBufSize);
Au->Channels = 2;
Au->SumDecodedSamples = 0;
Au->MaxOutputSample = Au->PCMBufSize / 4;
Au->LoopNum = -1;
Au->AuBufAvailable = 0;
Au->MaxOutputSample = 0;
Au->readPos = Au->startPos;
// create Au decoder
Au->decoder = new SimpleAudio(PSP_CODEC_MP3);
// close the audio if mp3Addr already exist.
if (mp3Map.find(mp3Addr) != mp3Map.end()) {
delete mp3Map[mp3Addr];
mp3Map.erase(mp3Addr);
}
mp3Map[mp3Addr] = ctx;
mp3Map[mp3Addr] = Au;
return mp3Addr;
}
@ -359,310 +155,142 @@ int sceMp3TermResource() {
return 0;
}
int __Mp3InitContext(Mp3Context *ctx) {
#ifdef USE_FFMPEG
InitFFmpeg();
u8 *avio_buffer = (u8*)(av_malloc(ctx->mp3BufSize));
ctx->avio_context = avio_alloc_context(avio_buffer, ctx->mp3BufSize, 0, (void*)ctx, readFunc, NULL, NULL);
ctx->avformat_context = avformat_alloc_context();
ctx->avformat_context->pb = ctx->avio_context;
int ret;
// Load audio buffer
if ((ret = avformat_open_input(&ctx->avformat_context, NULL, av_find_input_format("mp3"), NULL)) < 0) {
ERROR_LOG(ME, "avformat_open_input: Cannot open input %d", ret);
return -1;
}
if ((ret = avformat_find_stream_info(ctx->avformat_context, NULL)) < 0) {
ERROR_LOG(ME, "avformat_find_stream_info: Cannot find stream information %d", ret);
return -1;
}
AVCodec *dec;
// Select the audio stream
ret = av_find_best_stream(ctx->avformat_context, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);
if (ret < 0) {
if (ret == AVERROR_DECODER_NOT_FOUND) {
ERROR_LOG(HLE, "av_find_best_stream: No appropriate decoder found");
} else {
ERROR_LOG(HLE, "av_find_best_stream: Cannot find an audio stream in the input file %d", ret);
}
return -1;
}
ctx->audio_stream_index = ret;
ctx->decoder_context = ctx->avformat_context->streams[ctx->audio_stream_index]->codec;
// Init the audio decoder
if ((ret = avcodec_open2(ctx->decoder_context, dec, NULL)) < 0) {
ERROR_LOG(ME, "avcodec_open2: Cannot open audio decoder %d", ret);
return -1;
}
ctx->resampler_context = swr_alloc_set_opts(NULL,
ctx->decoder_context->channel_layout,
AV_SAMPLE_FMT_S16,
ctx->decoder_context->sample_rate,
ctx->decoder_context->channel_layout,
ctx->decoder_context->sample_fmt,
ctx->decoder_context->sample_rate,
0, NULL);
if (!ctx->resampler_context) {
ERROR_LOG(ME, "Could not allocate resampler context %d", ret);
return -1;
}
if ((ret = swr_init(ctx->resampler_context)) < 0) {
ERROR_LOG(ME, "Failed to initialize the resampling context %d", ret);
return -1;
}
return 0;
#endif
}
int __CalculateMp3Channels(int bitval) {
if (bitval == 0 || bitval == 1 || bitval == 2) { // Stereo / Joint Stereo / Dual Channel.
return 2;
} else if (bitval == 3) { // Mono.
return 1;
} else {
return -1;
}
}
int __CalculateMp3SampleRates(int bitval, int mp3version) {
if (mp3version == 3) { // MPEG Version 1
int valuemapping[] = { 44100, 48000, 32000, -1 };
return valuemapping[bitval];
} else if (mp3version == 2) { // MPEG Version 2
int valuemapping[] = { 22050, 24000, 16000, -1 };
return valuemapping[bitval];
} else if (mp3version == 0) { // MPEG Version 2.5
int valuemapping[] = { 11025, 12000, 8000, -1 };
return valuemapping[bitval];
} else {
return -1;
}
}
int __CalculateMp3Bitrates(int bitval, int mp3version, int mp3layer) {
if (mp3version == 3) { // MPEG Version 1
if (mp3layer == 3) { // Layer I
int valuemapping[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 };
return valuemapping[bitval];
} else if (mp3layer == 2) { // Layer II
int valuemapping[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 };
return valuemapping[bitval];
} else if (mp3layer == 1) { // Layer III
int valuemapping[] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 };
return valuemapping[bitval];
} else {
return -1;
}
} else if (mp3version == 2 || mp3version == 0) { // MPEG Version 2 or 2.5
if (mp3layer == 3) { // Layer I
int valuemapping[] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 };
return valuemapping[bitval];
} else if (mp3layer == 1 || mp3layer == 2) { // Layer II or III
int valuemapping[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 };
return valuemapping[bitval];
} else {
return -1;
}
} else {
return -1;
}
}
int __ParseMp3Header(Mp3Context *ctx) {
int header = bswap32(Memory::Read_U32(ctx->mp3Buf));
// ID3 tag , can be seen in Hanayaka Nari Wa ga Ichizoku.
if ((header & 0xFFFFFF00) == ID3) {
int size = bswap32(Memory::Read_U32(ctx->mp3Buf + ctx->mp3StreamStart + 6));
// Highest bit of each byte has to be ignored (format: 0x7F7F7F7F)
size = (size & 0x7F) | ((size & 0x7F00) >> 1) | ((size & 0x7F0000) >> 2) | ((size & 0x7F000000) >> 3);
header = bswap32(Memory::Read_U32(ctx->mp3Buf + ctx->mp3StreamStart + 10 + size));
}
return header;
}
int sceMp3Init(u32 mp3) {
DEBUG_LOG(ME, "sceMp3Init(%08x)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
// Parse the Mp3 header
int header = __ParseMp3Header(ctx);
int layer = (header >> 17) & 0x3;
ctx->mp3Version = ((header >> 19) & 0x3);
ctx->mp3SamplingRate = __CalculateMp3SampleRates((header >> 10) & 0x3, ctx->mp3Version);
ctx->mp3Channels = __CalculateMp3Channels((header >> 6) & 0x3);
ctx->mp3Bitrate = __CalculateMp3Bitrates((header >> 12) & 0xF, ctx->mp3Version, layer);
INFO_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%ikHz, bitrate=%ikbps", ctx->mp3Channels, ctx->mp3SamplingRate, ctx->mp3Bitrate);
#ifdef USE_FFMPEG
int ret = __Mp3InitContext(ctx);
if (ret != 0)
return ret;
av_dump_format(ctx->avformat_context, 0, "mp3", 0);
#endif
// TODO
// if startPos == 0, we have to read the header part of mp3 and get some information
// and move startPos to stream data position. Decode from header will not success.
if (ctx->startPos == 0){
}
return 0;
}
int sceMp3GetLoopNum(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetLoopNum(%08x)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3LoopNum;
return ctx->sceAuGetLoopNum();
}
int sceMp3GetMaxOutputSample(u32 mp3)
{
DEBUG_LOG(ME, "sceMp3GetMaxOutputSample(%08x)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3MaxSamples;
return ctx->sceAuGetMaxOutputSample();
}
int sceMp3GetSumDecodedSample(u32 mp3) {
ERROR_LOG_REPORT(ME, "UNIMPL sceMp3GetSumDecodedSample(%08X)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3SumDecodedSamples;
return ctx->sceAuGetSumDecodedSample();
}
int sceMp3SetLoopNum(u32 mp3, int loop) {
INFO_LOG(ME, "sceMp3SetLoopNum(%08X, %i)", mp3, loop);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
ctx->mp3LoopNum = loop;
return 0;
return ctx->sceAuSetLoopNum(loop);
}
int sceMp3GetMp3ChannelNum(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetMp3ChannelNum(%08X)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3Channels;
return ctx->sceAuGetChannelNum();
}
int sceMp3GetBitRate(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetBitRate(%08X)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3Bitrate;
return ctx->sceAuGetBitRate();
}
int sceMp3GetSamplingRate(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetSamplingRate(%08X)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3SamplingRate;
return ctx->sceAuGetSamplingRate();
}
int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) {
INFO_LOG(ME, "sceMp3GetInfoToAddStreamData(%08X, %08X, %08X, %08X)", mp3, dstPtr, towritePtr, srcposPtr);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
u32 buf, max_write;
if (ctx->readPosition < ctx->mp3StreamEnd) {
buf = ctx->mp3Buf + ctx->bufferWrite;
max_write = std::min(ctx->mp3BufSize - ctx->bufferWrite, ctx->mp3BufSize - ctx->bufferAvailable);
} else {
buf = 0;
max_write = 0;
}
if (Memory::IsValidAddress(dstPtr))
Memory::Write_U32(buf, dstPtr);
if (Memory::IsValidAddress(towritePtr))
Memory::Write_U32(max_write, towritePtr);
if (Memory::IsValidAddress(srcposPtr))
Memory::Write_U32(ctx->readPosition, srcposPtr);
return 0;
return ctx->sceAuGetInfoToAddStreamData(dstPtr, towritePtr, srcposPtr);
}
int sceMp3NotifyAddStreamData(u32 mp3, int size) {
INFO_LOG(ME, "sceMp3NotifyAddStreamData(%08X, %i)", mp3, size);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
ctx->readPosition += size;
ctx->bufferAvailable += size;
ctx->bufferWrite += size;
if (ctx->bufferWrite >= ctx->mp3BufSize)
ctx->bufferWrite %= ctx->mp3BufSize;
if (ctx->readPosition >= ctx->mp3StreamEnd && ctx->mp3LoopNum != 0) {
ctx->readPosition = ctx->mp3StreamStart;
if (ctx->mp3LoopNum > 0)
ctx->mp3LoopNum--;
}
return 0;
return ctx->sceAuNotifyAddStreamData(size);
}
int sceMp3ReleaseMp3Handle(u32 mp3) {
DEBUG_LOG(ME, "sceMp3ReleaseMp3Handle(%08X)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
mp3Map.erase(mp3Map.find(mp3));
delete ctx;
mp3Map.erase(mp3);
return 0;
}
@ -683,26 +311,25 @@ u32 sceMp3GetFrameNum(u32 mp3) {
}
u32 sceMp3GetMPEGVersion(u32 mp3) {
DEBUG_LOG(ME, "sceMp3GetMPEGVersion(%08x)", mp3);
Mp3Context *ctx = getMp3Ctx(mp3);
ERROR_LOG(ME, "UNIMPL sceMp3GetMPEGVersion(%08x)", mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
return ctx->mp3Version;
return 0;
}
u32 sceMp3ResetPlayPositionByFrame(u32 mp3, int position) {
DEBUG_LOG(ME, "sceMp3ResetPlayPositionByFrame(%08x, %i)", mp3, position);
Mp3Context *ctx = getMp3Ctx(mp3);
AuCtx *ctx = getMp3Ctx(mp3);
if (!ctx) {
ERROR_LOG(ME, "%s: bad mp3 handle %08x", __FUNCTION__, mp3);
return -1;
}
ctx->readPosition = position;
return 0;
return ctx->sceAuResetPlayPositionByFrame(position);
}
u32 sceMp3LowLevelInit() {

View File

@ -15,6 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HW/SimpleAudioDec.h"
#include "Core/HW/MediaEngine.h"
#include "Core/HW/BufferQueue.h"
@ -31,7 +32,7 @@ extern "C" {
bool SimpleAudio::GetAudioCodecID(int audioType){
#ifdef USE_FFMPEG
switch (audioType)
{
case PSP_CODEC_AAC:
@ -60,15 +61,15 @@ bool SimpleAudio::GetAudioCodecID(int audioType){
}
SimpleAudio::SimpleAudio(int audioType)
: codec_(0), codecCtx_(0), swrCtx_(0), audioType(audioType){
: codec_(0), codecCtx_(0), swrCtx_(0), audioType(audioType), outSamples(0){
#ifdef USE_FFMPEG
avcodec_register_all();
av_register_all();
InitFFmpeg();
frame_ = av_frame_alloc();
// Get Audio Codec ID
// Get Audio Codec ctx
if (!GetAudioCodecID(audioType)){
ERROR_LOG(ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType);
return;
@ -77,7 +78,7 @@ SimpleAudio::SimpleAudio(int audioType)
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));
ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ctx for audio (%s). Update your submodule.", GetCodecName(audioType));
return;
}
// Allocate codec context
@ -102,7 +103,7 @@ SimpleAudio::SimpleAudio(int audioType)
SimpleAudio::SimpleAudio(u32 ctxPtr, int audioType)
: codec_(0), codecCtx_(0), swrCtx_(0), ctxPtr(ctxPtr), audioType(audioType){
: codec_(0), codecCtx_(0), swrCtx_(0), ctxPtr(ctxPtr), audioType(audioType), outSamples(0){
#ifdef USE_FFMPEG
avcodec_register_all();
av_register_all();
@ -110,7 +111,7 @@ SimpleAudio::SimpleAudio(u32 ctxPtr, int audioType)
frame_ = av_frame_alloc();
// Get Audio Codec ID
// Get Audio Codec ctx
if (!GetAudioCodecID(audioType)){
ERROR_LOG(ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType);
return;
@ -119,7 +120,7 @@ SimpleAudio::SimpleAudio(u32 ctxPtr, int audioType)
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));
ERROR_LOG(ME, "This version of FFMPEG does not support AV_CODEC_ctx for audio (%s). Update your submodule.", GetCodecName(audioType));
return;
}
// Allocate codec context
@ -148,10 +149,9 @@ SimpleAudio::~SimpleAudio() {
av_frame_free(&frame_);
if (codecCtx_)
avcodec_close(codecCtx_);
frame_ = 0;
codecCtx_ = 0;
codec_ = 0;
if (swrCtx_)
swr_free(&swrCtx_);
#endif // USE_FFMPEG
}
@ -172,13 +172,20 @@ bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbyte
int got_frame = 0;
av_frame_unref(frame_);
*outbytes = 0;
srcPos = 0;
int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
if (len < 0) {
ERROR_LOG(ME, "Error decoding Audio frame");
// TODO: cleanup
return false;
}
av_free_packet(&packet);
// get bytes consumed in source
srcPos = len;
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
@ -209,7 +216,7 @@ bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbyte
}
swr_free(&swrCtx_);
// output samples per frame, we should *2 since we have two channels
int outSamples = swrRet * 2;
outSamples = swrRet * 2;
// each sample occupies 2 bytes
*outbytes = outSamples * 2;
@ -227,6 +234,14 @@ bool SimpleAudio::Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbyte
#endif // USE_FFMPEG
}
int SimpleAudio::getOutSamples(){
return outSamples;
}
int SimpleAudio::getSourcePos(){
return srcPos;
}
void AudioClose(SimpleAudio **ctx) {
#ifdef USE_FFMPEG
delete *ctx;
@ -241,3 +256,194 @@ bool isValidCodec(int codec){
return false;
}
// sceAu module starts from here
// return output pcm size, <0 error
u32 AuCtx::sceAuDecode(u32 pcmAddr)
{
if (!Memory::IsValidAddress(pcmAddr)){
ERROR_LOG(ME, "%s: output bufferAddress %08x is invalctx", __FUNCTION__, pcmAddr);
return -1;
}
auto inbuff = Memory::GetPointer(AuBuf);
auto outbuf = Memory::GetPointer(PCMBuf);
memset(outbuf, 0, PCMBufSize);
u32 outpcmbufsize = 0;
// move inbuff to writePos of buffer
inbuff += writePos;
// decode frames in AuBuf and output into PCMBuf if it is not exceed
if (AuBufAvailable > 0 && outpcmbufsize < PCMBufSize){
int pcmframesize;
// decode
decoder->Decode(inbuff, AuBufAvailable, outbuf, &pcmframesize);
if (pcmframesize == 0){
// no output pcm, we have either no data or no enough data to decode
// move back audio source readPos to the begin of the last incomplete frame if we not start looping and reset available AuBuf
if (readPos > startPos) { // this means we are not begin to loop yet
readPos -= AuBufAvailable;
}
AuBufAvailable = 0;
//break;
}
// count total output pcm size
outpcmbufsize += pcmframesize;
// count total output samples
SumDecodedSamples += decoder->getOutSamples();
// move inbuff position to next frame
int srcPos = decoder->getSourcePos();
inbuff += srcPos;
// decrease available AuBuf
AuBufAvailable -= srcPos;
// modify the writePos value
writePos += srcPos;
// move outbuff position to the current end of output
outbuf += pcmframesize;
}
Memory::Write_U32(PCMBuf, pcmAddr);
return outpcmbufsize;
}
/*
// return output pcm size, <0 error
u32 AuCtx::sceAuDecode(u32 pcmAddr)
{
if (!Memory::IsValidAddress(pcmAddr)){
ERROR_LOG(ME, "%s: output bufferAddress %08x is invalctx", __FUNCTION__, pcmAddr);
return -1;
}
auto inbuff = Memory::GetPointer(AuBuf);
auto outbuf = Memory::GetPointer(PCMBuf);
memset(outbuf, 0, PCMBufSize);
u32 outpcmbufsize = 0;
// move inbuff to writePos of buffer
inbuff += writePos;
// decode frames in AuBuf and output into PCMBuf if it is not exceed
if (AuBufAvailable > 0 && outpcmbufsize < PCMBufSize){
int pcmframesize;
// decode
decoder->Decode(inbuff, AuBufAvailable, outbuf, &pcmframesize);
if (pcmframesize == 0){
// no output pcm, we have either no data or no enough data to decode
// move back audio source readPos to the begin of the last incomplete frame if we not start looping and reset available AuBuf
if (readPos > startPos) { // this means we are not begin to loop yet
readPos -= AuBufAvailable;
}
AuBufAvailable = 0;
//break;
}
// count total output pcm size
outpcmbufsize += pcmframesize;
// count total output samples
SumDecodedSamples += decoder->getOutSamples();
// move inbuff position to next frame
int srcPos = decoder->getSourcePos();
inbuff += srcPos;
// decrease available AuBuf
AuBufAvailable -= srcPos;
// modify the writePos value
writePos += srcPos;
// move outbuff position to the current end of output
outbuf += pcmframesize;
}
Memory::Write_U32(PCMBuf, pcmAddr);
return outpcmbufsize;
}
*/
u32 AuCtx::sceAuGetLoopNum()
{
return LoopNum;
}
u32 AuCtx::sceAuSetLoopNum(int loop)
{
LoopNum = loop;
return 0;
}
// return 1 to read more data stream, 0 don't read
int AuCtx::sceAuCheckStreamDataNeeded()
{
// if we have no available Au buffer, and the current read position in source file is not the end of stream, then we can read
if (AuBufAvailable == 0 && readPos < endPos){
return 1;
}
return 0;
}
// check how many bytes we have read from source file
u32 AuCtx::sceAuNotifyAddStreamData(int size)
{
readPos += size;
AuBufAvailable += size;
writePos = 0;
if (readPos >= endPos && LoopNum != 0){
// if we need loop, reset readPos
readPos = startPos;
// reset LoopNum
if (LoopNum > 0){
LoopNum--;
}
}
return 0;
}
// read from stream position srcPos of size bytes into buff
u32 AuCtx::sceAuGetInfoToAddStreamData(u32 buff, u32 size, u32 srcPos)
{
// we can recharge AuBuf from its begining
if (Memory::IsValidAddress(buff))
Memory::Write_U32(AuBuf, buff);
if (Memory::IsValidAddress(size))
Memory::Write_U32(AuBufSize, size);
if (Memory::IsValidAddress(srcPos))
Memory::Write_U32(readPos, srcPos);
return 0;
}
u32 AuCtx::sceAuGetMaxOutputSample()
{
return MaxOutputSample;
}
u32 AuCtx::sceAuGetSumDecodedSample()
{
return SumDecodedSamples;
}
u32 AuCtx::sceAuResetPlayPosition()
{
readPos = startPos;
return 0;
}
int AuCtx::sceAuGetChannelNum(){
return Channels;
}
int AuCtx::sceAuGetBitRate(){
return BitRate;
}
int AuCtx::sceAuGetSamplingRate(){
return SamplingRate;
}
u32 AuCtx::sceAuResetPlayPositionByFrame(int position){
readPos = position;
return 0;
}

View File

@ -51,9 +51,13 @@ public:
bool Decode(void* inbuf, int inbytes, uint8_t *outbuf, int *outbytes);
bool IsOK() const { return codec_ != 0; }
int getOutSamples();
int getSourcePos();
u32 ctxPtr;
int audioType;
int outSamples; // output samples per frame
int srcPos; // source position after decode
private:
#ifdef USE_FFMPEG
@ -67,7 +71,7 @@ private:
#endif // USE_FFMPEG
};
// audioType
enum {
PSP_CODEC_AT3PLUS = 0x00001000,
PSP_CODEC_AT3 = 0x00001001,
@ -89,3 +93,90 @@ static const char *GetCodecName(int codec) {
}
};
bool isValidCodec(int codec);
class AuCtx{
public:
// Au source informations
u64 startPos;
u64 endPos;
u32 AuBuf;
u32 AuBufSize;
u32 PCMBuf;
u32 PCMBufSize;
int freq;
int BitRate;
int SamplingRate;
int Channels;
// audio settings
u32 SumDecodedSamples;
int LoopNum;
u32 MaxOutputSample;
// Au decoder
SimpleAudio *decoder;
// Au type
int audioType;
// buffers informations
int AuBufAvailable; // the available buffer of AuBuf to be able to recharge data
int readPos; // read position in audio source file
int writePos; // write position in AuBuf, i.e. the size of bytes decoded in AuBuf.
AuCtx() :decoder(NULL){};
~AuCtx(){
if (decoder){
AudioClose(&decoder);
decoder = NULL;
}
};
u32 sceAuExit();
u32 sceAuDecode(u32 pcmAddr);
u32 sceAuGetLoopNum();
u32 sceAuSetLoopNum(int loop);
int sceAuCheckStreamDataNeeded();
u32 sceAuNotifyAddStreamData(int size);
u32 sceAuGetInfoToAddStreamData(u32 buff, u32 size, u32 srcPos);
u32 sceAuGetMaxOutputSample();
u32 sceAuGetSumDecodedSample();
u32 sceAuResetPlayPosition();
int sceAuGetChannelNum();
int sceAuGetBitRate();
int sceAuGetSamplingRate();
u32 sceAuResetPlayPositionByFrame(int position);
void DoState(PointerWrap &p) {
auto s = p.Section("AuContext", 1);
if (!s)
return;
p.Do(startPos);
p.Do(endPos);
p.Do(AuBuf);
p.Do(AuBufSize);
p.Do(PCMBuf);
p.Do(PCMBufSize);
p.Do(freq);
p.Do(SumDecodedSamples);
p.Do(LoopNum);
p.Do(Channels);
p.Do(MaxOutputSample);
p.Do(AuBufAvailable);
p.Do(readPos);
p.Do(writePos);
p.Do(audioType);
p.Do(BitRate);
p.Do(SamplingRate);
if (p.mode == p.MODE_READ){
decoder = new SimpleAudio(audioType);
}
};
};