mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge branch 'mp3-support'
This commit is contained in:
commit
9a0e05f110
4 changed files with 328 additions and 111 deletions
|
@ -66,6 +66,7 @@ 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(FFMPEG "Set to OFF to disable FFMPEG usage" ${FFMPEG})
|
||||
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)
|
||||
|
@ -1115,6 +1116,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})
|
||||
|
|
|
@ -212,7 +212,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;
|
||||
}
|
||||
|
|
|
@ -17,31 +17,39 @@
|
|||
|
||||
#include <map>
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/sceMp3.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
#include "Core/Reporting.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 <libavutil/opt.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/timestamp.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/samplefmt.h>
|
||||
}
|
||||
#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);
|
||||
|
@ -53,32 +61,37 @@ 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;
|
||||
#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;
|
||||
static u32 lastMp3Handle = 0;
|
||||
|
||||
|
@ -87,11 +100,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);
|
||||
|
||||
|
@ -102,43 +117,88 @@ 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 = {0};
|
||||
AVPacket packet = {0};
|
||||
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[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);
|
||||
|
||||
/*
|
||||
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) {
|
||||
|
@ -149,8 +209,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;
|
||||
}
|
||||
|
||||
|
@ -162,7 +222,52 @@ 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<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(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) {
|
||||
|
@ -178,13 +283,17 @@ 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->mp3Channels = 2;
|
||||
ctx->mp3Bitrate = 128;
|
||||
ctx->mp3SamplingRate = 44100;*/
|
||||
ctx->mp3SamplingRate = 44100;
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
ctx->avformat_context = NULL;
|
||||
ctx->avio_context = NULL;
|
||||
#endif
|
||||
|
||||
mp3Map[mp3Addr] = ctx;
|
||||
return mp3Addr;
|
||||
|
@ -214,36 +323,74 @@ 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)
|
||||
ctx->mp3Channels = 2;
|
||||
else if(channels == 3)
|
||||
ctx->mp3Channels = 1;
|
||||
else
|
||||
ctx->mp3Channels = 0;
|
||||
|
||||
// 0 == VBR
|
||||
int bitrate = ((header >> 10) & 0x3);
|
||||
if(bitrate < (int)ARRAY_SIZE(MP3_BITRATES))
|
||||
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
|
||||
u8* avio_buffer = static_cast<u8*>(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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -254,31 +401,22 @@ 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;
|
||||
}
|
||||
|
||||
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->mp3BufPendingSize = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMp3GetSumDecodedSample(u32 mp3) {
|
||||
ERROR_LOG_REPORT(HLE, "UNIMPL sceMp3GetSumDecodedSample(%08X)", mp3);
|
||||
return 0;
|
||||
|
@ -292,10 +430,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);
|
||||
|
||||
|
@ -304,9 +443,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);
|
||||
|
||||
|
@ -315,9 +454,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);
|
||||
|
||||
|
@ -326,23 +465,54 @@ 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 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;
|
||||
}
|
||||
|
||||
|
@ -354,8 +524,15 @@ int sceMp3ReleaseMp3Handle(u32 mp3) {
|
|||
ERROR_LOG(HLE, "%s: bad mp3 handle %08x", __FUNCTION__, 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -381,11 +558,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>,"sceMp3ReserveMp3Handle"},
|
||||
{0x0DB149F4,WrapI_UI<sceMp3NotifyAddStreamData>,"sceMp3NotifyAddStreamData"},
|
||||
{0x2A368661,WrapI_U<sceMp3ResetPlayPosition>,"sceMp3ResetPlayPosition"},
|
||||
|
@ -412,7 +589,6 @@ const HLEFunction sceMp3[] =
|
|||
{0xe3ee2c81,0,"sceMp3_E3EE2C81"},
|
||||
};
|
||||
|
||||
void Register_sceMp3()
|
||||
{
|
||||
void Register_sceMp3() {
|
||||
RegisterModule("sceMp3", ARRAY_SIZE(sceMp3), sceMp3);
|
||||
}
|
||||
|
|
|
@ -301,6 +301,11 @@ void __MpegInit() {
|
|||
isCurrentMpegAnalyzed = false;
|
||||
isMpegInit = false;
|
||||
actionPostPut = __KernelRegisterActionType(PostPutAction::Create);
|
||||
|
||||
#ifdef USING_FFMPEG
|
||||
avcodec_register_all();
|
||||
av_register_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
void __MpegDoState(PointerWrap &p) {
|
||||
|
|
Loading…
Add table
Reference in a new issue