Skip to content

Commit

Permalink
Merge pull request #2143 from unknownbrackets/mpeg-fix
Browse files Browse the repository at this point in the history
Improvements to sceMpeg: fix end cutoff, early audio end, and minor
  • Loading branch information
hrydgard committed Jun 8, 2013
2 parents 94cce21 + 4de2777 commit 30536fa
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 76 deletions.
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

0 comments on commit 30536fa

Please sign in to comment.