From 501f705ba3c279cb583aae1703fe9bf204926092 Mon Sep 17 00:00:00 2001 From: Florent Castelli Date: Sun, 20 Jan 2013 14:30:16 +0100 Subject: [PATCH 1/6] Merge mp3 support from Orphis' old FFMPEG code. Conflicts: CMakeLists.txt Core/HLE/sceAudio.cpp Core/HLE/sceMp3.cpp Core/HLE/sceMpeg.cpp --- CMakeLists.txt | 36 ++++ Core/HLE/sceAudio.cpp | 13 +- Core/HLE/sceMp3.cpp | 370 ++++++++++++++++++++++++++++++------------ Core/HLE/sceMpeg.cpp | 5 + 4 files changed, 315 insertions(+), 109 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c982e1d46e..f8497ea1d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ option(IOS "Set to ON if targeting an iOS device" ${IOS}) option(USING_GLES2 "Set to ON if target device uses OpenGL ES 2.0" ${USING_GLES2}) option(USING_QT_UI "Set to ON if you wish to use the Qt frontend wrapper" ${USING_QT_UI}) option(HEADLESS "Set to OFF to not generate the PPSSPPHeadless target" ${HEADLESS}) +option(USE_FFMPEG "Build with FFMPEG support (beta)" ${USE_FFMPEG}) if(ANDROID) if(NOT ANDROID_ABI) @@ -1036,6 +1037,41 @@ set(NativeAssets assets/ppge_atlas.zim) set(LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT} ${nativeExtraLibs}) +if(USE_FFMPEG AND NOT DEFINED FFMPEG_BUILDDIR) + message(WARNING "FFMPEG_BUILDDIR variable is required to enable FFmpeg. Disabling it.") + unset(USE_FFMPEG) +endif(USE_FFMPEG AND NOT DEFINED FFMPEG_BUILDDIR) + +if(USE_FFMPEG) + include_directories(ffmpeg ${FFMPEG_BUILDDIR}) + + add_library(libavformat STATIC IMPORTED) + set_target_properties(libavformat PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavformat/libavformat.a) + add_library(libavcodec STATIC IMPORTED) + set_target_properties(libavcodec PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavcodec/libavcodec.a) + add_library(libavutil STATIC IMPORTED) + set_target_properties(libavutil PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libavutil/libavutil.a) + add_library(libswresample STATIC IMPORTED) + set_target_properties(libswresample PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libswresample/libswresample.a) + add_library(libswscale STATIC IMPORTED) + set_target_properties(libswscale PROPERTIES IMPORTED_LOCATION ${FFMPEG_BUILDDIR}/libswscale/libswscale.a) + + SET (FFMPEG_LIBRARIES + libavcodec + libavformat + libavutil + libswresample + libswscale + ) + + if(APPLE) + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} bz2 "-framework VideoDecodeAcceleration" "-framework CoreVideo") + endif(APPLE) + + set(LinkCommon ${LinkCommon} ${FFMPEG_LIBRARIES}) + add_definitions(-DUSE_FFMPEG) +endif(USE_FFMPEG) + if (TargetBin) if (IOS) add_executable(${TargetBin} MACOSX_BUNDLE ${NativeAppSource}) diff --git a/Core/HLE/sceAudio.cpp b/Core/HLE/sceAudio.cpp index ab2e9819e3..84296be4e0 100644 --- a/Core/HLE/sceAudio.cpp +++ b/Core/HLE/sceAudio.cpp @@ -346,15 +346,16 @@ u32 sceAudioSRCChRelease() { return 0; } -u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) { - if (vol > 0xFFFF) { - ERROR_LOG(HLE,"sceAudioSRCOutputBlocking(%08x, %08x) - invalid volume", vol, buf); +u32 sceAudioSRCOutputBlocking(u32 volume, u32 buf) { + if (volume > 0xFFFF) { + ERROR_LOG(HLE,"sceAudioSRCOutputBlocking(%08x, %08x) - invalid volume", volume, buf); return SCE_ERROR_AUDIO_INVALID_VOLUME; } - DEBUG_LOG(HLE, "sceAudioSRCOutputBlocking(%08x, %08x)", vol, buf); - chans[src].leftVolume = vol; - chans[src].rightVolume = vol; + chans[src].leftVolume = volume; + chans[src].rightVolume = volume; chans[src].sampleAddress = buf; + // __AudioEnqueue(chans[chanSRC], chanSRC, true); + // return chans[chanSRC].sampleCount; return __AudioEnqueue(chans[src], src, true); } diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 6808a08e2e..049b167746 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -1,46 +1,36 @@ -// Copyright (c) 2012- 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 +#include "sceMp3.h" #include "HLE.h" #include "../HW/MediaEngine.h" +#ifdef USE_FFMPEG +#ifndef PRId64 +#define PRId64 "%llu" +#endif +// Urgh! Why is this needed? +#ifdef ANDROID +#ifndef UINT64_C +#define UINT64_C(c) (c ## ULL) +#endif +#endif +extern "C" { +#include +#include +#include +#include +#include +} +#endif + static const int MP3_BITRATES[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}; -struct Mp3Context { - Mp3Context() : mediaengine(NULL) {} - ~Mp3Context() { - if (mediaengine != NULL) { - delete mediaengine; - } - } - +struct Mp3Context { void DoState(PointerWrap &p) { p.Do(mp3StreamStart); p.Do(mp3StreamEnd); p.Do(mp3Buf); p.Do(mp3BufSize); p.Do(mp3PcmBuf); - p.Do(mp3BufPendingSize); p.Do(mp3PcmBufSize); - p.Do(mp3InputFileReadPos); - p.Do(mp3InputBufWritePos); - p.Do(mp3InputBufSize); - p.Do(mp3InputFileSize); p.Do(mp3DecodedBytes); p.Do(mp3LoopNum); p.Do(mp3MaxSamples); @@ -52,32 +42,36 @@ struct Mp3Context { p.DoMarker("Mp3Context"); } - u64 mp3StreamStart; - u64 mp3StreamEnd; - u64 mp3StreamPosition; + int mp3StreamStart; + int mp3StreamEnd; u32 mp3Buf; int mp3BufSize; - int mp3BufPendingSize; u32 mp3PcmBuf; int mp3PcmBufSize; - int mp3InputFileReadPos; - int mp3InputBufWritePos; - int mp3InputBufSize; - int mp3InputFileSize; + int readPosition; + + int bufferRead; + int bufferWrite; + int bufferAvailable; + int mp3DecodedBytes; int mp3LoopNum; int mp3MaxSamples; + MediaEngine *mediaengine; int mp3Channels; int mp3Bitrate; int mp3SamplingRate; int mp3Version; - MediaEngine *mediaengine; + AVFormatContext *avformat_context; + AVIOContext *avio_context; + AVCodecContext *decoder_context; + SwrContext *resampler_context; + int audio_stream_index; }; - static std::map mp3Map; static u32 lastMp3Handle = 0; @@ -86,11 +80,13 @@ Mp3Context *getMp3Ctx(u32 mp3) { ERROR_LOG(HLE, "Bad mp3 handle %08x - using last one (%08x) instead", mp3, lastMp3Handle); mp3 = lastMp3Handle; } + if (mp3Map.find(mp3) == mp3Map.end()) return NULL; return mp3Map[mp3]; } +/* MP3 */ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { DEBUG_LOG(HLE, "sceMp3Decode(%08x,%08x)", mp3, outPcmPtr); @@ -101,43 +97,87 @@ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { } // Nothing to decode - if(ctx->mp3BufPendingSize == 0 || ctx->mp3StreamPosition >= ctx->mp3StreamEnd) { - if (ctx->mp3LoopNum == 0) { - return 0; - } else if (ctx->mp3LoopNum > 0) { - --ctx->mp3LoopNum; - } + 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 - // TODO: Actually decode the data -#ifdef _DEBUG + AVFrame frame; + AVPacket packet; + int got_frame, ret; + static int audio_frame_count = 0; + + while (bytesdecoded < ctx->mp3PcmBufSize) { + if ((ret = av_read_frame(ctx->avformat_context, &packet)) < 0) + break; + + if (packet.stream_index == ctx->audio_stream_index) { + avcodec_get_frame_defaults(&frame); + got_frame = 0; + ret = avcodec_decode_audio4(ctx->decoder_context, &frame, &got_frame, &packet); + if (ret < 0) { + ERROR_LOG(HLE, "avcodec_decode_audio4: Error decoding audio %d", ret); + continue; + } + if (got_frame) { + char buf[256]; + av_ts_make_time_string(buf, frame.pts, &ctx->decoder_context->time_base); + INFO_LOG(HLE, "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(HLE, "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(HLE, "swr_convert: Error while converting %d", ret); + return -1; + } + + //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, "%lli.mp3", ctx->mp3StreamPosition); + sprintf(fileName, "out.wav", mp3); - FILE * file = fopen(fileName, "wb"); - if(file) { - if(!Memory::IsValidAddress(ctx->mp3Buf)) { + FILE * file = fopen(fileName, "a+b"); + if (file) { + if (!Memory::IsValidAddress(ctx->mp3Buf)) { ERROR_LOG(HLE, "sceMp3Decode mp3Buf %08X is not a valid address!", ctx->mp3Buf); } - u8 * ptr = Memory::GetPointer(ctx->mp3Buf); - fwrite(ptr, 1, ctx->mp3BufPendingSize, file); - + //u8 * ptr = Memory::GetPointer(ctx->mp3Buf); + fwrite(Memory::GetPointer(ctx->mp3PcmBuf), 1, bytesdecoded, file); + fclose(file); } -#endif + #endif - ctx->mp3StreamPosition += ctx->mp3BufPendingSize; - if(ctx->mp3StreamPosition > ctx->mp3StreamEnd) - ctx->mp3StreamPosition = ctx->mp3StreamEnd; - - // Reset the pending buffer size so the program will know that we need to buffer more data - ctx->mp3BufPendingSize = (ctx->mp3StreamPosition < ctx->mp3StreamEnd)?-1:0; - - return ctx->mp3PcmBufSize; + return bytesdecoded; } int sceMp3ResetPlayPosition(u32 mp3) { @@ -148,8 +188,8 @@ int sceMp3ResetPlayPosition(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } - ctx->mp3StreamPosition = 0; - ctx->mp3BufPendingSize = -1; + + ctx->readPosition = ctx->mp3StreamStart; return 0; } @@ -161,7 +201,51 @@ int sceMp3CheckStreamDataNeeded(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } - return (ctx->mp3BufPendingSize < 0) && (ctx->mp3StreamPosition < ctx->mp3StreamEnd); + + return ctx->bufferAvailable != ctx->mp3BufSize && ctx->readPosition < ctx->mp3StreamEnd; +} + +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; + 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(HLE, "sceMp3Decode mp3Buf %08X is not a valid address!", ctx->mp3Buf); + } + + fwrite(buf, 1, res, file); + + fclose(file); + } +#endif + + return res; } u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { @@ -177,27 +261,29 @@ u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { ctx->mp3PcmBuf = Memory::Read_U32(mp3Addr+24); ctx->mp3PcmBufSize = Memory::Read_U32(mp3Addr+28); - ctx->mp3StreamPosition = ctx->mp3StreamStart; - ctx->mp3BufPendingSize = -1; + ctx->readPosition = ctx->mp3StreamStart; ctx->mp3MaxSamples = ctx->mp3PcmBufSize / 4 ; /*ctx->mp3Channels = 2; ctx->mp3Bitrate = 128; ctx->mp3SamplingRate = 44100;*/ + ctx->avformat_context = NULL; + ctx->avio_context = NULL; + mp3Map[mp3Addr] = ctx; return mp3Addr; } int sceMp3InitResource() { WARN_LOG(HLE, "UNIML: sceMp3InitResource"); - // Do nothing here + // Do nothing here return 0; } int sceMp3TermResource() { WARN_LOG(HLE, "UNIML: sceMp3TermResource"); - // Do nothing here + // Do nothing here return 0; } @@ -213,36 +299,90 @@ int sceMp3Init(u32 mp3) { // Read in the header and swap the endian int header = Memory::Read_U32(ctx->mp3Buf); header = (header >> 24) | - ((header<<8) & 0x00FF0000) | - ((header>>8) & 0x0000FF00) | - (header << 24); + ((header<<8) & 0x00FF0000) | + ((header>>8) & 0x0000FF00) | + (header << 24); int channels = ((header >> 6) & 0x3); - if(channels == 0 || channels == 1 || channels == 2) + if (channels == 0 || channels == 1 || channels == 2) ctx->mp3Channels = 2; - else if(channels == 3) + else if (channels == 3) ctx->mp3Channels = 1; - else + else ctx->mp3Channels = 0; // 0 == VBR int bitrate = ((header >> 10) & 0x3); - if(bitrate < (int)ARRAY_SIZE(MP3_BITRATES)) + if (bitrate < sizeof(MP3_BITRATES) / sizeof(MP3_BITRATES[0])) ctx->mp3Bitrate = MP3_BITRATES[bitrate]; else ctx->mp3Bitrate = -1; int samplerate = ((header >> 12) & 0x3); - if (samplerate == 0) + if (samplerate == 0) { ctx->mp3SamplingRate = 44100; - else if (samplerate == 1) + } else if (samplerate == 1) { ctx->mp3SamplingRate = 48000; - else if (samplerate == 2) + } else if (samplerate == 2) { ctx->mp3SamplingRate = 32000; - else + } else { ctx->mp3SamplingRate = 0; - + } + ctx->mp3Version = ((header >> 19) & 0x3); + + u8* avio_buffer = static_cast(av_malloc(ctx->mp3BufSize)); + ctx->avio_context = avio_alloc_context(avio_buffer, ctx->mp3BufSize, 0, ctx, readFunc, NULL, NULL); + ctx->avformat_context = avformat_alloc_context(); + ctx->avformat_context->pb = ctx->avio_context; + + int ret; + if ((ret = avformat_open_input(&ctx->avformat_context, NULL, av_find_input_format("mp3"), NULL)) < 0) { + ERROR_LOG(HLE, "avformat_open_input: Cannot open input %d", ret); + return -1; + } + + if ((ret = avformat_find_stream_info(ctx->avformat_context, NULL)) < 0) { + ERROR_LOG(HLE, "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) { + ERROR_LOG(HLE, "av_find_best_stream: Cannot find a 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(HLE, "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(HLE, "Could not allocate resampler context %d", ret); + return -1; + } + + if ((ret = swr_init(ctx->resampler_context)) < 0) { + ERROR_LOG(HLE, "Failed to initialize the resampling context %d", ret); + return -1; + } + + av_dump_format(ctx->avformat_context, 0, "mp3", 0); return 0; } @@ -253,16 +393,19 @@ int sceMp3GetLoopNum(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + return ctx->mp3LoopNum; } -int sceMp3GetMaxOutputSample(u32 mp3) { +int sceMp3GetMaxOutputSample(u32 mp3) +{ DEBUG_LOG(HLE, "sceMp3GetMaxOutputSample(%08x)", mp3); Mp3Context *ctx = getMp3Ctx(mp3); if (!ctx) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + return ctx->mp3MaxSamples; } @@ -274,7 +417,13 @@ int sceMp3NotifyAddStreamData(u32 mp3, int size) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } - ctx->mp3BufPendingSize = size; + + ctx->readPosition += size; + ctx->bufferAvailable += size; + ctx->bufferWrite += size; + if (ctx->bufferWrite == ctx->mp3BufSize) + ctx->bufferWrite = 0; + return 0; } @@ -291,10 +440,11 @@ int sceMp3SetLoopNum(u32 mp3, int loop) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + ctx->mp3LoopNum = loop; + return 0; } - int sceMp3GetMp3ChannelNum(u32 mp3) { DEBUG_LOG(HLE, "sceMp3GetMp3ChannelNum(%08X)", mp3); @@ -303,9 +453,9 @@ int sceMp3GetMp3ChannelNum(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + return ctx->mp3Channels; } - int sceMp3GetBitRate(u32 mp3) { DEBUG_LOG(HLE, "sceMp3GetBitRate(%08X)", mp3); @@ -314,9 +464,9 @@ int sceMp3GetBitRate(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + return ctx->mp3Bitrate; } - int sceMp3GetSamplingRate(u32 mp3) { DEBUG_LOG(HLE, "sceMp3GetSamplingRate(%08X)", mp3); @@ -325,26 +475,36 @@ int sceMp3GetSamplingRate(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + return ctx->mp3SamplingRate; } - int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) { DEBUG_LOG(HLE, "HACK: sceMp3GetInfoToAddStreamData(%08X, %08X, %08X, %08X)", mp3, dstPtr, towritePtr, srcposPtr); - + Mp3Context *ctx = getMp3Ctx(mp3); if (!ctx) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } - if(Memory::IsValidAddress(dstPtr)) - Memory::Write_U32(ctx->mp3Buf, dstPtr); - if(Memory::IsValidAddress(towritePtr)) - Memory::Write_U32(ctx->mp3BufSize, towritePtr); - if(Memory::IsValidAddress(srcposPtr)) - Memory::Write_U32((u32)ctx->mp3StreamPosition, srcposPtr); + + u32 buf, max_write; + if (ctx->readPosition < ctx->mp3StreamEnd) { + buf = ctx->mp3Buf; + 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; } - int sceMp3ReleaseMp3Handle(u32 mp3) { DEBUG_LOG(HLE, "sceMp3ReleaseMp3Handle(%08X)", mp3); @@ -353,8 +513,13 @@ int sceMp3ReleaseMp3Handle(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + + av_free(ctx->avio_context->buffer); + av_free(ctx->avio_context); mp3Map.erase(mp3Map.find(mp3)); + delete ctx; + return 0; } @@ -380,11 +545,11 @@ u32 sceMp3GetVersion(u32 mp3) { ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, mp3); return -1; } + return ctx->mp3Version; } -const HLEFunction sceMp3[] = -{ +const HLEFunction sceMp3[] = { {0x07EC321A,WrapU_U,"sceMp3ReserveMp3Handle"}, {0x0DB149F4,WrapI_UI,"sceMp3NotifyAddStreamData"}, {0x2A368661,WrapI_U,"sceMp3ResetPlayPosition"}, @@ -408,7 +573,6 @@ const HLEFunction sceMp3[] = {0x3548AEC8,WrapU_U,"sceMp3GetFrameNum"}, }; -void Register_sceMp3() -{ +void Register_sceMp3() { RegisterModule("sceMp3", ARRAY_SIZE(sceMp3), sceMp3); -} +} \ No newline at end of file diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 8fb8f9bf93..e544c8bf82 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -304,6 +304,11 @@ void __MpegInit(bool useMediaEngine_) { fakeMode = !useMediaEngine_; isCurrentMpegAnalyzed = false; actionPostPut = __KernelRegisterActionType(PostPutAction::Create); + +#ifdef USING_FFMPEG + avcodec_register_all(); + av_register_all(); +#endif } void __MpegDoState(PointerWrap &p) { From e65390184ecda0b0a4bdbdc702cbec3c56d7ae16 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 12 May 2013 19:48:12 +0200 Subject: [PATCH 2/6] Uncomment some unused stack-corrupting code from sceMp3Decode. Update ffmpeg. --- Core/HLE/sceMp3.cpp | 13 +++++++------ ffmpeg | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 049b167746..68729aa551 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -107,8 +107,8 @@ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { Memory::Write_U32(ctx->mp3PcmBuf, outPcmPtr); #else - AVFrame frame; - AVPacket packet; + AVFrame frame = {0}; + AVPacket packet = {0}; int got_frame, ret; static int audio_frame_count = 0; @@ -125,11 +125,11 @@ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { continue; } if (got_frame) { - char buf[256]; + char buf[1024] = ""; av_ts_make_time_string(buf, frame.pts, &ctx->decoder_context->time_base); - INFO_LOG(HLE, "audio_frame n:%d nb_samples:%d pts:%s", - audio_frame_count++, frame.nb_samples, buf); + INFO_LOG(HLE, "audio_frame n:%d nb_samples:%d pts:%s", audio_frame_count++, frame.nb_samples, buf); + /* u8 *audio_dst_data; int audio_dst_linesize; @@ -138,6 +138,7 @@ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { ERROR_LOG(HLE, "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); @@ -152,7 +153,7 @@ int sceMp3Decode(u32 mp3, u32 outPcmPtr) { //memcpy(Memory::GetPointer(ctx->mp3PcmBuf + bytesdecoded), audio_dst_data, decoded); bytesdecoded += decoded; - //av_freep(&audio_dst_data[0]); + // av_freep(&audio_dst_data[0]); } } av_free_packet(&packet); diff --git a/ffmpeg b/ffmpeg index f667ccddff..fe9c6b483d 160000 --- a/ffmpeg +++ b/ffmpeg @@ -1 +1 @@ -Subproject commit f667ccddffbfa09f946bcc9783d6fbfcb665e631 +Subproject commit fe9c6b483d42c2e481deea97fb6a382c050c10f2 From 0e1b6d8488c67de2b0ae6de658d8ca3d39921920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 May 2013 20:13:07 +0200 Subject: [PATCH 3/6] Fix sceMp3 build without USE_FFMPEG --- Core/HLE/sceMp3.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 68729aa551..6d19ec6e7d 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -64,12 +64,13 @@ struct Mp3Context { 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; @@ -269,8 +270,10 @@ u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { ctx->mp3Bitrate = 128; ctx->mp3SamplingRate = 44100;*/ +#ifdef USE_FFMPEG ctx->avformat_context = NULL; ctx->avio_context = NULL; +#endif mp3Map[mp3Addr] = ctx; return mp3Addr; @@ -332,6 +335,7 @@ int sceMp3Init(u32 mp3) { ctx->mp3Version = ((header >> 19) & 0x3); +#ifdef USE_FFMPEG u8* avio_buffer = static_cast(av_malloc(ctx->mp3BufSize)); ctx->avio_context = avio_alloc_context(avio_buffer, ctx->mp3BufSize, 0, ctx, readFunc, NULL, NULL); ctx->avformat_context = avformat_alloc_context(); @@ -384,6 +388,8 @@ int sceMp3Init(u32 mp3) { } av_dump_format(ctx->avformat_context, 0, "mp3", 0); +#endif + return 0; } @@ -515,8 +521,10 @@ int sceMp3ReleaseMp3Handle(u32 mp3) { return -1; } +#ifdef USE_FFMPEG av_free(ctx->avio_context->buffer); av_free(ctx->avio_context); +#endif mp3Map.erase(mp3Map.find(mp3)); delete ctx; @@ -576,4 +584,4 @@ const HLEFunction sceMp3[] = { void Register_sceMp3() { RegisterModule("sceMp3", ARRAY_SIZE(sceMp3), sceMp3); -} \ No newline at end of file +} From 780e252059f340bdd3bfa140fbd14ffb70615405 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 12 May 2013 11:41:31 -0700 Subject: [PATCH 4/6] Fix crash in mp3 reading. --- Core/HLE/sceMp3.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 6d19ec6e7d..280e918b86 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -223,6 +223,7 @@ int readFunc(void *opaque, uint8_t *buf, int buf_size) { if (ctx->bufferRead == ctx->mp3BufSize) ctx->bufferRead = 0; ctx->bufferAvailable -= to_read; + buf_size -= to_read; res += to_read; } From f864e81e72aa4057b5f206250056c8466c7c98aa Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 12 May 2013 22:29:43 +0200 Subject: [PATCH 5/6] Get mp3 sample rate and channels from FFMPEG instead of trying to detect ourselves. --- Core/HLE/sceMp3.cpp | 76 ++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index 280e918b86..e7a34a9261 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -267,9 +267,9 @@ u32 sceMp3ReserveMp3Handle(u32 mp3Addr) { ctx->readPosition = ctx->mp3StreamStart; ctx->mp3MaxSamples = ctx->mp3PcmBufSize / 4 ; - /*ctx->mp3Channels = 2; + ctx->mp3Channels = 2; ctx->mp3Bitrate = 128; - ctx->mp3SamplingRate = 44100;*/ + ctx->mp3SamplingRate = 44100; #ifdef USE_FFMPEG ctx->avformat_context = NULL; @@ -308,32 +308,6 @@ int sceMp3Init(u32 mp3) { ((header>>8) & 0x0000FF00) | (header << 24); - int channels = ((header >> 6) & 0x3); - if (channels == 0 || channels == 1 || channels == 2) - ctx->mp3Channels = 2; - else if (channels == 3) - ctx->mp3Channels = 1; - else - ctx->mp3Channels = 0; - - // 0 == VBR - int bitrate = ((header >> 10) & 0x3); - if (bitrate < sizeof(MP3_BITRATES) / sizeof(MP3_BITRATES[0])) - ctx->mp3Bitrate = MP3_BITRATES[bitrate]; - else - ctx->mp3Bitrate = -1; - - int samplerate = ((header >> 12) & 0x3); - if (samplerate == 0) { - ctx->mp3SamplingRate = 44100; - } else if (samplerate == 1) { - ctx->mp3SamplingRate = 48000; - } else if (samplerate == 2) { - ctx->mp3SamplingRate = 32000; - } else { - ctx->mp3SamplingRate = 0; - } - ctx->mp3Version = ((header >> 19) & 0x3); #ifdef USE_FFMPEG @@ -378,6 +352,13 @@ int sceMp3Init(u32 mp3) { ctx->decoder_context->sample_fmt, ctx->decoder_context->sample_rate, 0, NULL); + + // Let's just grab this info from FFMPEG, it seems more reliable than the code above. + + ctx->mp3SamplingRate = ctx->decoder_context->sample_rate; + ctx->mp3Channels = ctx->decoder_context->channels; + ctx->mp3Bitrate = ctx->decoder_context->bit_rate; + if (!ctx->resampler_context) { ERROR_LOG(HLE, "Could not allocate resampler context %d", ret); return -1; @@ -417,24 +398,6 @@ int sceMp3GetMaxOutputSample(u32 mp3) return ctx->mp3MaxSamples; } -int sceMp3NotifyAddStreamData(u32 mp3, int size) { - DEBUG_LOG(HLE, "sceMp3NotifyAddStreamData(%08X, %i)", mp3, size); - - Mp3Context *ctx = getMp3Ctx(mp3); - if (!ctx) { - ERROR_LOG(HLE, "%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 = 0; - - return 0; -} - int sceMp3GetSumDecodedSample(u32 mp3) { DEBUG_LOG(HLE, "UNIMPL: sceMp3GetSumDecodedSample(%08X)", mp3); return 0; @@ -486,6 +449,7 @@ int sceMp3GetSamplingRate(u32 mp3) { return ctx->mp3SamplingRate; } + int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcposPtr) { DEBUG_LOG(HLE, "HACK: sceMp3GetInfoToAddStreamData(%08X, %08X, %08X, %08X)", mp3, dstPtr, towritePtr, srcposPtr); @@ -513,6 +477,26 @@ int sceMp3GetInfoToAddStreamData(u32 mp3, u32 dstPtr, u32 towritePtr, u32 srcpos return 0; } + +int sceMp3NotifyAddStreamData(u32 mp3, int size) { + DEBUG_LOG(HLE, "sceMp3NotifyAddStreamData(%08X, %i)", mp3, size); + + Mp3Context *ctx = getMp3Ctx(mp3); + if (!ctx) { + ERROR_LOG(HLE, "%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 = 0; + + return 0; +} + int sceMp3ReleaseMp3Handle(u32 mp3) { DEBUG_LOG(HLE, "sceMp3ReleaseMp3Handle(%08X)", mp3); From b2d57ff3653b6f86af187ac4a481d7bbdfb19cb8 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 13 May 2013 19:25:33 +0200 Subject: [PATCH 6/6] VERBOSE a log statement --- Core/FileSystems/MetaFileSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 4393f406c1..f8958487a6 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -200,7 +200,7 @@ bool MetaFileSystem::MapFilePath(const std::string &_inpath, std::string &outpat outpath = realpath.substr(prefLen); *system = &(fileSystems[i]); - DEBUG_LOG(HLE, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); + VERBOSE_LOG(HLE, "MapFilePath: mapped \"%s\" to prefix: \"%s\", path: \"%s\"", inpath.c_str(), fileSystems[i].prefix.c_str(), outpath.c_str()); return true; }