Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to sceMpeg: fix end cutoff, early audio end, and minor #2143

Merged
merged 13 commits into from
Jun 8, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Core/HLE/sceKernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,11 @@ class KernelObjectPool {

bool GetIDType(SceUID handle, int *type) const
{
if (handle < handleOffset || handle >= handleOffset+maxCount || !occupied[handle-handleOffset])
{
ERROR_LOG(HLE, "Kernel: Bad object handle %i (%08x)", handle, handle);
return false;
}
KernelObject *t = pool[handle - handleOffset];
*type = t->GetIDType();
return true;
Expand Down
59 changes: 42 additions & 17 deletions Core/HLE/sceMpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ struct MpegContext {
MediaEngine *mediaengine;
};

static bool isMpegInit;
static u32 streamIdGen;
static bool isCurrentMpegAnalyzed;
static int actionPostPut;
Expand Down Expand Up @@ -299,13 +300,15 @@ void __MpegInit(bool useMediaEngine_) {
lastMpegHandle = 0;
streamIdGen = 1;
isCurrentMpegAnalyzed = false;
isMpegInit = false;
actionPostPut = __KernelRegisterActionType(PostPutAction::Create);
}

void __MpegDoState(PointerWrap &p) {
p.Do(lastMpegHandle);
p.Do(streamIdGen);
p.Do(isCurrentMpegAnalyzed);
p.Do(isMpegInit);
p.Do(actionPostPut);
__KernelRestoreActionType(actionPostPut, PostPutAction::Create);

Expand All @@ -322,15 +325,20 @@ void __MpegShutdown() {
mpegMap.clear();
}

u32 sceMpegInit()
{
if (!g_Config.bUseMediaEngine){
u32 sceMpegInit() {
if (!g_Config.bUseMediaEngine) {
WARN_LOG(HLE, "Media Engine disabled");
return -1;
}

WARN_LOG(HLE, "sceMpegInit()");
return 0;
if (isMpegInit) {
WARN_LOG(HLE, "sceMpegInit(): already initialized");
return ERROR_MPEG_ALREADY_INIT;
}

INFO_LOG(HLE, "sceMpegInit()");
isMpegInit = true;
return hleDelayResult(0, "mpeg init", 750);
}

u32 sceMpegRingbufferQueryMemSize(int packets)
Expand All @@ -351,7 +359,7 @@ u32 sceMpegRingbufferConstruct(u32 ringbufferAddr, u32 numPackets, u32 data, u32

u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 frameWidth, u32 mode, u32 ddrTop)
{
if (!g_Config.bUseMediaEngine){
if (!g_Config.bUseMediaEngine) {
WARN_LOG(HLE, "Media Engine disabled");
return -1;
}
Expand Down Expand Up @@ -410,7 +418,7 @@ u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 f

INFO_LOG(HLE, "%08x=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)",
mpegHandle, mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop);
return 0;
return hleDelayResult(0, "mpeg create", 29000);
}

int sceMpegDelete(u32 mpeg)
Expand Down Expand Up @@ -621,8 +629,8 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
SceMpegRingBuffer ringbuffer;
Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer);

if (ringbuffer.packetsRead == 0) {
// empty!
if (ringbuffer.packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) {
WARN_LOG(HLE, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr);
return hleDelayResult(MPEG_AVC_DECODE_ERROR_FATAL, "mpeg buffer empty", avcEmptyDelayMs);
}

Expand All @@ -632,14 +640,15 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i

if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) {
ctx->mediaengine->writeVideoImage(Memory::GetPointer(buffer), frameWidth, ctx->videoPixelMode);
ctx->avc.avcFrameStatus = 1;
ctx->videoFrameCount++;
} else {
ctx->avc.avcFrameStatus = 0;
}
ringbuffer.packetsFree = std::max(0, ringbuffer.packets - ctx->mediaengine->getBufferedSize() / 2048);

avcAu.pts = ctx->mediaengine->getVideoTimeStamp();

ctx->avc.avcFrameStatus = 1;
ctx->videoFrameCount++;

ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS;

// Flush structs back to memory
Expand Down Expand Up @@ -920,9 +929,13 @@ u32 sceMpegRingbufferPut(u32 ringbufferAddr, u32 numPackets, u32 available)

// Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc
if (ringbuffer.callback_addr) {
PostPutAction *action = (PostPutAction *) __KernelCreateAction(actionPostPut);
PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut);
action->setRingAddr(ringbufferAddr);
u32 args[3] = {(u32)ringbuffer.data, numPackets, (u32)ringbuffer.callback_args};
// TODO: Should call this multiple times until we get numPackets.
// Normally this would be if it did not read enough, but also if available > packets.
// Should ultimately return the TOTAL number of returned packets.
u32 packetsThisRound = std::min(numPackets, (u32)ringbuffer.packets);
u32 args[3] = {(u32)ringbuffer.data, packetsThisRound, (u32)ringbuffer.callback_args};
__KernelDirectMipsCall(ringbuffer.callback_addr, action, args, 3, false);
} else {
ERROR_LOG(HLE, "sceMpegRingbufferPut: callback_addr zero");
Expand All @@ -946,6 +959,9 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)

if (mpegRingbuffer.packetsRead == 0 || mpegRingbuffer.packetsFree == mpegRingbuffer.packets) {
DEBUG_LOG(HLE, "PSP_ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
sceAu.pts = -1;
sceAu.dts = -1;
sceAu.write(auAddr);
// TODO: Does this really reschedule?
return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs);
}
Expand Down Expand Up @@ -974,6 +990,7 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
int result = 0;

sceAu.pts = ctx->mediaengine->getVideoTimeStamp();
sceAu.dts = sceAu.pts - videoTimestampStep;
if (ctx->mediaengine->IsVideoEnd()) {
INFO_LOG(HLE, "video end reach. pts: %i dts: %i", (int)sceAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
mpegRingbuffer.packetsFree = mpegRingbuffer.packets;
Expand All @@ -997,9 +1014,16 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)

u32 sceMpegFinish()
{
ERROR_LOG(HLE, "sceMpegFinish(...)");
if (!isMpegInit)
{
WARN_LOG(HLE, "sceMpegFinish(...): not initialized");
return ERROR_MPEG_NOT_YET_INIT;
}

INFO_LOG(HLE, "sceMpegFinish(...)");
isMpegInit = false;
//__MpegFinish();
return 0;
return hleDelayResult(0, "mpeg finish", 250);
}

u32 sceMpegQueryMemSize()
Expand Down Expand Up @@ -1029,7 +1053,8 @@ int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
streamInfo->second.needsReset = false;
}

if (mpegRingbuffer.packetsFree == mpegRingbuffer.packets) {
// The audio can end earlier than the video does.
if (mpegRingbuffer.packetsFree == mpegRingbuffer.packets || (ctx->mediaengine->IsAudioEnd() && !ctx->mediaengine->IsVideoEnd())) {
DEBUG_LOG(HLE, "PSP_ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
// TODO: Does this really delay?
return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get atrac", mpegDecodeErrorDelayMs);
Expand Down
2 changes: 2 additions & 0 deletions Core/HLE/sceMpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ enum {
ERROR_PSMFPLAYER_NO_MORE_DATA = 0x8061600c,

ERROR_MPEG_NO_DATA = 0x80618001,
ERROR_MPEG_ALREADY_INIT = 0x80618005,
ERROR_MPEG_NOT_YET_INIT = 0x80618009,
};

// MPEG statics.
Expand Down
3 changes: 1 addition & 2 deletions Core/HLE/scePsmf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,7 @@ u32 scePsmfQueryStreamOffset(u32 bufferAddr, u32 offsetAddr)
if (Memory::IsValidAddress(offsetAddr)) {
Memory::Write_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_OFFSET_OFFSET)), offsetAddr);
}
// return 0 breaks history mode in Saint Seiya Omega
return 1;
return 0;
}

u32 scePsmfQueryStreamSize(u32 bufferAddr, u32 sizeAddr)
Expand Down
Loading