Exemple #1
0
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);
}
Exemple #2
0
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);
}
Exemple #4
0
u32 sceUtilityUnloadAvModule(u32 module)
{
	DEBUG_LOG(HLE,"sceUtilityUnloadAvModule(%i)", module);
	return hleDelayResult(0, "utility av module unloaded", 800);
}
Exemple #5
0
// 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);
		}
	}
}
Exemple #6
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);
}
Exemple #7
0
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);
}
Exemple #8
0
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);
}
Exemple #9
0
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);
}