/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.HLE.modules;
import jpcsp.HLE.CheckArgument;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLELogging;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.HLEUnimplemented;
import jpcsp.HLE.SceKernelErrorException;
import jpcsp.HLE.TPointer;
import jpcsp.HLE.TPointer32;
import java.util.HashMap;
import jpcsp.HLE.Modules;
import jpcsp.HLE.kernel.types.SceKernelErrors;
import jpcsp.HLE.modules.sceMpeg.PSMFEntry;
import jpcsp.HLE.modules.sceMpeg.PSMFHeader;
import jpcsp.util.Utilities;
import org.apache.log4j.Logger;
public class scePsmf extends HLEModule {
public static Logger log = Modules.getLogger("scePsmf");
@Override
public void start() {
psmfHeaderMap = new HashMap<Integer, PSMFHeader>();
super.start();
}
private HashMap<Integer, PSMFHeader> psmfHeaderMap;
public TPointer32 checkPsmf(TPointer32 psmf) {
int headerAddress = psmf.getValue(24);
if (!psmfHeaderMap.containsKey(headerAddress)) {
throw new SceKernelErrorException(SceKernelErrors.ERROR_PSMF_NOT_FOUND);
}
return psmf;
}
public TPointer32 checkPsmfWithEPMap(TPointer32 psmf) {
psmf = checkPsmf(psmf);
PSMFHeader header = getPsmfHeader(psmf);
if (!header.hasEPMap()) {
if (log.isDebugEnabled()) {
log.debug(String.format("checkPsmfWithEPMap returning 0x%08X(ERROR_PSMF_NOT_FOUND)", SceKernelErrors.ERROR_PSMF_NOT_FOUND));
}
throw new SceKernelErrorException(SceKernelErrors.ERROR_PSMF_NOT_FOUND);
}
return psmf;
}
private PSMFHeader getPsmfHeader(TPointer32 psmf) {
int headerAddress = psmf.getValue(24);
return psmfHeaderMap.get(headerAddress);
}
@HLELogging(level="info")
@HLEFunction(nid = 0xC22C8327, version = 150, checkInsideInterrupt = true, stackUsage = 0x50)
public int scePsmfSetPsmf(TPointer32 psmf, TPointer bufferAddr) {
Modules.sceMpegModule.analyseMpeg(bufferAddr.getAddress());
PSMFHeader header = Modules.sceMpegModule.psmfHeader;
psmfHeaderMap.put(bufferAddr.getAddress(), header);
// PSMF struct:
// This is an internal system data area which is used to store
// several parameters of the file being handled.
// It's size ranges from 28 bytes to 52 bytes, since when a pointer to
// a certain PSMF area does not exist (NULL), it's omitted from the struct
// (e.g.: no mark data or non existant EPMap).
psmf.setValue(0, header.getVersion()); // PSMF version.
psmf.setValue(4, header.getHeaderSize()); // The PSMF header size (0x800).
psmf.setValue(8, header.getStreamSize()); // The PSMF stream size.
psmf.setValue(12, 0); // Grouping Period ID.
psmf.setValue(16, 0); // Group ID.
psmf.setValue(20, header.getCurrentStreamNumber()); // Current stream's number.
psmf.setValue(24, bufferAddr.getAddress()); // Pointer to PSMF header.
// psmf + 28 - Pointer to current PSMF stream info (video/audio).
// psmf + 32 - Pointer to mark data (used for chapters in UMD_VIDEO).
// psmf + 36 - Pointer to current PSMF stream grouping period.
// psmf + 40 - Pointer to current PSMF stream group.
// psmf + 44 - Pointer to current PSMF stream.
// psmf + 48 - Pointer to PSMF EPMap.
return 0;
}
@HLEFunction(nid = 0xC7DB3A5B, version = 150, checkInsideInterrupt = true, stackUsage = 0x50)
public int scePsmfGetCurrentStreamType(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 typeAddr, TPointer32 channelAddr) {
PSMFHeader header = getPsmfHeader(psmf);
typeAddr.setValue(header.getCurrentStreamType());
channelAddr.setValue(header.getCurrentStreamChannel());
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetCurrentStreamType returning type=%d, channel=%d", typeAddr.getValue(), channelAddr.getValue()));
}
return 0;
}
@HLEFunction(nid = 0x28240568, version = 150, checkInsideInterrupt = true, stackUsage = 0x0)
public int scePsmfGetCurrentStreamNumber(@CheckArgument("checkPsmf") TPointer32 psmf) {
PSMFHeader header = getPsmfHeader(psmf);
return header.getCurrentStreamNumber();
}
@HLEFunction(nid = 0x1E6D9013, version = 150, checkInsideInterrupt = true, stackUsage = 0x20)
public int scePsmfSpecifyStreamWithStreamType(@CheckArgument("checkPsmf") TPointer32 psmf, int type, int ch) {
PSMFHeader header = getPsmfHeader(psmf);
if (!header.setStreamWithType(type, ch)) {
// Do not return SceKernelErrors.ERROR_PSMF_INVALID_ID, but set an invalid stream number.
header.setStreamNum(-1);
}
return 0;
}
@HLEFunction(nid = 0x4BC9BDE0, version = 150, checkInsideInterrupt = true, stackUsage = 0x40)
public int scePsmfSpecifyStream(@CheckArgument("checkPsmf") TPointer32 psmf, int streamNum) {
PSMFHeader header = getPsmfHeader(psmf);
header.setStreamNum(streamNum);
return 0;
}
@HLEFunction(nid = 0x76D3AEBA, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfGetPresentationStartTime(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 startTimeAddr) {
PSMFHeader header = getPsmfHeader(psmf);
int startTime = header.getPresentationStartTime();
startTimeAddr.setValue(startTime);
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetPresentationStartTime startTime=%d", startTime));
}
return 0;
}
@HLEFunction(nid = 0xBD8AE0D8, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfGetPresentationEndTime(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 endTimeAddr) {
PSMFHeader header = getPsmfHeader(psmf);
int endTime = header.getPresentationEndTime();
endTimeAddr.setValue(endTime);
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetPresentationEndTime endTime=%d", endTime));
}
return 0;
}
@HLEFunction(nid = 0xEAED89CD, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfGetNumberOfStreams(@CheckArgument("checkPsmf") TPointer32 psmf) {
PSMFHeader header = getPsmfHeader(psmf);
return header.getNumberOfStreams();
}
@HLEFunction(nid = 0x7491C438, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfGetNumberOfEPentries(@CheckArgument("checkPsmf") TPointer32 psmf) {
PSMFHeader header = getPsmfHeader(psmf);
return header.getEPMapEntriesNum();
}
@HLEFunction(nid = 0x0BA514E5, version = 150, checkInsideInterrupt = true, stackUsage = 0x20)
public int scePsmfGetVideoInfo(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 videoInfoAddr) {
PSMFHeader header = getPsmfHeader(psmf);
if (!header.isValidCurrentStreamNumber()) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetVideoInfo returning 0x%08X(ERROR_PSMF_INVALID_ID)", SceKernelErrors.ERROR_PSMF_INVALID_ID));
}
return SceKernelErrors.ERROR_PSMF_INVALID_ID;
}
videoInfoAddr.setValue(0, header.getVideoWidth());
videoInfoAddr.setValue(4, header.getVideoHeight());
return 0;
}
@HLEFunction(nid = 0xA83F7113, version = 150, checkInsideInterrupt = true, stackUsage = 0x20)
public int scePsmfGetAudioInfo(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 audioInfoAddr) {
PSMFHeader header = getPsmfHeader(psmf);
if (!header.isValidCurrentStreamNumber()) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetAudioInfo returning 0x%08X(ERROR_PSMF_INVALID_ID)", SceKernelErrors.ERROR_PSMF_INVALID_ID));
}
return SceKernelErrors.ERROR_PSMF_INVALID_ID;
}
audioInfoAddr.setValue(0, header.getAudioChannelConfig());
audioInfoAddr.setValue(4, header.getAudioSampleFrequency());
return 0;
}
@HLEFunction(nid = 0x971A3A90, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfCheckEPmap(@CheckArgument("checkPsmfWithEPMap") TPointer32 psmf) {
// checkPsmfWithEPMap is already returning the correct error code if no EPmap is present
return 0;
}
@HLEFunction(nid = 0x4E624A34, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfGetEPWithId(@CheckArgument("checkPsmfWithEPMap") TPointer32 psmf, int id, TPointer32 outAddr) {
PSMFHeader header = getPsmfHeader(psmf);
PSMFEntry entry = header.getEPMapEntry(id);
if (entry == null) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPWithId returning 0x%08X(ERROR_PSMF_INVALID_ID)", SceKernelErrors.ERROR_PSMF_INVALID_ID));
}
return SceKernelErrors.ERROR_PSMF_INVALID_ID;
}
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPWithId returning %s", entry));
}
outAddr.setValue(0, entry.getEntryPTS());
outAddr.setValue(4, entry.getEntryOffset());
outAddr.setValue(8, entry.getEntryIndex());
outAddr.setValue(12, entry.getEntryPicOffset());
return 0;
}
@HLEFunction(nid = 0x7C0E7AC3, version = 150, checkInsideInterrupt = true, stackUsage = 0x10)
public int scePsmfGetEPWithTimestamp(@CheckArgument("checkPsmfWithEPMap") TPointer32 psmf, int ts, TPointer32 entryAddr) {
PSMFHeader header = getPsmfHeader(psmf);
if (ts < header.getPresentationStartTime()) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPWithTimestamp returning 0x%08X(ERROR_PSMF_INVALID_TIMESTAMP)", SceKernelErrors.ERROR_PSMF_INVALID_TIMESTAMP));
}
return SceKernelErrors.ERROR_PSMF_INVALID_TIMESTAMP;
}
PSMFEntry entry = header.getEPMapEntryWithTimestamp(ts);
if (entry == null) {
// Unknown error code
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPWithTimestamp returning -1"));
}
return -1;
}
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPWithTimestamp returning %s", entry));
}
entryAddr.setValue(0, entry.getEntryPTS());
entryAddr.setValue(4, entry.getEntryOffset());
entryAddr.setValue(8, entry.getEntryIndex());
entryAddr.setValue(12, entry.getEntryPicOffset());
return 0;
}
@HLEFunction(nid = 0x5F457515, version = 150, checkInsideInterrupt = true, stackUsage = 0x20)
public int scePsmfGetEPidWithTimestamp(@CheckArgument("checkPsmfWithEPMap") TPointer32 psmf, int ts) {
PSMFHeader header = getPsmfHeader(psmf);
if (ts < header.getPresentationStartTime()) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPidWithTimestamp returning 0x%08X(ERROR_PSMF_INVALID_TIMESTAMP)", SceKernelErrors.ERROR_PSMF_INVALID_TIMESTAMP));
}
return SceKernelErrors.ERROR_PSMF_INVALID_TIMESTAMP;
}
PSMFEntry entry = header.getEPMapEntryWithTimestamp(ts);
if (entry == null) {
// Unknown error code
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPidWithTimestamp returning -1"));
}
return -1;
}
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetEPidWithTimestamp returning id 0x%X", entry.getId()));
}
return entry.getId();
}
@HLEFunction(nid = 0x5B70FCC1, version = 150, checkInsideInterrupt = true, stackUsage = 0x20)
public int scePsmfQueryStreamOffset(TPointer bufferAddr, TPointer32 offsetAddr) {
// Always let sceMpeg handle the PSMF analysis.
Modules.sceMpegModule.analyseMpeg(bufferAddr.getAddress());
offsetAddr.setValue(Modules.sceMpegModule.psmfHeader.mpegOffset);
return 0;
}
@HLEFunction(nid = 0x9553CC91, version = 150, checkInsideInterrupt = true, stackUsage = 0x0)
public int scePsmfQueryStreamSize(TPointer bufferAddr, TPointer32 sizeAddr) {
// Always let sceMpeg handle the PSMF analysis.
Modules.sceMpegModule.analyseMpeg(bufferAddr.getAddress());
sizeAddr.setValue(Modules.sceMpegModule.psmfHeader.mpegStreamSize);
return 0;
}
@HLEFunction(nid = 0x68D42328, version = 150, checkInsideInterrupt = true, stackUsage = 0xA0)
public int scePsmfGetNumberOfSpecificStreams(@CheckArgument("checkPsmf") TPointer32 psmf, int streamType) {
PSMFHeader header = getPsmfHeader(psmf);
int streamNum = header.getSpecificStreamNum(streamType);
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetNumberOfSpecificStreams returning %d", streamNum));
}
return streamNum;
}
@HLEFunction(nid = 0x0C120E1D, version = 150, checkInsideInterrupt = true)
public int scePsmfSpecifyStreamWithStreamTypeNumber(@CheckArgument("checkPsmf") TPointer32 psmf, int type, int typeNum) {
PSMFHeader header = getPsmfHeader(psmf);
if (!header.setStreamWithTypeNum(type, typeNum)) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfSpecifyStreamWithStreamTypeNumber returning 0x%08X(ERROR_PSMF_INVALID_ID)", SceKernelErrors.ERROR_PSMF_INVALID_ID));
}
return SceKernelErrors.ERROR_PSMF_INVALID_ID;
}
return 0;
}
@HLEFunction(nid = 0x2673646B, version = 150, checkInsideInterrupt = true, stackUsage = 0x100)
public int scePsmfVerifyPsmf(TPointer bufferAddr) {
if (log.isTraceEnabled()) {
log.trace(String.format("scePsmfVerifyPsmf %s", Utilities.getMemoryDump(bufferAddr.getAddress(), sceMpeg.MPEG_HEADER_BUFFER_MINIMUM_SIZE)));
}
int magic = bufferAddr.getValue32(sceMpeg.PSMF_MAGIC_OFFSET);
if (magic != sceMpeg.PSMF_MAGIC) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfVerifyPsmf returning 0x%08X(ERROR_PSMF_INVALID_PSMF)", SceKernelErrors.ERROR_PSMF_INVALID_PSMF));
}
return SceKernelErrors.ERROR_PSMF_INVALID_PSMF;
}
int rawVersion = bufferAddr.getValue32(sceMpeg.PSMF_STREAM_VERSION_OFFSET);
int version = sceMpeg.getMpegVersion(rawVersion);
if (version < 0) {
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfVerifyPsmf returning 0x%08X(ERROR_PSMF_INVALID_PSMF)", SceKernelErrors.ERROR_PSMF_INVALID_PSMF));
}
return SceKernelErrors.ERROR_PSMF_INVALID_PSMF;
}
return 0;
}
@HLEFunction(nid = 0xB78EB9E9, version = 150, checkInsideInterrupt = true, stackUsage = 0x0)
public int scePsmfGetHeaderSize(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 sizeAddr) {
PSMFHeader header = getPsmfHeader(psmf);
sizeAddr.setValue(header.getHeaderSize());
return 0;
}
@HLEFunction(nid = 0xA5EBFE81, version = 150, checkInsideInterrupt = true, stackUsage = 0x0)
public int scePsmfGetStreamSize(@CheckArgument("checkPsmf") TPointer32 psmf, TPointer32 sizeAddr) {
PSMFHeader header = getPsmfHeader(psmf);
sizeAddr.setValue(header.getStreamSize());
return 0;
}
@HLEFunction(nid = 0xE1283895, version = 150, checkInsideInterrupt = true, stackUsage = 0x0)
public int scePsmfGetPsmfVersion(@CheckArgument("checkPsmf") TPointer32 psmf) {
PSMFHeader header = getPsmfHeader(psmf);
// Convert the header version into a decimal number, e.g. 0x0015 -> 15
int headerVersion = header.getVersion();
int version = 0;
for (int i = 0; i < 4; i++, headerVersion >>= 8) {
int digit = headerVersion & 0x0F;
version = (version * 10) + digit;
}
if (log.isDebugEnabled()) {
log.debug(String.format("scePsmfGetPsmfVersion returning version=%d (headerVersion=0x%04X)", version, headerVersion));
}
return version;
}
@HLEUnimplemented
@HLEFunction(nid = 0xDE78E9FC, version = 150)
public int scePsmf_DE78E9FC(@CheckArgument("checkPsmf") TPointer32 psmf, int unknown) {
// Get number of Psmf Marks
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x43AC7DBB, version = 150)
public int scePsmf_43AC7DBB(@CheckArgument("checkPsmf") TPointer32 psmf, int unknown, int markNumber, TPointer markInfoAddr) {
// Get Psmf Mark Information
int markType = 0;
int markTimestamp = 0;
int markEntryEsStream = 0;
int markData = 0;
String markName = "Test";
markInfoAddr.setValue32(0, markType);
markInfoAddr.setValue32(4, markTimestamp);
markInfoAddr.setValue32(8, markEntryEsStream);
markInfoAddr.setValue32(12, markData);
markInfoAddr.setValue32(16, markName.length());
markInfoAddr.setStringNZ(20, markName.length(), markName);
return 0;
}
}