u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 initAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { WARN_LOG(HLE, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): bad mpeg handle", mpeg, auAddr, frameWidth, bufferAddr, initAddr); return 0; } if (!Memory::IsValidAddress(auAddr) || !Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(initAddr)) { ERROR_LOG(HLE, "sceMpegAvcDecode: bad addresses"); return 0; } if (frameWidth == 0) { // wtf, go sudoku passes in 0xccccccccc if (!ctx->defaultFrameWidth) { frameWidth = ctx->avc.avcDetailFrameWidth; } else { frameWidth = ctx->defaultFrameWidth; } } SceMpegAu avcAu; avcAu.read(auAddr); SceMpegRingBuffer ringbuffer = {0}; if (Memory::IsValidAddress(ctx->mpegRingbufferAddr)) { Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer); } else { ERROR_LOG(HLE, "Bogus mpegringbufferaddr"); return -1; } 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); } u32 buffer = Memory::Read_U32(bufferAddr); u32 init = Memory::Read_U32(initAddr); DEBUG_LOG(HLE, "*buffer = %08x, *init = %08x", buffer, init); if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) { int bufferSize = ctx->mediaengine->writeVideoImage(Memory::GetPointer(buffer), frameWidth, ctx->videoPixelMode); gpu->InvalidateCache(buffer, bufferSize, GPU_INVALIDATE_SAFE); ctx->avc.avcFrameStatus = 1; ctx->videoFrameCount++; } else { ctx->avc.avcFrameStatus = 0; } ringbuffer.packetsFree = ctx->mediaengine->getRemainSize() / 2048; avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp; // Flush structs back to memory avcAu.write(auAddr); Memory::WriteStruct(ctx->mpegRingbufferAddr, &ringbuffer); // return 0 in first call, and then return 1, as PSPSDK mentioned Memory::Write_U32(ctx->avc.avcDecodeResult ? 1 : 0, initAddr); ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; DEBUG_LOG(HLE, "sceMpegAvcDecode(%08x, %08x, %i, %08x, %08x)", mpeg, auAddr, frameWidth, bufferAddr, initAddr); if (ctx->videoFrameCount <= 1) return hleDelayResult(0, "mpeg decode", avcFirstDelayMs); else return hleDelayResult(0, "mpeg decode", avcDecodeDelayMs); //hleEatMicro(3300); //return hleDelayResult(0, "mpeg decode", 200); }
int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { WARN_LOG(HLE, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr); return 0; } if (!Memory::IsValidAddress(auAddr) || !Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(initAddr)) { ERROR_LOG(HLE, "sceMpegAvcDecodeYCbCr: bad addresses"); return 0; } SceMpegAu avcAu; avcAu.read(auAddr); SceMpegRingBuffer ringbuffer = {0}; if (Memory::IsValidAddress(ctx->mpegRingbufferAddr)) { Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer); } else { ERROR_LOG(HLE, "Bogus mpegringbufferaddr"); return -1; } if (ringbuffer.packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) { WARN_LOG(HLE, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty", mpeg, auAddr, bufferAddr, initAddr); return hleDelayResult(MPEG_AVC_DECODE_ERROR_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } u32 buffer = Memory::Read_U32(bufferAddr); u32 init = Memory::Read_U32(initAddr); DEBUG_LOG(HLE, "*buffer = %08x, *init = %08x", buffer, init); if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) { // Don't draw here, we'll draw in the Csc func. ctx->avc.avcFrameStatus = 1; ctx->videoFrameCount++; }else { ctx->avc.avcFrameStatus = 0; } ringbuffer.packetsFree = ctx->mediaengine->getRemainSize() / 2048; avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp; // Flush structs back to memory avcAu.write(auAddr); Memory::WriteStruct(ctx->mpegRingbufferAddr, &ringbuffer); // return 0 in first call, and then return 1, as PSPSDK mentioned Memory::Write_U32(ctx->avc.avcDecodeResult ? 1 : 0, initAddr); ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; DEBUG_LOG(HLE, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr); if (ctx->videoFrameCount <= 1) return hleDelayResult(0, "mpeg decode", avcFirstDelayMs); else return hleDelayResult(0, "mpeg decode", avcDecodeDelayMs); //hleEatMicro(3300); //return hleDelayResult(0, "mpeg decode", 200); }
u32 sceUtilityUnloadAvModule(u32 module) { INFO_LOG(SCEUTILITY,"0=sceUtilityUnloadAvModule(%i)", module); return hleDelayResult(0, "utility av module unloaded", 800); }
u32 sceUtilityUnloadAvModule(u32 module) { DEBUG_LOG(HLE,"sceUtilityUnloadAvModule(%i)", module); return hleDelayResult(0, "utility av module unloaded", 800); }
// Some games (GTA) never call this during gameplay, so bad place to put a framerate counter. static u32 sceDisplaySetFramebuf(u32 topaddr, int linesize, int pixelformat, int sync) { FrameBufferState fbstate = {0}; fbstate.topaddr = topaddr; fbstate.fmt = (GEBufferFormat)pixelformat; fbstate.stride = linesize; if (sync != PSP_DISPLAY_SETBUF_IMMEDIATE && sync != PSP_DISPLAY_SETBUF_NEXTFRAME) { return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "invalid sync mode"); } if (topaddr != 0 && !Memory::IsRAMAddress(topaddr) && !Memory::IsVRAMAddress(topaddr)) { return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address"); } if ((topaddr & 0xF) != 0) { return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_POINTER, "misaligned address"); } if ((linesize & 0x3F) != 0 || (linesize == 0 && topaddr != 0)) { return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid stride"); } if (pixelformat < 0 || pixelformat > GE_FORMAT_8888) { return hleLogError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_FORMAT, "invalid format"); } if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) { if (fbstate.fmt != latchedFramebuf.fmt || fbstate.stride != latchedFramebuf.stride) { return hleReportError(SCEDISPLAY, SCE_KERNEL_ERROR_INVALID_MODE, "must change latched framebuf first"); } } hleEatCycles(290); s64 delayCycles = 0; // Don't count transitions between display off and display on. if (topaddr != 0 && topaddr != framebuf.topaddr && framebuf.topaddr != 0 && g_Config.iForceMaxEmulatedFPS > 0) { // Sometimes we get a small number, there's probably no need to delay the thread for this. // sceDisplaySetFramebuf() isn't supposed to delay threads at all. This is a hack. const int FLIP_DELAY_CYCLES_MIN = 10; // Some games (like Final Fantasy 4) only call this too much in spurts. // The goal is to fix games where this would result in a consistent overhead. const int FLIP_DELAY_MIN_FLIPS = 30; u64 now = CoreTiming::GetTicks(); // 1001 to account for NTSC timing (59.94 fps.) u64 expected = msToCycles(1001) / g_Config.iForceMaxEmulatedFPS; u64 actual = now - lastFlipCycles; if (actual < expected - FLIP_DELAY_CYCLES_MIN) { if (lastFlipsTooFrequent >= FLIP_DELAY_MIN_FLIPS) { delayCycles = expected - actual; } else { ++lastFlipsTooFrequent; } } else { --lastFlipsTooFrequent; } lastFlipCycles = CoreTiming::GetTicks(); } if (sync == PSP_DISPLAY_SETBUF_IMMEDIATE) { // Write immediately to the current framebuffer parameters framebuf = fbstate; gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.stride, framebuf.fmt); } else { // Delay the write until vblank latchedFramebuf = fbstate; framebufIsLatched = true; // If we update the format or stride, this affects the current framebuf immediately. framebuf.fmt = latchedFramebuf.fmt; framebuf.stride = latchedFramebuf.stride; } if (delayCycles > 0) { // Okay, the game is going at too high a frame rate. God of War and Fat Princess both do this. // Simply eating the cycles works and is fast, but breaks other games (like Jeanne d'Arc.) // So, instead, we delay this HLE thread only (a small deviation from correct behavior.) return hleDelayResult(hleLogSuccessI(SCEDISPLAY, 0, "delaying frame thread"), "set framebuf", cyclesToUs(delayCycles)); } else { if (topaddr == 0) { return hleLogSuccessI(SCEDISPLAY, 0, "disabling display"); } else { return hleLogSuccessI(SCEDISPLAY, 0); } } }
int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr) { if (!g_Config.bUseMediaEngine){ WARN_LOG(HLE, "Media Engine disabled"); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { WARN_LOG(HLE, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr); return 0; } if (!Memory::IsValidAddress(auAddr) || !Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(initAddr)) { ERROR_LOG(HLE, "sceMpegAvcDecodeYCbCr: bad addresses"); return 0; } SceMpegAu avcAu; avcAu.read(auAddr); SceMpegRingBuffer ringbuffer; Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer); if (ringbuffer.packetsRead == 0) { // empty! return hleDelayResult(MPEG_AVC_DECODE_ERROR_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } u32 buffer = Memory::Read_U32(bufferAddr); u32 init = Memory::Read_U32(initAddr); DEBUG_LOG(HLE, "*buffer = %08x, *init = %08x", buffer, init); int packetsInRingBuffer = ringbuffer.packets - ringbuffer.packetsFree; int processedPackets = ringbuffer.packetsRead - packetsInRingBuffer; int processedSize = processedPackets * ringbuffer.packetSize; int packetsConsumed = 3; if (ctx->mpegStreamSize > 0 && ctx->mpegLastTimestamp > 0) { // Try a better approximation of the packets consumed based on the timestamp int processedSizeBasedOnTimestamp = (int) ((((float) avcAu.pts) / ctx->mpegLastTimestamp) * ctx->mpegStreamSize); if (processedSizeBasedOnTimestamp < processedSize) { packetsConsumed = 0; } else { packetsConsumed = (processedSizeBasedOnTimestamp - processedSize) / ringbuffer.packetSize; if (packetsConsumed > 10) { packetsConsumed = 10; } } DEBUG_LOG(HLE, "sceMpegAvcDecodeYCbCr consumed %d %d/%d %d", processedSizeBasedOnTimestamp, processedSize, ctx->mpegStreamSize, packetsConsumed); } if (ctx->mediaengine->stepVideo()) { // TODO: Write it somewhere or buffer it or something? packetsConsumed += ctx->mediaengine->readLength() / ringbuffer.packetSize; // Consuming all the remaining packets? if (ringbuffer.packetsFree + packetsConsumed >= ringbuffer.packets) { // Having not yet reached the last timestamp? if (ctx->mpegLastTimestamp > 0 && avcAu.pts < ctx->mpegLastTimestamp) { // Do not yet consume all the remaining packets, leave 2 packets packetsConsumed = ringbuffer.packets - ringbuffer.packetsFree - 2; } } ctx->mediaengine->setReadLength(ctx->mediaengine->readLength() - packetsConsumed * ringbuffer.packetSize); } else { // Consume all remaining packets packetsConsumed = ringbuffer.packets - ringbuffer.packetsFree; } ctx->avc.avcFrameStatus = 1; ctx->videoFrameCount++; // Update the ringbuffer with the consumed packets if (ringbuffer.packetsFree < ringbuffer.packets && packetsConsumed > 0) { ringbuffer.packetsFree = std::min(ringbuffer.packets, ringbuffer.packetsFree + packetsConsumed); DEBUG_LOG(HLE, "sceMpegAvcDecodeYCbCr consumed %d packets, remaining %d packets", packetsConsumed, ringbuffer.packets - ringbuffer.packetsFree); } ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; // Flush structs back to memory avcAu.write(auAddr); Memory::WriteStruct(ctx->mpegRingbufferAddr, &ringbuffer); Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr); // 1 = showing, 0 = not showing DEBUG_LOG(HLE, "UNIMPL sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr); if (ctx->videoFrameCount <= 1) return hleDelayResult(0, "mpeg decode", avcFirstDelayMs); else return hleDelayResult(0, "mpeg decode", avcDecodeDelayMs); }
u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 initAddr) { if (!g_Config.bUseMediaEngine){ WARN_LOG(HLE, "Media Engine disabled"); return -1; } MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { WARN_LOG(HLE, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): bad mpeg handle", mpeg, auAddr, frameWidth, bufferAddr, initAddr); return 0; } if (!Memory::IsValidAddress(auAddr) || !Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(initAddr)) { ERROR_LOG(HLE, "sceMpegAvcDecode: bad addresses"); return 0; } if (frameWidth == 0) { // wtf, go sudoku passes in 0xccccccccc if (!ctx->defaultFrameWidth) { frameWidth = ctx->avc.avcDetailFrameWidth; } else { frameWidth = ctx->defaultFrameWidth; } } SceMpegAu avcAu; avcAu.read(auAddr); SceMpegRingBuffer ringbuffer; Memory::ReadStruct(ctx->mpegRingbufferAddr, &ringbuffer); if (ringbuffer.packetsRead == 0) { // empty! return hleDelayResult(MPEG_AVC_DECODE_ERROR_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } u32 buffer = Memory::Read_U32(bufferAddr); u32 init = Memory::Read_U32(initAddr); DEBUG_LOG(HLE, "*buffer = %08x, *init = %08x", buffer, init); const int width = std::min((int)frameWidth, 480); const int height = ctx->avc.avcDetailFrameHeight; int packetsInRingBuffer = ringbuffer.packets - ringbuffer.packetsFree; int processedPackets = ringbuffer.packetsRead - packetsInRingBuffer; int processedSize = processedPackets * ringbuffer.packetSize; int packetsConsumed = 3; if (ctx->mpegStreamSize > 0 && ctx->mpegLastTimestamp > 0) { // Try a better approximation of the packets consumed based on the timestamp int processedSizeBasedOnTimestamp = (int) ((((float) avcAu.pts) / ctx->mpegLastTimestamp) * ctx->mpegStreamSize); if (processedSizeBasedOnTimestamp < processedSize) { packetsConsumed = 0; } else { packetsConsumed = (processedSizeBasedOnTimestamp - processedSize) / ringbuffer.packetSize; if (packetsConsumed > 10) { packetsConsumed = 10; } } DEBUG_LOG(HLE, "sceMpegAvcDecode consumed %d %d/%d %d", processedSizeBasedOnTimestamp, processedSize, ctx->mpegStreamSize, packetsConsumed); } if (ctx->mediaengine->stepVideo()) { ctx->mediaengine->writeVideoImage(buffer, frameWidth, ctx->videoPixelMode); packetsConsumed += ctx->mediaengine->readLength() / ringbuffer.packetSize; // The MediaEngine is already consuming all the remaining // packets when approaching the end of the video. The PSP // is only consuming the last packet when reaching the end, // not before. // Consuming all the remaining packets? if (ringbuffer.packetsFree + packetsConsumed >= ringbuffer.packets) { // Having not yet reached the last timestamp? if (ctx->mpegLastTimestamp > 0 && avcAu.pts < ctx->mpegLastTimestamp) { // Do not yet consume all the remaining packets, leave 2 packets packetsConsumed = ringbuffer.packets - ringbuffer.packetsFree - 2; } } ctx->mediaengine->setReadLength(ctx->mediaengine->readLength() - packetsConsumed * ringbuffer.packetSize); } else { // Consume all remaining packets packetsConsumed = ringbuffer.packets - ringbuffer.packetsFree; } ctx->avc.avcFrameStatus = 1; ctx->videoFrameCount++; // Update the ringbuffer with the consumed packets if (ringbuffer.packetsFree < ringbuffer.packets && packetsConsumed > 0) { ringbuffer.packetsFree = std::min(ringbuffer.packets, ringbuffer.packetsFree + packetsConsumed); DEBUG_LOG(HLE, "sceMpegAvcDecode consumed %d packets, remaining %d packets", packetsConsumed, ringbuffer.packets - ringbuffer.packetsFree); } ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS; // Flush structs back to memory avcAu.write(auAddr); Memory::WriteStruct(ctx->mpegRingbufferAddr, &ringbuffer); Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr); // 1 = showing, 0 = not showing DEBUG_LOG(HLE, "sceMpegAvcDecode(%08x, %08x, %i, %08x, %08x)", mpeg, auAddr, frameWidth, bufferAddr, initAddr); if (ctx->videoFrameCount <= 1) return hleDelayResult(0, "mpeg decode", avcFirstDelayMs); else return hleDelayResult(0, "mpeg decode", avcDecodeDelayMs); }
int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { WARN_LOG(HLE, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr); return -1; } SceMpegRingBuffer mpegRingbuffer; Memory::ReadStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer); SceMpegAu sceAu; sceAu.read(auAddr); 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); // TODO: Does this really reschedule? return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs); } auto streamInfo = ctx->streamMap.find(streamId); if (streamInfo == ctx->streamMap.end()) { ERROR_LOG(HLE, "sceMpegGetAvcAu - bad stream id %i", streamId); return -1; } if (streamInfo->second.needsReset) { sceAu.pts = 0; streamInfo->second.needsReset = false; } // Wait for audio if too much ahead if (ctx->atracRegistered && (sceAu.pts > sceAu.pts + getMaxAheadTimestamp(mpegRingbuffer))) { ERROR_LOG(HLE, "sceMpegGetAvcAu - video too much ahead"); // TODO: Does this really reschedule? return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs); } int result = 0; // read the au struct from ram // TODO: For now, always checking, since readVideoAu() is stubbed. if (!ctx->mediaengine->readVideoAu(&sceAu) || true) { // Only return this after the video already ended. if (ctx->endOfVideoReached) { if (mpegRingbuffer.packetsFree < mpegRingbuffer.packets) { mpegRingbuffer.packetsFree = mpegRingbuffer.packets; Memory::WriteStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer); } result = PSP_ERROR_MPEG_NO_DATA; } if (ctx->mpegLastTimestamp <= 0 || sceAu.pts >= ctx->mpegLastTimestamp) { NOTICE_LOG(HLE, "End of video reached"); ctx->endOfVideoReached = true; } else { ctx->endOfAudioReached = false; } } // The avcau struct may have been modified by mediaengine, write it back. sceAu.write(auAddr); if (Memory::IsValidAddress(attrAddr)) { Memory::Write_U32(1, attrAddr); } DEBUG_LOG(HLE, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); // TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something. // There's definitely more to it, but ultimately it seems games should expect it to delay randomly. return hleDelayResult(result, "mpeg get avc", 100); }
int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr) { MpegContext *ctx = getMpegCtx(mpeg); if (!ctx) { WARN_LOG(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr); return -1; } SceMpegRingBuffer mpegRingbuffer; Memory::ReadStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer); SceMpegAu sceAu; sceAu.read(auAddr); if (mpegRingbuffer.packetsRead == 0 || mpegRingbuffer.packetsFree == mpegRingbuffer.packets) { DEBUG_LOG(ME, "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); } auto streamInfo = ctx->streamMap.find(streamId); if (streamInfo == ctx->streamMap.end()) { ERROR_LOG(ME, "sceMpegGetAvcAu - bad stream id %i", streamId); return -1; } if (streamInfo->second.needsReset) { sceAu.pts = 0; streamInfo->second.needsReset = false; } /*// Wait for audio if too much ahead if (ctx->atracRegistered && (ctx->mediaengine->getVideoTimeStamp() > ctx->mediaengine->getAudioTimeStamp() + getMaxAheadTimestamp(mpegRingbuffer))) { ERROR_LOG(ME, "sceMpegGetAvcAu - video too much ahead"); // TODO: Does this really reschedule? return hleDelayResult(PSP_ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs); }*/ int result = 0; sceAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp; sceAu.dts = sceAu.pts - videoTimestampStep; if (ctx->mediaengine->IsVideoEnd()) { INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)sceAu.pts, (int)ctx->mediaengine->getLastTimeStamp()); mpegRingbuffer.packetsFree = mpegRingbuffer.packets; Memory::WriteStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer); result = PSP_ERROR_MPEG_NO_DATA; } // The avcau struct may have been modified by mediaengine, write it back. sceAu.write(auAddr); if (Memory::IsValidAddress(attrAddr)) { Memory::Write_U32(1, attrAddr); } DEBUG_LOG(ME, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr); // TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something. // There's definitely more to it, but ultimately it seems games should expect it to delay randomly. return hleDelayResult(result, "mpeg get avc", 100); }