Exemple #1
0
// Program signals that it has written data to the ringbuffer and gets a callback ?
u32 sceMpegRingbufferPut(u32 ringbufferAddr, u32 numPackets, u32 available)
{
	DEBUG_LOG(HLE, "sceMpegRingbufferPut(%08x, %i, %i)", ringbufferAddr, numPackets, available);
	numPackets = std::min(numPackets, available);
	if (numPackets <= 0)
		return 0;

	SceMpegRingBuffer ringbuffer;
	Memory::ReadStruct(ringbufferAddr, &ringbuffer);

	MpegContext *ctx = getMpegCtx(ringbuffer.mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer.mpeg);
		return 0;
	}

	// 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);
		action->setRingAddr(ringbufferAddr);
		// 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");
	}
	return 0;
}
Exemple #2
0
int sceMpegInitAu(u32 mpeg, u32 bufferAddr, u32 auPointer)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegInitAu(%08x, %i, %08x): bad mpeg handle", mpeg, bufferAddr, auPointer);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegInitAu(%08x, %i, %08x)", mpeg, bufferAddr, auPointer);

	SceMpegAu sceAu;
	sceAu.read(auPointer);

	if (bufferAddr >= 1 && bufferAddr <= (u32)NUM_ES_BUFFERS && ctx->esBuffers[bufferAddr - 1]) {
		// This esbuffer has been allocated for Avc.
		sceAu.esBuffer = bufferAddr;   // Can this be right??? not much of a buffer pointer..
		sceAu.esSize = MPEG_AVC_ES_SIZE;
		sceAu.dts = 0;
		sceAu.pts = 0;

		sceAu.write(auPointer);
	} else {
		// This esbuffer has been left as Atrac.
		sceAu.esBuffer = bufferAddr;
		sceAu.esSize = MPEG_ATRAC_ES_SIZE;
		sceAu.pts = 0;
		sceAu.dts = UNKNOWN_TIMESTAMP;

		sceAu.write(auPointer);
	}
	return 0;
}
Exemple #3
0
void PostPutAction::run(MipsCall &call) {
	SceMpegRingBuffer ringbuffer;
	Memory::ReadStruct(ringAddr_, &ringbuffer);

	MpegContext *ctx = getMpegCtx(ringbuffer.mpeg);

	int packetsAdded = currentMIPS->r[2];
	if (packetsAdded > 0) {
		if (packetsAdded > ringbuffer.packetsFree) {
			WARN_LOG(HLE, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAdded, ringbuffer.packetsFree);
			packetsAdded = ringbuffer.packetsFree;
		}
		int actuallyAdded = ctx->mediaengine->addStreamData(Memory::GetPointer(ringbuffer.data), packetsAdded * 2048) / 2048;
		if (actuallyAdded != packetsAdded) {
			WARN_LOG_REPORT(HLE, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames.");
		}
		ringbuffer.packetsRead += packetsAdded;
		ringbuffer.packetsWritten += packetsAdded;
		ringbuffer.packetsFree -= packetsAdded;
	}
	DEBUG_LOG(HLE, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAdded, ringbuffer.packetsRead, ringbuffer.packets);

	Memory::WriteStruct(ringAddr_, &ringbuffer);
	call.setReturnValue(packetsAdded);
}
Exemple #4
0
int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr)
{
	if (!Memory::IsValidAddress(detailAddr))
	{
		WARN_LOG(HLE, "sceMpegAvcDecodeDetail(%08x, %08x): invalid detailAddr", mpeg, detailAddr);
		return -1;
	}
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx)
	{
		WARN_LOG(HLE, "sceMpegAvcDecodeDetail(%08x, %08x): bad mpeg handle", mpeg, detailAddr);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegAvcDecodeDetail(%08x, %08x)", mpeg, detailAddr);

	Memory::Write_U32(ctx->avc.avcDecodeResult, detailAddr + 0);
	Memory::Write_U32(ctx->videoFrameCount, detailAddr + 4);
	Memory::Write_U32(ctx->avc.avcDetailFrameWidth, detailAddr + 8);
	Memory::Write_U32(ctx->avc.avcDetailFrameHeight, detailAddr + 12);
	Memory::Write_U32(0, detailAddr + 16);
	Memory::Write_U32(0, detailAddr + 20);
	Memory::Write_U32(0, detailAddr + 24);
	Memory::Write_U32(0, detailAddr + 28);
	Memory::Write_U32(ctx->avc.avcFrameStatus, detailAddr + 32);
	return 0;
}
Exemple #5
0
int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegQueryStreamOffset(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, offsetAddr);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegQueryStreamOffset(%08x, %08x, %08x)", mpeg, bufferAddr, offsetAddr);

	// Kinda destructive, no?
	AnalyzeMpeg(bufferAddr, ctx);

	if (ctx->mpegMagic != PSMF_MAGIC) {
		ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad PSMF magic");
		Memory::Write_U32(0, offsetAddr);
		return ERROR_MPEG_INVALID_VALUE;
	} else if (ctx->mpegVersion < 0) {
		ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad version");
		Memory::Write_U32(0, offsetAddr);
		return ERROR_MPEG_BAD_VERSION;
	} else if ((ctx->mpegOffset & 2047) != 0 || ctx->mpegOffset == 0) {
		ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad offset");
		Memory::Write_U32(0, offsetAddr);
		return ERROR_MPEG_INVALID_VALUE;
	}

	Memory::Write_U32(ctx->mpegOffset, offsetAddr);
	return 0;
}
Exemple #6
0
u32 sceMpegAtracDecode(u32 mpeg, u32 auAddr, u32 bufferAddr, int init)
{
	DEBUG_LOG(HLE, "UNIMPL sceMpegAtracDecode(%08x, %08x, %08x, %i)", mpeg, auAddr, bufferAddr, init);

	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		return 0;
	}

	if (!Memory::IsValidAddress(auAddr) || !Memory::IsValidAddress(bufferAddr)) {
		ERROR_LOG(HLE, "sceMpegAtracDecode: bad addresses");
		return 0;
	}

	SceMpegAu avcAu;
	avcAu.read(auAddr);

	Memory::Memset(bufferAddr, 0, MPEG_ATRAC_ES_OUTPUT_SIZE);
	ctx->mediaengine->getAudioSamples(Memory::GetPointer(bufferAddr));
	avcAu.pts = ctx->mediaengine->getAudioTimeStamp();

	avcAu.write(auAddr);


	return hleDelayResult(0, "mpeg atrac decode", atracDecodeDelayMs);
	//hleEatMicro(4000);
	//return hleDelayResult(0, "mpeg atrac decode", 200);
}
Exemple #7
0
u32 sceMpegAvcDecodeFlush(u32 mpeg)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	ERROR_LOG(HLE, "UNIMPL sceMpegAvcDecodeFlush(%08x)", mpeg);
	if ( ctx->videoFrameCount > 0 || ctx->audioFrameCount > 0) {
		//__MpegFinish();
	}
	return 0;
}
Exemple #8
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;
	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);

	if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) {
		// do nothing
		;
	}

	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
	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);
	//hleEatMicro(3300);
	//return hleDelayResult(0, "mpeg decode", 200);
}
Exemple #9
0
int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegGetAtracAu(%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);

	auto streamInfo = ctx->streamMap.find(streamId);
	if (streamInfo != ctx->streamMap.end() && streamInfo->second.needsReset)
	{
		sceAu.pts = 0;
		streamInfo->second.needsReset = false;
	}

	int result = 0;

	if (mpegRingbuffer.packetsFree == mpegRingbuffer.packets) {
		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);
	}

	//...
	// TODO: Just faking it.
	sceAu.pts += videoTimestampStep;
	sceAu.write(auAddr);

	// TODO: And also audio end?
	if (ctx->endOfVideoReached) {
		if (mpegRingbuffer.packetsFree < mpegRingbuffer.packets) {
			mpegRingbuffer.packetsFree = mpegRingbuffer.packets;
			Memory::WriteStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer);
		}
		result = PSP_ERROR_MPEG_NO_DATA;
	}

	if (Memory::IsValidAddress(attrAddr)) {
		Memory::Write_U32(0, attrAddr);
	}

	DEBUG_LOG(HLE, "%x=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr);
	// TODO: Not clear on exactly when this delays.
	return hleDelayResult(result, "mpeg get atrac", 100);
}
Exemple #10
0
int sceMpegRingbufferAvailableSize(u32 ringbufferAddr)
{
	if (!Memory::IsValidAddress(ringbufferAddr)) {
		ERROR_LOG(HLE, "sceMpegRingbufferAvailableSize(%08x) - bad address", ringbufferAddr);
		return -1;
	}

	SceMpegRingBuffer ringbuffer;
	Memory::ReadStruct(ringbufferAddr, &ringbuffer);
	DEBUG_LOG(HLE, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer.packetsFree, ringbufferAddr);
	MpegContext *ctx = getMpegCtx(ringbuffer.mpeg);
	int result = std::min(ringbuffer.packetsFree, ctx->mediaengine->getRemainSize() / 2048);
	return ringbuffer.packetsFree;
}
Exemple #11
0
int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegGetAtracAu(%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);

	auto streamInfo = ctx->streamMap.find(streamId);
	if (streamInfo != ctx->streamMap.end() && streamInfo->second.needsReset)
	{
		sceAu.pts = 0;
		streamInfo->second.needsReset = false;
	}

	// 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);
	}

	int result = 0;

	sceAu.pts = ctx->mediaengine->getAudioTimeStamp() + ctx->mpegFirstTimestamp;
	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;
		Memory::WriteStruct(ctx->mpegRingbufferAddr, &mpegRingbuffer);

		result = PSP_ERROR_MPEG_NO_DATA;
	}
	sceAu.write(auAddr);


	if (Memory::IsValidAddress(attrAddr)) {
		Memory::Write_U32(0, attrAddr);
	}

	DEBUG_LOG(HLE, "%x=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr);
	// TODO: Not clear on exactly when this delays.
	return hleDelayResult(result, "mpeg get atrac", 100);
}
Exemple #12
0
int sceMpegDelete(u32 mpeg)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegDelete(%08x): bad mpeg handle", mpeg);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegDelete(%08x)", mpeg);

	delete ctx;
	mpegMap.erase(Memory::Read_U32(mpeg));

	return 0;
}
Exemple #13
0
// YCbCr -> RGB color space conversion
u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth, u32 destAddr)
{
	DEBUG_LOG(HLE, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x)", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr);
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx)
		return -1;
	if ((!Memory::IsValidAddress(rangeAddr)) || (!Memory::IsValidAddress(destAddr)))
		return -1;
	int x  = Memory::Read_U32(rangeAddr);
	int y = Memory::Read_U32(rangeAddr + 4);
	int width    = Memory::Read_U32(rangeAddr + 8);
	int height   = Memory::Read_U32(rangeAddr + 12);
	int destSize = ctx->mediaengine->writeVideoImageWithRange(Memory::GetPointer(destAddr), frameWidth, ctx->videoPixelMode, 
		x, y, width, height);

	gpu->InvalidateCache(destAddr, destSize, GPU_INVALIDATE_SAFE);
	return 0;
}
Exemple #14
0
u32 sceMpegChangeGetAuMode(u32 mpeg, int streamUid, int mode)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegChangeGetAuMode(%08x, %i, %i): bad mpeg handle", mpeg, streamUid, mode);
		return -1;
	}

	// NOTE: Where is the info supposed to come from?
	StreamInfo info = {0};
	info.sid = streamUid;
	if (info.sid) {
		switch (info.type) {
		case MPEG_AVC_STREAM:
			if(mode == MPEG_AU_MODE_DECODE) {
				ctx->ignoreAvc = false;
			} else if (mode == MPEG_AU_MODE_SKIP) {
				ctx->ignoreAvc = true;
			}
			break;
		case MPEG_AUDIO_STREAM:
		case MPEG_ATRAC_STREAM:
			if(mode == MPEG_AU_MODE_DECODE) {
				ctx->ignoreAtrac = false;
			} else if (mode == MPEG_AU_MODE_SKIP) {
				ctx->ignoreAtrac = true;
			}
			break;
		case MPEG_PCM_STREAM:
			if(mode == MPEG_AU_MODE_DECODE) {
				ctx->ignorePcm = false;
			} else if (mode == MPEG_AU_MODE_SKIP) {
				ctx->ignorePcm = true;
			}
			break;
		default:
			ERROR_LOG(HLE, "UNIMPL sceMpegChangeGetAuMode(%08x, %i): unkown streamID", mpeg, streamUid);
			break;
		}
	} else {
			ERROR_LOG(HLE, "UNIMPL sceMpegChangeGetAuMode(%08x, %i): unkown streamID", mpeg, streamUid);
	}
	return 0;
}
Exemple #15
0
int sceMpegFreeAvcEsBuf(u32 mpeg, int esBuf)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegFreeAvcEsBuf(%08x, %i): bad mpeg handle", mpeg, esBuf);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegFreeAvcEsBuf(%08x, %i)", mpeg, esBuf);

	if (esBuf == 0) {
		return ERROR_MPEG_INVALID_VALUE;
	}
	if (esBuf >= 1 && esBuf <= NUM_ES_BUFFERS) {
		// TODO: Check if it's already been free'd?
		ctx->esBuffers[esBuf - 1] = false;
	}
	return 0;
}
Exemple #16
0
int sceMpegMallocAvcEsBuf(u32 mpeg)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegMallocAvcEsBuf(%08x): bad mpeg handle", mpeg);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegMallocAvcEsBuf(%08x)", mpeg);

	// Doesn't actually malloc, just keeps track of a couple of flags
	for (int i = 0; i < NUM_ES_BUFFERS; i++) {
		if (!ctx->esBuffers[i]) {
			ctx->esBuffers[i] = true;
			return i + 1;
		}
	}
	// No es buffer
	return 0;
}
Exemple #17
0
int sceMpegRingbufferAvailableSize(u32 ringbufferAddr)
{
	PSPPointer<SceMpegRingBuffer> ringbuffer;
	ringbuffer = ringbufferAddr;

	if (!ringbuffer.IsValid()) {
		ERROR_LOG(HLE, "sceMpegRingbufferAvailableSize(%08x) - bad address", ringbufferAddr);
		return -1;
	}

	MpegContext *ctx = getMpegCtx(ringbuffer->mpeg);
	if (!ctx) {
		ERROR_LOG(HLE, "sceMpegRingbufferAvailableSize(%08x) - bad mpeg", ringbufferAddr);
		return -1;
	}

	hleEatCycles(2020);
	DEBUG_LOG(HLE, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packetsFree, ringbufferAddr);
	return ringbuffer->packetsFree;
}
Exemple #18
0
int sceMpegRegistStream(u32 mpeg, u32 streamType, u32 streamNum)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx)
	{
		WARN_LOG(HLE, "sceMpegRegistStream(%08x, %i, %i): bad mpeg handle", mpeg, streamType, streamNum);
		return -1;
	}

	INFO_LOG(HLE, "sceMpegRegistStream(%08x, %i, %i)", mpeg, streamType, streamNum);

	switch (streamType) {
	case MPEG_AVC_STREAM:
		ctx->avcRegistered = true;
		ctx->mediaengine->setVideoStream(streamNum);
		break;
	case MPEG_AUDIO_STREAM:
	case MPEG_ATRAC_STREAM:
		ctx->atracRegistered = true;
		ctx->mediaengine->setAudioStream(streamNum);
		break;
	case MPEG_PCM_STREAM:
		ctx->pcmRegistered = true;
		break;
	case MPEG_DATA_STREAM:
		ctx->dataRegistered = true;
		break;
	default : 
		DEBUG_LOG(HLE, "sceMpegRegistStream(%i) : unknown stream type", streamType);
		break;
	}
	// ...
	u32 sid = streamIdGen++;
	StreamInfo info;
	info.type = streamType;
	info.num = streamNum;
	info.needsReset = true;
	ctx->streamMap[sid] = info;
	return sid;
}
Exemple #19
0
void PostPutAction::run(MipsCall &call) {
	SceMpegRingBuffer ringbuffer;
	Memory::ReadStruct(ringAddr_, &ringbuffer);

	MpegContext *ctx = getMpegCtx(ringbuffer.mpeg);

	int packetsAdded = currentMIPS->r[2];
	if (packetsAdded > 0) {
		if (ctx)
			ctx->mediaengine->feedPacketData(ringbuffer.data, packetsAdded * ringbuffer.packetSize);
		if (packetsAdded > ringbuffer.packetsFree) {
			WARN_LOG(HLE, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAdded, ringbuffer.packetsFree);
			packetsAdded = ringbuffer.packetsFree;
		}
		ringbuffer.packetsRead += packetsAdded;
		ringbuffer.packetsWritten += packetsAdded;
		ringbuffer.packetsFree -= packetsAdded;
	}

	Memory::WriteStruct(ringAddr_, &ringbuffer);
	call.setReturnValue(packetsAdded);
}
Exemple #20
0
u32 sceMpegFlushAllStream(u32 mpeg)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegFlushAllStream(%08x): bad mpeg handle", mpeg);
		return -1;
	}
	WARN_LOG(HLE, "UNIMPL sceMpegFlushAllStream(%08x)", mpeg);

	ctx->isAnalyzed = false;

	if (Memory::IsValidAddress(ctx->mpegRingbufferAddr))
	{
		auto ringbuffer = Memory::GetStruct<SceMpegRingBuffer>(ctx->mpegRingbufferAddr);

		ringbuffer->packetsFree = ringbuffer->packets;
		ringbuffer->packetsRead = 0;
		ringbuffer->packetsWritten = 0;
	}

	return 0;
}
Exemple #21
0
// Program signals that it has written data to the ringbuffer and gets a callback ?
u32 sceMpegRingbufferPut(u32 ringbufferAddr, u32 numPackets, u32 available)
{
	DEBUG_LOG(HLE, "sceMpegRingbufferPut(%08x, %i, %i)", ringbufferAddr, numPackets, available);
	numPackets = std::min(numPackets, available);
	if (numPackets <= 0) {
		ERROR_LOG(HLE, "sub-zero number of packets put");
		return 0;
	}

	SceMpegRingBuffer ringbuffer;
	Memory::ReadStruct(ringbufferAddr, &ringbuffer);

	MpegContext *ctx = getMpegCtx(ringbuffer.mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer.mpeg);
		return 0;
	}

	// Clamp to length of mpeg stream - this seems like a hack as we don't have access to the context here really
	int mpegStreamPackets = (ctx->mpegStreamSize + ringbuffer.packetSize - 1) / ringbuffer.packetSize;
	int remainingPackets = mpegStreamPackets - ringbuffer.packetsRead;
	if (remainingPackets < 0) {
		remainingPackets = 0;
	}
	numPackets = std::min(numPackets, (u32)remainingPackets);

	// 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);
		action->setRingAddr(ringbufferAddr);
		u32 args[3] = {(u32)ringbuffer.data, numPackets, (u32)ringbuffer.callback_args};
		__KernelDirectMipsCall(ringbuffer.callback_addr, action, args, 3, false);
	} else {
		ERROR_LOG(HLE, "sceMpegRingbufferPut: callback_addr zero");
	}
	return 0;
}
Exemple #22
0
u32 sceMpegUnRegistStream(u32 mpeg, int streamUid)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx)
	{
		WARN_LOG(HLE, "sceMpegUnRegistStream(%08x, %i): bad mpeg handle", mpeg, streamUid);
		return -1;
	}

	StreamInfo info = {0};

	switch (info.type) {
	case MPEG_AVC_STREAM:
		ctx->avcRegistered = false;
		break;
	case MPEG_AUDIO_STREAM:
	case MPEG_ATRAC_STREAM:
		ctx->atracRegistered = false;
		break;
	case MPEG_PCM_STREAM:
		ctx->pcmRegistered = false;
		break;
	case MPEG_DATA_STREAM:
		ctx->dataRegistered = false;
		break;
	default : 
		DEBUG_LOG(HLE, "sceMpegUnRegistStream(%i) : unknown streamID ", streamUid);
		break;
	}
	ctx->streamMap[streamUid] = info;
	info.type = -1;
	info.sid = -1 ;
	info.needsReset = true;
	ctx->isAnalyzed = false;
	return 0;
}
Exemple #23
0
int sceMpegAvcDecodeMode(u32 mpeg, u32 modeAddr)
{
	MpegContext *ctx = getMpegCtx(mpeg);
	if (!ctx) {
		WARN_LOG(HLE, "sceMpegAvcDecodeMode(%08x, %08x): bad mpeg handle", mpeg, modeAddr);
		return -1;
	}

	DEBUG_LOG(HLE, "sceMpegAvcDecodeMode(%08x, %08x)", mpeg, modeAddr);
	if (Memory::IsValidAddress(modeAddr)) {
		int mode = Memory::Read_U32(modeAddr);
		int pixelMode = Memory::Read_U32(modeAddr + 4);
		if (pixelMode >= TPSM_PIXEL_STORAGE_MODE_16BIT_BGR5650 && pixelMode <= TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888) {
			ctx->videoPixelMode = pixelMode;
		} else {
			ERROR_LOG(HLE, "sceMpegAvcDecodeMode(%i, %i): unknown pixelMode ", mode, pixelMode);
		}
	} else {
			ERROR_LOG(HLE, "sceMpegAvcDecodeMode(%08x, %08x): invalid modeAddr", mpeg, modeAddr);
			return -1;
	}

	return 0;
}
Exemple #24
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 #25
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;

	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, "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);
}
Exemple #26
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;

	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);
	//hleEatMicro(3300);
	//return hleDelayResult(0, "mpeg decode", 200);
}
Exemple #27
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 #28
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);
		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(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 && (ctx->mediaengine->getVideoTimeStamp() > ctx->mediaengine->getAudioTimeStamp() + 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;

	sceAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
	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;
		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(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 #29
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);
}