mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-12-02 18:46:52 +00:00
Merge pull request #8799 from unknownbrackets/psmf
Correct some more scePsmf functions
This commit is contained in:
commit
3649231d66
@ -164,9 +164,9 @@ public:
|
||||
return currentStreamNum >= 0 && streamMap.find(currentStreamNum) != streamMap.end();
|
||||
}
|
||||
|
||||
bool setStreamNum(int num);
|
||||
bool setStreamWithType(int type, int channel);
|
||||
bool setStreamWithTypeNumber(int type, int n);
|
||||
bool setStreamNum(u32 psmfStruct, int num, bool updateCached = true);
|
||||
bool setStreamWithType(u32 psmfStruct, int type, int channel);
|
||||
bool setStreamWithTypeNumber(u32 psmfStruct, int type, int n);
|
||||
|
||||
int FindEPWithTimestamp(int pts) const;
|
||||
|
||||
@ -189,13 +189,12 @@ public:
|
||||
int currentStreamNum;
|
||||
int currentStreamType;
|
||||
int currentStreamChannel;
|
||||
int currentAudioStreamNum;
|
||||
int currentVideoStreamNum;
|
||||
|
||||
// parameters gotten from streams
|
||||
// I guess this is the seek information?
|
||||
u32 EPMapOffset;
|
||||
u32 EPMapEntriesNum;
|
||||
// These shouldn't be here, just here for convenience with old states.
|
||||
int videoWidth;
|
||||
int videoHeight;
|
||||
int audioChannels;
|
||||
@ -273,13 +272,18 @@ public:
|
||||
|
||||
class PsmfStream {
|
||||
public:
|
||||
enum {
|
||||
USE_PSMF = -2,
|
||||
INVALID = -1,
|
||||
};
|
||||
|
||||
// Used for save states.
|
||||
PsmfStream() {
|
||||
PsmfStream() : videoWidth_(USE_PSMF), videoHeight_(USE_PSMF), audioChannels_(USE_PSMF), audioFrequency_(USE_PSMF) {
|
||||
}
|
||||
|
||||
PsmfStream(int type, int channel) {
|
||||
this->type = type;
|
||||
this->channel = channel;
|
||||
PsmfStream(int type, int channel) : videoWidth_(INVALID), videoHeight_(INVALID), audioChannels_(INVALID), audioFrequency_(INVALID) {
|
||||
type_ = type;
|
||||
channel_ = channel;
|
||||
}
|
||||
|
||||
void readMPEGVideoStreamParams(const u8 *addr, const u8 *data, Psmf *psmf) {
|
||||
@ -288,8 +292,8 @@ public:
|
||||
// two unknowns here
|
||||
psmf->EPMapOffset = ReadUnalignedU32BE(&addr[4]);
|
||||
psmf->EPMapEntriesNum = ReadUnalignedU32BE(&addr[8]);
|
||||
psmf->videoWidth = addr[12] * 16;
|
||||
psmf->videoHeight = addr[13] * 16;
|
||||
videoWidth_ = addr[12] * 16;
|
||||
videoHeight_ = addr[13] * 16;
|
||||
|
||||
const u32 EP_MAP_STRIDE = 1 + 1 + 4 + 4;
|
||||
psmf->EPMap.clear();
|
||||
@ -309,31 +313,41 @@ public:
|
||||
void readPrivateAudioStreamParams(const u8 *addr, Psmf *psmf) {
|
||||
int streamId = addr[0];
|
||||
int privateStreamId = addr[1];
|
||||
psmf->audioChannels = addr[14];
|
||||
psmf->audioFrequency = addr[15];
|
||||
audioChannels_ = addr[14];
|
||||
// Note: "frequency" is usually 2. But that's what scePsmfGetAudioInfo() writes too.
|
||||
audioFrequency_ = addr[15];
|
||||
// two unknowns here
|
||||
INFO_LOG(ME, "PSMF private audio found: id=%02x, privid=%02x, channels=%i, freq=%i", streamId, privateStreamId, psmf->audioChannels, psmf->audioFrequency);
|
||||
}
|
||||
|
||||
bool matchesType(int ty) {
|
||||
if (ty == PSMF_AUDIO_STREAM) {
|
||||
return type == PSMF_ATRAC_STREAM || type == PSMF_PCM_STREAM;
|
||||
return type_ == PSMF_ATRAC_STREAM || type_ == PSMF_PCM_STREAM;
|
||||
}
|
||||
return type == ty;
|
||||
return type_ == ty;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) {
|
||||
auto s = p.Section("PsmfStream", 1);
|
||||
auto s = p.Section("PsmfStream", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
p.Do(type);
|
||||
p.Do(channel);
|
||||
p.Do(type_);
|
||||
p.Do(channel_);
|
||||
if (s >= 2) {
|
||||
p.Do(videoWidth_);
|
||||
p.Do(videoHeight_);
|
||||
p.Do(audioChannels_);
|
||||
p.Do(audioFrequency_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int type;
|
||||
int channel;
|
||||
int type_;
|
||||
int channel_;
|
||||
int videoWidth_;
|
||||
int videoHeight_;
|
||||
int audioChannels_;
|
||||
int audioFrequency_;
|
||||
};
|
||||
|
||||
|
||||
@ -355,8 +369,6 @@ Psmf::Psmf(const u8 *ptr, u32 data) {
|
||||
currentStreamNum = -1;
|
||||
currentStreamType = -1;
|
||||
currentStreamChannel = -1;
|
||||
currentAudioStreamNum = -1;
|
||||
currentVideoStreamNum = -1;
|
||||
|
||||
for (int i = 0; i < numStreams; i++) {
|
||||
PsmfStream *stream = 0;
|
||||
@ -439,8 +451,9 @@ void Psmf::DoState(PointerWrap &p) {
|
||||
p.Do(numStreams);
|
||||
|
||||
p.Do(currentStreamNum);
|
||||
p.Do(currentAudioStreamNum);
|
||||
p.Do(currentVideoStreamNum);
|
||||
int legacyStreamNums = 0;
|
||||
p.Do(legacyStreamNums);
|
||||
p.Do(legacyStreamNums);
|
||||
|
||||
p.Do(EPMapOffset);
|
||||
p.Do(EPMapEntriesNum);
|
||||
@ -462,8 +475,8 @@ void Psmf::DoState(PointerWrap &p) {
|
||||
currentStreamChannel = -1;
|
||||
auto streamInfo = streamMap.find(currentStreamNum);
|
||||
if (streamInfo != streamMap.end()) {
|
||||
currentStreamType = streamInfo->second->type;
|
||||
currentStreamChannel = streamInfo->second->channel;
|
||||
currentStreamType = streamInfo->second->type_;
|
||||
currentStreamChannel = streamInfo->second->channel_;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -540,46 +553,39 @@ void PsmfPlayer::DoState(PointerWrap &p) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Psmf::setStreamNum(int num) {
|
||||
bool Psmf::setStreamNum(u32 psmfStruct, int num, bool updateCached) {
|
||||
auto data = PSPPointer<PsmfData>::Create(psmfStruct);
|
||||
currentStreamNum = num;
|
||||
currentStreamType = -1;
|
||||
currentStreamChannel = -1;
|
||||
data->streamNum = num;
|
||||
|
||||
// One of the functions can set this to invalid without invalidating these values.
|
||||
if (updateCached) {
|
||||
currentStreamType = -1;
|
||||
currentStreamChannel = -1;
|
||||
}
|
||||
if (!isValidCurrentStreamNumber())
|
||||
return false;
|
||||
PsmfStreamMap::iterator iter = streamMap.find(currentStreamNum);
|
||||
if (iter == streamMap.end())
|
||||
return false;
|
||||
|
||||
// TODO: This information is *probably* only for the scePsmf lookups?
|
||||
// Not sure if we need to communicate with the media engine.
|
||||
int type = iter->second->type;
|
||||
switch (type) {
|
||||
case PSMF_AVC_STREAM:
|
||||
currentVideoStreamNum = num;
|
||||
break;
|
||||
|
||||
case PSMF_ATRAC_STREAM:
|
||||
case PSMF_PCM_STREAM:
|
||||
currentAudioStreamNum = num;
|
||||
break;
|
||||
}
|
||||
|
||||
currentStreamType = type;
|
||||
currentStreamChannel = iter->second->channel;
|
||||
// This information seems to only be for the scePsmf lookups.
|
||||
currentStreamType = iter->second->type_;
|
||||
currentStreamChannel = iter->second->channel_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Psmf::setStreamWithType(int type, int channel) {
|
||||
bool Psmf::setStreamWithType(u32 psmfStruct, int type, int channel) {
|
||||
for (auto iter : streamMap) {
|
||||
// Note: this does NOT support PSMF_AUDIO_STREAM.
|
||||
if (iter.second->type == type && iter.second->channel == channel) {
|
||||
return setStreamNum(iter.first);
|
||||
if (iter.second->type_ == type && iter.second->channel_ == channel) {
|
||||
return setStreamNum(psmfStruct, iter.first);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Psmf::setStreamWithTypeNumber(int type, int n) {
|
||||
bool Psmf::setStreamWithTypeNumber(u32 psmfStruct, int type, int n) {
|
||||
for (auto iter : streamMap) {
|
||||
if (iter.second->matchesType(type)) {
|
||||
if (n != 0) {
|
||||
@ -588,7 +594,7 @@ bool Psmf::setStreamWithTypeNumber(int type, int n) {
|
||||
continue;
|
||||
}
|
||||
// Okay, this is the one.
|
||||
return setStreamNum(iter.first);
|
||||
return setStreamNum(psmfStruct, iter.first);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -618,16 +624,20 @@ int Psmf::FindEPWithTimestamp(int pts) const {
|
||||
static std::map<u32, Psmf *> psmfMap;
|
||||
static std::map<u32, PsmfPlayer *> psmfPlayerMap;
|
||||
|
||||
static Psmf *getPsmf(u32 psmf)
|
||||
{
|
||||
static Psmf *getPsmf(u32 psmf) {
|
||||
auto psmfstruct = PSPPointer<PsmfData>::Create(psmf);
|
||||
if (!psmfstruct.IsValid())
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
auto iter = psmfMap.find(psmfstruct->headerOffset);
|
||||
if (iter != psmfMap.end())
|
||||
if (iter != psmfMap.end()) {
|
||||
// TODO: Migrate to only using PSP RAM.
|
||||
// Each instance can have its own selected stream. This is important.
|
||||
iter->second->currentStreamNum = psmfstruct->streamNum;
|
||||
return iter->second;
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static PsmfPlayer *getPsmfPlayer(u32 psmfplayer)
|
||||
@ -675,30 +685,44 @@ void __PsmfShutdown()
|
||||
psmfPlayerMap.clear();
|
||||
}
|
||||
|
||||
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData)
|
||||
{
|
||||
if (!Memory::IsValidAddress(psmfData)) {
|
||||
// TODO: Check error code.
|
||||
ERROR_LOG_REPORT(ME, "scePsmfSetPsmf(%08x, %08x): bad address", psmfStruct, psmfData);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
|
||||
static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
|
||||
if (!Memory::IsValidAddress(psmfData) || !Memory::IsValidAddress(psmfData)) {
|
||||
// Crashes on a PSP.
|
||||
return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
|
||||
}
|
||||
|
||||
INFO_LOG(ME, "scePsmfSetPsmf(%08x, %08x)", psmfStruct, psmfData);
|
||||
|
||||
Psmf *psmf = new Psmf(Memory::GetPointer(psmfData), psmfData);
|
||||
if (psmf->magic != PSMF_MAGIC) {
|
||||
delete psmf;
|
||||
return hleLogError(ME, ERROR_PSMF_INVALID_PSMF, "invalid psmf data");
|
||||
}
|
||||
// Note: devkit 00000000 supports only '0012'(0F), '0013'(1F), and '0014'(2F). 03000310+ supports '0015'(3F.)
|
||||
if (psmf->version == 0) {
|
||||
delete psmf;
|
||||
return hleLogError(ME, ERROR_PSMF_BAD_VERSION, "invalid psmf version");
|
||||
}
|
||||
if (psmf->streamOffset == 0) {
|
||||
delete psmf;
|
||||
return hleLogError(ME, ERROR_PSMF_INVALID_VALUE, "invalid psmf version");
|
||||
}
|
||||
|
||||
// Note: this structure changes between versions.
|
||||
// TODO: These values are not right, but games probably don't read them.
|
||||
PsmfData data = {0};
|
||||
data.version = psmf->version;
|
||||
data.headerSize = 0x800;
|
||||
data.streamSize = psmf->streamSize;
|
||||
data.streamNum = psmf->numStreams;
|
||||
data.headerOffset = psmf->headerOffset;
|
||||
Memory::WriteStruct(psmfStruct, &data);
|
||||
|
||||
// Because the Psmf struct is sometimes copied, we use a value inside as an id.
|
||||
auto iter = psmfMap.find(data.headerOffset);
|
||||
if (iter != psmfMap.end())
|
||||
delete iter->second;
|
||||
psmfMap[data.headerOffset] = psmf;
|
||||
Memory::WriteStruct(psmfStruct, &data);
|
||||
return 0;
|
||||
|
||||
return hleLogSuccessI(ME, 0);
|
||||
}
|
||||
|
||||
static u32 scePsmfGetNumberOfStreams(u32 psmfStruct) {
|
||||
@ -731,9 +755,9 @@ static u32 scePsmfSpecifyStreamWithStreamType(u32 psmfStruct, u32 streamType, u3
|
||||
if (!psmf) {
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
|
||||
}
|
||||
if (!psmf->setStreamWithType(streamType, channel)) {
|
||||
if (!psmf->setStreamWithType(psmfStruct, streamType, channel)) {
|
||||
// An invalid type seems to make the stream number invalid, but retain the old type/channel.
|
||||
psmf->currentStreamNum = ERROR_PSMF_INVALID_ID;
|
||||
psmf->setStreamNum(psmfStruct, ERROR_PSMF_INVALID_ID, false);
|
||||
// Also, returns 0 even when no stream found.
|
||||
return hleLogWarning(ME, 0, "no stream found");
|
||||
}
|
||||
@ -745,7 +769,7 @@ static u32 scePsmfSpecifyStreamWithStreamTypeNumber(u32 psmfStruct, u32 streamTy
|
||||
if (!psmf) {
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
|
||||
}
|
||||
if (!psmf->setStreamWithTypeNumber(streamType, typeNum)) {
|
||||
if (!psmf->setStreamWithTypeNumber(psmfStruct, streamType, typeNum)) {
|
||||
// Don't update stream, just bail out.
|
||||
return hleLogWarning(ME, ERROR_PSMF_INVALID_ID, "no stream found");
|
||||
}
|
||||
@ -757,8 +781,8 @@ static u32 scePsmfSpecifyStream(u32 psmfStruct, int streamNum) {
|
||||
if (!psmf) {
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
|
||||
}
|
||||
if (!psmf->setStreamNum(streamNum)) {
|
||||
psmf->setStreamNum(ERROR_PSMF_NOT_INITIALIZED);
|
||||
if (!psmf->setStreamNum(psmfStruct, streamNum)) {
|
||||
psmf->setStreamNum(psmfStruct, ERROR_PSMF_NOT_INITIALIZED);
|
||||
return hleLogWarning(ME, ERROR_PSMF_INVALID_ID, "bad stream id");
|
||||
}
|
||||
return hleLogSuccessI(ME, 0);
|
||||
@ -767,29 +791,41 @@ static u32 scePsmfSpecifyStream(u32 psmfStruct, int streamNum) {
|
||||
static u32 scePsmfGetVideoInfo(u32 psmfStruct, u32 videoInfoAddr) {
|
||||
Psmf *psmf = getPsmf(psmfStruct);
|
||||
if (!psmf) {
|
||||
ERROR_LOG(ME, "scePsmfGetVideoInfo(%08x, %08x): invalid psmf", psmfStruct, videoInfoAddr);
|
||||
return ERROR_PSMF_NOT_FOUND;
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
|
||||
} else if (!psmf->isValidCurrentStreamNumber()) {
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected");
|
||||
} else if (!Memory::IsValidRange(videoInfoAddr, 8)) {
|
||||
// Would crash.
|
||||
return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
|
||||
}
|
||||
INFO_LOG(ME, "scePsmfGetVideoInfo(%08x, %08x)", psmfStruct, videoInfoAddr);
|
||||
if (Memory::IsValidAddress(videoInfoAddr)) {
|
||||
Memory::Write_U32(psmf->videoWidth, videoInfoAddr);
|
||||
Memory::Write_U32(psmf->videoHeight, videoInfoAddr + 4);
|
||||
|
||||
auto info = psmf->streamMap[psmf->currentStreamNum];
|
||||
if (info->videoWidth_ == PsmfStream::INVALID) {
|
||||
return hleLogError(ME, ERROR_PSMF_INVALID_ID, "not a video stream");
|
||||
}
|
||||
return 0;
|
||||
Memory::Write_U32(info->videoWidth_ == PsmfStream::USE_PSMF ? psmf->videoWidth : info->videoWidth_, videoInfoAddr);
|
||||
Memory::Write_U32(info->videoHeight_ == PsmfStream::USE_PSMF ? psmf->videoHeight : info->videoHeight_, videoInfoAddr + 4);
|
||||
return hleLogSuccessI(ME, 0);
|
||||
}
|
||||
|
||||
static u32 scePsmfGetAudioInfo(u32 psmfStruct, u32 audioInfoAddr) {
|
||||
Psmf *psmf = getPsmf(psmfStruct);
|
||||
if (!psmf) {
|
||||
ERROR_LOG(ME, "scePsmfGetAudioInfo(%08x, %08x): invalid psmf", psmfStruct, audioInfoAddr);
|
||||
return ERROR_PSMF_NOT_FOUND;
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
|
||||
} else if (!psmf->isValidCurrentStreamNumber()) {
|
||||
return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected");
|
||||
} else if (!Memory::IsValidRange(audioInfoAddr, 8)) {
|
||||
// Would crash.
|
||||
return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
|
||||
}
|
||||
INFO_LOG(ME, "scePsmfGetAudioInfo(%08x, %08x)", psmfStruct, audioInfoAddr);
|
||||
if (Memory::IsValidAddress(audioInfoAddr)) {
|
||||
Memory::Write_U32(psmf->audioChannels, audioInfoAddr);
|
||||
Memory::Write_U32(psmf->audioFrequency, audioInfoAddr + 4);
|
||||
|
||||
auto info = psmf->streamMap[psmf->currentStreamNum];
|
||||
if (info->audioChannels_ == PsmfStream::INVALID) {
|
||||
return hleLogError(ME, ERROR_PSMF_INVALID_ID, "not an audio stream");
|
||||
}
|
||||
return 0;
|
||||
Memory::Write_U32(info->audioChannels_ == PsmfStream::USE_PSMF ? psmf->audioChannels : info->audioChannels_, audioInfoAddr);
|
||||
Memory::Write_U32(info->audioFrequency_ == PsmfStream::USE_PSMF ? psmf->audioFrequency : info->audioFrequency_, audioInfoAddr + 4);
|
||||
return hleLogSuccessI(ME, 0);
|
||||
}
|
||||
|
||||
static u32 scePsmfGetCurrentStreamType(u32 psmfStruct, u32 typeAddr, u32 channelAddr) {
|
||||
@ -1048,10 +1084,8 @@ static int scePsmfPlayerCreate(u32 psmfPlayer, u32 dataPtr)
|
||||
return ERROR_PSMFPLAYER_INVALID_PARAM;
|
||||
}
|
||||
if (!psmfPlayerMap.empty()) {
|
||||
ERROR_LOG_REPORT(ME, "scePsmfPlayerCreate(%08x, %08x): already have an active player", psmfPlayer, dataPtr);
|
||||
// TODO: Tests show this is what we should do. Leaving it off for now to see if safe.
|
||||
//*player = 0;
|
||||
//return ERROR_MPEG_ALREADY_INIT;
|
||||
*player = 0;
|
||||
return hleReportError(ME, ERROR_MPEG_ALREADY_INIT, "already have an active player");
|
||||
}
|
||||
|
||||
INFO_LOG(ME, "scePsmfPlayerCreate(%08x, %08x)", psmfPlayer, dataPtr);
|
||||
@ -2038,8 +2072,8 @@ const HLEFunction scePsmf[] = {
|
||||
{0XBD8AE0D8, &WrapU_UU<scePsmfGetPresentationEndTime>, "scePsmfGetPresentationEndTime", 'x', "xx" },
|
||||
{0XEAED89CD, &WrapU_U<scePsmfGetNumberOfStreams>, "scePsmfGetNumberOfStreams", 'i', "x" },
|
||||
{0X7491C438, &WrapU_U<scePsmfGetNumberOfEPentries>, "scePsmfGetNumberOfEPentries", 'x', "x" },
|
||||
{0X0BA514E5, &WrapU_UU<scePsmfGetVideoInfo>, "scePsmfGetVideoInfo", 'x', "xx" },
|
||||
{0XA83F7113, &WrapU_UU<scePsmfGetAudioInfo>, "scePsmfGetAudioInfo", 'x', "xx" },
|
||||
{0X0BA514E5, &WrapU_UU<scePsmfGetVideoInfo>, "scePsmfGetVideoInfo", 'i', "xp" },
|
||||
{0XA83F7113, &WrapU_UU<scePsmfGetAudioInfo>, "scePsmfGetAudioInfo", 'i', "xp" },
|
||||
{0X971A3A90, &WrapU_U<scePsmfCheckEPMap>, "scePsmfCheckEPmap", 'x', "x" },
|
||||
{0X68D42328, &WrapU_UI<scePsmfGetNumberOfSpecificStreams>, "scePsmfGetNumberOfSpecificStreams", 'i', "xi" },
|
||||
{0X5B70FCC1, &WrapU_UU<scePsmfQueryStreamOffset>, "scePsmfQueryStreamOffset", 'x', "xx" },
|
||||
|
Loading…
Reference in New Issue
Block a user