From c216b535eefaa374599c53379c99542511f25310 Mon Sep 17 00:00:00 2001 From: kaienfr Date: Fri, 11 Apr 2014 15:09:31 +0200 Subject: [PATCH] Save current changes --- Core/HLE/sceMp3.cpp | 517 ++++++------------------------------- Core/HW/SimpleAudioDec.cpp | 230 ++++++++++++++++- Core/HW/SimpleAudioDec.h | 93 ++++++- 3 files changed, 382 insertions(+), 458 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index d44c1958da..6e6ba3b992 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -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 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 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(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() { diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index a0e686c7dc..ea153aa56f 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -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; +} \ No newline at end of file diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 1e1aec07c1..3a3cf0c8c7 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -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); + } + }; +}; + + + +