1 // Copyright (c) 2012- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18 #include "Common/Serialize/Serializer.h"
19 #include "Common/Serialize/SerializeFuncs.h"
20 #include "Common/Serialize/SerializeMap.h"
21 #include "Core/MemMapHelpers.h"
22 #include "Core/Reporting.h"
23 #include "Core/System.h"
24 #include "Core/FileSystems/MetaFileSystem.h"
25 #include "Core/HLE/HLE.h"
26 #include "Core/HLE/HLEHelperThread.h"
27 #include "Core/HLE/FunctionWrappers.h"
28 #include "Core/HLE/scePsmf.h"
29 #include "Core/HLE/sceMpeg.h"
30 #include "Core/HLE/sceKernelMemory.h"
31 #include "Core/HW/MediaEngine.h"
32 #include "Core/CoreTiming.h"
33 #include "GPU/GPUInterface.h"
34 #include "GPU/GPUState.h"
35
36 #include <map>
37 #include <algorithm>
38
39 // "Go Sudoku" is a good way to test this code...
40 const int PSMF_AVC_STREAM = 0;
41 const int PSMF_ATRAC_STREAM = 1;
42 const int PSMF_PCM_STREAM = 2;
43 const int PSMF_DATA_STREAM = 3;
44 const int PSMF_AUDIO_STREAM = 15;
45 const int PSMF_PLAYER_VERSION_FULL = 0;
46 const int PSMF_PLAYER_VERSION_BASIC = 1;
47 const int PSMF_PLAYER_VERSION_NET = 2;
48 const int PSMF_PLAYER_CONFIG_LOOP = 0;
49 const int PSMF_PLAYER_CONFIG_NO_LOOP = 1;
50 const int PSMF_PLAYER_CONFIG_MODE_LOOP = 0;
51 const int PSMF_PLAYER_CONFIG_MODE_PIXEL_TYPE = 1;
52
53 const int PSMF_PLAYER_WARMUP_FRAMES = 3;
54
55 static const int VIDEO_FRAME_DURATION_TS = 3003;
56
57 static const int audioSamples = 2048;
58 static const int audioSamplesBytes = audioSamples * 4;
59 static int videoPixelMode = GE_CMODE_32BIT_ABGR8888;
60 static int videoLoopStatus = PSMF_PLAYER_CONFIG_NO_LOOP;
61 static int psmfPlayerLibVersion = 0;
62
63 int eventPsmfPlayerStatusChange = -1;
64
65 enum PsmfPlayerError {
66 ERROR_PSMF_NOT_INITIALIZED = 0x80615001,
67 ERROR_PSMF_BAD_VERSION = 0x80615002,
68 ERROR_PSMF_NOT_FOUND = 0x80615025,
69 ERROR_PSMF_INVALID_ID = 0x80615100,
70 ERROR_PSMF_INVALID_VALUE = 0x806151fe,
71 ERROR_PSMF_INVALID_TIMESTAMP = 0x80615500,
72 ERROR_PSMF_INVALID_PSMF = 0x80615501,
73
74 ERROR_PSMFPLAYER_INVALID_STATUS = 0x80616001,
75 ERROR_PSMFPLAYER_INVALID_STREAM = 0x80616003,
76 ERROR_PSMFPLAYER_BUFFER_SIZE = 0x80616005,
77 ERROR_PSMFPLAYER_INVALID_CONFIG = 0x80616006,
78 ERROR_PSMFPLAYER_INVALID_PARAM = 0x80616008,
79 ERROR_PSMFPLAYER_NO_MORE_DATA = 0x8061600c,
80 };
81
82 enum PsmfPlayerStatus {
83 PSMF_PLAYER_STATUS_NONE = 0x0,
84 PSMF_PLAYER_STATUS_INIT = 0x1,
85 PSMF_PLAYER_STATUS_STANDBY = 0x2,
86 PSMF_PLAYER_STATUS_PLAYING = 0x4,
87 PSMF_PLAYER_STATUS_ERROR = 0x100,
88 PSMF_PLAYER_STATUS_PLAYING_FINISHED = 0x200,
89 };
90
91 enum PsmfPlayerMode {
92 PSMF_PLAYER_MODE_PLAY = 0,
93 PSMF_PLAYER_MODE_SLOWMOTION = 1,
94 PSMF_PLAYER_MODE_STEPFRAME = 2,
95 PSMF_PLAYER_MODE_PAUSE = 3,
96 PSMF_PLAYER_MODE_FORWARD = 4,
97 PSMF_PLAYER_MODE_REWIND = 5,
98 };
99
100 struct PsmfData {
101 u32_le version;
102 u32_le headerSize;
103 u32_le headerOffset;
104 u32_le streamSize;
105 u32_le streamOffset;
106 u32_le streamNum;
107 u32_le unk1;
108 u32_le unk2;
109 };
110
111 struct PsmfPlayerCreateData {
112 PSPPointer<u8> buffer;
113 u32_le bufferSize;
114 s32_le threadPriority;
115 };
116
117 struct PsmfPlayerData {
118 s32_le videoCodec;
119 s32_le videoStreamNum;
120 s32_le audioCodec;
121 s32_le audioStreamNum;
122 s32_le playMode;
123 s32_le playSpeed;
124 };
125
126 struct PsmfInfo {
127 u32_le lastFrameTS;
128 s32_le numVideoStreams;
129 s32_le numAudioStreams;
130 s32_le numPCMStreams;
131 s32_le playerVersion;
132 };
133
134 struct PsmfVideoData {
135 s32_le frameWidth;
136 u32_le displaybuf;
137 u32_le displaypts;
138 };
139
140 struct PsmfEntry {
141 int EPPts;
142 int EPOffset;
143 int EPIndex;
144 int EPPicOffset;
145 };
146
147 // Some of our platforms don't play too nice with direct unaligned access.
ReadUnalignedU32BE(const u8 * p)148 static u32 ReadUnalignedU32BE(const u8 *p) {
149 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
150 }
151
152 class PsmfStream;
153
154 // This does NOT match the raw structure. Due to endianness etc,
155 // we read it manually.
156 // TODO: Change to work directly with the data in RAM instead of this
157 // JPSCP-esque class.
158 typedef std::map<int, PsmfStream *> PsmfStreamMap;
159
160 class Psmf {
161 public:
162 // For savestates only.
Psmf()163 Psmf() {}
164 Psmf(const u8 *ptr, u32 data);
165 ~Psmf();
166 void DoState(PointerWrap &p);
167
isValidCurrentStreamNumber() const168 bool isValidCurrentStreamNumber() const {
169 return currentStreamNum >= 0 && streamMap.find(currentStreamNum) != streamMap.end();
170 }
171
172 bool setStreamNum(u32 psmfStruct, int num, bool updateCached = true);
173 bool setStreamWithType(u32 psmfStruct, int type, int channel);
174 bool setStreamWithTypeNumber(u32 psmfStruct, int type, int n);
175
176 int FindEPWithTimestamp(int pts) const;
177
178 u32 magic;
179 u32 version;
180 u32 streamOffset;
181 u32 streamSize;
182 u32 headerSize;
183 u32 headerOffset;
184 u32 streamType;
185 u32 streamChannel;
186 // 0x50
187 u32 streamDataTotalSize;
188 u32 presentationStartTime;
189 u32 presentationEndTime;
190 u32 streamDataNextBlockSize;
191 u32 streamDataNextInnerBlockSize;
192
193 int numStreams;
194 int currentStreamNum;
195 int currentStreamType;
196 int currentStreamChannel;
197
198 // parameters gotten from streams
199 // I guess this is the seek information?
200 u32 EPMapOffset;
201 u32 EPMapEntriesNum;
202 // These shouldn't be here, just here for convenience with old states.
203 int videoWidth;
204 int videoHeight;
205 int audioChannels;
206 int audioFrequency;
207 std::vector<PsmfEntry> EPMap;
208
209 PsmfStreamMap streamMap;
210 };
211
212 class PsmfPlayer {
213 public:
214 // For savestates only.
PsmfPlayer()215 PsmfPlayer() : videoWidth(480), videoHeight(272) {
216 mediaengine = new MediaEngine();
217 }
218 PsmfPlayer(const PsmfPlayerCreateData *data);
~PsmfPlayer()219 ~PsmfPlayer() {
220 AbortFinish();
221 if (mediaengine)
222 delete mediaengine;
223 pspFileSystem.CloseFile(filehandle);
224 }
225 void DoState(PointerWrap &p);
226
ScheduleFinish(u32 handle)227 void ScheduleFinish(u32 handle) {
228 if (!finishThread) {
229 finishThread = new HLEHelperThread("scePsmfPlayer", "scePsmfPlayer", "__PsmfPlayerFinish", playbackThreadPriority, 0x200);
230 finishThread->Start(handle, 0);
231 }
232 }
233
AbortFinish()234 void AbortFinish() {
235 if (finishThread) {
236 delete finishThread;
237 finishThread = nullptr;
238 }
239 }
240
HasReachedEnd()241 bool HasReachedEnd() {
242 // The pts are ignored - the end is when we're out of data.
243 return mediaengine->IsVideoEnd() && (mediaengine->IsNoAudioData() || !mediaengine->IsActuallyPlayingAudio());
244 }
245
246 int filehandle = 0;
247 u32 fileoffset;
248 int readSize;
249 int streamSize;
250 u8 tempbuf[0x10000];
251
252 int videoCodec;
253 int videoStreamNum;
254 int audioCodec;
255 int audioStreamNum;
256 int playMode;
257 int playSpeed;
258 u64 totalDurationTimestamp;
259
260 int displayBuffer;
261 int displayBufferSize;
262 int playbackThreadPriority;
263 int totalVideoStreams;
264 int totalAudioStreams;
265 int playerVersion;
266 int videoStep;
267 int warmUp;
268 s64 seekDestTimeStamp;
269
270 int videoWidth;
271 int videoHeight;
272
273 SceMpegAu psmfPlayerAtracAu;
274 SceMpegAu psmfPlayerAvcAu;
275 PsmfPlayerStatus status;
276
277 MediaEngine *mediaengine;
278 HLEHelperThread *finishThread = nullptr;
279 };
280
281 class PsmfStream {
282 public:
283 enum {
284 USE_PSMF = -2,
285 INVALID = -1,
286 };
287
288 // Used for save states.
PsmfStream()289 PsmfStream() : videoWidth_(USE_PSMF), videoHeight_(USE_PSMF), audioChannels_(USE_PSMF), audioFrequency_(USE_PSMF) {
290 }
291
PsmfStream(int type,int channel)292 PsmfStream(int type, int channel) : videoWidth_(INVALID), videoHeight_(INVALID), audioChannels_(INVALID), audioFrequency_(INVALID) {
293 type_ = type;
294 channel_ = channel;
295 }
296
readMPEGVideoStreamParams(const u8 * addr,const u8 * data,Psmf * psmf)297 void readMPEGVideoStreamParams(const u8 *addr, const u8 *data, Psmf *psmf) {
298 int streamId = addr[0];
299 int privateStreamId = addr[1];
300 // two unknowns here
301 psmf->EPMapOffset = ReadUnalignedU32BE(&addr[4]);
302 psmf->EPMapEntriesNum = ReadUnalignedU32BE(&addr[8]);
303 videoWidth_ = addr[12] * 16;
304 videoHeight_ = addr[13] * 16;
305
306 const u32 EP_MAP_STRIDE = 1 + 1 + 4 + 4;
307 psmf->EPMap.clear();
308 for (u32 i = 0; i < psmf->EPMapEntriesNum; i++) {
309 const u8 *const entryAddr = data + psmf->EPMapOffset + EP_MAP_STRIDE * i;
310 PsmfEntry entry;
311 entry.EPIndex = entryAddr[0];
312 entry.EPPicOffset = entryAddr[1];
313 entry.EPPts = ReadUnalignedU32BE(&entryAddr[2]);
314 entry.EPOffset = ReadUnalignedU32BE(&entryAddr[6]);
315 psmf->EPMap.push_back(entry);
316 }
317
318 INFO_LOG(ME, "PSMF MPEG data found: id=%02x, privid=%02x, epmoff=%08x, epmnum=%08x, width=%i, height=%i", streamId, privateStreamId, psmf->EPMapOffset, psmf->EPMapEntriesNum, psmf->videoWidth, psmf->videoHeight);
319 }
320
readPrivateAudioStreamParams(const u8 * addr,Psmf * psmf)321 void readPrivateAudioStreamParams(const u8 *addr, Psmf *psmf) {
322 int streamId = addr[0];
323 int privateStreamId = addr[1];
324 audioChannels_ = addr[14];
325 // Note: "frequency" is usually 2. But that's what scePsmfGetAudioInfo() writes too.
326 audioFrequency_ = addr[15];
327 // two unknowns here
328 INFO_LOG(ME, "PSMF private audio found: id=%02x, privid=%02x, channels=%i, freq=%i", streamId, privateStreamId, psmf->audioChannels, psmf->audioFrequency);
329 }
330
matchesType(int ty)331 bool matchesType(int ty) {
332 if (ty == PSMF_AUDIO_STREAM) {
333 return type_ == PSMF_ATRAC_STREAM || type_ == PSMF_PCM_STREAM;
334 }
335 return type_ == ty;
336 }
337
DoState(PointerWrap & p)338 void DoState(PointerWrap &p) {
339 auto s = p.Section("PsmfStream", 1, 2);
340 if (!s)
341 return;
342
343 Do(p, type_);
344 Do(p, channel_);
345 if (s >= 2) {
346 Do(p, videoWidth_);
347 Do(p, videoHeight_);
348 Do(p, audioChannels_);
349 Do(p, audioFrequency_);
350 }
351 }
352
353 int type_;
354 int channel_;
355 int videoWidth_;
356 int videoHeight_;
357 int audioChannels_;
358 int audioFrequency_;
359 };
360
361
Psmf(const u8 * ptr,u32 data)362 Psmf::Psmf(const u8 *ptr, u32 data) {
363 headerOffset = data;
364 magic = *(u32_le *)&ptr[0];
365 version = *(u32_le *)&ptr[4];
366 streamOffset = ReadUnalignedU32BE(&ptr[8]);
367 streamSize = ReadUnalignedU32BE(&ptr[12]);
368 streamDataTotalSize = ReadUnalignedU32BE(&ptr[0x50]);
369 presentationStartTime = getMpegTimeStamp(ptr + PSMF_FIRST_TIMESTAMP_OFFSET);
370 presentationEndTime = getMpegTimeStamp(ptr + PSMF_LAST_TIMESTAMP_OFFSET);
371 streamDataNextBlockSize = ReadUnalignedU32BE(&ptr[0x6A]);
372 streamDataNextInnerBlockSize = ReadUnalignedU32BE(&ptr[0x7C]);
373 numStreams = *(u16_be *)&ptr[0x80];
374 // TODO: Always?
375 headerSize = 0x800;
376
377 currentStreamNum = -1;
378 currentStreamType = -1;
379 currentStreamChannel = -1;
380
381 for (int i = 0; i < numStreams; i++) {
382 PsmfStream *stream = 0;
383 const u8 *const currentStreamAddr = ptr + 0x82 + i * 16;
384 int streamId = currentStreamAddr[0];
385 if ((streamId & PSMF_VIDEO_STREAM_ID) == PSMF_VIDEO_STREAM_ID) {
386 stream = new PsmfStream(PSMF_AVC_STREAM, streamId & 0x0F);
387 stream->readMPEGVideoStreamParams(currentStreamAddr, ptr, this);
388 } else if ((streamId & PSMF_AUDIO_STREAM_ID) == PSMF_AUDIO_STREAM_ID) {
389 int type = PSMF_ATRAC_STREAM;
390 int privateStreamId = currentStreamAddr[1];
391 if ((privateStreamId & 0xF0) != 0) {
392 WARN_LOG_REPORT(ME, "Unknown private stream type, assuming PCM: %02x", privateStreamId);
393 type = PSMF_PCM_STREAM;
394 }
395 stream = new PsmfStream(type, privateStreamId & 0x0F);
396 stream->readPrivateAudioStreamParams(currentStreamAddr, this);
397 }
398 if (stream) {
399 currentStreamNum++;
400 streamMap[currentStreamNum] = stream;
401 }
402 }
403
404 // Default to the first stream.
405 currentStreamNum = 0;
406 }
407
~Psmf()408 Psmf::~Psmf() {
409 for (auto it = streamMap.begin(), end = streamMap.end(); it != end; ++it) {
410 delete it->second;
411 }
412 streamMap.clear();
413 }
414
PsmfPlayer(const PsmfPlayerCreateData * data)415 PsmfPlayer::PsmfPlayer(const PsmfPlayerCreateData *data) {
416 videoCodec = -1;
417 videoStreamNum = -1;
418 audioCodec = -1;
419 audioStreamNum = -1;
420 playMode = 0;
421 playSpeed = 1;
422 totalDurationTimestamp = 0;
423 status = PSMF_PLAYER_STATUS_INIT;
424 mediaengine = new MediaEngine();
425 finishThread = nullptr;
426 filehandle = 0;
427 fileoffset = 0;
428 readSize = 0;
429 streamSize = 0;
430 videoStep = 0;
431 warmUp = 0;
432 seekDestTimeStamp = 0;
433
434 psmfPlayerAtracAu.dts =-1;
435 psmfPlayerAtracAu.pts = -1;
436 psmfPlayerAvcAu.dts = -1;
437 psmfPlayerAvcAu.pts = -1;
438
439 displayBuffer = data->buffer.ptr;
440 displayBufferSize = data->bufferSize;
441 playbackThreadPriority = data->threadPriority;
442 }
443
DoState(PointerWrap & p)444 void Psmf::DoState(PointerWrap &p) {
445 auto s = p.Section("Psmf", 1, 3);
446 if (!s)
447 return;
448
449 Do(p, magic);
450 Do(p, version);
451 Do(p, streamOffset);
452 Do(p, streamSize);
453 Do(p, headerOffset);
454 Do(p, streamDataTotalSize);
455 Do(p, presentationStartTime);
456 Do(p, presentationEndTime);
457 Do(p, streamDataNextBlockSize);
458 Do(p, streamDataNextInnerBlockSize);
459 Do(p, numStreams);
460
461 Do(p, currentStreamNum);
462 int legacyStreamNums = 0;
463 Do(p, legacyStreamNums);
464 Do(p, legacyStreamNums);
465
466 Do(p, EPMapOffset);
467 Do(p, EPMapEntriesNum);
468 Do(p, videoWidth);
469 Do(p, videoHeight);
470 Do(p, audioChannels);
471 Do(p, audioFrequency);
472
473 if (s >= 2) {
474 Do(p, EPMap);
475 }
476
477 Do(p, streamMap);
478 if (s >= 3) {
479 Do(p, currentStreamType);
480 Do(p, currentStreamChannel);
481 } else {
482 currentStreamType = -1;
483 currentStreamChannel = -1;
484 auto streamInfo = streamMap.find(currentStreamNum);
485 if (streamInfo != streamMap.end()) {
486 currentStreamType = streamInfo->second->type_;
487 currentStreamChannel = streamInfo->second->channel_;
488 }
489 }
490 }
491
DoState(PointerWrap & p)492 void PsmfPlayer::DoState(PointerWrap &p) {
493 auto s = p.Section("PsmfPlayer", 1, 8);
494 if (!s)
495 return;
496
497 Do(p, videoCodec);
498 Do(p, videoStreamNum);
499 Do(p, audioCodec);
500 Do(p, audioStreamNum);
501 Do(p, playMode);
502 Do(p, playSpeed);
503
504 Do(p, displayBuffer);
505 Do(p, displayBufferSize);
506 Do(p, playbackThreadPriority);
507 int oldMaxAheadTimestamp = 0;
508 Do(p, oldMaxAheadTimestamp);
509 if (s >= 4) {
510 Do(p, totalDurationTimestamp);
511 } else {
512 long oldTimestamp;
513 Do(p, oldTimestamp);
514 totalDurationTimestamp = oldTimestamp;
515 }
516 if (s >= 2) {
517 Do(p, totalVideoStreams);
518 Do(p, totalAudioStreams);
519 Do(p, playerVersion);
520 } else {
521 totalVideoStreams = 1;
522 totalAudioStreams = 1;
523 playerVersion = PSMF_PLAYER_VERSION_FULL;
524 }
525 if (s >= 3) {
526 Do(p, videoStep);
527 } else {
528 videoStep = 0;
529 }
530 if (s >= 4) {
531 Do(p, warmUp);
532 } else {
533 warmUp = 10000;
534 }
535 if (s >= 5) {
536 Do(p, seekDestTimeStamp);
537 } else {
538 seekDestTimeStamp = 0;
539 }
540 DoClass(p, mediaengine);
541 Do(p, filehandle);
542 Do(p, fileoffset);
543 Do(p, readSize);
544 Do(p, streamSize);
545
546 Do(p, status);
547 if (s >= 4) {
548 Do(p, psmfPlayerAtracAu);
549 }
550 Do(p, psmfPlayerAvcAu);
551 if (s >= 7) {
552 bool hasFinishThread = finishThread != nullptr;
553 Do(p, hasFinishThread);
554 if (hasFinishThread) {
555 Do(p, finishThread);
556 } else {
557 if (finishThread)
558 finishThread->Forget();
559 delete finishThread;
560 finishThread = nullptr;
561 }
562 } else if (s >= 6) {
563 Do(p, finishThread);
564 } else {
565 if (finishThread)
566 finishThread->Forget();
567 delete finishThread;
568 finishThread = nullptr;
569 }
570
571 if (s >= 8) {
572 Do(p, videoWidth);
573 Do(p, videoHeight);
574 }
575 }
576
setStreamNum(u32 psmfStruct,int num,bool updateCached)577 bool Psmf::setStreamNum(u32 psmfStruct, int num, bool updateCached) {
578 auto data = PSPPointer<PsmfData>::Create(psmfStruct);
579 currentStreamNum = num;
580 data->streamNum = num;
581
582 // One of the functions can set this to invalid without invalidating these values.
583 if (updateCached) {
584 currentStreamType = -1;
585 currentStreamChannel = -1;
586 }
587 if (!isValidCurrentStreamNumber())
588 return false;
589 PsmfStreamMap::iterator iter = streamMap.find(currentStreamNum);
590 if (iter == streamMap.end())
591 return false;
592
593 // This information seems to only be for the scePsmf lookups.
594 currentStreamType = iter->second->type_;
595 currentStreamChannel = iter->second->channel_;
596 return true;
597 }
598
setStreamWithType(u32 psmfStruct,int type,int channel)599 bool Psmf::setStreamWithType(u32 psmfStruct, int type, int channel) {
600 for (auto iter : streamMap) {
601 // Note: this does NOT support PSMF_AUDIO_STREAM.
602 if (iter.second->type_ == type && iter.second->channel_ == channel) {
603 return setStreamNum(psmfStruct, iter.first);
604 }
605 }
606 return false;
607 }
608
setStreamWithTypeNumber(u32 psmfStruct,int type,int n)609 bool Psmf::setStreamWithTypeNumber(u32 psmfStruct, int type, int n) {
610 for (auto iter : streamMap) {
611 if (iter.second->matchesType(type)) {
612 if (n != 0) {
613 // Keep counting...
614 n--;
615 continue;
616 }
617 // Okay, this is the one.
618 return setStreamNum(psmfStruct, iter.first);
619 }
620 }
621 return false;
622 }
623
FindEPWithTimestamp(int pts) const624 int Psmf::FindEPWithTimestamp(int pts) const {
625 int best = -1;
626 int bestPts = 0;
627
628 for (int i = 0; i < (int)EPMap.size(); ++i) {
629 const int matchPts = EPMap[i].EPPts;
630 if (matchPts == pts) {
631 // Exact match, take it.
632 return i;
633 }
634 // TODO: Does it actually do fuzzy matching?
635 if (matchPts < pts && matchPts >= bestPts) {
636 best = i;
637 bestPts = matchPts;
638 }
639 }
640
641 return best;
642 }
643
644
645 static std::map<u32, Psmf *> psmfMap;
646 static std::map<u32, PsmfPlayer *> psmfPlayerMap;
647
getPsmf(u32 psmf)648 static Psmf *getPsmf(u32 psmf) {
649 auto psmfstruct = PSPPointer<PsmfData>::Create(psmf);
650 if (!psmfstruct.IsValid())
651 return nullptr;
652
653 auto iter = psmfMap.find(psmfstruct->headerOffset);
654 if (iter != psmfMap.end()) {
655 // TODO: Migrate to only using PSP RAM.
656 // Each instance can have its own selected stream. This is important.
657 iter->second->currentStreamNum = psmfstruct->streamNum;
658 return iter->second;
659 } else {
660 return nullptr;
661 }
662 }
663
getPsmfPlayer(u32 psmfplayer)664 static PsmfPlayer *getPsmfPlayer(u32 psmfplayer)
665 {
666 auto iter = psmfPlayerMap.find(Memory::Read_U32(psmfplayer));
667 if (iter != psmfPlayerMap.end())
668 return iter->second;
669 else
670 return 0;
671 }
672
__PsmfPlayerStatusChange(u64 userdata,int cyclesLate)673 static void __PsmfPlayerStatusChange(u64 userdata, int cyclesLate) {
674 PsmfPlayerStatus status = PsmfPlayerStatus(userdata & 0xFFFFFFFF);
675 u32 psmfPlayer = userdata >> 32;
676 PsmfPlayer *player = getPsmfPlayer(psmfPlayer);
677 if (player) {
678 player->status = status;
679 }
680 }
681
__PsmfInit()682 void __PsmfInit() {
683 videoPixelMode = GE_CMODE_32BIT_ABGR8888;
684 videoLoopStatus = PSMF_PLAYER_CONFIG_NO_LOOP;
685 psmfPlayerLibVersion = 0;
686 eventPsmfPlayerStatusChange = CoreTiming::RegisterEvent("PsmfPlayerStatusChange", &__PsmfPlayerStatusChange);
687 }
688
__PsmfPlayerLoadModule(int devkitVersion)689 void __PsmfPlayerLoadModule(int devkitVersion) {
690 psmfPlayerLibVersion = devkitVersion;
691 }
692
__PsmfDoState(PointerWrap & p)693 void __PsmfDoState(PointerWrap &p) {
694 auto s = p.Section("scePsmf", 1);
695 if (!s)
696 return;
697
698 Do(p, psmfMap);
699 }
700
__PsmfPlayerDoState(PointerWrap & p)701 void __PsmfPlayerDoState(PointerWrap &p) {
702 auto s = p.Section("scePsmfPlayer", 1, 3);
703 if (!s)
704 return;
705
706 Do(p, psmfPlayerMap);
707 Do(p, videoPixelMode);
708 Do(p, videoLoopStatus);
709 if (s < 3) {
710 eventPsmfPlayerStatusChange = -1;
711 } else {
712 Do(p, eventPsmfPlayerStatusChange);
713 }
714 CoreTiming::RestoreRegisterEvent(eventPsmfPlayerStatusChange, "PsmfPlayerStatusChangeEvent", &__PsmfPlayerStatusChange);
715 if (s < 2) {
716 // Assume the latest, which is what we were emulating before.
717 psmfPlayerLibVersion = 0x06060010;
718 } else {
719 Do(p, psmfPlayerLibVersion);
720 }
721 }
722
__PsmfShutdown()723 void __PsmfShutdown() {
724 for (auto it = psmfMap.begin(), end = psmfMap.end(); it != end; ++it)
725 delete it->second;
726 for (auto it = psmfPlayerMap.begin(), end = psmfPlayerMap.end(); it != end; ++it)
727 delete it->second;
728 psmfMap.clear();
729 psmfPlayerMap.clear();
730 }
731
DelayPsmfStateChange(u32 psmfPlayer,u32 newState,s64 delayUs)732 static void DelayPsmfStateChange(u32 psmfPlayer, u32 newState, s64 delayUs) {
733 CoreTiming::ScheduleEvent(usToCycles(delayUs), eventPsmfPlayerStatusChange, (u64)psmfPlayer << 32 | newState);
734 }
735
scePsmfSetPsmf(u32 psmfStruct,u32 psmfData)736 static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
737 if (!Memory::IsValidAddress(psmfData) || !Memory::IsValidAddress(psmfData)) {
738 // Crashes on a PSP.
739 return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
740 }
741
742 Psmf *psmf = new Psmf(Memory::GetPointer(psmfData), psmfData);
743 if (psmf->magic != PSMF_MAGIC) {
744 delete psmf;
745 return hleLogError(ME, ERROR_PSMF_INVALID_PSMF, "invalid psmf data");
746 }
747 // Note: devkit 00000000 supports only '0012'(0F), '0013'(1F), and '0014'(2F). 03000310+ supports '0015'(3F.)
748 if (psmf->version == 0) {
749 delete psmf;
750 return hleLogError(ME, ERROR_PSMF_BAD_VERSION, "invalid psmf version");
751 }
752 if (psmf->streamOffset == 0) {
753 delete psmf;
754 return hleLogError(ME, ERROR_PSMF_INVALID_VALUE, "invalid psmf version");
755 }
756
757 // Note: this structure changes between versions.
758 // TODO: These values are not right, but games probably don't read them.
759 PsmfData data = {0};
760 data.version = psmf->version;
761 data.headerSize = 0x800;
762 data.streamSize = psmf->streamSize;
763 // This should be and needs to be the current stream.
764 data.streamNum = psmf->currentStreamNum;
765 data.headerOffset = psmf->headerOffset;
766 Memory::WriteStruct(psmfStruct, &data);
767
768 // Because the Psmf struct is sometimes copied, we use a value inside as an id.
769 auto iter = psmfMap.find(data.headerOffset);
770 if (iter != psmfMap.end())
771 delete iter->second;
772 psmfMap[data.headerOffset] = psmf;
773
774 return hleLogSuccessI(ME, 0);
775 }
776
scePsmfGetNumberOfStreams(u32 psmfStruct)777 static u32 scePsmfGetNumberOfStreams(u32 psmfStruct) {
778 Psmf *psmf = getPsmf(psmfStruct);
779 if (!psmf) {
780 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
781 }
782 return hleLogSuccessI(ME, psmf->numStreams);
783 }
784
scePsmfGetNumberOfSpecificStreams(u32 psmfStruct,int streamType)785 static u32 scePsmfGetNumberOfSpecificStreams(u32 psmfStruct, int streamType) {
786 Psmf *psmf = getPsmf(psmfStruct);
787 if (!psmf) {
788 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
789 }
790
791 int streamNum = 0;
792 for (auto it : psmf->streamMap) {
793 if (it.second->matchesType(streamType)) {
794 streamNum++;
795 }
796 }
797
798 return hleLogSuccessI(ME, streamNum);
799 }
800
scePsmfSpecifyStreamWithStreamType(u32 psmfStruct,u32 streamType,u32 channel)801 static u32 scePsmfSpecifyStreamWithStreamType(u32 psmfStruct, u32 streamType, u32 channel) {
802 Psmf *psmf = getPsmf(psmfStruct);
803 if (!psmf) {
804 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
805 }
806 if (!psmf->setStreamWithType(psmfStruct, streamType, channel)) {
807 // An invalid type seems to make the stream number invalid, but retain the old type/channel.
808 psmf->setStreamNum(psmfStruct, ERROR_PSMF_INVALID_ID, false);
809 // Also, returns 0 even when no stream found.
810 return hleLogWarning(ME, 0, "no stream found");
811 }
812 return hleLogSuccessI(ME, 0);
813 }
814
scePsmfSpecifyStreamWithStreamTypeNumber(u32 psmfStruct,u32 streamType,u32 typeNum)815 static u32 scePsmfSpecifyStreamWithStreamTypeNumber(u32 psmfStruct, u32 streamType, u32 typeNum) {
816 Psmf *psmf = getPsmf(psmfStruct);
817 if (!psmf) {
818 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
819 }
820 if (!psmf->setStreamWithTypeNumber(psmfStruct, streamType, typeNum)) {
821 // Don't update stream, just bail out.
822 return hleLogWarning(ME, ERROR_PSMF_INVALID_ID, "no stream found");
823 }
824 return hleLogSuccessI(ME, 0);
825 }
826
scePsmfSpecifyStream(u32 psmfStruct,int streamNum)827 static u32 scePsmfSpecifyStream(u32 psmfStruct, int streamNum) {
828 Psmf *psmf = getPsmf(psmfStruct);
829 if (!psmf) {
830 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
831 }
832 if (!psmf->setStreamNum(psmfStruct, streamNum)) {
833 psmf->setStreamNum(psmfStruct, ERROR_PSMF_NOT_INITIALIZED);
834 return hleLogWarning(ME, ERROR_PSMF_INVALID_ID, "bad stream id");
835 }
836 return hleLogSuccessI(ME, 0);
837 }
838
scePsmfGetVideoInfo(u32 psmfStruct,u32 videoInfoAddr)839 static u32 scePsmfGetVideoInfo(u32 psmfStruct, u32 videoInfoAddr) {
840 Psmf *psmf = getPsmf(psmfStruct);
841 if (!psmf) {
842 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
843 } else if (!psmf->isValidCurrentStreamNumber()) {
844 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected");
845 } else if (!Memory::IsValidRange(videoInfoAddr, 8)) {
846 // Would crash.
847 return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
848 }
849
850 auto info = psmf->streamMap[psmf->currentStreamNum];
851 if (info->videoWidth_ == PsmfStream::INVALID) {
852 return hleLogError(ME, ERROR_PSMF_INVALID_ID, "not a video stream");
853 }
854 Memory::Write_U32(info->videoWidth_ == PsmfStream::USE_PSMF ? psmf->videoWidth : info->videoWidth_, videoInfoAddr);
855 Memory::Write_U32(info->videoHeight_ == PsmfStream::USE_PSMF ? psmf->videoHeight : info->videoHeight_, videoInfoAddr + 4);
856 return hleLogSuccessI(ME, 0);
857 }
858
scePsmfGetAudioInfo(u32 psmfStruct,u32 audioInfoAddr)859 static u32 scePsmfGetAudioInfo(u32 psmfStruct, u32 audioInfoAddr) {
860 Psmf *psmf = getPsmf(psmfStruct);
861 if (!psmf) {
862 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
863 } else if (!psmf->isValidCurrentStreamNumber()) {
864 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid stream selected");
865 } else if (!Memory::IsValidRange(audioInfoAddr, 8)) {
866 // Would crash.
867 return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
868 }
869
870 auto info = psmf->streamMap[psmf->currentStreamNum];
871 if (info->audioChannels_ == PsmfStream::INVALID) {
872 return hleLogError(ME, ERROR_PSMF_INVALID_ID, "not an audio stream");
873 }
874 Memory::Write_U32(info->audioChannels_ == PsmfStream::USE_PSMF ? psmf->audioChannels : info->audioChannels_, audioInfoAddr);
875 Memory::Write_U32(info->audioFrequency_ == PsmfStream::USE_PSMF ? psmf->audioFrequency : info->audioFrequency_, audioInfoAddr + 4);
876 return hleLogSuccessI(ME, 0);
877 }
878
scePsmfGetCurrentStreamType(u32 psmfStruct,u32 typeAddr,u32 channelAddr)879 static u32 scePsmfGetCurrentStreamType(u32 psmfStruct, u32 typeAddr, u32 channelAddr) {
880 Psmf *psmf = getPsmf(psmfStruct);
881 if (!psmf) {
882 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
883 }
884 if (psmf->currentStreamNum == (int)ERROR_PSMF_NOT_INITIALIZED) {
885 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "no stream set");
886 }
887 if (!Memory::IsValidAddress(typeAddr) || !Memory::IsValidAddress(channelAddr)) {
888 return hleLogError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointers");
889 }
890 if (psmf->currentStreamType != -1) {
891 Memory::Write_U32(psmf->currentStreamType, typeAddr);
892 Memory::Write_U32(psmf->currentStreamChannel, channelAddr);
893 }
894 return hleLogSuccessI(ME, 0);
895 }
896
scePsmfGetStreamSize(u32 psmfStruct,u32 sizeAddr)897 static u32 scePsmfGetStreamSize(u32 psmfStruct, u32 sizeAddr)
898 {
899 Psmf *psmf = getPsmf(psmfStruct);
900 if (!psmf) {
901 ERROR_LOG(ME, "scePsmfGetStreamSize(%08x, %08x): invalid psmf", psmfStruct, sizeAddr);
902 return ERROR_PSMF_NOT_FOUND;
903 }
904 DEBUG_LOG(ME, "scePsmfGetStreamSize(%08x, %08x)", psmfStruct, sizeAddr);
905 if (Memory::IsValidAddress(sizeAddr)) {
906 Memory::Write_U32(psmf->streamSize, sizeAddr);
907 }
908 return 0;
909 }
910
scePsmfQueryStreamOffset(u32 bufferAddr,u32 offsetAddr)911 static u32 scePsmfQueryStreamOffset(u32 bufferAddr, u32 offsetAddr)
912 {
913 WARN_LOG(ME, "scePsmfQueryStreamOffset(%08x, %08x)", bufferAddr, offsetAddr);
914 if (Memory::IsValidAddress(offsetAddr)) {
915 Memory::Write_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_OFFSET_OFFSET)), offsetAddr);
916 }
917 return 0;
918 }
919
scePsmfQueryStreamSize(u32 bufferAddr,u32 sizeAddr)920 static u32 scePsmfQueryStreamSize(u32 bufferAddr, u32 sizeAddr)
921 {
922 WARN_LOG(ME, "scePsmfQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr);
923 if (Memory::IsValidAddress(sizeAddr)) {
924 Memory::Write_U32(bswap32(Memory::Read_U32(bufferAddr + PSMF_STREAM_SIZE_OFFSET)), sizeAddr);
925 }
926 return 0;
927 }
928
scePsmfGetHeaderSize(u32 psmfStruct,u32 sizeAddr)929 static u32 scePsmfGetHeaderSize(u32 psmfStruct, u32 sizeAddr)
930 {
931 Psmf *psmf = getPsmf(psmfStruct);
932 if (!psmf) {
933 ERROR_LOG(ME, "scePsmfGetHeaderSize(%08x, %08x): invalid psmf", psmfStruct, sizeAddr);
934 return ERROR_PSMF_NOT_FOUND;
935 }
936 DEBUG_LOG(ME, "scePsmfGetHeaderSize(%08x, %08x)", psmfStruct, sizeAddr);
937 if (Memory::IsValidAddress(sizeAddr)) {
938 Memory::Write_U32(psmf->headerSize, sizeAddr);
939 }
940 return 0;
941 }
942
scePsmfGetPsmfVersion(u32 psmfStruct)943 static u32 scePsmfGetPsmfVersion(u32 psmfStruct)
944 {
945 Psmf *psmf = getPsmf(psmfStruct);
946 if (!psmf) {
947 ERROR_LOG(ME, "scePsmfGetPsmfVersion(%08x): invalid psmf", psmfStruct);
948 return ERROR_PSMF_NOT_FOUND;
949 }
950 DEBUG_LOG(ME, "scePsmfGetPsmfVersion(%08x)", psmfStruct);
951 return psmf->version;
952 }
953
scePsmfVerifyPsmf(u32 psmfAddr)954 static u32 scePsmfVerifyPsmf(u32 psmfAddr)
955 {
956 u32 magic = Memory::Read_U32(psmfAddr);
957 if (magic != PSMF_MAGIC) {
958 ERROR_LOG(ME, "scePsmfVerifyPsmf(%08x): bad magic %08x", psmfAddr, magic);
959 return ERROR_PSMF_NOT_FOUND;
960 }
961 int version = Memory::Read_U32(psmfAddr + PSMF_STREAM_VERSION_OFFSET);
962 if (version < 0) {
963 ERROR_LOG(ME, "scePsmfVerifyPsmf(%08x): bad version %08x", psmfAddr, version);
964 return ERROR_PSMF_NOT_FOUND;
965 }
966 // Kurohyou 2 (at least the demo) uses an uninitialized value that happens to be zero on the PSP.
967 // It appears to be written by scePsmfVerifyPsmf(), so we write some bytes into the stack here.
968 Memory::Memset(currentMIPS->r[MIPS_REG_SP] - 0x20, 0, 0x20, "PsmfStack");
969 DEBUG_LOG(ME, "scePsmfVerifyPsmf(%08x)", psmfAddr);
970 return 0;
971 }
972
scePsmfGetNumberOfEPentries(u32 psmfStruct)973 static u32 scePsmfGetNumberOfEPentries(u32 psmfStruct)
974 {
975 Psmf *psmf = getPsmf(psmfStruct);
976 if (!psmf) {
977 ERROR_LOG(ME, "scePsmfGetNumberOfEPentries(%08x): invalid psmf", psmfStruct);
978 return ERROR_PSMF_NOT_FOUND;
979 }
980 DEBUG_LOG(ME, "scePsmfGetNumberOfEPentries(%08x)", psmfStruct);
981 return psmf->EPMapEntriesNum;
982 }
983
scePsmfGetPresentationStartTime(u32 psmfStruct,u32 startTimeAddr)984 static u32 scePsmfGetPresentationStartTime(u32 psmfStruct, u32 startTimeAddr)
985 {
986 Psmf *psmf = getPsmf(psmfStruct);
987 if (!psmf) {
988 ERROR_LOG(ME, "scePsmfGetPresentationStartTime(%08x, %08x): invalid psmf", psmfStruct, startTimeAddr);
989 return ERROR_PSMF_NOT_FOUND;
990 }
991 DEBUG_LOG(ME, "scePsmfGetPresentationStartTime(%08x, %08x)", psmfStruct, startTimeAddr);
992 if (Memory::IsValidAddress(startTimeAddr)) {
993 Memory::Write_U32(psmf->presentationStartTime, startTimeAddr);
994 }
995 return 0;
996 }
997
scePsmfGetPresentationEndTime(u32 psmfStruct,u32 endTimeAddr)998 static u32 scePsmfGetPresentationEndTime(u32 psmfStruct, u32 endTimeAddr)
999 {
1000 Psmf *psmf = getPsmf(psmfStruct);
1001 if (!psmf) {
1002 ERROR_LOG(ME, "scePsmfGetPresentationEndTime(%08x, %08x): invalid psmf", psmfStruct, endTimeAddr);
1003 return ERROR_PSMF_NOT_FOUND;
1004 }
1005 DEBUG_LOG(ME, "scePsmfGetPresentationEndTime(%08x, %08x)", psmfStruct, endTimeAddr);
1006 if (Memory::IsValidAddress(endTimeAddr)) {
1007 Memory::Write_U32(psmf->presentationEndTime, endTimeAddr);
1008 }
1009 return 0;
1010 }
1011
scePsmfGetCurrentStreamNumber(u32 psmfStruct)1012 static u32 scePsmfGetCurrentStreamNumber(u32 psmfStruct) {
1013 Psmf *psmf = getPsmf(psmfStruct);
1014 if (!psmf) {
1015 return hleLogError(ME, ERROR_PSMF_NOT_INITIALIZED, "invalid psmf");
1016 }
1017 if (psmf->currentStreamNum < 0) {
1018 return hleLogError(ME, psmf->currentStreamNum, "invalid stream");
1019 }
1020 return hleLogSuccessI(ME, psmf->currentStreamNum);
1021 }
1022
scePsmfCheckEPMap(u32 psmfStruct)1023 static u32 scePsmfCheckEPMap(u32 psmfStruct)
1024 {
1025 Psmf *psmf = getPsmf(psmfStruct);
1026 if (!psmf) {
1027 ERROR_LOG(ME, "scePsmfCheckEPMap(%08x): invalid psmf", psmfStruct);
1028 return ERROR_PSMF_NOT_FOUND;
1029 }
1030
1031 DEBUG_LOG(ME, "scePsmfCheckEPMap(%08x)", psmfStruct);
1032 return psmf->EPMap.empty() ? ERROR_PSMF_NOT_FOUND : 0;
1033 }
1034
scePsmfGetEPWithId(u32 psmfStruct,int epid,u32 entryAddr)1035 static u32 scePsmfGetEPWithId(u32 psmfStruct, int epid, u32 entryAddr)
1036 {
1037 Psmf *psmf = getPsmf(psmfStruct);
1038 if (!psmf) {
1039 ERROR_LOG(ME, "scePsmfGetEPWithId(%08x, %i, %08x): invalid psmf", psmfStruct, epid, entryAddr);
1040 return ERROR_PSMF_NOT_INITIALIZED;
1041 }
1042 DEBUG_LOG(ME, "scePsmfGetEPWithId(%08x, %i, %08x)", psmfStruct, epid, entryAddr);
1043
1044 if (epid < 0 || epid >= (int)psmf->EPMap.size()) {
1045 ERROR_LOG(ME, "scePsmfGetEPWithId(%08x, %i): invalid id", psmfStruct, epid);
1046 return ERROR_PSMF_NOT_FOUND;
1047 }
1048 if (Memory::IsValidAddress(entryAddr)) {
1049 Memory::WriteStruct(entryAddr, &psmf->EPMap[epid]);
1050 }
1051 return 0;
1052 }
1053
scePsmfGetEPWithTimestamp(u32 psmfStruct,u32 ts,u32 entryAddr)1054 static u32 scePsmfGetEPWithTimestamp(u32 psmfStruct, u32 ts, u32 entryAddr)
1055 {
1056 Psmf *psmf = getPsmf(psmfStruct);
1057 if (!psmf) {
1058 ERROR_LOG(ME, "scePsmfGetEPWithTimestamp(%08x, %i, %08x): invalid psmf", psmfStruct, ts, entryAddr);
1059 return ERROR_PSMF_NOT_INITIALIZED;
1060 }
1061 DEBUG_LOG(ME, "scePsmfGetEPWithTimestamp(%08x, %i, %08x)", psmfStruct, ts, entryAddr);
1062
1063 if (ts < psmf->presentationStartTime) {
1064 ERROR_LOG(ME, "scePsmfGetEPWithTimestamp(%08x, %i): invalid timestamp", psmfStruct, ts);
1065 return ERROR_PSMF_NOT_FOUND;
1066 }
1067
1068 int epid = psmf->FindEPWithTimestamp(ts);
1069 if (epid < 0 || epid >= (int)psmf->EPMap.size()) {
1070 ERROR_LOG(ME, "scePsmfGetEPWithTimestamp(%08x, %i): invalid id", psmfStruct, epid);
1071 return ERROR_PSMF_NOT_FOUND;
1072 }
1073
1074 if (Memory::IsValidAddress(entryAddr)) {
1075 Memory::WriteStruct(entryAddr, &psmf->EPMap[epid]);
1076 }
1077 return 0;
1078 }
1079
scePsmfGetEPidWithTimestamp(u32 psmfStruct,u32 ts)1080 static u32 scePsmfGetEPidWithTimestamp(u32 psmfStruct, u32 ts)
1081 {
1082 Psmf *psmf = getPsmf(psmfStruct);
1083 if (!psmf) {
1084 ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid psmf", psmfStruct, ts);
1085 return ERROR_PSMF_NOT_FOUND;
1086 }
1087 DEBUG_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i)", psmfStruct, ts);
1088
1089 if (psmf->EPMap.empty()) {
1090 ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x): EPMap is empty", psmfStruct);
1091 return ERROR_PSMF_NOT_FOUND;
1092 }
1093
1094 if (ts < psmf->presentationStartTime) {
1095 ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid timestamp", psmfStruct, ts);
1096 return ERROR_PSMF_INVALID_TIMESTAMP;
1097 }
1098
1099 int epid = psmf->FindEPWithTimestamp(ts);
1100 if (epid < 0 || epid >= (int)psmf->EPMap.size()) {
1101 ERROR_LOG(ME, "scePsmfGetEPidWithTimestamp(%08x, %i): invalid id", psmfStruct, epid);
1102 return ERROR_PSMF_INVALID_ID;
1103 }
1104
1105 return epid;
1106 }
1107
scePsmfPlayerCreate(u32 psmfPlayer,u32 dataPtr)1108 static int scePsmfPlayerCreate(u32 psmfPlayer, u32 dataPtr) {
1109 auto player = PSPPointer<u32_le>::Create(psmfPlayer);
1110 const auto data = PSPPointer<const PsmfPlayerCreateData>::Create(dataPtr);
1111
1112 if (!player.IsValid() || !data.IsValid()) {
1113 // Crashes on a PSP.
1114 return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad pointers");
1115 }
1116 if (!data->buffer.IsValid()) {
1117 // Also crashes on a PSP.
1118 *player = 0;
1119 return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "invalid buffer address %08x", data->buffer.ptr);
1120 }
1121 if (data->bufferSize < 0x00285800) {
1122 *player = 0;
1123 return hleReportError(ME, ERROR_PSMFPLAYER_BUFFER_SIZE, "buffer too small %08x", data->bufferSize);
1124 }
1125 if (data->threadPriority < 0x10 || data->threadPriority >= 0x6E) {
1126 *player = 0;
1127 return hleReportError(ME, ERROR_PSMFPLAYER_INVALID_PARAM, "bad thread priority %02x", data->threadPriority);
1128 }
1129 if (!psmfPlayerMap.empty()) {
1130 *player = 0;
1131 return hleReportError(ME, ERROR_MPEG_ALREADY_INIT, "already have an active player");
1132 }
1133
1134 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1135 if (!psmfplayer) {
1136 psmfplayer = new PsmfPlayer(data);
1137 if (psmfPlayerMap.find(psmfPlayer) != psmfPlayerMap.end())
1138 delete psmfPlayerMap[psmfPlayer];
1139 psmfPlayerMap[psmfPlayer] = psmfplayer;
1140
1141 // Write something there to identify it with.
1142 *player = psmfPlayer;
1143 }
1144
1145 // These really shouldn't be globals. But, you can only have one psmfplayer anyway.
1146 videoPixelMode = GE_CMODE_32BIT_ABGR8888;
1147 videoLoopStatus = PSMF_PLAYER_CONFIG_NO_LOOP;
1148
1149 int delayUs = 20000;
1150 DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_INIT, delayUs);
1151 return hleLogSuccessInfoI(ME, hleDelayResult(0, "player create", delayUs));
1152 }
1153
scePsmfPlayerStop(u32 psmfPlayer)1154 static int scePsmfPlayerStop(u32 psmfPlayer) {
1155 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1156 if (!psmfplayer) {
1157 return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player");
1158 }
1159 if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) {
1160 return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "not yet playing");
1161 }
1162 psmfplayer->AbortFinish();
1163
1164 int delayUs = 3000;
1165 DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_STANDBY, delayUs);
1166 return hleLogSuccessInfoI(ME, hleDelayResult(0, "psmfplayer stop", delayUs));
1167 }
1168
scePsmfPlayerBreak(u32 psmfPlayer)1169 static int scePsmfPlayerBreak(u32 psmfPlayer) {
1170 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1171 if (!psmfplayer) {
1172 return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player", psmfPlayer);
1173 }
1174
1175 psmfplayer->AbortFinish();
1176
1177 return hleLogWarning(ME, 0);
1178 }
1179
_PsmfPlayerFillRingbuffer(PsmfPlayer * psmfplayer)1180 static int _PsmfPlayerFillRingbuffer(PsmfPlayer *psmfplayer) {
1181 if (psmfplayer->filehandle <= 0)
1182 return -1;
1183 u8* buf = psmfplayer->tempbuf;
1184 int tempbufSize = (int)sizeof(psmfplayer->tempbuf);
1185 int size;
1186 // Let's not burn a bunch of time adding data all at once.
1187 int addMax = std::max(2048 * 100, tempbufSize);
1188 do {
1189 size = std::min(psmfplayer->mediaengine->getRemainSize(), tempbufSize);
1190 size = std::min(psmfplayer->mediaengine->getAudioRemainSize(), size);
1191 size = std::min(psmfplayer->streamSize - psmfplayer->readSize, size);
1192 if (size <= 0)
1193 break;
1194 size = (int)pspFileSystem.ReadFile(psmfplayer->filehandle, buf, size);
1195 psmfplayer->readSize += size;
1196 psmfplayer->mediaengine->addStreamData(buf, size);
1197 addMax -= size;
1198 if (addMax <= 0)
1199 break;
1200 } while (size > 0);
1201
1202 if (psmfplayer->readSize >= psmfplayer->streamSize && videoLoopStatus == PSMF_PLAYER_CONFIG_LOOP) {
1203 // Start looping, but only if we've finished.
1204 if (psmfplayer->HasReachedEnd()) {
1205 psmfplayer->readSize = 0;
1206 pspFileSystem.SeekFile(psmfplayer->filehandle, psmfplayer->fileoffset, FILEMOVE_BEGIN);
1207 psmfplayer->mediaengine->reloadStream();
1208 }
1209 }
1210 return 0;
1211 }
1212
_PsmfPlayerSetPsmfOffset(u32 psmfPlayer,const char * filename,int offset,bool docallback)1213 static int _PsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int offset, bool docallback) {
1214 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1215 if (!psmfplayer || psmfplayer->status != PSMF_PLAYER_STATUS_INIT) {
1216 return hleReportError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player or status");
1217 }
1218 if (!filename) {
1219 return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_PARAM, "invalid filename");
1220 }
1221
1222 int delayUs = 1100;
1223
1224 psmfplayer->filehandle = pspFileSystem.OpenFile(filename, (FileAccess) FILEACCESS_READ);
1225 if (psmfplayer->filehandle < 0) {
1226 return hleLogError(ME, hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "psmfplayer set", delayUs), "invalid file data or does not exist");
1227 }
1228
1229 if (offset != 0)
1230 pspFileSystem.SeekFile(psmfplayer->filehandle, offset, FILEMOVE_BEGIN);
1231 u8 *buf = psmfplayer->tempbuf;
1232 int tempbufSize = (int)sizeof(psmfplayer->tempbuf);
1233 int size = (int)pspFileSystem.ReadFile(psmfplayer->filehandle, buf, 2048);
1234 delayUs += 2000;
1235
1236 const u32 magic = *(u32_le *)buf;
1237 if (magic != PSMF_MAGIC) {
1238 // TODO: Let's keep trying as we were before.
1239 ERROR_LOG_REPORT(ME, "scePsmfPlayerSetPsmf*: incorrect PSMF magic (%08x), bad data", magic);
1240 //return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "incorrect PSMF magic (%08x), bad data", magic);
1241 }
1242
1243 // TODO: Merge better with Psmf.
1244 u16 numStreams = *(u16_be *)(buf + 0x80);
1245 if (numStreams > 128) {
1246 return hleReportError(ME, hleDelayResult(SCE_KERNEL_ERROR_ILLEGAL_ARGUMENT, "psmfplayer set", delayUs), "too many streams in PSMF video, bogus data");
1247 }
1248
1249 psmfplayer->totalVideoStreams = 0;
1250 psmfplayer->totalAudioStreams = 0;
1251 psmfplayer->videoWidth = buf[142] * 16;
1252 psmfplayer->videoHeight = buf[143] * 16;
1253
1254 psmfplayer->playerVersion = PSMF_PLAYER_VERSION_FULL;
1255 for (u16 i = 0; i < numStreams; i++) {
1256 const u8 *currentStreamAddr = buf + 0x82 + i * 16;
1257 const int streamId = *currentStreamAddr;
1258 if ((streamId & PSMF_VIDEO_STREAM_ID) == PSMF_VIDEO_STREAM_ID) {
1259 ++psmfplayer->totalVideoStreams;
1260 // If we don't have EP info for /any/ video stream, revert to BASIC.
1261 const u32 epOffset = ReadUnalignedU32BE(currentStreamAddr + 4);
1262 const u32 epEntries = ReadUnalignedU32BE(currentStreamAddr + 8);
1263 // TODO: Actually, if these don't match, it seems to be an invalid PSMF.
1264 if (epOffset == 0 || epEntries == 0) {
1265 psmfplayer->playerVersion = PSMF_PLAYER_VERSION_BASIC;
1266 }
1267 } else if ((streamId & PSMF_AUDIO_STREAM_ID) == PSMF_AUDIO_STREAM_ID) {
1268 ++psmfplayer->totalAudioStreams;
1269 } else {
1270 WARN_LOG_REPORT(ME, "scePsmfPlayerSetPsmf*: unexpected streamID %x", streamId);
1271 }
1272 }
1273 // TODO: It seems like it's invalid if there's not at least 1 video stream.
1274
1275 int mpegoffset = *(s32_be *)(buf + PSMF_STREAM_OFFSET_OFFSET);
1276 psmfplayer->readSize = size - mpegoffset;
1277 if (psmfPlayerLibVersion >= 0x05050010) {
1278 psmfplayer->streamSize = *(s32_be *)(buf + PSMF_STREAM_SIZE_OFFSET);
1279 } else {
1280 // Older versions just read until the end of the file.
1281 PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
1282 psmfplayer->streamSize = info.size - offset - mpegoffset;
1283 }
1284 psmfplayer->fileoffset = offset + mpegoffset;
1285 psmfplayer->mediaengine->loadStream(buf, 2048, std::max(2048 * 500, tempbufSize));
1286 _PsmfPlayerFillRingbuffer(psmfplayer);
1287 psmfplayer->totalDurationTimestamp = psmfplayer->mediaengine->getLastTimeStamp();
1288
1289 DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_STANDBY, delayUs);
1290 return hleLogSuccessInfoI(ME, hleDelayResult(0, "psmfplayer set", delayUs));
1291 }
1292
scePsmfPlayerSetPsmf(u32 psmfPlayer,const char * filename)1293 static int scePsmfPlayerSetPsmf(u32 psmfPlayer, const char *filename) {
1294 return _PsmfPlayerSetPsmfOffset(psmfPlayer, filename, 0, false);
1295 }
1296
scePsmfPlayerSetPsmfCB(u32 psmfPlayer,const char * filename)1297 static int scePsmfPlayerSetPsmfCB(u32 psmfPlayer, const char *filename) {
1298 // TODO: hleCheckCurrentCallbacks?
1299 return _PsmfPlayerSetPsmfOffset(psmfPlayer, filename, 0, true);
1300 }
1301
scePsmfPlayerSetPsmfOffset(u32 psmfPlayer,const char * filename,int offset)1302 static int scePsmfPlayerSetPsmfOffset(u32 psmfPlayer, const char *filename, int offset) {
1303 return _PsmfPlayerSetPsmfOffset(psmfPlayer, filename, offset, false);
1304 }
1305
scePsmfPlayerSetPsmfOffsetCB(u32 psmfPlayer,const char * filename,int offset)1306 static int scePsmfPlayerSetPsmfOffsetCB(u32 psmfPlayer, const char *filename, int offset) {
1307 // TODO: hleCheckCurrentCallbacks?
1308 return _PsmfPlayerSetPsmfOffset(psmfPlayer, filename, offset, true);
1309 }
1310
scePsmfPlayerGetAudioOutSize(u32 psmfPlayer)1311 static int scePsmfPlayerGetAudioOutSize(u32 psmfPlayer) {
1312 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1313 if (!psmfplayer) {
1314 return hleLogError(ME, ERROR_PSMFPLAYER_INVALID_STATUS, "invalid psmf player");
1315 }
1316 return hleLogWarning(ME, audioSamplesBytes);
1317 }
1318
__PsmfPlayerContinueSeek(PsmfPlayer * psmfplayer,int tries=50)1319 static bool __PsmfPlayerContinueSeek(PsmfPlayer *psmfplayer, int tries = 50) {
1320 if (psmfplayer->seekDestTimeStamp <= 0) {
1321 return true;
1322 }
1323
1324 while (!psmfplayer->mediaengine->seekTo(psmfplayer->seekDestTimeStamp, videoPixelMode)) {
1325 if (--tries <= 0) {
1326 return false;
1327 }
1328 _PsmfPlayerFillRingbuffer(psmfplayer);
1329 if (psmfplayer->mediaengine->IsVideoEnd()) {
1330 break;
1331 }
1332 }
1333
1334 // Seek is done, so forget about it.
1335 psmfplayer->seekDestTimeStamp = 0;
1336 return true;
1337 }
1338
scePsmfPlayerStart(u32 psmfPlayer,u32 psmfPlayerData,int initPts)1339 static int scePsmfPlayerStart(u32 psmfPlayer, u32 psmfPlayerData, int initPts)
1340 {
1341 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1342 if (!psmfplayer) {
1343 ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid psmf player", psmfPlayer, psmfPlayerData, initPts);
1344 return ERROR_PSMFPLAYER_INVALID_STATUS;
1345 }
1346 if (psmfplayer->status == PSMF_PLAYER_STATUS_INIT) {
1347 ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): psmf not yet set", psmfPlayer, psmfPlayerData, initPts);
1348 return ERROR_PSMFPLAYER_INVALID_STATUS;
1349 }
1350
1351 auto playerData = PSPPointer<PsmfPlayerData>::Create(psmfPlayerData);
1352 if (!playerData.IsValid()) {
1353 // Crashes on a PSP.
1354 ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): bad data address", psmfPlayer, psmfPlayerData, initPts);
1355 return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
1356 }
1357 if (playerData->playMode < 0 || playerData->playMode > (int)PSMF_PLAYER_MODE_REWIND) {
1358 ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid mode", psmfPlayer, psmfPlayerData, initPts);
1359 return ERROR_PSMFPLAYER_INVALID_PARAM;
1360 }
1361 if (initPts >= psmfplayer->mediaengine->getLastTimeStamp()) {
1362 ERROR_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d): pts is outside video", psmfPlayer, psmfPlayerData, initPts);
1363 return ERROR_PSMFPLAYER_INVALID_PARAM;
1364 }
1365
1366 if (psmfplayer->totalAudioStreams > 0) {
1367 if (playerData->audioCodec != 0x0F && playerData->audioCodec != 0x01) {
1368 ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid audio codec %02x", psmfPlayer, psmfPlayerData, initPts, playerData->audioCodec);
1369 return ERROR_PSMFPLAYER_INVALID_STREAM;
1370 }
1371 if (playerData->audioStreamNum >= psmfplayer->totalAudioStreams) {
1372 ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to change audio stream to %d", psmfPlayer, psmfPlayerData, initPts, playerData->audioStreamNum);
1373 return ERROR_PSMFPLAYER_INVALID_CONFIG;
1374 }
1375 }
1376 if (playerData->videoCodec != 0x0E && playerData->videoCodec != 0x00) {
1377 ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): invalid video codec %02x", psmfPlayer, psmfPlayerData, initPts, playerData->videoCodec);
1378 return ERROR_PSMFPLAYER_INVALID_STREAM;
1379 }
1380 if (playerData->videoStreamNum < 0 || playerData->videoStreamNum >= psmfplayer->totalVideoStreams) {
1381 ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to change video stream to %d", psmfPlayer, psmfPlayerData, initPts, playerData->videoStreamNum);
1382 return ERROR_PSMFPLAYER_INVALID_CONFIG;
1383 }
1384
1385 switch ((PsmfPlayerMode)(s32)playerData->playMode) {
1386 case PSMF_PLAYER_MODE_FORWARD:
1387 case PSMF_PLAYER_MODE_REWIND:
1388 if (psmfplayer->playerVersion == PSMF_PLAYER_VERSION_BASIC) {
1389 WARN_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): no EP data for FORWARD/REWIND", psmfPlayer, psmfPlayerData, initPts);
1390 return ERROR_PSMFPLAYER_INVALID_PARAM;
1391 }
1392 WARN_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unsupported playMode", psmfPlayer, psmfPlayerData, initPts);
1393 break;
1394
1395 case PSMF_PLAYER_MODE_PLAY:
1396 case PSMF_PLAYER_MODE_PAUSE:
1397 break;
1398
1399 default:
1400 WARN_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unsupported playMode", psmfPlayer, psmfPlayerData, initPts);
1401 break;
1402 }
1403
1404 if (psmfplayer->playerVersion == PSMF_PLAYER_VERSION_BASIC && initPts != 0) {
1405 ERROR_LOG_REPORT(ME, "scePsmfPlayerStart(%08x, %08x, %d): unable to seek without EPmap", psmfPlayer, psmfPlayerData, initPts);
1406 return ERROR_PSMFPLAYER_INVALID_PARAM;
1407 }
1408
1409 psmfplayer->AbortFinish();
1410 psmfplayer->mediaengine->setVideoStream(playerData->videoStreamNum);
1411 psmfplayer->videoCodec = playerData->videoCodec;
1412 psmfplayer->videoStreamNum = playerData->videoStreamNum;
1413 if (psmfplayer->totalAudioStreams > 0) {
1414 psmfplayer->mediaengine->setAudioStream(playerData->audioStreamNum);
1415 psmfplayer->audioCodec = playerData->audioCodec;
1416 psmfplayer->audioStreamNum = playerData->audioStreamNum;
1417 }
1418 psmfplayer->playMode = playerData->playMode;
1419 psmfplayer->playSpeed = playerData->playSpeed;
1420
1421 WARN_LOG(ME, "scePsmfPlayerStart(%08x, %08x, %d,(mode %d, speed %d)", psmfPlayer, psmfPlayerData, initPts, playerData->playMode, playerData->playSpeed);
1422
1423 // Does not alter current pts, it just catches up when Update()/etc. get there.
1424
1425 int delayUs = psmfplayer->status == PSMF_PLAYER_STATUS_PLAYING ? 3000 : 0;
1426 if (delayUs == 0)
1427 psmfplayer->status = PSMF_PLAYER_STATUS_PLAYING;
1428 else
1429 DelayPsmfStateChange(psmfPlayer, PSMF_PLAYER_STATUS_PLAYING, delayUs);
1430 psmfplayer->warmUp = 0;
1431
1432 psmfplayer->mediaengine->openContext();
1433
1434 s64 dist = initPts - psmfplayer->mediaengine->getVideoTimeStamp();
1435 if (dist < 0 || dist > VIDEO_FRAME_DURATION_TS * 60) {
1436 // When seeking backwards, we just start populating the stream from the start.
1437 pspFileSystem.SeekFile(psmfplayer->filehandle, 0, FILEMOVE_BEGIN);
1438
1439 u8 *buf = psmfplayer->tempbuf;
1440 int tempbufSize = (int)sizeof(psmfplayer->tempbuf);
1441 int size = (int)pspFileSystem.ReadFile(psmfplayer->filehandle, buf, tempbufSize);
1442 psmfplayer->mediaengine->loadStream(buf, size, std::max(2048 * 500, tempbufSize));
1443
1444 int mpegoffset = *(s32_be *)(buf + PSMF_STREAM_OFFSET_OFFSET);
1445 psmfplayer->readSize = size - mpegoffset;
1446
1447 Psmf psmf(psmfplayer->tempbuf, 0);
1448
1449 int lastOffset = 0;
1450 for (auto it = psmf.EPMap.begin(), end = psmf.EPMap.end(); it != end; ++it) {
1451 if (initPts <= it->EPPts - (int)psmf.presentationStartTime) {
1452 break;
1453 }
1454 lastOffset = it->EPOffset;
1455 }
1456
1457 psmfplayer->readSize = lastOffset * 2048;
1458 pspFileSystem.SeekFile(psmfplayer->filehandle, psmfplayer->fileoffset + psmfplayer->readSize, FILEMOVE_BEGIN);
1459
1460 _PsmfPlayerFillRingbuffer(psmfplayer);
1461 }
1462
1463 psmfplayer->seekDestTimeStamp = initPts;
1464 __PsmfPlayerContinueSeek(psmfplayer);
1465 return delayUs == 0 ? 0 : hleDelayResult(0, "psmfplayer start", delayUs);
1466 }
1467
scePsmfPlayerDelete(u32 psmfPlayer)1468 static int scePsmfPlayerDelete(u32 psmfPlayer)
1469 {
1470 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1471 if (!psmfplayer) {
1472 ERROR_LOG(ME, "scePsmfPlayerDelete(%08x): invalid psmf player", psmfPlayer);
1473 return ERROR_PSMFPLAYER_INVALID_STATUS;
1474 }
1475
1476 INFO_LOG(ME, "scePsmfPlayerDelete(%08x)", psmfPlayer);
1477 delete psmfplayer;
1478 psmfPlayerMap.erase(Memory::Read_U32(psmfPlayer));
1479 Memory::Write_U32(0, psmfPlayer);
1480
1481 return hleDelayResult(0, "psmfplayer deleted", 20000);
1482 }
1483
scePsmfPlayerUpdate(u32 psmfPlayer)1484 static int scePsmfPlayerUpdate(u32 psmfPlayer)
1485 {
1486 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1487 if (!psmfplayer) {
1488 ERROR_LOG(ME, "scePsmfPlayerUpdate(%08x): invalid psmf player", psmfPlayer);
1489 return ERROR_PSMFPLAYER_INVALID_STATUS;
1490 }
1491 if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) {
1492 ERROR_LOG(ME, "scePsmfPlayerUpdate(%08x): not playing yet", psmfPlayer);
1493 return ERROR_PSMFPLAYER_INVALID_STATUS;
1494 }
1495
1496 DEBUG_LOG(ME, "scePsmfPlayerUpdate(%08x)", psmfPlayer);
1497 if (psmfplayer->HasReachedEnd()) {
1498 if (videoLoopStatus == PSMF_PLAYER_CONFIG_NO_LOOP && psmfplayer->videoStep >= 1) {
1499 if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING_FINISHED) {
1500 psmfplayer->ScheduleFinish(psmfPlayer);
1501 INFO_LOG(ME, "scePsmfPlayerUpdate(%08x): video end scheduled", psmfPlayer);
1502 }
1503 }
1504 }
1505 psmfplayer->videoStep++;
1506
1507 return 0;
1508 }
1509
scePsmfPlayerReleasePsmf(u32 psmfPlayer)1510 static int scePsmfPlayerReleasePsmf(u32 psmfPlayer)
1511 {
1512 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1513 if (!psmfplayer) {
1514 ERROR_LOG(ME, "scePsmfPlayerReleasePsmf(%08x): invalid psmf player", psmfPlayer);
1515 return ERROR_PSMFPLAYER_INVALID_STATUS;
1516 }
1517 if (psmfplayer->status < PSMF_PLAYER_STATUS_STANDBY) {
1518 ERROR_LOG(ME, "scePsmfPlayerReleasePsmf(%08x): not set yet", psmfPlayer);
1519 return ERROR_PSMFPLAYER_INVALID_STATUS;
1520 }
1521
1522 WARN_LOG(ME, "scePsmfPlayerReleasePsmf(%08x)", psmfPlayer);
1523 psmfplayer->status = PSMF_PLAYER_STATUS_INIT;
1524 return 0;
1525 }
1526
__PsmfUpdatePts(PsmfPlayer * psmfplayer,PsmfVideoData * videoData)1527 static void __PsmfUpdatePts(PsmfPlayer *psmfplayer, PsmfVideoData *videoData) {
1528 // getVideoTimestamp() includes the frame duration, remove it for this frame's pts.
1529 psmfplayer->psmfPlayerAvcAu.pts = psmfplayer->mediaengine->getVideoTimeStamp() - VIDEO_FRAME_DURATION_TS;
1530 if (videoData) {
1531 videoData->displaypts = (u32)psmfplayer->psmfPlayerAvcAu.pts;
1532 }
1533 }
1534
scePsmfPlayerGetVideoData(u32 psmfPlayer,u32 videoDataAddr)1535 static int scePsmfPlayerGetVideoData(u32 psmfPlayer, u32 videoDataAddr)
1536 {
1537 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1538 if (!psmfplayer) {
1539 ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid psmf player", psmfPlayer, videoDataAddr);
1540 return ERROR_PSMFPLAYER_INVALID_STATUS;
1541 }
1542 if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) {
1543 ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): psmf not playing", psmfPlayer, videoDataAddr);
1544 return ERROR_PSMFPLAYER_INVALID_STATUS;
1545 }
1546 auto videoData = PSPPointer<PsmfVideoData>::Create(videoDataAddr);
1547 if (!videoData.IsValid()) {
1548 ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid data pointer", psmfPlayer, videoDataAddr);
1549 // Technically just crashes if videoData is not valid.
1550 return SCE_KERNEL_ERROR_INVALID_POINTER;
1551 }
1552 if (videoData->frameWidth < 0) {
1553 ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): illegal bufw %d", psmfPlayer, videoDataAddr, videoData->frameWidth);
1554 return SCE_KERNEL_ERROR_PRIV_REQUIRED;
1555 }
1556 if (videoData->frameWidth != 0 && videoData->frameWidth < psmfplayer->mediaengine->VideoWidth()) {
1557 ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): bufw %d smaller than width %d", psmfPlayer, videoDataAddr, videoData->frameWidth, psmfplayer->mediaengine->VideoWidth());
1558 return SCE_KERNEL_ERROR_INVALID_VALUE;
1559 }
1560
1561 hleEatCycles(20000);
1562
1563 if (!__PsmfPlayerContinueSeek(psmfplayer)) {
1564 DEBUG_LOG(HLE, "scePsmfPlayerGetVideoData(%08x, %08x): still seeking", psmfPlayer, videoDataAddr);
1565 return ERROR_PSMFPLAYER_NO_MORE_DATA;
1566 }
1567
1568 // On a real PSP, this takes a potentially variable amount of time.
1569 // Normally a minimum of 3 without audio, 5 with. But if you don't delay sufficiently between, hundreds.
1570 // It should be okay if we start videos quicker, but some games expect the first couple to fail.
1571 if (psmfplayer->warmUp < PSMF_PLAYER_WARMUP_FRAMES) {
1572 DEBUG_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): warming up", psmfPlayer, videoDataAddr);
1573 ++psmfplayer->warmUp;
1574 return ERROR_PSMFPLAYER_NO_MORE_DATA;
1575 }
1576 // In case we change warm up later, save a high value in savestates - video started.
1577 psmfplayer->warmUp = 10000;
1578
1579 // It's fine to pass an invalid value here if it's still warming up, but after that it's not okay.
1580 if (!Memory::IsValidAddress(videoData->displaybuf)) {
1581 ERROR_LOG(ME, "scePsmfPlayerGetVideoData(%08x, %08x): invalid buffer pointer %08x", psmfPlayer, videoDataAddr, videoData->displaybuf);
1582 return SCE_KERNEL_ERROR_INVALID_POINTER;
1583 }
1584
1585 bool doVideoStep = true;
1586 if (psmfplayer->playMode == PSMF_PLAYER_MODE_PAUSE) {
1587 doVideoStep = false;
1588 } else if (!psmfplayer->mediaengine->IsNoAudioData() && psmfplayer->mediaengine->IsActuallyPlayingAudio()) {
1589 s64 deltapts = psmfplayer->mediaengine->getVideoTimeStamp() - psmfplayer->mediaengine->getAudioTimeStamp();
1590 // Don't skip the very first frame, sometimes audio starts with an early timestamp.
1591 if (deltapts > 0 && psmfplayer->mediaengine->getVideoTimeStamp() > 0) {
1592 // Don't advance, just return the same frame again.
1593 // TODO: This also seems somewhat based on Update() calls, but audio is involved too...
1594 doVideoStep = false;
1595 } else {
1596 // This is an approximation, it should allow a certain amount ahead before skipping frames.
1597 while (deltapts <= -(VIDEO_FRAME_DURATION_TS * 5)) {
1598 psmfplayer->mediaengine->stepVideo(videoPixelMode, true);
1599 deltapts = psmfplayer->mediaengine->getVideoTimeStamp() - psmfplayer->mediaengine->getAudioTimeStamp();
1600 }
1601 }
1602 } else {
1603 // No audio, based on Update() calls. playSpeed doesn't seem to matter?
1604 if (psmfplayer->videoStep <= 1 && psmfplayer->mediaengine->getVideoTimeStamp() > 0) {
1605 doVideoStep = false;
1606 } else {
1607 psmfplayer->videoStep = 0;
1608 }
1609 }
1610
1611 if (doVideoStep) {
1612 psmfplayer->mediaengine->stepVideo(videoPixelMode);
1613 }
1614
1615 // It seems the frameWidth is rounded down to even values, and defaults to 512.
1616 int bufw = videoData->frameWidth == 0 ? 512 : videoData->frameWidth & ~1;
1617 // Always write the video frame, even after the video has ended.
1618 int displaybufSize = psmfplayer->mediaengine->writeVideoImage(videoData->displaybuf, bufw, videoPixelMode);
1619 gpu->NotifyVideoUpload(videoData->displaybuf, displaybufSize, bufw, videoPixelMode);
1620 __PsmfUpdatePts(psmfplayer, videoData);
1621
1622 _PsmfPlayerFillRingbuffer(psmfplayer);
1623
1624 DEBUG_LOG(ME, "%08x=scePsmfPlayerGetVideoData(%08x, %08x)", 0, psmfPlayer, videoDataAddr);
1625 return hleDelayResult(0, "psmfPlayer video decode", 3000);
1626 }
1627
scePsmfPlayerGetAudioData(u32 psmfPlayer,u32 audioDataAddr)1628 static int scePsmfPlayerGetAudioData(u32 psmfPlayer, u32 audioDataAddr)
1629 {
1630 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1631 if (!psmfplayer) {
1632 ERROR_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): invalid psmf player", psmfPlayer, audioDataAddr);
1633 return ERROR_PSMFPLAYER_INVALID_STATUS;
1634 }
1635 if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) {
1636 ERROR_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): not yet playing", psmfPlayer, audioDataAddr);
1637 return ERROR_PSMFPLAYER_INVALID_STATUS;
1638 }
1639 if (!Memory::IsValidAddress(audioDataAddr)) {
1640 ERROR_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): invalid audio pointer", psmfPlayer, audioDataAddr);
1641 return SCE_KERNEL_ERROR_INVALID_POINTER;
1642 }
1643
1644 // Don't return audio frames before we would return video frames.
1645 if (psmfplayer->warmUp < PSMF_PLAYER_WARMUP_FRAMES) {
1646 DEBUG_LOG(ME, "scePsmfPlayerGetAudioData(%08x, %08x): warming up", psmfPlayer, audioDataAddr);
1647 return ERROR_PSMFPLAYER_NO_MORE_DATA;
1648 }
1649
1650 if (psmfplayer->playMode == PSMF_PLAYER_MODE_PAUSE) {
1651 INFO_LOG(HLE, "scePsmfPlayerGetAudioData(%08x): paused mode", psmfPlayer);
1652 return ERROR_PSMFPLAYER_NO_MORE_DATA;
1653 }
1654
1655 int ret = 0;
1656 if (psmfplayer->mediaengine->getAudioSamples(audioDataAddr) == 0) {
1657 if (psmfplayer->totalAudioStreams > 0 && (s64)psmfplayer->psmfPlayerAvcAu.pts < (s64)psmfplayer->totalDurationTimestamp - VIDEO_FRAME_DURATION_TS) {
1658 // Write zeros for any missing trailing frames so it syncs with the video.
1659 Memory::Memset(audioDataAddr, 0, audioSamplesBytes, "PsmfAudioClear");
1660 } else {
1661 ret = (int)ERROR_PSMFPLAYER_NO_MORE_DATA;
1662 }
1663 }
1664
1665 DEBUG_LOG(ME, "%08x=scePsmfPlayerGetAudioData(%08x, %08x)", ret, psmfPlayer, audioDataAddr);
1666 if (ret != 0) {
1667 hleEatCycles(10000);
1668 } else {
1669 hleEatCycles(30000);
1670 }
1671 hleReSchedule("psmfplayer audio decode");
1672 return ret;
1673 }
1674
scePsmfPlayerGetCurrentStatus(u32 psmfPlayer)1675 static int scePsmfPlayerGetCurrentStatus(u32 psmfPlayer)
1676 {
1677 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1678 if (!psmfplayer) {
1679 // Mana Khemia and other games call this even when not necessary.
1680 // It's annoying so the logging is verbose'd out.
1681 VERBOSE_LOG(ME, "scePsmfPlayerGetCurrentStatus(%08x): invalid psmf player", psmfPlayer);
1682 return ERROR_PSMFPLAYER_INVALID_STATUS;
1683 }
1684 if (psmfplayer->status == PSMF_PLAYER_STATUS_NONE) {
1685 ERROR_LOG(ME, "scePsmfPlayerGetCurrentStatus(%08x): not initialized", psmfPlayer);
1686 return ERROR_PSMFPLAYER_INVALID_STATUS;
1687 }
1688
1689 DEBUG_LOG(ME, "%d=scePsmfPlayerGetCurrentStatus(%08x)", psmfplayer->status, psmfPlayer);
1690 return psmfplayer->status;
1691 }
1692
scePsmfPlayerGetCurrentPts(u32 psmfPlayer,u32 currentPtsAddr)1693 static u32 scePsmfPlayerGetCurrentPts(u32 psmfPlayer, u32 currentPtsAddr)
1694 {
1695 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1696 if (!psmfplayer) {
1697 ERROR_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): invalid psmf player", psmfPlayer, currentPtsAddr);
1698 return ERROR_PSMFPLAYER_INVALID_STATUS;
1699 }
1700 if (psmfplayer->status < PSMF_PLAYER_STATUS_STANDBY) {
1701 ERROR_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): not initialized", psmfPlayer, currentPtsAddr);
1702 return ERROR_PSMFPLAYER_INVALID_STATUS;
1703 }
1704 if (psmfplayer->psmfPlayerAvcAu.pts < 0) {
1705 VERBOSE_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x): no frame yet", psmfPlayer, currentPtsAddr);
1706 return ERROR_PSMFPLAYER_NO_MORE_DATA;
1707 }
1708
1709 DEBUG_LOG(ME, "scePsmfPlayerGetCurrentPts(%08x, %08x)", psmfPlayer, currentPtsAddr);
1710 if (Memory::IsValidAddress(currentPtsAddr)) {
1711 Memory::Write_U32(psmfplayer->psmfPlayerAvcAu.pts, currentPtsAddr);
1712 }
1713 return 0;
1714 }
1715
scePsmfPlayerGetPsmfInfo(u32 psmfPlayer,u32 psmfInfoAddr,u32 widthAddr,u32 heightAddr)1716 static u32 scePsmfPlayerGetPsmfInfo(u32 psmfPlayer, u32 psmfInfoAddr, u32 widthAddr, u32 heightAddr) {
1717 auto info = PSPPointer<PsmfInfo>::Create(psmfInfoAddr);
1718 if (!Memory::IsValidAddress(psmfPlayer) || !info.IsValid()) {
1719 ERROR_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x): invalid addresses", psmfPlayer, psmfInfoAddr);
1720 // PSP would crash.
1721 return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
1722 }
1723
1724 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1725 if (!psmfplayer) {
1726 ERROR_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x): invalid psmf player", psmfPlayer, psmfInfoAddr);
1727 return ERROR_PSMFPLAYER_INVALID_STATUS;
1728 }
1729 if (psmfplayer->status < PSMF_PLAYER_STATUS_STANDBY) {
1730 ERROR_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x): psmf not set yet", psmfPlayer);
1731 return ERROR_PSMFPLAYER_INVALID_STATUS;
1732 }
1733
1734 DEBUG_LOG(ME, "scePsmfPlayerGetPsmfInfo(%08x, %08x)", psmfPlayer, psmfInfoAddr);
1735 // The first frame is at 0, so subtract one frame's duration to get the last frame's timestamp.
1736 info->lastFrameTS = psmfplayer->totalDurationTimestamp - VIDEO_FRAME_DURATION_TS;
1737 info->numVideoStreams = psmfplayer->totalVideoStreams;
1738 info->numAudioStreams = psmfplayer->totalAudioStreams;
1739 // pcm stream num?
1740 info->numPCMStreams = 0;
1741 info->playerVersion = psmfplayer->playerVersion;
1742
1743 if (psmfPlayerLibVersion == 0x03090510) {
1744 // LocoRoco 2 depends on these for sizing its video output. Without this, its height is zero
1745 // and nothing is drawn.
1746 // Can't ask mediaengine for width/height here, it's too early, so we grabbed it from the
1747 // header in scePsmfPlayerSetPsmf.
1748 if (Memory::IsValidAddress(widthAddr) && psmfplayer->videoWidth) {
1749 Memory::Write_U32(psmfplayer->videoWidth, widthAddr);
1750 }
1751 if (Memory::IsValidAddress(heightAddr) && psmfplayer->videoHeight) {
1752 Memory::Write_U32(psmfplayer->videoHeight, heightAddr);
1753 }
1754 }
1755 return 0;
1756 }
1757
scePsmfPlayerGetCurrentPlayMode(u32 psmfPlayer,u32 playModeAddr,u32 playSpeedAddr)1758 static u32 scePsmfPlayerGetCurrentPlayMode(u32 psmfPlayer, u32 playModeAddr, u32 playSpeedAddr)
1759 {
1760 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1761 if (!psmfplayer) {
1762 ERROR_LOG(ME, "scePsmfPlayerGetCurrentPlayMode(%08x, %08x, %08x): invalid psmf player", psmfPlayer, playModeAddr, playSpeedAddr);
1763 return ERROR_PSMFPLAYER_INVALID_STATUS;
1764 }
1765
1766 DEBUG_LOG(ME, "scePsmfPlayerGetCurrentPlayMode(%08x, %08x, %08x)", psmfPlayer, playModeAddr, playSpeedAddr);
1767 if (Memory::IsValidAddress(playModeAddr)) {
1768 Memory::Write_U32(psmfplayer->playMode, playModeAddr);
1769 }
1770 if (Memory::IsValidAddress(playSpeedAddr)) {
1771 Memory::Write_U32(psmfplayer->playSpeed, playSpeedAddr);
1772 }
1773 return 0;
1774 }
1775
scePsmfPlayerGetCurrentVideoStream(u32 psmfPlayer,u32 videoCodecAddr,u32 videoStreamNumAddr)1776 static u32 scePsmfPlayerGetCurrentVideoStream(u32 psmfPlayer, u32 videoCodecAddr, u32 videoStreamNumAddr)
1777 {
1778 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1779 if (!psmfplayer) {
1780 ERROR_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x, %08x, %08x): invalid psmf player", psmfPlayer, videoCodecAddr, videoStreamNumAddr);
1781 return ERROR_PSMFPLAYER_INVALID_STATUS;
1782 }
1783 if (psmfplayer->status == PSMF_PLAYER_STATUS_INIT) {
1784 ERROR_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x): psmf not yet set", psmfPlayer);
1785 return ERROR_PSMFPLAYER_INVALID_STATUS;
1786 }
1787
1788 DEBUG_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x, %08x, %08x)", psmfPlayer, videoCodecAddr, videoStreamNumAddr);
1789 if (Memory::IsValidAddress(videoCodecAddr)) {
1790 Memory::Write_U32(psmfplayer->videoCodec == 0x0E ? 0 : psmfplayer->videoCodec, videoCodecAddr);
1791 }
1792 if (Memory::IsValidAddress(videoStreamNumAddr)) {
1793 Memory::Write_U32(psmfplayer->videoStreamNum, videoStreamNumAddr);
1794 }
1795 return 0;
1796 }
1797
scePsmfPlayerGetCurrentAudioStream(u32 psmfPlayer,u32 audioCodecAddr,u32 audioStreamNumAddr)1798 static u32 scePsmfPlayerGetCurrentAudioStream(u32 psmfPlayer, u32 audioCodecAddr, u32 audioStreamNumAddr)
1799 {
1800 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1801 if (!psmfplayer) {
1802 ERROR_LOG(ME, "scePsmfPlayerGetCurrentAudioStream(%08x, %08x, %08x): invalid psmf player", psmfPlayer, audioCodecAddr, audioStreamNumAddr);
1803 return ERROR_PSMFPLAYER_INVALID_STATUS;
1804 }
1805 if (psmfplayer->status == PSMF_PLAYER_STATUS_INIT) {
1806 ERROR_LOG(ME, "scePsmfPlayerGetCurrentVideoStream(%08x): psmf not yet set", psmfPlayer);
1807 return ERROR_PSMFPLAYER_INVALID_STATUS;
1808 }
1809
1810 DEBUG_LOG(ME, "scePsmfPlayerGetCurrentAudioStream(%08x, %08x, %08x)", psmfPlayer, audioCodecAddr, audioStreamNumAddr);
1811 if (Memory::IsValidAddress(audioCodecAddr)) {
1812 Memory::Write_U32(psmfplayer->audioCodec == 0x0F ? 1 : psmfplayer->audioCodec, audioCodecAddr);
1813 }
1814 if (Memory::IsValidAddress(audioStreamNumAddr)) {
1815 Memory::Write_U32(psmfplayer->audioStreamNum, audioStreamNumAddr);
1816 }
1817 return 0;
1818 }
1819
scePsmfPlayerSetTempBuf(u32 psmfPlayer,u32 tempBufAddr,u32 tempBufSize)1820 static int scePsmfPlayerSetTempBuf(u32 psmfPlayer, u32 tempBufAddr, u32 tempBufSize)
1821 {
1822 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1823 if (!psmfplayer) {
1824 ERROR_LOG(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): invalid psmf player", psmfPlayer, tempBufAddr, tempBufSize);
1825 return ERROR_PSMFPLAYER_INVALID_STATUS;
1826 }
1827 if (psmfplayer->status != PSMF_PLAYER_STATUS_INIT) {
1828 ERROR_LOG_REPORT(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): invalid status %x", psmfPlayer, tempBufAddr, tempBufSize, psmfplayer->status);
1829 return ERROR_PSMFPLAYER_INVALID_STATUS;
1830 }
1831 if (tempBufSize < 0x00010000) {
1832 ERROR_LOG_REPORT(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x): buffer too small", psmfPlayer, tempBufAddr, tempBufSize);
1833 return ERROR_PSMFPLAYER_INVALID_PARAM;
1834 }
1835
1836 INFO_LOG(ME, "scePsmfPlayerSetTempBuf(%08x, %08x, %08x)", psmfPlayer, tempBufAddr, tempBufSize);
1837 // fake it right now, use tempbuf from memory directly
1838 //psmfplayer->tempbuf = tempBufAddr;
1839 //psmfplayer->tempbufSize = tempBufSize;
1840
1841 return 0;
1842 }
1843
scePsmfPlayerChangePlayMode(u32 psmfPlayer,int playMode,int playSpeed)1844 static u32 scePsmfPlayerChangePlayMode(u32 psmfPlayer, int playMode, int playSpeed)
1845 {
1846 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1847 if (!psmfplayer) {
1848 ERROR_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): invalid psmf player", psmfPlayer, playMode, playSpeed);
1849 return ERROR_PSMFPLAYER_INVALID_STATUS;
1850 }
1851 if (psmfplayer->status < PSMF_PLAYER_STATUS_PLAYING) {
1852 ERROR_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): not playing yet", psmfPlayer, playMode, playSpeed);
1853 return ERROR_PSMFPLAYER_INVALID_STATUS;
1854 }
1855 if (playMode < 0 || playMode > (int)PSMF_PLAYER_MODE_REWIND) {
1856 ERROR_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): invalid mode", psmfPlayer, playMode, playSpeed);
1857 return ERROR_PSMFPLAYER_INVALID_CONFIG;
1858 }
1859
1860 switch (playMode) {
1861 case PSMF_PLAYER_MODE_FORWARD:
1862 case PSMF_PLAYER_MODE_REWIND:
1863 if (psmfplayer->playerVersion == PSMF_PLAYER_VERSION_BASIC) {
1864 ERROR_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): no EP data for FORWARD/REWIND", psmfPlayer, playMode, playSpeed);
1865 return ERROR_PSMFPLAYER_INVALID_STREAM;
1866 }
1867 psmfplayer->playSpeed = playSpeed;
1868 WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): unsupported playMode", psmfPlayer, playMode, playSpeed);
1869 break;
1870
1871 case PSMF_PLAYER_MODE_PLAY:
1872 case PSMF_PLAYER_MODE_PAUSE:
1873 if (psmfplayer->playSpeed != playSpeed) {
1874 WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): play speed not changed", psmfPlayer, playMode, playSpeed);
1875 } else {
1876 DEBUG_LOG(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i)", psmfPlayer, playMode, playSpeed);
1877 }
1878 break;
1879
1880 default:
1881 if (psmfplayer->playSpeed != playSpeed) {
1882 WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): play speed not changed", psmfPlayer, playMode, playSpeed);
1883 }
1884 WARN_LOG_REPORT(ME, "scePsmfPlayerChangePlayMode(%08x, %i, %i): unsupported playMode", psmfPlayer, playMode, playSpeed);
1885 break;
1886 }
1887
1888 psmfplayer->playMode = playMode;
1889 return 0;
1890 }
1891
scePsmfPlayerSelectAudio(u32 psmfPlayer)1892 static u32 scePsmfPlayerSelectAudio(u32 psmfPlayer)
1893 {
1894 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1895 if (!psmfplayer) {
1896 ERROR_LOG(ME, "scePsmfPlayerSelectAudio(%08x): invalid psmf player", psmfPlayer);
1897 return ERROR_PSMFPLAYER_INVALID_STATUS;
1898 }
1899 if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) {
1900 ERROR_LOG(ME, "scePsmfPlayerSelectAudio(%08x): not playing", psmfPlayer);
1901 return ERROR_PSMFPLAYER_INVALID_STATUS;
1902 }
1903
1904 int next = psmfplayer->audioStreamNum + 1;
1905 if (next >= psmfplayer->totalAudioStreams)
1906 next = 0;
1907
1908 if (next == psmfplayer->audioStreamNum || !psmfplayer->mediaengine->setAudioStream(next)) {
1909 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectAudio(%08x): no stream to switch to", psmfPlayer);
1910 return ERROR_PSMFPLAYER_INVALID_STREAM;
1911 }
1912
1913 WARN_LOG_REPORT(ME, "scePsmfPlayerSelectAudio(%08x)", psmfPlayer);
1914 psmfplayer->audioStreamNum = next;
1915 return 0;
1916 }
1917
scePsmfPlayerSelectVideo(u32 psmfPlayer)1918 static u32 scePsmfPlayerSelectVideo(u32 psmfPlayer)
1919 {
1920 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1921 if (!psmfplayer) {
1922 ERROR_LOG(ME, "scePsmfPlayerSelectVideo(%08x): invalid psmf player", psmfPlayer);
1923 return ERROR_PSMFPLAYER_INVALID_STATUS;
1924 }
1925 if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) {
1926 ERROR_LOG(ME, "scePsmfPlayerSelectVideo(%08x): not playing", psmfPlayer);
1927 return ERROR_PSMFPLAYER_INVALID_STATUS;
1928 }
1929
1930 int next = psmfplayer->videoStreamNum + 1;
1931 if (next >= psmfplayer->totalVideoStreams)
1932 next = 0;
1933
1934 if (next == psmfplayer->videoStreamNum || !psmfplayer->mediaengine->setVideoStream(next)) {
1935 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectVideo(%08x): no stream to switch to", psmfPlayer);
1936 return ERROR_PSMFPLAYER_INVALID_STREAM;
1937 }
1938
1939 WARN_LOG_REPORT(ME, "scePsmfPlayerSelectVideo(%08x)", psmfPlayer);
1940 psmfplayer->videoStreamNum = next;
1941 return 0;
1942 }
1943
scePsmfPlayerSelectSpecificVideo(u32 psmfPlayer,int videoCodec,int videoStreamNum)1944 static u32 scePsmfPlayerSelectSpecificVideo(u32 psmfPlayer, int videoCodec, int videoStreamNum)
1945 {
1946 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1947 if (!psmfplayer) {
1948 ERROR_LOG(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): invalid psmf player", psmfPlayer, videoCodec, videoStreamNum);
1949 return ERROR_PSMFPLAYER_INVALID_STATUS;
1950 }
1951 if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) {
1952 ERROR_LOG(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): not playing", psmfPlayer, videoCodec, videoStreamNum);
1953 return ERROR_PSMFPLAYER_INVALID_STATUS;
1954 }
1955 if (psmfplayer->totalVideoStreams < 2) {
1956 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): unable to change stream", psmfPlayer, videoCodec, videoStreamNum);
1957 return ERROR_PSMFPLAYER_INVALID_STREAM;
1958 }
1959 if (videoStreamNum < 0 || videoStreamNum >= psmfplayer->totalVideoStreams) {
1960 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): bad stream num param", psmfPlayer, videoCodec, videoStreamNum);
1961 return ERROR_PSMFPLAYER_INVALID_CONFIG;
1962 }
1963 if (videoCodec != 0x0E && videoCodec != 0x00) {
1964 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): invalid codec", psmfPlayer, videoCodec, videoStreamNum);
1965 return ERROR_PSMFPLAYER_INVALID_STREAM;
1966 }
1967 if (psmfplayer->totalVideoStreams < 2 || !psmfplayer->mediaengine->setVideoStream(videoStreamNum)) {
1968 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i): unable to change stream", psmfPlayer, videoCodec, videoStreamNum);
1969 return ERROR_PSMFPLAYER_INVALID_STREAM;
1970 }
1971
1972 WARN_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificVideo(%08x, %i, %i)", psmfPlayer, videoCodec, videoStreamNum);
1973 if (psmfplayer->videoStreamNum != videoStreamNum) {
1974 hleDelayResult(0, "psmf select video", 100);
1975 }
1976 psmfplayer->videoCodec = videoCodec;
1977 psmfplayer->videoStreamNum = videoStreamNum;
1978 return 0;
1979 }
1980
1981 // WARNING: This function appears to be buggy in most libraries.
scePsmfPlayerSelectSpecificAudio(u32 psmfPlayer,int audioCodec,int audioStreamNum)1982 static u32 scePsmfPlayerSelectSpecificAudio(u32 psmfPlayer, int audioCodec, int audioStreamNum)
1983 {
1984 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
1985 if (!psmfplayer) {
1986 ERROR_LOG(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): invalid psmf player", psmfPlayer, audioCodec, audioStreamNum);
1987 return ERROR_PSMFPLAYER_INVALID_STATUS;
1988 }
1989 if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) {
1990 ERROR_LOG(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): not playing", psmfPlayer, audioCodec, audioStreamNum);
1991 return ERROR_PSMFPLAYER_INVALID_STATUS;
1992 }
1993 if (psmfplayer->totalAudioStreams < 2) {
1994 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): unable to change stream", psmfPlayer, audioCodec, audioStreamNum);
1995 return ERROR_PSMFPLAYER_INVALID_STREAM;
1996 }
1997 if (audioStreamNum < 0 || audioStreamNum >= psmfplayer->totalAudioStreams) {
1998 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): bad stream num param", psmfPlayer, audioCodec, audioStreamNum);
1999 return ERROR_PSMFPLAYER_INVALID_CONFIG;
2000 }
2001 if (audioCodec != 0x0F && audioCodec != 0x01) {
2002 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): invalid codec", psmfPlayer, audioCodec, audioStreamNum);
2003 return ERROR_PSMFPLAYER_INVALID_STREAM;
2004 }
2005 if (psmfplayer->totalAudioStreams < 2 || !psmfplayer->mediaengine->setAudioStream(audioStreamNum)) {
2006 ERROR_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i): unable to change stream", psmfPlayer, audioCodec, audioStreamNum);
2007 return ERROR_PSMFPLAYER_INVALID_STREAM;
2008 }
2009
2010 WARN_LOG_REPORT(ME, "scePsmfPlayerSelectSpecificAudio(%08x, %i, %i)", psmfPlayer, audioCodec, audioStreamNum);
2011 if (psmfplayer->audioStreamNum != audioStreamNum) {
2012 hleDelayResult(0, "psmf select audio", 100);
2013 }
2014 psmfplayer->audioCodec = audioCodec;
2015 psmfplayer->audioStreamNum = audioStreamNum;
2016 return 0;
2017 }
2018
scePsmfPlayerConfigPlayer(u32 psmfPlayer,int configMode,int configAttr)2019 static u32 scePsmfPlayerConfigPlayer(u32 psmfPlayer, int configMode, int configAttr)
2020 {
2021 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
2022 if (!psmfplayer) {
2023 ERROR_LOG(ME, "scePsmfPlayerConfigPlayer(%08x, %i, %i): invalid psmf player", psmfPlayer, configMode, configAttr);
2024 return ERROR_PSMFPLAYER_INVALID_STATUS;
2025 }
2026 // This one works in any status as long as it's created.
2027
2028 switch (configMode) {
2029 case PSMF_PLAYER_CONFIG_MODE_LOOP:
2030 if (configAttr != 0 && configAttr != 1) {
2031 ERROR_LOG_REPORT(ME, "scePsmfPlayerConfigPlayer(%08x, loop, %i): invalid value", psmfPlayer, configAttr);
2032 return ERROR_PSMFPLAYER_INVALID_PARAM;
2033 }
2034 INFO_LOG(ME, "scePsmfPlayerConfigPlayer(%08x, loop, %i)", psmfPlayer, configAttr);
2035 videoLoopStatus = configAttr;
2036 break;
2037 case PSMF_PLAYER_CONFIG_MODE_PIXEL_TYPE:
2038 if (configAttr < -1 || configAttr > 3) {
2039 ERROR_LOG_REPORT(ME, "scePsmfPlayerConfigPlayer(%08x, pixelType, %i): invalid value", psmfPlayer, configAttr);
2040 return ERROR_PSMFPLAYER_INVALID_PARAM;
2041 }
2042 INFO_LOG(ME, "scePsmfPlayerConfigPlayer(%08x, pixelType, %i)", psmfPlayer, configAttr);
2043 // Does -1 mean default or something?
2044 if (configAttr != -1) {
2045 videoPixelMode = configAttr;
2046 } else {
2047 // TODO: At least for one video, this was the same as 8888.
2048 videoPixelMode = GE_CMODE_32BIT_ABGR8888;
2049 }
2050 break;
2051 default:
2052 ERROR_LOG_REPORT(ME, "scePsmfPlayerConfigPlayer(%08x, %i, %i): unknown parameter", psmfPlayer, configMode, configAttr);
2053 return ERROR_PSMFPLAYER_INVALID_CONFIG;
2054 }
2055
2056 return 0;
2057 }
2058
__PsmfPlayerFinish(u32 psmfPlayer)2059 static int __PsmfPlayerFinish(u32 psmfPlayer) {
2060 PsmfPlayer *psmfplayer = getPsmfPlayer(psmfPlayer);
2061 if (!psmfplayer) {
2062 ERROR_LOG_REPORT(ME, "__PsmfPlayerFinish(%08x): invalid psmf player", psmfPlayer);
2063 return ERROR_PSMFPLAYER_INVALID_STATUS;
2064 }
2065 if (psmfplayer->status != PSMF_PLAYER_STATUS_PLAYING) {
2066 ERROR_LOG_REPORT(ME, "__PsmfPlayerFinish(%08x): unexpected status %d", psmfPlayer, psmfplayer->status);
2067 return ERROR_PSMFPLAYER_INVALID_STATUS;
2068 }
2069
2070 INFO_LOG(ME, "__PsmfPlayerFinish(%08x): video end reached", psmfPlayer);
2071 psmfplayer->status = PSMF_PLAYER_STATUS_PLAYING_FINISHED;
2072 return 0;
2073 }
2074
2075 const HLEFunction scePsmf[] = {
2076 {0XC22C8327, &WrapU_UU<scePsmfSetPsmf>, "scePsmfSetPsmf", 'x', "xx" ,HLE_CLEAR_STACK_BYTES, 0x50},
2077 {0XC7DB3A5B, &WrapU_UUU<scePsmfGetCurrentStreamType>, "scePsmfGetCurrentStreamType", 'i', "xpp" ,HLE_CLEAR_STACK_BYTES, 0x50},
2078 {0X28240568, &WrapU_U<scePsmfGetCurrentStreamNumber>, "scePsmfGetCurrentStreamNumber", 'i', "x" },
2079 {0X1E6D9013, &WrapU_UUU<scePsmfSpecifyStreamWithStreamType>, "scePsmfSpecifyStreamWithStreamType", 'i', "xii" ,HLE_CLEAR_STACK_BYTES, 0x20},
2080 {0X0C120E1D, &WrapU_UUU<scePsmfSpecifyStreamWithStreamTypeNumber>, "scePsmfSpecifyStreamWithStreamTypeNumber", 'i', "xii"},
2081 {0X4BC9BDE0, &WrapU_UI<scePsmfSpecifyStream>, "scePsmfSpecifyStream", 'i', "xi" ,HLE_CLEAR_STACK_BYTES, 0x40},
2082 {0X76D3AEBA, &WrapU_UU<scePsmfGetPresentationStartTime>, "scePsmfGetPresentationStartTime", 'x', "xx" ,HLE_CLEAR_STACK_BYTES, 0x10},
2083 {0XBD8AE0D8, &WrapU_UU<scePsmfGetPresentationEndTime>, "scePsmfGetPresentationEndTime", 'x', "xx" ,HLE_CLEAR_STACK_BYTES, 0x10},
2084 {0XEAED89CD, &WrapU_U<scePsmfGetNumberOfStreams>, "scePsmfGetNumberOfStreams", 'i', "x" ,HLE_CLEAR_STACK_BYTES, 0x10},
2085 {0X7491C438, &WrapU_U<scePsmfGetNumberOfEPentries>, "scePsmfGetNumberOfEPentries", 'x', "x" ,HLE_CLEAR_STACK_BYTES, 0x10},
2086 {0X0BA514E5, &WrapU_UU<scePsmfGetVideoInfo>, "scePsmfGetVideoInfo", 'i', "xp" ,HLE_CLEAR_STACK_BYTES, 0x20},
2087 {0XA83F7113, &WrapU_UU<scePsmfGetAudioInfo>, "scePsmfGetAudioInfo", 'i', "xp" ,HLE_CLEAR_STACK_BYTES, 0x20},
2088 {0X971A3A90, &WrapU_U<scePsmfCheckEPMap>, "scePsmfCheckEPmap", 'x', "x" ,HLE_CLEAR_STACK_BYTES, 0x10},
2089 {0X68D42328, &WrapU_UI<scePsmfGetNumberOfSpecificStreams>, "scePsmfGetNumberOfSpecificStreams", 'i', "xi" ,HLE_CLEAR_STACK_BYTES, 0x20},
2090 {0X5B70FCC1, &WrapU_UU<scePsmfQueryStreamOffset>, "scePsmfQueryStreamOffset", 'x', "xx" },
2091 {0X9553CC91, &WrapU_UU<scePsmfQueryStreamSize>, "scePsmfQueryStreamSize", 'x', "xx" },
2092 {0XB78EB9E9, &WrapU_UU<scePsmfGetHeaderSize>, "scePsmfGetHeaderSize", 'x', "xx" },
2093 {0XA5EBFE81, &WrapU_UU<scePsmfGetStreamSize>, "scePsmfGetStreamSize", 'x', "xx" },
2094 {0XE1283895, &WrapU_U<scePsmfGetPsmfVersion>, "scePsmfGetPsmfVersion", 'x', "x" },
2095 {0X2673646B, &WrapU_U<scePsmfVerifyPsmf>, "scePsmfVerifyPsmf", 'x', "x" ,HLE_CLEAR_STACK_BYTES, 0x100},
2096 {0X4E624A34, &WrapU_UIU<scePsmfGetEPWithId>, "scePsmfGetEPWithId", 'x', "xix" ,HLE_CLEAR_STACK_BYTES, 0x10},
2097 {0X7C0E7AC3, &WrapU_UUU<scePsmfGetEPWithTimestamp>, "scePsmfGetEPWithTimestamp", 'x', "xxx" ,HLE_CLEAR_STACK_BYTES, 0x10},
2098 {0X5F457515, &WrapU_UU<scePsmfGetEPidWithTimestamp>, "scePsmfGetEPidWithTimestamp", 'x', "xx" ,HLE_CLEAR_STACK_BYTES, 0x20},
2099 {0X43AC7DBB, nullptr, "scePsmfGetPsmfMark", '?', "" },
2100 {0XDE78E9FC, nullptr, "scePsmfGetNumberOfPsmfMarks", '?', "" },
2101 };
2102
2103 const HLEFunction scePsmfPlayer[] =
2104 {
2105 {0X235D8787, &WrapI_UU<scePsmfPlayerCreate>, "scePsmfPlayerCreate", 'i', "xx" },
2106 {0X1078C008, &WrapI_U<scePsmfPlayerStop>, "scePsmfPlayerStop", 'i', "x" },
2107 {0X1E57A8E7, &WrapU_UII<scePsmfPlayerConfigPlayer>, "scePsmfPlayerConfigPlayer", 'x', "xii"},
2108 {0X2BEB1569, &WrapI_U<scePsmfPlayerBreak>, "scePsmfPlayerBreak", 'i', "x" },
2109 {0X3D6D25A9, &WrapI_UC<scePsmfPlayerSetPsmf>, "scePsmfPlayerSetPsmf", 'i', "xs" },
2110 {0X58B83577, &WrapI_UC<scePsmfPlayerSetPsmfCB>, "scePsmfPlayerSetPsmfCB", 'i', "xs" },
2111 {0X3EA82A4B, &WrapI_U<scePsmfPlayerGetAudioOutSize>, "scePsmfPlayerGetAudioOutSize", 'i', "x" },
2112 {0X3ED62233, &WrapU_UU<scePsmfPlayerGetCurrentPts>, "scePsmfPlayerGetCurrentPts", 'x', "xx" },
2113 {0X46F61F8B, &WrapI_UU<scePsmfPlayerGetVideoData>, "scePsmfPlayerGetVideoData", 'i', "xx" },
2114 {0X68F07175, &WrapU_UUU<scePsmfPlayerGetCurrentAudioStream>, "scePsmfPlayerGetCurrentAudioStream", 'x', "xxx"},
2115 {0X75F03FA2, &WrapU_UII<scePsmfPlayerSelectSpecificVideo>, "scePsmfPlayerSelectSpecificVideo", 'x', "xii"},
2116 {0X85461EFF, &WrapU_UII<scePsmfPlayerSelectSpecificAudio>, "scePsmfPlayerSelectSpecificAudio", 'x', "xii"},
2117 {0X8A9EBDCD, &WrapU_U<scePsmfPlayerSelectVideo>, "scePsmfPlayerSelectVideo", 'x', "x" },
2118 {0X95A84EE5, &WrapI_UUI<scePsmfPlayerStart>, "scePsmfPlayerStart", 'i', "xxi"},
2119 {0X9B71A274, &WrapI_U<scePsmfPlayerDelete>, "scePsmfPlayerDelete", 'i', "x" },
2120 {0X9FF2B2E7, &WrapU_UUU<scePsmfPlayerGetCurrentVideoStream>, "scePsmfPlayerGetCurrentVideoStream", 'x', "xxx"},
2121 {0XA0B8CA55, &WrapI_U<scePsmfPlayerUpdate>, "scePsmfPlayerUpdate", 'i', "x" },
2122 {0XA3D81169, &WrapU_UII<scePsmfPlayerChangePlayMode>, "scePsmfPlayerChangePlayMode", 'x', "xii"},
2123 {0XB8D10C56, &WrapU_U<scePsmfPlayerSelectAudio>, "scePsmfPlayerSelectAudio", 'x', "x" },
2124 {0XB9848A74, &WrapI_UU<scePsmfPlayerGetAudioData>, "scePsmfPlayerGetAudioData", 'i', "xx" },
2125 {0XDF089680, &WrapU_UUUU<scePsmfPlayerGetPsmfInfo>, "scePsmfPlayerGetPsmfInfo", 'x', "xxxx" },
2126 {0XE792CD94, &WrapI_U<scePsmfPlayerReleasePsmf>, "scePsmfPlayerReleasePsmf", 'i', "x" },
2127 {0XF3EFAA91, &WrapU_UUU<scePsmfPlayerGetCurrentPlayMode>, "scePsmfPlayerGetCurrentPlayMode", 'x', "xxx"},
2128 {0XF8EF08A6, &WrapI_U<scePsmfPlayerGetCurrentStatus>, "scePsmfPlayerGetCurrentStatus", 'i', "x" },
2129 {0X2D0E4E0A, &WrapI_UUU<scePsmfPlayerSetTempBuf>, "scePsmfPlayerSetTempBuf", 'i', "xxx"},
2130 {0X76C0F4AE, &WrapI_UCI<scePsmfPlayerSetPsmfOffset>, "scePsmfPlayerSetPsmfOffset", 'i', "xsi"},
2131 {0XA72DB4F9, &WrapI_UCI<scePsmfPlayerSetPsmfOffsetCB>, "scePsmfPlayerSetPsmfOffsetCB", 'i', "xsi"},
2132 {0X340C12CB, nullptr, "scePsmfPlayer_340C12CB", '?', "" },
2133 // Fake function for PPSSPP's use.
2134 {0X05B193B7, &WrapI_U<__PsmfPlayerFinish>, "__PsmfPlayerFinish", 'i', "x" },
2135 };
2136
Register_scePsmf()2137 void Register_scePsmf() {
2138 RegisterModule("scePsmf",ARRAY_SIZE(scePsmf),scePsmf);
2139 }
2140
Register_scePsmfPlayer()2141 void Register_scePsmfPlayer() {
2142 RegisterModule("scePsmfPlayer",ARRAY_SIZE(scePsmfPlayer),scePsmfPlayer);
2143 }
2144