Write the ringbuffer struct based on mpeg version.

This way it can easily match tests.
This commit is contained in:
Unknown W. Brackets 2014-03-01 17:19:55 -08:00
parent cda1bc2772
commit fc1ab072b3
3 changed files with 74 additions and 72 deletions

View file

@ -225,8 +225,10 @@ static void InitRingbuffer(SceMpegRingBuffer *buf, int packets, int data, int si
buf->dataUpperBound = data + packets * 2048; buf->dataUpperBound = data + packets * 2048;
buf->semaID = 0; buf->semaID = 0;
buf->mpeg = 0; buf->mpeg = 0;
// TODO: This appears in tests, but may not be in all versions. // This isn't in ver 0104, but it is in 010A.
//buf->gp = __KernelGetModuleGP(__KernelGetCurThreadModuleId()); // TODO: Which versions in between those does it exist in?
if (mpegLibVersion >= 0x010A)
buf->gp = __KernelGetModuleGP(__KernelGetCurThreadModuleId());
} }
u32 convertTimestampToDate(u32 ts) { u32 convertTimestampToDate(u32 ts) {
@ -281,11 +283,13 @@ void AnalyzeMpeg(u8 *buffer, MpegContext *ctx) {
if (ctx->mediaengine && (ctx->mpegStreamSize > 0) && !ctx->isAnalyzed) { if (ctx->mediaengine && (ctx->mpegStreamSize > 0) && !ctx->isAnalyzed) {
// init mediaEngine // init mediaEngine
SceMpegRingBuffer ringbuffer = {0}; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
if(ctx->mpegRingbufferAddr != 0){ if (ringbuffer.IsValid()) {
Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer); ctx->mediaengine->loadStream(buffer, ctx->mpegOffset, ringbuffer->packets * ringbuffer->packetSize);
}; } else {
ctx->mediaengine->loadStream(buffer, ctx->mpegOffset, ringbuffer.packets * ringbuffer.packetSize); // TODO: Does this make any sense?
ctx->mediaengine->loadStream(buffer, ctx->mpegOffset, 0);
}
ctx->mediaengine->setVideoDim(); ctx->mediaengine->setVideoDim();
} }
@ -430,16 +434,14 @@ u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 f
return ERROR_MPEG_NO_MEMORY; return ERROR_MPEG_NO_MEMORY;
} }
SceMpegRingBuffer ringbuffer; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringbufferAddr);
if(ringbufferAddr != 0){ if (ringbuffer.IsValid()) {
Memory::ReadStruct(ringbufferAddr, &ringbuffer); if (ringbuffer->packetSize == 0) {
if (ringbuffer.packetSize == 0) { ringbuffer->packetsFree = 0;
ringbuffer.packetsFree = 0;
} else { } else {
ringbuffer.packetsFree = (ringbuffer.dataUpperBound - ringbuffer.data) / ringbuffer.packetSize; ringbuffer->packetsFree = (ringbuffer->dataUpperBound - ringbuffer->data) / ringbuffer->packetSize;
} }
ringbuffer.mpeg = mpegAddr; ringbuffer->mpeg = mpegAddr;
Memory::WriteStruct(ringbufferAddr, &ringbuffer);
} }
// Generate, and write mpeg handle into mpeg data, for some reason // Generate, and write mpeg handle into mpeg data, for some reason
@ -450,9 +452,9 @@ u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 f
Memory::Memcpy(mpegHandle, "LIBMPEG\0", 8); Memory::Memcpy(mpegHandle, "LIBMPEG\0", 8);
Memory::Memcpy(mpegHandle + 8, "001\0", 4); Memory::Memcpy(mpegHandle + 8, "001\0", 4);
Memory::Write_U32(-1, mpegHandle + 12); Memory::Write_U32(-1, mpegHandle + 12);
if (ringbufferAddr) { if (ringbuffer.IsValid()) {
Memory::Write_U32(ringbufferAddr, mpegHandle + 16); Memory::Write_U32(ringbufferAddr, mpegHandle + 16);
Memory::Write_U32(ringbuffer.dataUpperBound, mpegHandle + 20); Memory::Write_U32(ringbuffer->dataUpperBound, mpegHandle + 20);
} }
MpegContext *ctx = new MpegContext; MpegContext *ctx = new MpegContext;
mpegMap[mpegHandle] = ctx; mpegMap[mpegHandle] = ctx;
@ -689,16 +691,13 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
SceMpegAu avcAu; SceMpegAu avcAu;
avcAu.read(auAddr); avcAu.read(auAddr);
SceMpegRingBuffer ringbuffer = {0}; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
if (!ringbuffer.IsValid()) {
if (Memory::IsValidAddress(ctx->mpegRingbufferAddr)) {
Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer);
} else {
ERROR_LOG(ME, "Bogus mpegringbufferaddr"); ERROR_LOG(ME, "Bogus mpegringbufferaddr");
return -1; return -1;
} }
if (ringbuffer.packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) { if (ringbuffer->packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) {
WARN_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr); WARN_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr);
return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs); return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs);
} }
@ -715,13 +714,12 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
} else { } else {
ctx->avc.avcFrameStatus = 0; ctx->avc.avcFrameStatus = 0;
} }
ringbuffer.packetsFree = ctx->mediaengine->getRemainSize() / 2048; ringbuffer->packetsFree = ctx->mediaengine->getRemainSize() / 2048;
avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp; avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
// Flush structs back to memory // Flush structs back to memory
avcAu.write(auAddr); avcAu.write(auAddr);
Memory::WriteStruct(ctx->mpegRingbufferAddr, &ringbuffer);
// Save the current frame's status to initAddr // Save the current frame's status to initAddr
Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr); Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr);
@ -849,15 +847,13 @@ int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr)
SceMpegAu avcAu; SceMpegAu avcAu;
avcAu.read(auAddr); avcAu.read(auAddr);
SceMpegRingBuffer ringbuffer = {0}; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
if (Memory::IsValidAddress(ctx->mpegRingbufferAddr)) { if (!ringbuffer.IsValid()) {
Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer);
} else {
ERROR_LOG(ME, "Bogus mpegringbufferaddr"); ERROR_LOG(ME, "Bogus mpegringbufferaddr");
return -1; return -1;
} }
if (ringbuffer.packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) { if (ringbuffer->packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) {
WARN_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty", mpeg, auAddr, bufferAddr, initAddr); WARN_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty", mpeg, auAddr, bufferAddr, initAddr);
return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs); return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs);
} }
@ -873,13 +869,12 @@ int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr)
}else { }else {
ctx->avc.avcFrameStatus = 0; ctx->avc.avcFrameStatus = 0;
} }
ringbuffer.packetsFree = ctx->mediaengine->getRemainSize() / 2048; ringbuffer->packetsFree = ctx->mediaengine->getRemainSize() / 2048;
avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp; avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
// Flush structs back to memory // Flush structs back to memory
avcAu.write(auAddr); avcAu.write(auAddr);
Memory::WriteStruct(ctx->mpegRingbufferAddr, &ringbuffer);
// Save the current frame's status to initAddr // Save the current frame's status to initAddr
Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr); Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr);
@ -990,33 +985,31 @@ int sceMpegRingbufferAvailableSize(u32 ringbufferAddr)
} }
void PostPutAction::run(MipsCall &call) { void PostPutAction::run(MipsCall &call) {
SceMpegRingBuffer ringbuffer; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringAddr_);
Memory::ReadStruct(ringAddr_, &ringbuffer);
MpegContext *ctx = getMpegCtx(ringbuffer.mpeg); MpegContext *ctx = getMpegCtx(ringbuffer->mpeg);
int packetsAdded = currentMIPS->r[2]; int packetsAdded = currentMIPS->r[2];
if (ringbuffer.packetsRead == 0 && ctx->mediaengine && packetsAdded > 0) { if (ringbuffer->packetsRead == 0 && ctx->mediaengine && packetsAdded > 0) {
// init mediaEngine // init mediaEngine
AnalyzeMpeg(ctx->mpegheader, ctx); AnalyzeMpeg(ctx->mpegheader, ctx);
ctx->mediaengine->loadStream(ctx->mpegheader, 2048, ringbuffer.packets * ringbuffer.packetSize); ctx->mediaengine->loadStream(ctx->mpegheader, 2048, ringbuffer->packets * ringbuffer->packetSize);
} }
if (packetsAdded > 0) { if (packetsAdded > 0) {
if (packetsAdded > ringbuffer.packetsFree) { if (packetsAdded > ringbuffer->packetsFree) {
WARN_LOG(ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAdded, ringbuffer.packetsFree); WARN_LOG(ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAdded, ringbuffer->packetsFree);
packetsAdded = ringbuffer.packetsFree; packetsAdded = ringbuffer->packetsFree;
} }
int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(Memory::GetPointer(ringbuffer.data), packetsAdded * 2048) / 2048; int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(Memory::GetPointer(ringbuffer->data), packetsAdded * 2048) / 2048;
if (actuallyAdded != packetsAdded) { if (actuallyAdded != packetsAdded) {
WARN_LOG_REPORT(ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames."); WARN_LOG_REPORT(ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames.");
} }
ringbuffer.packetsRead += packetsAdded; ringbuffer->packetsRead += packetsAdded;
ringbuffer.packetsWritten += packetsAdded; ringbuffer->packetsWritten += packetsAdded;
ringbuffer.packetsFree -= packetsAdded; ringbuffer->packetsFree -= packetsAdded;
} }
DEBUG_LOG(ME, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAdded, ringbuffer.packetsRead, ringbuffer.packets); DEBUG_LOG(ME, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAdded, ringbuffer->packetsRead, ringbuffer->packets);
Memory::WriteStruct(ringAddr_, &ringbuffer);
call.setReturnValue(packetsAdded); call.setReturnValue(packetsAdded);
} }
@ -1031,27 +1024,31 @@ u32 sceMpegRingbufferPut(u32 ringbufferAddr, u32 numPackets, u32 available)
return 0; return 0;
} }
SceMpegRingBuffer ringbuffer; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringbufferAddr);
Memory::ReadStruct(ringbufferAddr, &ringbuffer); if (!ringbuffer.IsValid()) {
// Would have crashed before, TODO test behavior.
ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut(%08x, %i, %i): invalid ringbuffer address", ringbufferAddr, numPackets, available);
return -1;
}
MpegContext *ctx = getMpegCtx(ringbuffer.mpeg); MpegContext *ctx = getMpegCtx(ringbuffer->mpeg);
if (!ctx) { if (!ctx) {
WARN_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer.mpeg); WARN_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer->mpeg);
return -1; return -1;
} }
// Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc // Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc
if (ringbuffer.callback_addr != 0) { if (ringbuffer->callback_addr != 0) {
PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut); PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut);
action->setRingAddr(ringbufferAddr); action->setRingAddr(ringbufferAddr);
// TODO: Should call this multiple times until we get numPackets. // 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. // Normally this would be if it did not read enough, but also if available > packets.
// Should ultimately return the TOTAL number of returned packets. // Should ultimately return the TOTAL number of returned packets.
u32 packetsThisRound = std::min(numPackets, (u32)ringbuffer.packets); u32 packetsThisRound = std::min(numPackets, (u32)ringbuffer->packets);
u32 args[3] = {(u32)ringbuffer.data, packetsThisRound, (u32)ringbuffer.callback_args}; u32 args[3] = {(u32)ringbuffer->data, packetsThisRound, (u32)ringbuffer->callback_args};
__KernelDirectMipsCall(ringbuffer.callback_addr, action, args, 3, false); __KernelDirectMipsCall(ringbuffer->callback_addr, action, args, 3, false);
} else { } else {
ERROR_LOG(ME, "sceMpegRingbufferPut: callback_addr zero"); ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut: callback_addr zero");
} }
return 0; return 0;
} }
@ -1064,13 +1061,17 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
return -1; return -1;
} }
SceMpegRingBuffer mpegRingbuffer; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
Memory::ReadStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer); if (!ringbuffer.IsValid()) {
// Would have crashed before, TODO test behavior.
ERROR_LOG_REPORT(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr);
return -1;
}
SceMpegAu avcAu; SceMpegAu avcAu;
avcAu.read(auAddr); avcAu.read(auAddr);
if (mpegRingbuffer.packetsRead == 0 || mpegRingbuffer.packetsFree == mpegRingbuffer.packets) { if (ringbuffer->packetsRead == 0 || ringbuffer->packetsFree == ringbuffer->packets) {
DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr); DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
avcAu.pts = -1; avcAu.pts = -1;
avcAu.dts = -1; avcAu.dts = -1;
@ -1107,8 +1108,7 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
if (ctx->mediaengine->IsVideoEnd()) { if (ctx->mediaengine->IsVideoEnd()) {
INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)avcAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)avcAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
mpegRingbuffer.packetsFree = mpegRingbuffer.packets; ringbuffer->packetsFree = ringbuffer->packets;
Memory::WriteStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer);
result = ERROR_MPEG_NO_DATA; result = ERROR_MPEG_NO_DATA;
} }
@ -1156,8 +1156,12 @@ int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
return -1; return -1;
} }
SceMpegRingBuffer mpegRingbuffer; auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
Memory::ReadStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer); if (!ringbuffer.IsValid()) {
// Would have crashed before, TODO test behavior.
WARN_LOG(ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr);
return -1;
}
SceMpegAu atracAu; SceMpegAu atracAu;
atracAu.read(auAddr); atracAu.read(auAddr);
@ -1174,7 +1178,7 @@ int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
} }
// The audio can end earlier than the video does. // The audio can end earlier than the video does.
if (mpegRingbuffer.packetsFree == mpegRingbuffer.packets) { if (ringbuffer->packetsFree == ringbuffer->packets) {
DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr); DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
// TODO: Does this really delay? // TODO: Does this really delay?
return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get atrac", mpegDecodeErrorDelayMs); return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get atrac", mpegDecodeErrorDelayMs);
@ -1185,8 +1189,7 @@ int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
if (ctx->mediaengine->IsVideoEnd()) { if (ctx->mediaengine->IsVideoEnd()) {
INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
mpegRingbuffer.packetsFree = mpegRingbuffer.packets; ringbuffer->packetsFree = ringbuffer->packets;
Memory::WriteStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer);
result = ERROR_MPEG_NO_DATA; result = ERROR_MPEG_NO_DATA;
} }
@ -1324,9 +1327,8 @@ u32 sceMpegFlushAllStream(u32 mpeg)
ctx->isAnalyzed = false; ctx->isAnalyzed = false;
if (Memory::IsValidAddress(ctx->mpegRingbufferAddr)) { auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr); if (ringbuffer.IsValid()) {
ringbuffer->packetsFree = ringbuffer->packets; ringbuffer->packetsFree = ringbuffer->packets;
ringbuffer->packetsRead = 0; ringbuffer->packetsRead = 0;
ringbuffer->packetsWritten = 0; ringbuffer->packetsWritten = 0;

View file

@ -76,8 +76,8 @@ struct SceMpegRingBuffer {
s32_le dataUpperBound; s32_le dataUpperBound;
s32_le semaID; // unused? s32_le semaID; // unused?
u32_le mpeg; // pointer to mpeg struct, fixed up in sceMpegCreate u32_le mpeg; // pointer to mpeg struct, fixed up in sceMpegCreate
// TODO: This appears in tests, but may not be in all versions. // Note: not available in all versions.
//u32_le gp; u32_le gp;
}; };
void __MpegInit(); void __MpegInit();

View file

@ -242,6 +242,8 @@ tests_good = [
"umd/callbacks/umd", "umd/callbacks/umd",
"umd/wait/wait", "umd/wait/wait",
"io/directory/directory", "io/directory/directory",
"video/mpeg/ringbuffer/construct",
"video/mpeg/ringbuffer/destruct",
"video/mpeg/ringbuffer/memsize", "video/mpeg/ringbuffer/memsize",
"video/mpeg/ringbuffer/packnum", "video/mpeg/ringbuffer/packnum",
] ]
@ -317,8 +319,6 @@ tests_next = [
"umd/raw_access/raw_access", "umd/raw_access/raw_access",
"video/mpeg/basic", "video/mpeg/basic",
"video/mpeg/ringbuffer/avail", "video/mpeg/ringbuffer/avail",
"video/mpeg/ringbuffer/construct",
"video/mpeg/ringbuffer/destruct",
"video/pmf/pmf", "video/pmf/pmf",
"video/pmf_simple/pmf_simple", "video/pmf_simple/pmf_simple",
"video/psmfplayer/basic", "video/psmfplayer/basic",