Merge pull request #8799 from unknownbrackets/psmf

Correct some more scePsmf functions
This commit is contained in:
Henrik Rydgård 2016-06-05 08:22:12 +02:00
commit 3649231d66

View File

@ -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" },