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 // This code is part shamelessly "inspired" from JPSCP.
19 #include <map>
20 #include <algorithm>
21 #include <memory>
22
23 #include "Common/Serialize/SerializeFuncs.h"
24 #include "Common/Serialize/SerializeMap.h"
25 #include "Common/Swap.h"
26 #include "Core/HLE/sceMpeg.h"
27 #include "Core/HLE/sceKernelModule.h"
28 #include "Core/HLE/sceKernelThread.h"
29 #include "Core/HLE/HLE.h"
30 #include "Core/HLE/FunctionWrappers.h"
31 #include "Core/HW/MediaEngine.h"
32 #include "Core/Config.h"
33 #include "Core/MemMapHelpers.h"
34 #include "Core/Reporting.h"
35 #include "GPU/GPUInterface.h"
36 #include "GPU/GPUState.h"
37 #include "Core/HLE/sceKernelMemory.h"
38 #include "Core/Core.h"
39
40 // MPEG AVC elementary stream.
41 static const int MPEG_AVC_ES_SIZE = 2048; // MPEG packet size.
42
43 // MPEG ATRAC elementary stream.
44 static const int MPEG_ATRAC_ES_SIZE = 2112;
45 static const int MPEG_ATRAC_ES_OUTPUT_SIZE = 8192;
46
47 // MPEG PCM elementary stream.
48 static const int MPEG_PCM_ES_SIZE = 320;
49 static const int MPEG_PCM_ES_OUTPUT_SIZE = 320;
50
51 // MPEG Userdata elementary stream.
52 static const int MPEG_DATA_ES_SIZE = 0xA0000;
53 static const int MPEG_DATA_ES_OUTPUT_SIZE = 0xA0000;
54 static const int MPEG_DATA_ES_BUFFERS = 2;
55
56 // MPEG analysis results.
57 static const int MPEG_VERSION_0012 = 0;
58 static const int MPEG_VERSION_0013 = 1;
59 static const int MPEG_VERSION_0014 = 2;
60 static const int MPEG_VERSION_0015 = 3;
61
62 // PSMF analysis results.
63 static const int PSMF_VERSION_0012 = 0x32313030;
64 static const int PSMF_VERSION_0013 = 0x33313030;
65 static const int PSMF_VERSION_0014 = 0x34313030;
66 static const int PSMF_VERSION_0015 = 0x35313030;
67
68 // MPEG streams.
69 static const int MPEG_AVC_STREAM = 0;
70 static const int MPEG_ATRAC_STREAM = 1;
71 static const int MPEG_PCM_STREAM = 2;
72 static const int MPEG_DATA_STREAM = 3; // Arbitrary user defined type. Can represent audio or video.
73 static const int MPEG_AUDIO_STREAM = 15;
74 static const int MPEG_AU_MODE_DECODE = 0;
75 static const int MPEG_AU_MODE_SKIP = 1;
76 static const u32 MPEG_MEMSIZE_0104 = 0x0b3DB;
77 static const u32 MPEG_MEMSIZE_0105 = 0x10000; // 64k.
78 static const int MPEG_AVC_DECODE_SUCCESS = 1; // Internal value.
79 static const int MPEG_WARMUP_FRAMES = 1;
80
81 static const int atracDecodeDelayMs = 3000;
82 static const int avcFirstDelayMs = 3600;
83 static const int avcCscDelayMs = 4000;
84 static const int avcDecodeDelayMs = 5400; // Varies between 4700 and 6000.
85 static const int avcEmptyDelayMs = 320;
86 static const int mpegDecodeErrorDelayMs = 100;
87 static const int mpegTimestampPerSecond = 90000; // How many MPEG Timestamp units in a second.
88 static const int videoTimestampStep = 3003; // Value based on pmfplayer (mpegTimestampPerSecond / 29.970 (fps)).
89 static const int audioTimestampStep = 4180; // For audio play at 44100 Hz (2048 samples / 44100 * mpegTimestampPerSecond == 4180)
90 static const int audioFirstTimestamp = 90000; // The first MPEG audio AU has always this timestamp
91 static const int maxAheadTimestamp = 40000;
92 static const s64 UNKNOWN_TIMESTAMP = -1;
93
94 // At least 2048 bytes of MPEG data is provided when analysing the MPEG header
95 static const int MPEG_HEADER_BUFFER_MINIMUM_SIZE = 2048;
96
97 // For PMP media
98 static u32 pmp_videoSource = 0; //pointer to the video source (SceMpegLLi structure)
99 static int pmp_nBlocks = 0; //number of blocks received in the last sceMpegbase_BEA18F91 call
100 static std::list<AVFrame*> pmp_queue; //list of pmp video frames have been decoded and will be played
101 static std::list<u32> pmp_ContextList; //list of pmp media contexts
102 static bool pmp_oldStateLoaded = false; // for dostate
103
104 // Calculate the number of total packets added to the ringbuffer by calling the sceMpegRingbufferPut() once.
105 static int ringbufferPutPacketsAdded = 0;
106 static bool useRingbufferPutCallbackMulti = true;
107
108 #ifdef USE_FFMPEG
109
110 extern "C" {
111 #include "libavformat/avformat.h"
112 #include "libavutil/imgutils.h"
113 #include "libswscale/swscale.h"
114 }
115 static AVPixelFormat pmp_want_pix_fmt;
116
117 #endif
118
119 struct SceMpegLLI
120 {
121 u32 pSrc;
122 u32 pDst;
123 u32 Next;
124 int iSize;
125 };
126
read(u32 addr)127 void SceMpegAu::read(u32 addr) {
128 Memory::ReadStruct(addr, this);
129 pts = (pts & 0xFFFFFFFFULL) << 32 | (((u64)pts) >> 32);
130 dts = (dts & 0xFFFFFFFFULL) << 32 | (((u64)dts) >> 32);
131 }
132
write(u32 addr)133 void SceMpegAu::write(u32 addr) {
134 pts = (pts & 0xFFFFFFFFULL) << 32 | (((u64)pts) >> 32);
135 dts = (dts & 0xFFFFFFFFULL) << 32 | (((u64)dts) >> 32);
136 Memory::WriteStruct(addr, this);
137 }
138
139 /*
140 // Currently unused
141 static int getMaxAheadTimestamp(const SceMpegRingBuffer &ringbuf) {
142 return std::max(maxAheadTimestamp, 700 * ringbuf.packets); // empiric value from JPCSP, thanks!
143 }
144 */
145
146 const u8 defaultMpegheader[2048] = {0x50,0x53,0x4d,0x46,0x30,0x30,0x31,0x35,0x00,0x00,0x08,0x00,0x00,
147 0x10,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
148 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
149 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
150 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4e,0x00,
151 0x00,0x00,0x01,0x5f,0x90,0x00,0x00,0x00,0x0d,0xbe,0xca,0x00,0x00,0x61,0xa8,0x00,0x01,0x5f,
152 0x90,0x02,0x01,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x01,0x5f,0x90,0x00,0x00,0x00,0x0d,0xbe,
153 0xca,0x00,0x01,0x00,0x00,0x00,0x22,0x00,0x02,0xe0,0x00,0x20,0xfb,0x00,0x00,0x00,0x00,0x00,
154 0x00,0x00,0x00,0x1e,0x11,0x00,0x00,0xbd,0x00,0x20,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
155 0x00,0x00,0x00,0x02,0x02};
156
157 // Internal structure
158 struct AvcContext {
159 int avcDetailFrameWidth;
160 int avcDetailFrameHeight;
161 int avcDecodeResult;
162 int avcFrameStatus;
163 };
164
165 struct StreamInfo {
166 int type;
167 int num;
168 int sid;
169 bool needsReset;
170 };
171
172 typedef std::map<u32, StreamInfo> StreamInfoMap;
173
174 // Internal structure
175 struct MpegContext {
MpegContextMpegContext176 MpegContext() : ringbufferNeedsReverse(false), mediaengine(nullptr) {
177 memcpy(mpegheader, defaultMpegheader, 2048);
178 }
~MpegContextMpegContext179 ~MpegContext() {
180 delete mediaengine;
181 }
182
DoStateMpegContext183 void DoState(PointerWrap &p) {
184 auto s = p.Section("MpegContext", 1, 3);
185 if (!s)
186 return;
187 if (s >= 3)
188 Do(p, mpegwarmUp);
189 else
190 mpegwarmUp = 1000;
191 DoArray(p, mpegheader, 2048);
192 Do(p, defaultFrameWidth);
193 Do(p, videoFrameCount);
194 Do(p, audioFrameCount);
195 Do(p, endOfAudioReached);
196 Do(p, endOfVideoReached);
197 Do(p, videoPixelMode);
198 Do(p, mpegMagic);
199 Do(p, mpegVersion);
200 Do(p, mpegRawVersion);
201 Do(p, mpegOffset);
202 Do(p, mpegStreamSize);
203 Do(p, mpegFirstTimestamp);
204 Do(p, mpegLastTimestamp);
205 Do(p, mpegFirstDate);
206 Do(p, mpegLastDate);
207 Do(p, mpegRingbufferAddr);
208 DoArray(p, esBuffers, MPEG_DATA_ES_BUFFERS);
209 Do(p, avc);
210 Do(p, avcRegistered);
211 Do(p, atracRegistered);
212 Do(p, pcmRegistered);
213 Do(p, dataRegistered);
214 Do(p, ignoreAtrac);
215 Do(p, ignorePcm);
216 Do(p, ignoreAvc);
217 Do(p, isAnalyzed);
218 Do<u32, StreamInfo>(p, streamMap);
219 DoClass(p, mediaengine);
220 ringbufferNeedsReverse = s < 2;
221 }
222
223 u8 mpegheader[2048];
224 u32 defaultFrameWidth;
225 int videoFrameCount;
226 int audioFrameCount;
227 bool endOfAudioReached;
228 bool endOfVideoReached;
229 int videoPixelMode;
230 u32 mpegMagic;
231 int mpegVersion;
232 u32 mpegRawVersion;
233 u32 mpegOffset;
234 u32 mpegStreamSize;
235 s64 mpegFirstTimestamp;
236 s64 mpegLastTimestamp;
237 u32 mpegFirstDate;
238 u32 mpegLastDate;
239 u32 mpegRingbufferAddr;
240 int mpegwarmUp;
241 bool esBuffers[MPEG_DATA_ES_BUFFERS];
242 AvcContext avc;
243
244 bool avcRegistered;
245 bool atracRegistered;
246 bool pcmRegistered;
247 bool dataRegistered;
248
249 bool ignoreAtrac;
250 bool ignorePcm;
251 bool ignoreAvc;
252
253 bool isAnalyzed;
254 bool ringbufferNeedsReverse;
255
256 StreamInfoMap streamMap;
257 MediaEngine *mediaengine;
258 };
259
260 static bool isMpegInit;
261 static int mpegLibVersion;
262 static u32 streamIdGen;
263 static int actionPostPut;
264 static std::map<u32, MpegContext *> mpegMap;
265
getMpegCtx(u32 mpegAddr)266 static MpegContext *getMpegCtx(u32 mpegAddr) {
267 if (!Memory::IsValidAddress(mpegAddr))
268 return nullptr;
269
270 u32 mpeg = Memory::Read_U32(mpegAddr);
271 auto found = mpegMap.find(mpeg);
272 if (found == mpegMap.end())
273 return nullptr;
274
275 MpegContext *res = found->second;
276 // Take this opportunity to upgrade savestates if necessary.
277 if (res->ringbufferNeedsReverse) {
278 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(res->mpegRingbufferAddr);
279 ringbuffer->packetsAvail = ringbuffer->packets - ringbuffer->packetsAvail;
280 res->ringbufferNeedsReverse = false;
281 }
282 return res;
283 }
284
InitRingbuffer(SceMpegRingBuffer * buf,int packets,int data,int size,int callback_addr,int callback_args)285 static void InitRingbuffer(SceMpegRingBuffer *buf, int packets, int data, int size, int callback_addr, int callback_args) {
286 buf->packets = packets;
287 buf->packetsRead = 0;
288 buf->packetsWritePos = 0;
289 buf->packetsAvail = 0;
290 buf->packetSize = 2048;
291 buf->data = data;
292 buf->callback_addr = callback_addr;
293 buf->callback_args = callback_args;
294 buf->dataUpperBound = data + packets * 2048;
295 buf->semaID = 0;
296 buf->mpeg = 0;
297 // This isn't in ver 0104, but it is in 0105.
298 if (mpegLibVersion >= 0x0105)
299 buf->gp = __KernelGetModuleGP(__KernelGetCurThreadModuleId());
300 }
301
convertTimestampToDate(u32 ts)302 static u32 convertTimestampToDate(u32 ts) {
303 return ts; // TODO
304 }
305
getMpegVersion(u32 mpegRawVersion)306 static u32 getMpegVersion(u32 mpegRawVersion) {
307 switch (mpegRawVersion) {
308 case PSMF_VERSION_0012: return MPEG_VERSION_0012;
309 case PSMF_VERSION_0013: return MPEG_VERSION_0013;
310 case PSMF_VERSION_0014: return MPEG_VERSION_0014;
311 case PSMF_VERSION_0015: return MPEG_VERSION_0015;
312 default: return -1;
313 }
314 }
315
AnalyzeMpeg(u8 * buffer,u32 validSize,MpegContext * ctx)316 static void AnalyzeMpeg(u8 *buffer, u32 validSize, MpegContext *ctx) {
317 ctx->mpegMagic = *(u32_le*)buffer;
318 ctx->mpegRawVersion = *(u32_le*)(buffer + PSMF_STREAM_VERSION_OFFSET);
319 ctx->mpegVersion = getMpegVersion(ctx->mpegRawVersion);
320 ctx->mpegOffset = bswap32(*(u32_le*)(buffer + PSMF_STREAM_OFFSET_OFFSET));
321 ctx->mpegStreamSize = bswap32(*(u32_le*)(buffer + PSMF_STREAM_SIZE_OFFSET));
322 ctx->mpegFirstTimestamp = getMpegTimeStamp(buffer + PSMF_FIRST_TIMESTAMP_OFFSET);
323 ctx->mpegLastTimestamp = getMpegTimeStamp(buffer + PSMF_LAST_TIMESTAMP_OFFSET);
324 ctx->mpegFirstDate = convertTimestampToDate(ctx->mpegFirstTimestamp);
325 ctx->mpegLastDate = convertTimestampToDate(ctx->mpegLastTimestamp);
326 ctx->mpegwarmUp = 0;
327 ctx->avc.avcDetailFrameWidth = (*(u8*)(buffer + 142)) * 0x10;
328 ctx->avc.avcDetailFrameHeight = (*(u8*)(buffer + 143)) * 0x10;
329 ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS;
330 ctx->avc.avcFrameStatus = 0;
331 ctx->videoFrameCount = 0;
332 ctx->audioFrameCount = 0;
333 ctx->endOfAudioReached = false;
334 ctx->endOfVideoReached = false;
335
336 // Sanity Check ctx->mpegFirstTimestamp
337 if (ctx->mpegFirstTimestamp != 90000) {
338 WARN_LOG_REPORT(ME, "Unexpected mpeg first timestamp: %llx / %lld", ctx->mpegFirstTimestamp, ctx->mpegFirstTimestamp);
339 }
340
341 if (ctx->mpegMagic != PSMF_MAGIC || ctx->mpegVersion < 0 ||
342 (ctx->mpegOffset & 2047) != 0 || ctx->mpegOffset == 0) {
343 // mpeg header is invalid!
344 return;
345 }
346
347 if (!ctx->isAnalyzed && ctx->mediaengine && ctx->mpegStreamSize > 0 && validSize >= ctx->mpegOffset) {
348 // init mediaEngine
349 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
350 if (ringbuffer.IsValid()) {
351 ctx->mediaengine->loadStream(buffer, ctx->mpegOffset, ringbuffer->packets * ringbuffer->packetSize);
352 } else {
353 // TODO: Does this make any sense?
354 ctx->mediaengine->loadStream(buffer, ctx->mpegOffset, 0);
355 }
356
357 // When used with scePsmf, some applications attempt to use sceMpegQueryStreamOffset
358 // and sceMpegQueryStreamSize, which forces a packet overwrite in the Media Engine and in
359 // the MPEG ringbuffer.
360 // Mark the current MPEG as analyzed to filter this, and restore it at sceMpegFinish.
361 ctx->isAnalyzed = true;
362 }
363
364 // copy header struct to mpeg header.
365 memcpy(ctx->mpegheader, buffer, validSize >= 2048 ? 2048 : validSize);
366 *(u32_le*)(ctx->mpegheader + PSMF_STREAM_OFFSET_OFFSET) = 0x80000;
367
368 INFO_LOG(ME, "Stream offset: %d, Stream size: 0x%X", ctx->mpegOffset, ctx->mpegStreamSize);
369 INFO_LOG(ME, "First timestamp: %lld, Last timestamp: %lld", ctx->mpegFirstTimestamp, ctx->mpegLastTimestamp);
370 }
371
372 class PostPutAction : public PSPAction {
373 public:
PostPutAction()374 PostPutAction() {}
setRingAddr(u32 ringAddr)375 void setRingAddr(u32 ringAddr) { ringAddr_ = ringAddr; }
Create()376 static PSPAction *Create() { return new PostPutAction; }
DoState(PointerWrap & p)377 void DoState(PointerWrap &p) override {
378 auto s = p.Section("PostPutAction", 1);
379 if (!s)
380 return;
381
382 Do(p, ringAddr_);
383 }
384 void run(MipsCall &call) override;
385 private:
386 u32 ringAddr_;
387 };
388
__MpegInit()389 void __MpegInit() {
390 isMpegInit = false;
391 mpegLibVersion = 0x010A;
392 streamIdGen = 1;
393 actionPostPut = __KernelRegisterActionType(PostPutAction::Create);
394
395 #ifdef USE_FFMPEG
396 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100)
397 avcodec_register_all();
398 #endif
399 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100)
400 av_register_all();
401 #endif
402 #endif
403 }
404
__MpegDoState(PointerWrap & p)405 void __MpegDoState(PointerWrap &p) {
406 auto s = p.Section("sceMpeg", 1, 3);
407 if (!s)
408 return;
409
410 if (s < 2) {
411 int oldLastMpeg = -1;
412 bool oldIsMpegAnalyzed = false;
413 Do(p, oldLastMpeg);
414 Do(p, streamIdGen);
415 Do(p, oldIsMpegAnalyzed);
416 // Let's assume the oldest version.
417 mpegLibVersion = 0x0101;
418 } else {
419 if (s < 3) {
420 useRingbufferPutCallbackMulti = false;
421 ringbufferPutPacketsAdded = 0;
422 } else {
423 Do(p, ringbufferPutPacketsAdded);
424 }
425 Do(p, streamIdGen);
426 Do(p, mpegLibVersion);
427 }
428 Do(p, isMpegInit);
429 Do(p, actionPostPut);
430 __KernelRestoreActionType(actionPostPut, PostPutAction::Create);
431
432 Do(p, mpegMap);
433 }
434
__MpegShutdown()435 void __MpegShutdown() {
436 std::map<u32, MpegContext *>::iterator it, end;
437 for (it = mpegMap.begin(), end = mpegMap.end(); it != end; ++it) {
438 delete it->second;
439 }
440 mpegMap.clear();
441 }
442
__MpegLoadModule(int version)443 void __MpegLoadModule(int version) {
444 mpegLibVersion = version;
445 }
446
sceMpegInit()447 static u32 sceMpegInit() {
448 if (isMpegInit) {
449 WARN_LOG(ME, "sceMpegInit(): already initialized");
450 // TODO: Need to properly hook module load/unload for this to work right.
451 //return ERROR_MPEG_ALREADY_INIT;
452 } else {
453 INFO_LOG(ME, "sceMpegInit()");
454 }
455 isMpegInit = true;
456 return hleDelayResult(0, "mpeg init", 750);
457 }
458
__MpegRingbufferQueryMemSize(int packets)459 static u32 __MpegRingbufferQueryMemSize(int packets) {
460 return packets * (104 + 2048);
461 }
462
sceMpegRingbufferQueryMemSize(int packets)463 static u32 sceMpegRingbufferQueryMemSize(int packets) {
464 u32 size = __MpegRingbufferQueryMemSize(packets);
465 DEBUG_LOG(ME, "%i = sceMpegRingbufferQueryMemSize(%i)", size, packets);
466 return size;
467 }
468
469
sceMpegRingbufferConstruct(u32 ringbufferAddr,u32 numPackets,u32 data,u32 size,u32 callbackAddr,u32 callbackArg)470 static u32 sceMpegRingbufferConstruct(u32 ringbufferAddr, u32 numPackets, u32 data, u32 size, u32 callbackAddr, u32 callbackArg) {
471 if (!Memory::IsValidAddress(ringbufferAddr)) {
472 ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): bad ringbuffer, should crash", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
473 return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
474 }
475
476 if ((int)size < 0) {
477 ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): invalid size", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
478 return ERROR_MPEG_NO_MEMORY;
479 }
480
481 if (__MpegRingbufferQueryMemSize(numPackets) > size) {
482 if (numPackets < 0x00100000) {
483 ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
484 return ERROR_MPEG_NO_MEMORY;
485 } else {
486 // The PSP's firmware allows some cases here, due to a bug in its validation.
487 ERROR_LOG_REPORT(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x): too many packets for buffer, bogus size", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
488 }
489 }
490
491 DEBUG_LOG(ME, "sceMpegRingbufferConstruct(%08x, %i, %08x, %08x, %08x, %08x)", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
492 auto ring = PSPPointer<SceMpegRingBuffer>::Create(ringbufferAddr);
493 InitRingbuffer(ring, numPackets, data, size, callbackAddr, callbackArg);
494 return 0;
495 }
496
MpegRequiredMem()497 static u32 MpegRequiredMem() {
498 if (mpegLibVersion < 0x0105) {
499 return MPEG_MEMSIZE_0104;
500 }
501 return MPEG_MEMSIZE_0105;
502 }
503
sceMpegCreate(u32 mpegAddr,u32 dataPtr,u32 size,u32 ringbufferAddr,u32 frameWidth,u32 mode,u32 ddrTop)504 static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 frameWidth, u32 mode, u32 ddrTop)
505 {
506 if (!Memory::IsValidAddress(mpegAddr)) {
507 WARN_LOG(ME, "sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i): invalid addresses", mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop);
508 return -1;
509 }
510
511 if (size < MpegRequiredMem()) {
512 WARN_LOG(ME, "ERROR_MPEG_NO_MEMORY=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)", mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop);
513 return ERROR_MPEG_NO_MEMORY;
514 }
515
516 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringbufferAddr);
517 if (ringbuffer.IsValid()) {
518 if (ringbuffer->packetSize == 0) {
519 ringbuffer->packetsAvail = 0;
520 } else {
521 ringbuffer->packetsAvail = ringbuffer->packets - (ringbuffer->dataUpperBound - ringbuffer->data) / ringbuffer->packetSize;
522 }
523 ringbuffer->mpeg = mpegAddr;
524 }
525
526 // Generate, and write mpeg handle into mpeg data, for some reason
527 int mpegHandle = dataPtr + 0x30;
528 Memory::Write_U32(mpegHandle, mpegAddr);
529
530 // Initialize fake mpeg struct.
531 Memory::Memcpy(mpegHandle, "LIBMPEG\0", 8, "Mpeg");
532 Memory::Memcpy(mpegHandle + 8, "001\0", 4, "Mpeg");
533 Memory::Write_U32(-1, mpegHandle + 12);
534 if (ringbuffer.IsValid()) {
535 Memory::Write_U32(ringbufferAddr, mpegHandle + 16);
536 Memory::Write_U32(ringbuffer->dataUpperBound, mpegHandle + 20);
537 }
538 MpegContext *ctx = new MpegContext();
539 if (mpegMap.find(mpegHandle) != mpegMap.end()) {
540 WARN_LOG_REPORT(HLE, "Replacing existing mpeg context at %08x", mpegAddr);
541 // Otherwise, it would leak.
542 delete mpegMap[mpegHandle];
543 }
544 mpegMap[mpegHandle] = ctx;
545
546 // Initialize mpeg values.
547 ctx->mpegRingbufferAddr = ringbufferAddr;
548 ctx->videoFrameCount = 0;
549 ctx->audioFrameCount = 0;
550 ctx->videoPixelMode = GE_CMODE_32BIT_ABGR8888; // TODO: What's the actual default?
551 ctx->avcRegistered = false;
552 ctx->atracRegistered = false;
553 ctx->pcmRegistered = false;
554 ctx->dataRegistered = false;
555 ctx->ignoreAtrac = false;
556 ctx->ignorePcm = false;
557 ctx->ignoreAvc = false;
558 ctx->defaultFrameWidth = frameWidth;
559 ctx->mpegStreamSize = 0;
560 ctx->mpegOffset = 0;
561 for (int i = 0; i < MPEG_DATA_ES_BUFFERS; i++) {
562 ctx->esBuffers[i] = false;
563 }
564
565 // Detailed "analysis" is done later in Query* for some reason.
566 ctx->isAnalyzed = false;
567 ctx->mediaengine = new MediaEngine();
568
569 INFO_LOG(ME, "%08x=sceMpegCreate(%08x, %08x, %i, %08x, %i, %i, %i)", mpegHandle, mpegAddr, dataPtr, size, ringbufferAddr, frameWidth, mode, ddrTop);
570 return hleDelayResult(0, "mpeg create", 29000);
571 }
572
sceMpegDelete(u32 mpeg)573 static int sceMpegDelete(u32 mpeg)
574 {
575 MpegContext *ctx = getMpegCtx(mpeg);
576 if (!ctx) {
577 WARN_LOG(ME, "sceMpegDelete(%08x): bad mpeg handle", mpeg);
578 return -1;
579 }
580
581 DEBUG_LOG(ME, "sceMpegDelete(%08x)", mpeg);
582
583 delete ctx;
584 mpegMap.erase(Memory::Read_U32(mpeg));
585
586 return hleDelayResult(0, "mpeg delete", 40000);
587 }
588
589
sceMpegAvcDecodeMode(u32 mpeg,u32 modeAddr)590 static int sceMpegAvcDecodeMode(u32 mpeg, u32 modeAddr)
591 {
592 if (!Memory::IsValidAddress(modeAddr)) {
593 WARN_LOG(ME, "sceMpegAvcDecodeMode(%08x, %08x): invalid addresses", mpeg, modeAddr);
594 return -1;
595 }
596
597 MpegContext *ctx = getMpegCtx(mpeg);
598 if (!ctx) {
599 WARN_LOG(ME, "sceMpegAvcDecodeMode(%08x, %08x): bad mpeg handle", mpeg, modeAddr);
600 return -1;
601 }
602
603 DEBUG_LOG(ME, "sceMpegAvcDecodeMode(%08x, %08x)", mpeg, modeAddr);
604
605 int mode = Memory::Read_U32(modeAddr);
606 int pixelMode = Memory::Read_U32(modeAddr + 4);
607 if (pixelMode >= GE_CMODE_16BIT_BGR5650 && pixelMode <= GE_CMODE_32BIT_ABGR8888) {
608 ctx->videoPixelMode = pixelMode;
609 } else {
610 ERROR_LOG(ME, "sceMpegAvcDecodeMode(%i, %i): unknown pixelMode ", mode, pixelMode);
611 }
612 return 0;
613 }
614
sceMpegQueryStreamOffset(u32 mpeg,u32 bufferAddr,u32 offsetAddr)615 static int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr)
616 {
617 if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(offsetAddr)) {
618 ERROR_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x): invalid addresses", mpeg, bufferAddr, offsetAddr);
619 return -1;
620 }
621
622 MpegContext *ctx = getMpegCtx(mpeg);
623 if (!ctx) {
624 WARN_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, offsetAddr);
625 return -1;
626 }
627
628 DEBUG_LOG(ME, "sceMpegQueryStreamOffset(%08x, %08x, %08x)", mpeg, bufferAddr, offsetAddr);
629
630 // Kinda destructive, no?
631 AnalyzeMpeg(Memory::GetPointer(bufferAddr), Memory::ValidSize(bufferAddr, 32768), ctx);
632
633 if (ctx->mpegMagic != PSMF_MAGIC) {
634 ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad PSMF magic");
635 Memory::Write_U32(0, offsetAddr);
636 return ERROR_MPEG_INVALID_VALUE;
637 } else if (ctx->mpegVersion < 0) {
638 ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad version");
639 Memory::Write_U32(0, offsetAddr);
640 return ERROR_MPEG_BAD_VERSION;
641 } else if ((ctx->mpegOffset & 2047) != 0 || ctx->mpegOffset == 0) {
642 ERROR_LOG(ME, "sceMpegQueryStreamOffset: Bad offset");
643 Memory::Write_U32(0, offsetAddr);
644 return ERROR_MPEG_INVALID_VALUE;
645 }
646
647 Memory::Write_U32(ctx->mpegOffset, offsetAddr);
648 return 0;
649 }
650
sceMpegQueryStreamSize(u32 bufferAddr,u32 sizeAddr)651 static u32 sceMpegQueryStreamSize(u32 bufferAddr, u32 sizeAddr)
652 {
653 if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(sizeAddr)) {
654 ERROR_LOG(ME, "sceMpegQueryStreamSize(%08x, %08x): invalid addresses", bufferAddr, sizeAddr);
655 return -1;
656 }
657
658 DEBUG_LOG(ME, "sceMpegQueryStreamSize(%08x, %08x)", bufferAddr, sizeAddr);
659
660 MpegContext ctx;
661 ctx.mediaengine = 0;
662
663 AnalyzeMpeg(Memory::GetPointer(bufferAddr), Memory::ValidSize(bufferAddr, 32768), &ctx);
664
665 if (ctx.mpegMagic != PSMF_MAGIC) {
666 ERROR_LOG(ME, "sceMpegQueryStreamSize: Bad PSMF magic");
667 Memory::Write_U32(0, sizeAddr);
668 return ERROR_MPEG_INVALID_VALUE;
669 } else if ((ctx.mpegOffset & 2047) != 0 ) {
670 ERROR_LOG(ME, "sceMpegQueryStreamSize: Bad offset");
671 Memory::Write_U32(0, sizeAddr);
672 return ERROR_MPEG_INVALID_VALUE;
673 }
674
675 Memory::Write_U32(ctx.mpegStreamSize, sizeAddr);
676 return 0;
677 }
678
sceMpegRegistStream(u32 mpeg,u32 streamType,u32 streamNum)679 static int sceMpegRegistStream(u32 mpeg, u32 streamType, u32 streamNum)
680 {
681 MpegContext *ctx = getMpegCtx(mpeg);
682 if (!ctx) {
683 WARN_LOG(ME, "sceMpegRegistStream(%08x, %i, %i): bad mpeg handle", mpeg, streamType, streamNum);
684 return -1;
685 }
686
687 INFO_LOG(ME, "sceMpegRegistStream(%08x, %i, %i)", mpeg, streamType, streamNum);
688
689 switch (streamType) {
690 case MPEG_AVC_STREAM:
691 ctx->avcRegistered = true;
692 ctx->mediaengine->addVideoStream(streamNum);
693 // TODO: Probably incorrect?
694 ctx->mediaengine->setVideoStream(streamNum);
695 break;
696 case MPEG_AUDIO_STREAM:
697 case MPEG_ATRAC_STREAM:
698 ctx->atracRegistered = true;
699 // TODO: Probably incorrect?
700 ctx->mediaengine->setAudioStream(streamNum);
701 break;
702 case MPEG_PCM_STREAM:
703 ctx->pcmRegistered = true;
704 break;
705 case MPEG_DATA_STREAM:
706 ctx->dataRegistered = true;
707 break;
708 default :
709 DEBUG_LOG(ME, "sceMpegRegistStream(%i) : unknown stream type", streamType);
710 break;
711 }
712 // ...
713 u32 sid = streamIdGen++;
714 StreamInfo info;
715 info.type = streamType;
716 info.num = streamNum;
717 info.sid = sid;
718 info.needsReset = true;
719 ctx->streamMap[sid] = info;
720 return sid;
721 }
722
sceMpegMallocAvcEsBuf(u32 mpeg)723 static int sceMpegMallocAvcEsBuf(u32 mpeg)
724 {
725 MpegContext *ctx = getMpegCtx(mpeg);
726 if (!ctx) {
727 WARN_LOG(ME, "sceMpegMallocAvcEsBuf(%08x): bad mpeg handle", mpeg);
728 return -1;
729 }
730
731 DEBUG_LOG(ME, "sceMpegMallocAvcEsBuf(%08x)", mpeg);
732
733 // Doesn't actually malloc, just keeps track of a couple of flags
734 for (int i = 0; i < MPEG_DATA_ES_BUFFERS; i++) {
735 if (!ctx->esBuffers[i]) {
736 ctx->esBuffers[i] = true;
737 return i + 1;
738 }
739 }
740 // No es buffer
741 return 0;
742 }
743
sceMpegFreeAvcEsBuf(u32 mpeg,int esBuf)744 static int sceMpegFreeAvcEsBuf(u32 mpeg, int esBuf)
745 {
746 MpegContext *ctx = getMpegCtx(mpeg);
747 if (!ctx) {
748 WARN_LOG(ME, "sceMpegFreeAvcEsBuf(%08x, %i): bad mpeg handle", mpeg, esBuf);
749 return -1;
750 }
751
752 DEBUG_LOG(ME, "sceMpegFreeAvcEsBuf(%08x, %i)", mpeg, esBuf);
753
754 if (esBuf == 0) {
755 return ERROR_MPEG_INVALID_VALUE;
756 }
757
758 if (esBuf >= 1 && esBuf <= MPEG_DATA_ES_BUFFERS) {
759 // TODO: Check if it's already been free'd?
760 ctx->esBuffers[esBuf - 1] = false;
761 }
762 return 0;
763 }
764
765 // check the existence of pmp media context
isContextExist(u32 ctxAddr)766 static bool isContextExist(u32 ctxAddr){
767 for (auto it = pmp_ContextList.begin(); it != pmp_ContextList.end(); ++it){
768 if (*it == ctxAddr){
769 return true;
770 }
771 }
772 return false;
773 }
774
775 // Initialize Pmp video parameters and decoder.
InitPmp(MpegContext * ctx)776 static bool InitPmp(MpegContext * ctx){
777 #ifdef USE_FFMPEG
778 InitFFmpeg();
779 auto mediaengine = ctx->mediaengine;
780 mediaengine->m_isVideoEnd = false;
781 mediaengine->m_firstTimeStamp = 0;
782 mediaengine->m_lastTimeStamp = 0;
783 ctx->mpegFirstTimestamp = 0;
784 ctx->mpegLastTimestamp = 0;
785
786 // wanted output pixel format
787 // reference values for pix_fmt:
788 // GE_CMODE_16BIT_BGR5650 <--> AV_PIX_FMT_BGR565LE
789 // GE_CMODE_16BIT_ABGR5551 <--> AV_PIX_FMT_BGR555LE;
790 // GE_CMODE_16BIT_ABGR4444 <--> AV_PIX_FMT_BGR444LE;
791 // GE_CMODE_32BIT_ABGR8888 <--> AV_PIX_FMT_RGBA;
792 pmp_want_pix_fmt = AV_PIX_FMT_RGBA;
793
794 // Create H264 video codec
795 AVCodec * pmp_Codec = avcodec_find_decoder(AV_CODEC_ID_H264);
796 if (pmp_Codec == NULL){
797 ERROR_LOG(ME, "Can not find H264 codec, please update ffmpeg");
798 return false;
799 }
800
801 // Create CodecContext
802 AVCodecContext * pmp_CodecCtx = avcodec_alloc_context3(pmp_Codec);
803 if (pmp_CodecCtx == NULL){
804 ERROR_LOG(ME, "Can not allocate pmp Codec Context");
805 return false;
806 }
807
808 pmp_CodecCtx->flags |= AV_CODEC_FLAG_OUTPUT_CORRUPT | AV_CODEC_FLAG_LOW_DELAY;
809
810 // each pmp video context is corresponding to one pmp video codec
811 mediaengine->m_pCodecCtxs[0] = pmp_CodecCtx;
812
813 // initialize H264 video parameters
814 // set pmp video size. Better to get from pmp file directly if possible. Any idea?
815 pmp_CodecCtx->width = 480;
816 pmp_CodecCtx->height = 272;
817 mediaengine->m_desHeight = pmp_CodecCtx->height;
818 mediaengine->m_desWidth = pmp_CodecCtx->width;
819
820 // Open pmp video codec
821 if (avcodec_open2(pmp_CodecCtx, pmp_Codec, NULL) < 0){
822 ERROR_LOG(ME, "Can not open pmp video codec");
823 return false;
824 }
825
826 // initialize ctx->mediaengine->m_pFrame and ctx->mediaengine->m_pFrameRGB
827 if (!mediaengine->m_pFrame){
828 mediaengine->m_pFrame = av_frame_alloc();
829 }
830 if (!mediaengine->m_pFrameRGB){
831 mediaengine->m_pFrameRGB = av_frame_alloc();
832 }
833
834 // get RGBA picture buffer
835 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
836 mediaengine->m_bufSize = av_image_get_buffer_size(pmp_want_pix_fmt, pmp_CodecCtx->width, pmp_CodecCtx->height, 1);
837 #else
838 mediaengine->m_bufSize = avpicture_get_size(pmp_want_pix_fmt, pmp_CodecCtx->width, pmp_CodecCtx->height);
839 #endif
840 mediaengine->m_buffer = (u8*)av_malloc(mediaengine->m_bufSize);
841
842 return true;
843 #else
844 // we can not play pmp video without ffmpeg
845 return false;
846 #endif
847 }
848
849 // This class H264Frames is used for collecting small pieces of frames into larger frames for ffmpeg to decode
850 // Basically, this will avoid incomplete frame decoding issue and improve much better the video quality.
851 class H264Frames{
852 public:
853 int size;
854 u8* stream;
855
H264Frames()856 H264Frames() :size(0), stream(NULL){};
857
H264Frames(u8 * str,int sz)858 H264Frames(u8* str, int sz) :size(sz){
859 stream = new u8[size];
860 memcpy(stream, str, size);
861 };
862
H264Frames(H264Frames * frame)863 H264Frames(H264Frames *frame){
864 size = frame->size;
865 stream = new u8[size];
866 memcpy(stream, frame->stream, size);
867 };
868
~H264Frames()869 ~H264Frames(){
870 size = 0;
871 if (stream){
872 delete[] stream;
873 stream = NULL;
874 }
875 };
876
add(H264Frames * p)877 void add(H264Frames *p){
878 add(p->stream, p->size);
879 };
880
add(u8 * str,int sz)881 void add(u8* str, int sz){
882 int newsize = size + sz;
883 u8* newstream = new u8[newsize];
884 // join two streams
885 memcpy(newstream, stream, size);
886 memcpy(newstream + size, str, sz);
887 // delete old stream
888 delete[] stream;
889 // replace with new stream
890 stream = newstream;
891 size = newsize;
892 };
893
remove(int pos)894 void remove(int pos){
895 // remove stream from begining to pos
896 if (pos == 0){
897 // nothing to remove
898 }
899 else if (pos >= size){
900 // we remove all
901 size = 0;
902 if (stream){
903 delete[] stream;
904 stream = NULL;
905 }
906 }
907 else{
908 // we remove the front part
909 size -= pos;
910 u8* str = new u8[size];
911 memcpy(str, stream + pos, size);
912 delete[] stream;
913 stream = str;
914 }
915 };
916 #ifndef USE_FFMPEG
917 #define AV_INPUT_BUFFER_PADDING_SIZE 16
918 #endif
919 #ifndef AV_INPUT_BUFFER_PADDING_SIZE
920 #define AV_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
921 #endif
addpadding()922 void addpadding(){
923 u8* str = new u8[size + AV_INPUT_BUFFER_PADDING_SIZE];
924 memcpy(str, stream, size);
925 memset(str + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
926 size += AV_INPUT_BUFFER_PADDING_SIZE;
927 delete[] stream;
928 stream = str;
929 }
930 };
931
932 // collect pmp video frames
933 static H264Frames *pmpframes;
934
935 // decode pmp video to RGBA format
decodePmpVideo(PSPPointer<SceMpegRingBuffer> ringbuffer,u32 pmpctxAddr)936 static bool decodePmpVideo(PSPPointer<SceMpegRingBuffer> ringbuffer, u32 pmpctxAddr){
937
938 #ifdef USE_FFMPEG
939 // the current video is pmp iff pmp_videoSource is a valid addresse
940 MpegContext* ctx = getMpegCtx(pmpctxAddr);
941 if (Memory::IsValidAddress(pmp_videoSource)){
942 // We should initialize pmp codec for each pmp context
943 if (isContextExist(pmpctxAddr) == false){
944 bool ret = InitPmp(ctx);
945 if (!ret){
946 ERROR_LOG(ME, "Pmp video initialization failed");
947 return false;
948 }
949 // add the initialized context into ContextList
950 pmp_ContextList.push_front(pmpctxAddr);
951 }
952
953 ringbuffer->packetsRead = pmp_nBlocks;
954
955 MediaEngine* mediaengine = ctx->mediaengine;
956 AVFrame* pFrame = mediaengine->m_pFrame;
957 AVFrame* pFrameRGB = mediaengine->m_pFrameRGB;
958 auto pCodecCtx = mediaengine->m_pCodecCtxs[0];
959
960 // pmpframes could be destroied when close a video to load another one
961 if (!pmpframes)
962 pmpframes = new H264Frames;
963
964 // joint all blocks into H264Frames
965 for (int i = 0; i < pmp_nBlocks; i++){
966 auto lli = PSPPointer<SceMpegLLI>::Create(pmp_videoSource);
967 // add source block into pmpframes
968 pmpframes->add(Memory::GetPointer(lli->pSrc), lli->iSize);
969 // get next block
970 pmp_videoSource += sizeof(SceMpegLLI);
971 }
972
973 pmpframes->addpadding();
974
975 // initialize packet
976 AVPacket packet;
977 av_new_packet(&packet, pCodecCtx->width*pCodecCtx->height);
978
979 // set packet to source block
980 packet.data = pmpframes->stream;
981 packet.size = pmpframes->size;
982
983 // reuse pFrame and pFrameRGB
984 int got_picture = 0;
985 av_frame_unref(pFrame);
986 av_frame_unref(pFrameRGB);
987
988 // hook pFrameRGB output to buffer
989 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
990 av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, mediaengine->m_buffer, pmp_want_pix_fmt, pCodecCtx->width, pCodecCtx->height, 1);
991 #else
992 avpicture_fill((AVPicture *)pFrameRGB, mediaengine->m_buffer, pmp_want_pix_fmt, pCodecCtx->width, pCodecCtx->height);
993 #endif
994
995
996 // decode video frame
997 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
998 if (packet.size != 0)
999 avcodec_send_packet(pCodecCtx, &packet);
1000 int len = avcodec_receive_frame(pCodecCtx, pFrame);
1001 if (len == 0) {
1002 len = pFrame->pkt_size;
1003 got_picture = 1;
1004 } else if (len == AVERROR(EAGAIN)) {
1005 len = 0;
1006 got_picture = 0;
1007 } else {
1008 got_picture = 0;
1009 }
1010 #else
1011 int len = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
1012 #endif
1013 DEBUG_LOG(ME, "got_picture %d", got_picture);
1014 if (got_picture){
1015 SwsContext *img_convert_ctx = NULL;
1016 img_convert_ctx = sws_getContext(
1017 pCodecCtx->width,
1018 pCodecCtx->height,
1019 pCodecCtx->pix_fmt,
1020 pCodecCtx->width,
1021 pCodecCtx->height,
1022 pmp_want_pix_fmt,
1023 SWS_BILINEAR,
1024 NULL, NULL, NULL);
1025
1026 if (!img_convert_ctx) {
1027 ERROR_LOG(ME, "Cannot initialize sws conversion context");
1028 return false;
1029 }
1030
1031 // Convert to RGBA
1032 int swsRet = sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data,
1033 pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
1034 if (swsRet < 0){
1035 ERROR_LOG(ME, "sws_scale: Error while converting %d", swsRet);
1036 return false;
1037 }
1038 // free sws context
1039 sws_freeContext(img_convert_ctx);
1040
1041 // update timestamp
1042 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
1043 int64_t bestPts = mediaengine->m_pFrame->best_effort_timestamp;
1044 int64_t ptsDuration = mediaengine->m_pFrame->pkt_duration;
1045 #else
1046 int64_t bestPts = av_frame_get_best_effort_timestamp(mediaengine->m_pFrame);
1047 int64_t ptsDuration = av_frame_get_pkt_duration(mediaengine->m_pFrame);
1048 #endif
1049 if (bestPts != AV_NOPTS_VALUE)
1050 mediaengine->m_videopts = bestPts + ptsDuration - mediaengine->m_firstTimeStamp;
1051 else
1052 mediaengine->m_videopts += ptsDuration;
1053
1054 // push the decoded frame into pmp_queue
1055 pmp_queue.push_back(pFrameRGB);
1056
1057 // write frame into ppm file
1058 // SaveFrame(pNewFrameRGB, pCodecCtx->width, pCodecCtx->height);
1059 }
1060 // free some pointers
1061 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
1062 av_packet_unref(&packet);
1063 #else
1064 av_free_packet(&packet);
1065 #endif
1066 pmpframes->~H264Frames();
1067 // must reset pmp_VideoSource address to zero after decoding.
1068 pmp_videoSource = 0;
1069 return true;
1070 }
1071 // not a pmp video, return false
1072 return false;
1073 #else
1074 return false;
1075 #endif
1076 }
1077
1078
__VideoPmpInit()1079 void __VideoPmpInit() {
1080 pmp_oldStateLoaded = false;
1081 pmpframes = new H264Frames();
1082 }
1083
__VideoPmpShutdown()1084 void __VideoPmpShutdown() {
1085 #ifdef USE_FFMPEG
1086 // We need to empty pmp_queue to not leak memory.
1087 for (auto it = pmp_queue.begin(); it != pmp_queue.end(); ++it){
1088 av_free(*it);
1089 }
1090 pmp_queue.clear();
1091 pmp_ContextList.clear();
1092 delete pmpframes;
1093 pmpframes = NULL;
1094 #endif
1095 }
1096
__VideoPmpDoState(PointerWrap & p)1097 void __VideoPmpDoState(PointerWrap &p){
1098 auto s = p.Section("PMPVideo", 0, 1);
1099 if (!s) {
1100 if (p.mode == PointerWrap::MODE_READ)
1101 pmp_oldStateLoaded = true;
1102 return;
1103 }
1104
1105 Do(p, pmp_videoSource);
1106 Do(p, pmp_nBlocks);
1107 if (p.mode == PointerWrap::MODE_READ){
1108 // for loadstate, we will reinitialize the pmp codec
1109 __VideoPmpShutdown();
1110 }
1111 }
1112
sceMpegAvcDecode(u32 mpeg,u32 auAddr,u32 frameWidth,u32 bufferAddr,u32 initAddr)1113 static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 initAddr)
1114 {
1115 MpegContext *ctx = getMpegCtx(mpeg);
1116 if (!ctx) {
1117 WARN_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): bad mpeg handle", mpeg, auAddr, frameWidth, bufferAddr, initAddr);
1118 return -1;
1119 }
1120
1121 if (frameWidth == 0) { // wtf, go sudoku passes in 0xcccccccc
1122 if (!ctx->defaultFrameWidth) {
1123 frameWidth = ctx->avc.avcDetailFrameWidth;
1124 } else {
1125 frameWidth = ctx->defaultFrameWidth;
1126 }
1127 }
1128
1129 SceMpegAu avcAu;
1130 avcAu.read(auAddr);
1131
1132 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
1133 if (!ringbuffer.IsValid()) {
1134 ERROR_LOG(ME, "Bogus mpegringbufferaddr");
1135 return -1;
1136 }
1137
1138 u32 buffer = Memory::Read_U32(bufferAddr);
1139 u32 init = Memory::Read_U32(initAddr);
1140 DEBUG_LOG(ME, "video: bufferAddr = %08x, *buffer = %08x, *init = %08x", bufferAddr, buffer, init);
1141
1142 // check and decode pmp video
1143 bool ispmp = false;
1144 if (decodePmpVideo(ringbuffer, mpeg)){
1145 DEBUG_LOG(ME, "Using ffmpeg to decode pmp video");
1146 ispmp = true;
1147 }
1148
1149 if (ringbuffer->packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) {
1150 WARN_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %d, %08x, %08x): mpeg buffer empty", mpeg, auAddr, frameWidth, bufferAddr, initAddr);
1151 return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs);
1152 }
1153
1154 s32 beforeAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048;
1155
1156 // We stored the video stream id here in sceMpegGetAvcAu().
1157 ctx->mediaengine->setVideoStream(avcAu.esBuffer);
1158
1159 if (ispmp){
1160 #ifdef USE_FFMPEG
1161 while (pmp_queue.size() != 0){
1162 // playing all pmp_queue frames
1163 ctx->mediaengine->m_pFrameRGB = pmp_queue.front();
1164 int bufferSize = ctx->mediaengine->writeVideoImage(buffer, frameWidth, ctx->videoPixelMode);
1165 gpu->NotifyVideoUpload(buffer, bufferSize, frameWidth, ctx->videoPixelMode);
1166 ctx->avc.avcFrameStatus = 1;
1167 ctx->videoFrameCount++;
1168
1169 // free front frame
1170 hleDelayResult(0, "pmp video decode", 30);
1171 pmp_queue.pop_front();
1172 }
1173 #endif
1174 }
1175 else if(ctx->mediaengine->stepVideo(ctx->videoPixelMode)) {
1176 int bufferSize = ctx->mediaengine->writeVideoImage(buffer, frameWidth, ctx->videoPixelMode);
1177 gpu->NotifyVideoUpload(buffer, bufferSize, frameWidth, ctx->videoPixelMode);
1178 ctx->avc.avcFrameStatus = 1;
1179 ctx->videoFrameCount++;
1180 } else {
1181 ctx->avc.avcFrameStatus = 0;
1182 }
1183 s32 afterAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048;
1184 // Don't actually reset avail, we only change it by what was decoded.
1185 // Garbage frames can cause this to be incorrect, but some games expect that.
1186 if (mpegLibVersion <= 0x0103) {
1187 ringbuffer->packetsAvail += afterAvail - beforeAvail;
1188 } else {
1189 ringbuffer->packetsAvail = afterAvail;
1190 }
1191
1192 avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
1193
1194 // Flush structs back to memory
1195 avcAu.write(auAddr);
1196
1197 // Save the current frame's status to initAddr
1198 Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr);
1199 ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS;
1200
1201 DEBUG_LOG(ME, "sceMpegAvcDecode(%08x, %08x, %i, %08x, %08x)", mpeg, auAddr, frameWidth, bufferAddr, initAddr);
1202
1203 if (ctx->videoFrameCount <= 1)
1204 return hleDelayResult(0, "mpeg decode", avcFirstDelayMs);
1205 else
1206 return hleDelayResult(0, "mpeg decode", avcDecodeDelayMs);
1207 //hleEatMicro(3300);
1208 //return hleDelayResult(0, "mpeg decode", 200);
1209 }
1210
sceMpegAvcDecodeStop(u32 mpeg,u32 frameWidth,u32 bufferAddr,u32 statusAddr)1211 static u32 sceMpegAvcDecodeStop(u32 mpeg, u32 frameWidth, u32 bufferAddr, u32 statusAddr)
1212 {
1213 if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(statusAddr)){
1214 ERROR_LOG(ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): invalid addresses", mpeg, frameWidth, bufferAddr, statusAddr);
1215 return -1;
1216 }
1217
1218 MpegContext *ctx = getMpegCtx(mpeg);
1219 if (!ctx) {
1220 WARN_LOG(ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, frameWidth, bufferAddr, statusAddr);
1221 return -1;
1222 }
1223
1224 DEBUG_LOG(ME, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x)", mpeg, frameWidth, bufferAddr, statusAddr);
1225
1226 // No last frame generated
1227 Memory::Write_U32(0, statusAddr);
1228 return 0;
1229 }
1230
sceMpegUnRegistStream(u32 mpeg,int streamUid)1231 static u32 sceMpegUnRegistStream(u32 mpeg, int streamUid)
1232 {
1233 MpegContext *ctx = getMpegCtx(mpeg);
1234 if (!ctx) {
1235 WARN_LOG(ME, "sceMpegUnRegistStream(%08x, %i): bad mpeg handle", mpeg, streamUid);
1236 return -1;
1237 }
1238
1239 StreamInfo info = {0};
1240
1241 switch (info.type) {
1242 case MPEG_AVC_STREAM:
1243 ctx->avcRegistered = false;
1244 break;
1245 case MPEG_AUDIO_STREAM:
1246 case MPEG_ATRAC_STREAM:
1247 ctx->atracRegistered = false;
1248 break;
1249 case MPEG_PCM_STREAM:
1250 ctx->pcmRegistered = false;
1251 break;
1252 case MPEG_DATA_STREAM:
1253 ctx->dataRegistered = false;
1254 break;
1255 default :
1256 DEBUG_LOG(ME, "sceMpegUnRegistStream(%i) : unknown streamID ", streamUid);
1257 break;
1258 }
1259 ctx->streamMap[streamUid] = info;
1260 info.type = -1;
1261 info.sid = -1 ;
1262 info.needsReset = true;
1263 ctx->isAnalyzed = false;
1264 return 0;
1265 }
1266
sceMpegAvcDecodeDetail(u32 mpeg,u32 detailAddr)1267 static int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr)
1268 {
1269 if (!Memory::IsValidAddress(detailAddr)){
1270 WARN_LOG(ME, "sceMpegAvcDecodeDetail(%08x, %08x): invalid addresses", mpeg, detailAddr);
1271 return -1;
1272 }
1273
1274 MpegContext *ctx = getMpegCtx(mpeg);
1275 if (!ctx) {
1276 WARN_LOG(ME, "sceMpegAvcDecodeDetail(%08x, %08x): bad mpeg handle", mpeg, detailAddr);
1277 return -1;
1278 }
1279
1280 DEBUG_LOG(ME, "sceMpegAvcDecodeDetail(%08x, %08x)", mpeg, detailAddr);
1281
1282 Memory::Write_U32(ctx->avc.avcDecodeResult, detailAddr + 0);
1283 Memory::Write_U32(ctx->videoFrameCount, detailAddr + 4);
1284 Memory::Write_U32(ctx->avc.avcDetailFrameWidth, detailAddr + 8);
1285 Memory::Write_U32(ctx->avc.avcDetailFrameHeight, detailAddr + 12);
1286 Memory::Write_U32(0, detailAddr + 16);
1287 Memory::Write_U32(0, detailAddr + 20);
1288 Memory::Write_U32(0, detailAddr + 24);
1289 Memory::Write_U32(0, detailAddr + 28);
1290 Memory::Write_U32(ctx->avc.avcFrameStatus, detailAddr + 32);
1291 return 0;
1292 }
1293
sceMpegAvcDecodeStopYCbCr(u32 mpeg,u32 bufferAddr,u32 statusAddr)1294 static u32 sceMpegAvcDecodeStopYCbCr(u32 mpeg, u32 bufferAddr, u32 statusAddr)
1295 {
1296 if (!Memory::IsValidAddress(bufferAddr) || !Memory::IsValidAddress(statusAddr)) {
1297 ERROR_LOG(ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): invalid addresses", mpeg, bufferAddr, statusAddr);
1298 return -1;
1299 }
1300
1301 MpegContext *ctx = getMpegCtx(mpeg);
1302 if (!ctx) {
1303 WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, bufferAddr, statusAddr);
1304 return -1;
1305 }
1306
1307 ERROR_LOG(ME, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x)", mpeg, bufferAddr, statusAddr);
1308 Memory::Write_U32(0, statusAddr);
1309 return 0;
1310 }
1311
sceMpegAvcDecodeYCbCr(u32 mpeg,u32 auAddr,u32 bufferAddr,u32 initAddr)1312 static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr)
1313 {
1314 MpegContext *ctx = getMpegCtx(mpeg);
1315 if (!ctx) {
1316 WARN_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, auAddr, bufferAddr, initAddr);
1317 return -1;
1318 }
1319
1320 SceMpegAu avcAu;
1321 avcAu.read(auAddr);
1322
1323 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
1324 if (!ringbuffer.IsValid()) {
1325 ERROR_LOG(ME, "Bogus mpegringbufferaddr");
1326 return -1;
1327 }
1328
1329 if (ringbuffer->packetsRead == 0 || ctx->mediaengine->IsVideoEnd()) {
1330 WARN_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x): mpeg buffer empty", mpeg, auAddr, bufferAddr, initAddr);
1331 return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs);
1332 }
1333
1334 s32 beforeAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048;
1335
1336 // We stored the video stream id here in sceMpegGetAvcAu().
1337 ctx->mediaengine->setVideoStream(avcAu.esBuffer);
1338
1339 u32 buffer = Memory::Read_U32(bufferAddr);
1340 u32 init = Memory::Read_U32(initAddr);
1341 DEBUG_LOG(ME, "*buffer = %08x, *init = %08x", buffer, init);
1342
1343 if (ctx->mediaengine->stepVideo(ctx->videoPixelMode)) {
1344 // Don't draw here, we'll draw in the Csc func.
1345 ctx->avc.avcFrameStatus = 1;
1346 ctx->videoFrameCount++;
1347 } else {
1348 ctx->avc.avcFrameStatus = 0;
1349 }
1350 s32 afterAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048;
1351 // Don't actually reset avail, we only change it by what was decoded.
1352 // Garbage frames can cause this to be incorrect, but some games expect that.
1353 if (mpegLibVersion <= 0x0103) {
1354 ringbuffer->packetsAvail += afterAvail - beforeAvail;
1355 } else {
1356 ringbuffer->packetsAvail = afterAvail;
1357 }
1358
1359 avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
1360
1361 // Flush structs back to memory
1362 avcAu.write(auAddr);
1363
1364 // Save the current frame's status to initAddr
1365 Memory::Write_U32(ctx->avc.avcFrameStatus, initAddr);
1366 ctx->avc.avcDecodeResult = MPEG_AVC_DECODE_SUCCESS;
1367
1368 DEBUG_LOG(ME, "sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr);
1369
1370 if (ctx->videoFrameCount <= 1)
1371 return hleDelayResult(0, "mpeg decode", avcFirstDelayMs);
1372 else
1373 return hleDelayResult(0, "mpeg decode", avcDecodeDelayMs);
1374 //hleEatMicro(3300);
1375 //return hleDelayResult(0, "mpeg decode", 200);
1376 }
1377
sceMpegAvcDecodeFlush(u32 mpeg)1378 static u32 sceMpegAvcDecodeFlush(u32 mpeg)
1379 {
1380 MpegContext *ctx = getMpegCtx(mpeg);
1381 if (!ctx) {
1382 WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeFlush(%08x): bad mpeg handle", mpeg);
1383 return -1;
1384 }
1385
1386 ERROR_LOG(ME, "UNIMPL sceMpegAvcDecodeFlush(%08x)", mpeg);
1387 if ( ctx->videoFrameCount > 0 || ctx->audioFrameCount > 0) {
1388 //__MpegFinish();
1389 }
1390 return 0;
1391 }
1392
sceMpegInitAu(u32 mpeg,u32 bufferAddr,u32 auPointer)1393 static int sceMpegInitAu(u32 mpeg, u32 bufferAddr, u32 auPointer)
1394 {
1395 MpegContext *ctx = getMpegCtx(mpeg);
1396 if (!ctx) {
1397 WARN_LOG(ME, "sceMpegInitAu(%08x, %i, %08x): bad mpeg handle", mpeg, bufferAddr, auPointer);
1398 return -1;
1399 }
1400
1401 DEBUG_LOG(ME, "sceMpegInitAu(%08x, %i, %08x)", mpeg, bufferAddr, auPointer);
1402
1403 SceMpegAu sceAu;
1404 sceAu.read(auPointer);
1405
1406 if (bufferAddr >= 1 && bufferAddr <= (u32)MPEG_DATA_ES_BUFFERS && ctx->esBuffers[bufferAddr - 1]) {
1407 // This esbuffer has been allocated for Avc.
1408 // Default to 0, since we stuff the stream id in here. Technically, we shouldn't.
1409 // TODO: Do something better to track the AU data. This used to be bufferAddr.
1410 sceAu.esBuffer = 0;
1411 sceAu.esSize = MPEG_AVC_ES_SIZE;
1412 sceAu.dts = 0;
1413 sceAu.pts = 0;
1414
1415 sceAu.write(auPointer);
1416 } else {
1417 // This esbuffer has been left as Atrac.
1418 // Default to 0, since we stuff the stream id in here. Technically, we shouldn't.
1419 // TODO: Do something better to track the AU data. This used to be bufferAddr.
1420 sceAu.esBuffer = 0;
1421 sceAu.esSize = MPEG_ATRAC_ES_SIZE;
1422 sceAu.pts = 0;
1423 sceAu.dts = UNKNOWN_TIMESTAMP;
1424
1425 sceAu.write(auPointer);
1426 }
1427 return 0;
1428 }
1429
sceMpegQueryAtracEsSize(u32 mpeg,u32 esSizeAddr,u32 outSizeAddr)1430 static int sceMpegQueryAtracEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr)
1431 {
1432 if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) {
1433 ERROR_LOG(ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr);
1434 return -1;
1435 }
1436
1437 MpegContext *ctx = getMpegCtx(mpeg);
1438 if (!ctx) {
1439 WARN_LOG(ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr);
1440 return -1;
1441 }
1442
1443 DEBUG_LOG(ME, "sceMpegQueryAtracEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr);
1444
1445 Memory::Write_U32(MPEG_ATRAC_ES_SIZE, esSizeAddr);
1446 Memory::Write_U32(MPEG_ATRAC_ES_OUTPUT_SIZE, outSizeAddr);
1447 return 0;
1448 }
1449
sceMpegRingbufferAvailableSize(u32 ringbufferAddr)1450 static int sceMpegRingbufferAvailableSize(u32 ringbufferAddr)
1451 {
1452 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringbufferAddr);
1453
1454 if (!ringbuffer.IsValid()) {
1455 ERROR_LOG(ME, "sceMpegRingbufferAvailableSize(%08x): invalid ringbuffer, should crash", ringbufferAddr);
1456 return SCE_KERNEL_ERROR_ILLEGAL_ADDRESS;
1457 }
1458
1459 MpegContext *ctx = getMpegCtx(ringbuffer->mpeg);
1460 if (!ctx) {
1461 ERROR_LOG(ME, "sceMpegRingbufferAvailableSize(%08x): bad mpeg handle", ringbufferAddr);
1462 return ERROR_MPEG_NOT_YET_INIT;
1463 }
1464
1465 ctx->mpegRingbufferAddr = ringbufferAddr;
1466 hleEatCycles(2020);
1467 hleReSchedule("mpeg ringbuffer avail");
1468
1469 static int lastAvail = 0;
1470 if (lastAvail != ringbuffer->packetsAvail) {
1471 DEBUG_LOG(ME, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packets - ringbuffer->packetsAvail, ringbufferAddr);
1472 lastAvail = ringbuffer->packetsAvail;
1473 } else {
1474 VERBOSE_LOG(ME, "%i=sceMpegRingbufferAvailableSize(%08x)", ringbuffer->packets - ringbuffer->packetsAvail, ringbufferAddr);
1475 }
1476 return ringbuffer->packets - ringbuffer->packetsAvail;
1477 }
1478
run(MipsCall & call)1479 void PostPutAction::run(MipsCall &call) {
1480 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringAddr_);
1481
1482 MpegContext *ctx = getMpegCtx(ringbuffer->mpeg);
1483 int writeOffset = ringbuffer->packetsWritePos % (s32)ringbuffer->packets;
1484 const u8 *data = Memory::GetPointer(ringbuffer->data + writeOffset * 2048);
1485
1486 int packetsAddedThisRound = currentMIPS->r[MIPS_REG_V0];
1487 if (packetsAddedThisRound > 0) {
1488 ringbufferPutPacketsAdded += packetsAddedThisRound;
1489 }
1490
1491 // It seems validation is done only by older mpeg libs.
1492 if (mpegLibVersion < 0x0105 && packetsAddedThisRound > 0) {
1493 // TODO: Faster / less wasteful validation.
1494 std::unique_ptr<MpegDemux> demuxer(new MpegDemux(packetsAddedThisRound * 2048, 0));
1495 int readOffset = ringbuffer->packetsRead % (s32)ringbuffer->packets;
1496 const u8 *buf = Memory::GetPointer(ringbuffer->data + readOffset * 2048);
1497 bool invalid = false;
1498 for (int i = 0; i < packetsAddedThisRound; ++i) {
1499 demuxer->addStreamData(buf, 2048);
1500 buf += 2048;
1501
1502 if (!demuxer->demux(0xFFFF)) {
1503 invalid = true;
1504 }
1505 }
1506 if (invalid) {
1507 // Bail out early - don't accept any of the packets, even the good ones.
1508 ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut(): invalid mpeg data");
1509 call.setReturnValue(ERROR_MPEG_INVALID_VALUE);
1510
1511 if (mpegLibVersion <= 0x0103) {
1512 // Act like they were actually added, but don't increment read pos.
1513 ringbuffer->packetsWritePos += packetsAddedThisRound;
1514 ringbuffer->packetsAvail += packetsAddedThisRound;
1515 }
1516 return;
1517 }
1518 }
1519
1520 if (ringbuffer->packetsRead == 0 && ctx->mediaengine && packetsAddedThisRound > 0) {
1521 // init mediaEngine
1522 AnalyzeMpeg(ctx->mpegheader, 2048, ctx);
1523 ctx->mediaengine->loadStream(ctx->mpegheader, 2048, ringbuffer->packets * ringbuffer->packetSize);
1524 }
1525 if (packetsAddedThisRound > 0) {
1526 if (packetsAddedThisRound > ringbuffer->packets - ringbuffer->packetsAvail) {
1527 WARN_LOG(ME, "sceMpegRingbufferPut clamping packetsAdded old=%i new=%i", packetsAddedThisRound, ringbuffer->packets - ringbuffer->packetsAvail);
1528 packetsAddedThisRound = ringbuffer->packets - ringbuffer->packetsAvail;
1529 }
1530 int actuallyAdded = ctx->mediaengine == NULL ? 8 : ctx->mediaengine->addStreamData(data, packetsAddedThisRound * 2048) / 2048;
1531 if (actuallyAdded != packetsAddedThisRound) {
1532 WARN_LOG_REPORT(ME, "sceMpegRingbufferPut(): unable to enqueue all added packets, going to overwrite some frames.");
1533 }
1534 ringbuffer->packetsRead += packetsAddedThisRound;
1535 ringbuffer->packetsWritePos += packetsAddedThisRound;
1536 ringbuffer->packetsAvail += packetsAddedThisRound;
1537 }
1538 DEBUG_LOG(ME, "packetAdded: %i packetsRead: %i packetsTotal: %i", packetsAddedThisRound, ringbuffer->packetsRead, ringbuffer->packets);
1539
1540 if (packetsAddedThisRound < 0 && ringbufferPutPacketsAdded == 0) {
1541 // Return an error.
1542 call.setReturnValue(packetsAddedThisRound);
1543 } else {
1544 call.setReturnValue(ringbufferPutPacketsAdded);
1545 }
1546 }
1547
1548
1549 // Program signals that it has written data to the ringbuffer and gets a callback ?
sceMpegRingbufferPut(u32 ringbufferAddr,int numPackets,int available)1550 static u32 sceMpegRingbufferPut(u32 ringbufferAddr, int numPackets, int available)
1551 {
1552 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ringbufferAddr);
1553 if (!ringbuffer.IsValid()) {
1554 // Would have crashed before, TODO test behavior.
1555 ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut(%08x, %i, %i): invalid ringbuffer address", ringbufferAddr, numPackets, available);
1556 return -1;
1557 }
1558
1559 numPackets = std::min(numPackets, available);
1560 // Generally, program will call sceMpegRingbufferAvailableSize() before this func.
1561 // Seems still need to check actual available, Patapon 3 for example.
1562 numPackets = std::min(numPackets, ringbuffer->packets - ringbuffer->packetsAvail);
1563 if (numPackets <= 0) {
1564 DEBUG_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): no packets to enqueue", ringbufferAddr, numPackets, available);
1565 return 0;
1566 }
1567
1568 MpegContext *ctx = getMpegCtx(ringbuffer->mpeg);
1569 if (!ctx) {
1570 WARN_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i): bad mpeg handle %08x", ringbufferAddr, numPackets, available, ringbuffer->mpeg);
1571 return -1;
1572 }
1573 ringbufferPutPacketsAdded = 0;
1574 // Execute callback function as a direct MipsCall, no blocking here so no messing around with wait states etc
1575 if (ringbuffer->callback_addr != 0) {
1576 DEBUG_LOG(ME, "sceMpegRingbufferPut(%08x, %i, %i)", ringbufferAddr, numPackets, available);
1577
1578 // Call this multiple times until we get numPackets.
1579 // Normally this would be if it did not read enough, but also if available > packets.
1580 // Should ultimately return the TOTAL number of returned packets.
1581 int writeOffset = ringbuffer->packetsWritePos % (s32)ringbuffer->packets;
1582 u32 packetsThisRound = 0;
1583 while (numPackets) {
1584 PostPutAction *action = (PostPutAction *)__KernelCreateAction(actionPostPut);
1585 action->setRingAddr(ringbufferAddr);
1586
1587 packetsThisRound = std::min(numPackets, (s32)ringbuffer->packets - writeOffset);
1588 numPackets -= packetsThisRound;
1589 u32 args[3] = { (u32)ringbuffer->data + (u32)writeOffset * 2048, packetsThisRound, (u32)ringbuffer->callback_args };
1590 hleEnqueueCall(ringbuffer->callback_addr, 3, args, action);
1591 writeOffset = (writeOffset + packetsThisRound) % (s32)ringbuffer->packets;
1592 // Old savestate don't use this feature, just for compatibility.
1593 if (!useRingbufferPutCallbackMulti)
1594 break;
1595 }
1596 } else {
1597 ERROR_LOG_REPORT(ME, "sceMpegRingbufferPut: callback_addr zero");
1598 }
1599 return 0;
1600 }
1601
sceMpegGetAvcAu(u32 mpeg,u32 streamId,u32 auAddr,u32 attrAddr)1602 static int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
1603 {
1604 MpegContext *ctx = getMpegCtx(mpeg);
1605 if (!ctx) {
1606 WARN_LOG(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr);
1607 return -1;
1608 }
1609
1610 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
1611 if (!ringbuffer.IsValid()) {
1612 // Would have crashed before, TODO test behavior.
1613 ERROR_LOG_REPORT(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr);
1614 return -1;
1615 }
1616
1617 if (PSP_CoreParameter().compat.flags().MpegAvcWarmUp) {
1618 if (ctx->mpegwarmUp == 0) {
1619 DEBUG_LOG(ME, "sceMpegGetAvcAu(%08x, %08x, %08x, %08x): warming up", mpeg, streamId, auAddr, attrAddr);
1620 ctx->mpegwarmUp++;
1621 return ERROR_MPEG_NO_DATA;
1622 }
1623 }
1624
1625 SceMpegAu avcAu;
1626 avcAu.read(auAddr);
1627
1628 if (ringbuffer->packetsRead == 0 || ringbuffer->packetsAvail == 0) {
1629 DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
1630 avcAu.pts = -1;
1631 avcAu.dts = -1;
1632 avcAu.write(auAddr);
1633 // TODO: Does this really reschedule?
1634 return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs);
1635 }
1636
1637 auto streamInfo = ctx->streamMap.find(streamId);
1638 if (streamInfo == ctx->streamMap.end()) {
1639 WARN_LOG_REPORT(ME, "sceMpegGetAvcAu: invalid video stream %08x", streamId);
1640 return -1;
1641 }
1642
1643 if (streamInfo->second.needsReset) {
1644 avcAu.pts = 0;
1645 streamInfo->second.needsReset = false;
1646 }
1647
1648 // esBuffer is the memory where this au data goes. We don't write the data to memory.
1649 // Instead, let's abuse it to keep track of the stream number.
1650 avcAu.esBuffer = streamInfo->second.num;
1651
1652 /*// Wait for audio if too much ahead
1653 if (ctx->atracRegistered && (ctx->mediaengine->getVideoTimeStamp() > ctx->mediaengine->getAudioTimeStamp() + getMaxAheadTimestamp(mpegRingbuffer)))
1654 {
1655 ERROR_LOG(ME, "sceMpegGetAvcAu - video too much ahead");
1656 // TODO: Does this really reschedule?
1657 return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get avc", mpegDecodeErrorDelayMs);
1658 }*/
1659
1660 int result = 0;
1661
1662 avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;
1663 avcAu.dts = avcAu.pts - videoTimestampStep;
1664
1665 if (ctx->mediaengine->IsVideoEnd()) {
1666 INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)avcAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
1667 ringbuffer->packetsAvail = 0;
1668
1669 result = ERROR_MPEG_NO_DATA;
1670 }
1671
1672 // The avcau struct may have been modified by mediaengine, write it back.
1673 avcAu.write(auAddr);
1674
1675 // Jeanne d'Arc return 00000000 as attrAddr here and cause WriteToHardware error
1676 if (Memory::IsValidAddress(attrAddr)) {
1677 Memory::Write_U32(1, attrAddr);
1678 }
1679
1680 DEBUG_LOG(ME, "%x=sceMpegGetAvcAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr);
1681 // TODO: sceMpegGetAvcAu seems to modify esSize, and delay when it's > 1000 or something.
1682 // There's definitely more to it, but ultimately it seems games should expect it to delay randomly.
1683 return hleDelayResult(result, "mpeg get avc", 100);
1684 }
1685
sceMpegFinish()1686 static u32 sceMpegFinish()
1687 {
1688 if (!isMpegInit) {
1689 WARN_LOG(ME, "sceMpegFinish(...): not initialized");
1690 // TODO: Need to properly hook module load/unload for this to work right.
1691 //return ERROR_MPEG_NOT_YET_INIT;
1692 } else {
1693 INFO_LOG(ME, "sceMpegFinish(...)");
1694 __VideoPmpShutdown();
1695 }
1696 isMpegInit = false;
1697 //__MpegFinish();
1698 return hleDelayResult(0, "mpeg finish", 250);
1699 }
1700
sceMpegQueryMemSize()1701 static u32 sceMpegQueryMemSize() {
1702 return hleLogSuccessX(ME, MpegRequiredMem());
1703 }
1704
sceMpegGetAtracAu(u32 mpeg,u32 streamId,u32 auAddr,u32 attrAddr)1705 static int sceMpegGetAtracAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
1706 {
1707 MpegContext *ctx = getMpegCtx(mpeg);
1708 if (!ctx) {
1709 WARN_LOG(ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamId, auAddr, attrAddr);
1710 return -1;
1711 }
1712
1713 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
1714 if (!ringbuffer.IsValid()) {
1715 // Would have crashed before, TODO test behavior.
1716 WARN_LOG(ME, "sceMpegGetAtracAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamId, auAddr, attrAddr);
1717 return -1;
1718 }
1719
1720 SceMpegAu atracAu;
1721 atracAu.read(auAddr);
1722
1723 auto streamInfo = ctx->streamMap.find(streamId);
1724 if (streamInfo != ctx->streamMap.end() && streamInfo->second.needsReset) {
1725 atracAu.pts = 0;
1726 streamInfo->second.needsReset = false;
1727 }
1728 if (streamInfo == ctx->streamMap.end()) {
1729 WARN_LOG_REPORT(ME, "sceMpegGetAtracAu: invalid audio stream %08x", streamId);
1730 // TODO: Why was this changed to not return an error?
1731 }
1732
1733 // The audio can end earlier than the video does.
1734 if (ringbuffer->packetsAvail == 0) {
1735 DEBUG_LOG(ME, "ERROR_MPEG_NO_DATA=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", mpeg, streamId, auAddr, attrAddr);
1736 // TODO: Does this really delay?
1737 return hleDelayResult(ERROR_MPEG_NO_DATA, "mpeg get atrac", mpegDecodeErrorDelayMs);
1738 }
1739
1740 // esBuffer is the memory where this au data goes. We don't write the data to memory.
1741 // Instead, let's abuse it to keep track of the stream number.
1742 if (streamInfo != ctx->streamMap.end()) {
1743 atracAu.esBuffer = streamInfo->second.num;
1744 ctx->mediaengine->setAudioStream(streamInfo->second.num);
1745 }
1746
1747 int result = 0;
1748 atracAu.pts = ctx->mediaengine->getAudioTimeStamp() + ctx->mpegFirstTimestamp;
1749
1750 if (ctx->mediaengine->IsVideoEnd()) {
1751 INFO_LOG(ME, "video end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
1752 ringbuffer->packetsAvail = 0;
1753 // TODO: Is this correct?
1754 if (!ctx->mediaengine->IsNoAudioData()) {
1755 WARN_LOG_REPORT(ME, "Video end without audio end, potentially skipping some audio?");
1756 }
1757 result = ERROR_MPEG_NO_DATA;
1758 }
1759
1760 if (ctx->atracRegistered && ctx->mediaengine->IsNoAudioData() && !ctx->endOfAudioReached) {
1761 WARN_LOG(ME, "Audio end reach. pts: %i dts: %i", (int)atracAu.pts, (int)ctx->mediaengine->getLastTimeStamp());
1762 ctx->endOfAudioReached = true;
1763 }
1764 if (ctx->mediaengine->IsNoAudioData()) {
1765 result = ERROR_MPEG_NO_DATA;
1766 }
1767
1768 atracAu.write(auAddr);
1769
1770 // 3rd birthday return 00000000 as attrAddr here and cause WriteToHardware error
1771 if (Memory::IsValidAddress(attrAddr)) {
1772 Memory::Write_U32(0, attrAddr);
1773 }
1774
1775 DEBUG_LOG(ME, "%x=sceMpegGetAtracAu(%08x, %08x, %08x, %08x)", result, mpeg, streamId, auAddr, attrAddr);
1776 // TODO: Not clear on exactly when this delays.
1777 return hleDelayResult(result, "mpeg get atrac", 100);
1778 }
1779
sceMpegQueryPcmEsSize(u32 mpeg,u32 esSizeAddr,u32 outSizeAddr)1780 static int sceMpegQueryPcmEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr)
1781 {
1782 if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) {
1783 ERROR_LOG(ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr);
1784 return -1;
1785 }
1786
1787 MpegContext *ctx = getMpegCtx(mpeg);
1788 if (!ctx) {
1789 WARN_LOG(ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr);
1790 return -1;
1791 }
1792
1793 ERROR_LOG(ME, "sceMpegQueryPcmEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr);
1794
1795 Memory::Write_U32(MPEG_PCM_ES_SIZE, esSizeAddr);
1796 Memory::Write_U32(MPEG_PCM_ES_OUTPUT_SIZE, outSizeAddr);
1797 return 0;
1798 }
1799
1800
sceMpegChangeGetAuMode(u32 mpeg,int streamUid,int mode)1801 static u32 sceMpegChangeGetAuMode(u32 mpeg, int streamUid, int mode)
1802 {
1803 MpegContext *ctx = getMpegCtx(mpeg);
1804 if (!ctx) {
1805 WARN_LOG(ME, "sceMpegChangeGetAuMode(%08x, %i, %i): bad mpeg handle", mpeg, streamUid, mode);
1806 return ERROR_MPEG_INVALID_VALUE;
1807 }
1808 if (mode != MPEG_AU_MODE_DECODE && mode != MPEG_AU_MODE_SKIP) {
1809 ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): bad mode", mpeg, streamUid, mode);
1810 return ERROR_MPEG_INVALID_VALUE;
1811 }
1812
1813 auto stream = ctx->streamMap.find(streamUid);
1814 if (stream == ctx->streamMap.end()) {
1815 ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID", mpeg, streamUid, mode);
1816 return ERROR_MPEG_INVALID_VALUE;
1817 } else {
1818 StreamInfo &info = stream->second;
1819 DEBUG_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): changing type=%d", mpeg, streamUid, mode, info.type);
1820 switch (info.type) {
1821 case MPEG_AVC_STREAM:
1822 if (mode == MPEG_AU_MODE_DECODE) {
1823 ctx->ignoreAvc = false;
1824 } else if (mode == MPEG_AU_MODE_SKIP) {
1825 ctx->ignoreAvc = true;
1826 }
1827 break;
1828 case MPEG_AUDIO_STREAM:
1829 case MPEG_ATRAC_STREAM:
1830 if (mode == MPEG_AU_MODE_DECODE) {
1831 ctx->ignoreAtrac = false;
1832 } else if (mode == MPEG_AU_MODE_SKIP) {
1833 ctx->ignoreAtrac = true;
1834 }
1835 break;
1836 case MPEG_PCM_STREAM:
1837 if (mode == MPEG_AU_MODE_DECODE) {
1838 ctx->ignorePcm = false;
1839 } else if (mode == MPEG_AU_MODE_SKIP) {
1840 ctx->ignorePcm = true;
1841 }
1842 break;
1843 default:
1844 ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAuMode(%08x, %i, %i): unknown streamID", mpeg, streamUid, mode);
1845 break;
1846 }
1847 }
1848 return 0;
1849 }
1850
sceMpegChangeGetAvcAuMode(u32 mpeg,u32 stream_addr,int mode)1851 static u32 sceMpegChangeGetAvcAuMode(u32 mpeg, u32 stream_addr, int mode)
1852 {
1853 if (!Memory::IsValidAddress(stream_addr)) {
1854 ERROR_LOG(ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): invalid addresses", mpeg, stream_addr, mode);
1855 return -1;
1856 }
1857
1858 MpegContext *ctx = getMpegCtx(mpeg);
1859 if (!ctx) {
1860 WARN_LOG(ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i): bad mpeg handle", mpeg, stream_addr, mode);
1861 return -1;
1862 }
1863
1864 ERROR_LOG_REPORT_ONCE(mpegChangeAvcAu, ME, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i)", mpeg, stream_addr, mode);
1865 return 0;
1866 }
1867
sceMpegGetPcmAu(u32 mpeg,int streamUid,u32 auAddr,u32 attrAddr)1868 static u32 sceMpegGetPcmAu(u32 mpeg, int streamUid, u32 auAddr, u32 attrAddr)
1869 {
1870 MpegContext *ctx = getMpegCtx(mpeg);
1871 if (!ctx) {
1872 WARN_LOG(ME, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x): bad mpeg handle", mpeg, streamUid, auAddr, attrAddr);
1873 return -1;
1874 }
1875 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
1876 if (!ringbuffer.IsValid()) {
1877 // Would have crashed before, TODO test behavior
1878 WARN_LOG(ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): invalid ringbuffer address", mpeg, streamUid, auAddr, attrAddr);
1879 return -1;
1880 }
1881 if (!Memory::IsValidAddress(streamUid)) {
1882 WARN_LOG(ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): didn't get a fake stream", mpeg, streamUid, auAddr, attrAddr);
1883 return ERROR_MPEG_INVALID_ADDR;
1884 }
1885 SceMpegAu atracAu;
1886 atracAu.read(auAddr);
1887 auto streamInfo = ctx->streamMap.find(streamUid);
1888 if (streamInfo == ctx->streamMap.end()) {
1889 WARN_LOG(ME, "sceMpegGetPcmAu(%08x, %08x, %08x, %08x): bad streamUid ", mpeg, streamUid, auAddr, attrAddr);
1890 return -1;
1891 }
1892
1893 atracAu.write(auAddr);
1894 u32 attr = 1 << 7; // Sampling rate (1 = 44.1kHz).
1895 attr |= 2; // Number of channels (1 - MONO / 2 - STEREO).
1896 if (Memory::IsValidAddress(attrAddr))
1897 Memory::Write_U32(attr, attrAddr);
1898
1899 ERROR_LOG_REPORT_ONCE(mpegPcmAu, ME, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x)", mpeg, streamUid, auAddr, attrAddr);
1900 return 0;
1901 }
1902
__MpegRingbufferQueryPackNum(u32 memorySize)1903 static int __MpegRingbufferQueryPackNum(u32 memorySize) {
1904 return memorySize / (2048 + 104);
1905 }
1906
sceMpegRingbufferQueryPackNum(u32 memorySize)1907 static int sceMpegRingbufferQueryPackNum(u32 memorySize) {
1908 DEBUG_LOG(ME, "sceMpegRingbufferQueryPackNum(%i)", memorySize);
1909 return __MpegRingbufferQueryPackNum(memorySize);
1910 }
1911
sceMpegFlushAllStream(u32 mpeg)1912 static u32 sceMpegFlushAllStream(u32 mpeg)
1913 {
1914 MpegContext *ctx = getMpegCtx(mpeg);
1915 if (!ctx) {
1916 WARN_LOG(ME, "sceMpegFlushAllStream(%08x): bad mpeg handle", mpeg);
1917 return -1;
1918 }
1919
1920 WARN_LOG(ME, "UNIMPL sceMpegFlushAllStream(%08x)", mpeg);
1921
1922 ctx->isAnalyzed = false;
1923
1924 auto ringbuffer = PSPPointer<SceMpegRingBuffer>::Create(ctx->mpegRingbufferAddr);
1925 if (ringbuffer.IsValid()) {
1926 ringbuffer->packetsAvail = 0;
1927 ringbuffer->packetsRead = 0;
1928 ringbuffer->packetsWritePos = 0;
1929 }
1930
1931 return 0;
1932 }
1933
sceMpegFlushStream(u32 mpeg,int stream_addr)1934 static u32 sceMpegFlushStream(u32 mpeg, int stream_addr)
1935 {
1936 if (!Memory::IsValidAddress(stream_addr)) {
1937 ERROR_LOG(ME, "UNIMPL sceMpegFlushStream(%08x, %i): invalid addresses", mpeg , stream_addr);
1938 return -1;
1939 }
1940
1941 MpegContext *ctx = getMpegCtx(mpeg);
1942 if (!ctx) {
1943 WARN_LOG(ME, "UNIMPL sceMpegFlushStream(%08x, %i): bad mpeg handle", mpeg , stream_addr);
1944 return -1;
1945 }
1946
1947 ERROR_LOG(ME, "UNIMPL sceMpegFlushStream(%08x, %i)", mpeg , stream_addr);
1948 //__MpegFinish();
1949 return 0;
1950 }
1951
sceMpegAvcCopyYCbCr(u32 mpeg,u32 sourceAddr,u32 YCbCrAddr)1952 static u32 sceMpegAvcCopyYCbCr(u32 mpeg, u32 sourceAddr, u32 YCbCrAddr)
1953 {
1954 if (!Memory::IsValidAddress(sourceAddr) || !Memory::IsValidAddress(YCbCrAddr)) {
1955 ERROR_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): invalid addresses", mpeg, sourceAddr, YCbCrAddr);
1956 return -1;
1957 }
1958
1959 MpegContext *ctx = getMpegCtx(mpeg);
1960 if (!ctx) {
1961 ERROR_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x): bad mpeg handle", mpeg, sourceAddr, YCbCrAddr);
1962 return -1;
1963 }
1964
1965 WARN_LOG(ME, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x)", mpeg, sourceAddr, YCbCrAddr);
1966 return 0;
1967 }
1968
sceMpegAtracDecode(u32 mpeg,u32 auAddr,u32 bufferAddr,int init)1969 static u32 sceMpegAtracDecode(u32 mpeg, u32 auAddr, u32 bufferAddr, int init)
1970 {
1971 MpegContext *ctx = getMpegCtx(mpeg);
1972 if (!ctx) {
1973 WARN_LOG(ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i): bad mpeg handle", mpeg, auAddr, bufferAddr, init);
1974 return -1;
1975 }
1976
1977 if (!Memory::IsValidAddress(bufferAddr)) {
1978 WARN_LOG(ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i): invalid addresses", mpeg, auAddr, bufferAddr, init);
1979 return -1;
1980 }
1981
1982 DEBUG_LOG(ME, "sceMpegAtracDecode(%08x, %08x, %08x, %i)", mpeg, auAddr, bufferAddr, init);
1983
1984 SceMpegAu atracAu;
1985 atracAu.read(auAddr);
1986
1987 // We kept track of the stream number here in sceMpegGetAtracAu().
1988 ctx->mediaengine->setAudioStream(atracAu.esBuffer);
1989
1990 Memory::Memset(bufferAddr, 0, MPEG_ATRAC_ES_OUTPUT_SIZE, "MpegAtracClear");
1991 ctx->mediaengine->getAudioSamples(bufferAddr);
1992 atracAu.pts = ctx->mediaengine->getAudioTimeStamp() + ctx->mpegFirstTimestamp;
1993
1994 atracAu.write(auAddr);
1995
1996
1997 return hleDelayResult(0, "mpeg atrac decode", atracDecodeDelayMs);
1998 //hleEatMicro(4000);
1999 //return hleDelayResult(0, "mpeg atrac decode", 200);
2000 }
2001
2002 // YCbCr -> RGB color space conversion
sceMpegAvcCsc(u32 mpeg,u32 sourceAddr,u32 rangeAddr,int frameWidth,u32 destAddr)2003 static u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth, u32 destAddr)
2004 {
2005 if (!Memory::IsValidAddress(sourceAddr) || !Memory::IsValidAddress(rangeAddr) || !Memory::IsValidAddress(destAddr)) {
2006 ERROR_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): invalid addresses", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr);
2007 return -1;
2008 }
2009
2010 MpegContext *ctx = getMpegCtx(mpeg);
2011 if (!ctx) {
2012 WARN_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x): bad mpeg handle", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr);
2013 return -1;
2014 }
2015
2016 DEBUG_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x)", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr);
2017
2018 if (frameWidth == 0) {
2019 if (!ctx->defaultFrameWidth) {
2020 frameWidth = ctx->avc.avcDetailFrameWidth;
2021 } else {
2022 frameWidth = ctx->defaultFrameWidth;
2023 }
2024 }
2025
2026 int x = Memory::Read_U32(rangeAddr);
2027 int y = Memory::Read_U32(rangeAddr + 4);
2028 int width = Memory::Read_U32(rangeAddr + 8);
2029 int height = Memory::Read_U32(rangeAddr + 12);
2030
2031 if (x < 0 || y < 0 || width < 0 || height < 0) {
2032 WARN_LOG(ME, "sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x) returning ERROR_INVALID_VALUE", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr);
2033 return SCE_KERNEL_ERROR_INVALID_VALUE;
2034 }
2035
2036 int destSize = ctx->mediaengine->writeVideoImageWithRange(destAddr, frameWidth, ctx->videoPixelMode, x, y, width, height);
2037 gpu->NotifyVideoUpload(destAddr, destSize, frameWidth, ctx->videoPixelMode);
2038
2039 // Do not use avcDecodeDelayMs 's value
2040 // Will cause video 's screen dislocation in Bleach heat of soul 6
2041 // https://github.com/hrydgard/ppsspp/issues/5535
2042 // If do not use DelayResult,Wil cause flickering in Dengeki no Pilot: Tenkuu no Kizuna
2043 // https://github.com/hrydgard/ppsspp/issues/7549
2044
2045 return hleDelayResult(0, "mpeg avc csc", avcCscDelayMs);
2046 }
2047
sceMpegRingbufferDestruct(u32 ringbufferAddr)2048 static u32 sceMpegRingbufferDestruct(u32 ringbufferAddr)
2049 {
2050 DEBUG_LOG(ME, "sceMpegRingbufferDestruct(%08x)", ringbufferAddr);
2051 // Apparently, does nothing.
2052 return 0;
2053 }
2054
sceMpegAvcInitYCbCr(u32 mpeg,int mode,int width,int height,u32 ycbcr_addr)2055 static u32 sceMpegAvcInitYCbCr(u32 mpeg, int mode, int width, int height, u32 ycbcr_addr)
2056 {
2057 if (!Memory::IsValidAddress(ycbcr_addr)) {
2058 ERROR_LOG(ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): invalid addresses", mpeg, mode, width, height, ycbcr_addr);
2059 return -1;
2060 }
2061
2062 MpegContext *ctx = getMpegCtx(mpeg);
2063 if (!ctx) {
2064 WARN_LOG(ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x): bad mpeg handle", mpeg, mode, width, height, ycbcr_addr);
2065 return -1;
2066 }
2067
2068 ERROR_LOG(ME, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, ycbcr_addr);
2069 return 0;
2070 }
2071
sceMpegAvcQueryYCbCrSize(u32 mpeg,u32 mode,u32 width,u32 height,u32 resultAddr)2072 static int sceMpegAvcQueryYCbCrSize(u32 mpeg, u32 mode, u32 width, u32 height, u32 resultAddr)
2073 {
2074 if ((width & 15) != 0 || (height & 15) != 0 || height > 272 || width > 480) {
2075 ERROR_LOG(ME, "sceMpegAvcQueryYCbCrSize: bad w/h %i x %i", width, height);
2076 return ERROR_MPEG_INVALID_VALUE;
2077 }
2078
2079 DEBUG_LOG(ME, "sceMpegAvcQueryYCbCrSize(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, resultAddr);
2080
2081 int size = (width / 2) * (height / 2) * 6 + 128;
2082 Memory::Write_U32(size, resultAddr);
2083 return 0;
2084 }
2085
sceMpegQueryUserdataEsSize(u32 mpeg,u32 esSizeAddr,u32 outSizeAddr)2086 static u32 sceMpegQueryUserdataEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr)
2087 {
2088 if (!Memory::IsValidAddress(esSizeAddr) || !Memory::IsValidAddress(outSizeAddr)) {
2089 ERROR_LOG(ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x): invalid addresses", mpeg, esSizeAddr, outSizeAddr);
2090 return -1;
2091 }
2092
2093 MpegContext *ctx = getMpegCtx(mpeg);
2094 if (!ctx) {
2095 WARN_LOG(ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x): bad mpeg handle", mpeg, esSizeAddr, outSizeAddr);
2096 return -1;
2097 }
2098
2099 DEBUG_LOG(ME, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr);
2100
2101 Memory::Write_U32(MPEG_DATA_ES_SIZE, esSizeAddr);
2102 Memory::Write_U32(MPEG_DATA_ES_OUTPUT_SIZE, outSizeAddr);
2103 return 0;
2104 }
2105
sceMpegAvcResourceGetAvcDecTopAddr(u32 mpeg)2106 static u32 sceMpegAvcResourceGetAvcDecTopAddr(u32 mpeg)
2107 {
2108 ERROR_LOG(ME, "UNIMPL sceMpegAvcResourceGetAvcDecTopAddr(%08x)", mpeg);
2109 // it's just a random address
2110 return 0x12345678;
2111 }
2112
sceMpegAvcResourceFinish(u32 mpeg)2113 static u32 sceMpegAvcResourceFinish(u32 mpeg)
2114 {
2115 DEBUG_LOG(ME,"UNIMPL sceMpegAvcResourceFinish(%08x)", mpeg);
2116 return 0;
2117 }
2118
sceMpegAvcResourceGetAvcEsBuf(u32 mpeg)2119 static u32 sceMpegAvcResourceGetAvcEsBuf(u32 mpeg)
2120 {
2121 ERROR_LOG_REPORT_ONCE(mpegResourceEsBuf, ME, "UNIMPL sceMpegAvcResourceGetAvcEsBuf(%08x)", mpeg);
2122 return 0;
2123 }
2124
sceMpegAvcResourceInit(u32 mpeg)2125 static u32 sceMpegAvcResourceInit(u32 mpeg)
2126 {
2127 if (mpeg != 1) {
2128 return ERROR_MPEG_INVALID_VALUE;
2129 }
2130
2131 ERROR_LOG(ME, "UNIMPL sceMpegAvcResourceInit(%08x)", mpeg);
2132 return 0;
2133 }
2134
convertABGRToYCbCr(u32 abgr)2135 static u32 convertABGRToYCbCr(u32 abgr) {
2136 //see http://en.wikipedia.org/wiki/Yuv#Y.27UV444_to_RGB888_conversion for more information.
2137 u8 r = (abgr >> 0) & 0xFF;
2138 u8 g = (abgr >> 8) & 0xFF;
2139 u8 b = (abgr >> 16) & 0xFF;
2140 int y = 0.299f * r + 0.587f * g + 0.114f * b + 0;
2141 int cb = -0.169f * r - 0.331f * g + 0.499f * b + 128.0f;
2142 int cr = 0.499f * r - 0.418f * g - 0.0813f * b + 128.0f;
2143
2144 // check yCbCr value
2145 if ( y > 0xFF) y = 0xFF; if ( y < 0) y = 0;
2146 if (cb > 0xFF) cb = 0xFF; if (cb < 0) cb = 0;
2147 if (cr > 0xFF) cr = 0xFF; if (cr < 0) cr = 0;
2148
2149 return (y << 16) | (cb << 8) | cr;
2150 }
2151
__MpegAvcConvertToYuv420(const void * data,u32 bufferOutputAddr,int width,int height)2152 static int __MpegAvcConvertToYuv420(const void *data, u32 bufferOutputAddr, int width, int height) {
2153 u32 *imageBuffer = (u32*)data;
2154 int sizeY = width * height;
2155 int sizeCb = sizeY >> 2;
2156 u8 *Y = (u8*)Memory::GetPointer(bufferOutputAddr);
2157 u8 *Cb = Y + sizeY;
2158 u8 *Cr = Cb + sizeCb;
2159
2160 for (int y = 0; y < height; ++y) {
2161 for (int x = 0; x < width; x += 4) {
2162 u32 abgr0 = imageBuffer[x + 0];
2163 u32 abgr1 = imageBuffer[x + 1];
2164 u32 abgr2 = imageBuffer[x + 2];
2165 u32 abgr3 = imageBuffer[x + 3];
2166
2167 u32 yCbCr0 = convertABGRToYCbCr(abgr0);
2168 u32 yCbCr1 = convertABGRToYCbCr(abgr1);
2169 u32 yCbCr2 = convertABGRToYCbCr(abgr2);
2170 u32 yCbCr3 = convertABGRToYCbCr(abgr3);
2171
2172 Y[x + 0] = (yCbCr0 >> 16) & 0xFF;
2173 Y[x + 1] = (yCbCr1 >> 16) & 0xFF;
2174 Y[x + 2] = (yCbCr2 >> 16) & 0xFF;
2175 Y[x + 3] = (yCbCr3 >> 16) & 0xFF;
2176
2177 *Cb++ = (yCbCr0 >> 8) & 0xFF;
2178 *Cr++ = yCbCr0 & 0xFF;
2179 }
2180 imageBuffer += width;
2181 Y += width ;
2182 }
2183 return (width << 16) | height;
2184 }
2185
sceMpegAvcConvertToYuv420(u32 mpeg,u32 bufferOutputAddr,u32 unknown1,int unknown2)2186 static int sceMpegAvcConvertToYuv420(u32 mpeg, u32 bufferOutputAddr, u32 unknown1, int unknown2)
2187 {
2188 if (!Memory::IsValidAddress(bufferOutputAddr)) {
2189 ERROR_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): invalid addresses", mpeg, bufferOutputAddr, unknown1, unknown2);
2190 return -1;
2191 }
2192
2193 MpegContext *ctx = getMpegCtx(mpeg);
2194 if (!ctx) {
2195 WARN_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, bufferOutputAddr, unknown1, unknown2);
2196 return -1;
2197 }
2198
2199 if (ctx->mediaengine->m_buffer == 0){
2200 WARN_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x): m_buffer is zero ", mpeg, bufferOutputAddr, unknown1, unknown2);
2201 return ERROR_MPEG_AVC_INVALID_VALUE;
2202 }
2203
2204 DEBUG_LOG(ME, "sceMpegAvcConvertToYuv420(%08x, %08x, %08x, %08x)", mpeg, bufferOutputAddr, unknown1, unknown2);
2205 const u8 *data = ctx->mediaengine->getFrameImage();
2206 int width = ctx->mediaengine->m_desWidth;
2207 int height = ctx->mediaengine->m_desHeight;
2208
2209 if (data) {
2210 __MpegAvcConvertToYuv420(data, bufferOutputAddr, width, height);
2211 }
2212 return 0;
2213 }
2214
sceMpegGetUserdataAu(u32 mpeg,u32 streamUid,u32 auAddr,u32 resultAddr)2215 static int sceMpegGetUserdataAu(u32 mpeg, u32 streamUid, u32 auAddr, u32 resultAddr)
2216 {
2217 MpegContext *ctx = getMpegCtx(mpeg);
2218 if (!ctx) {
2219 WARN_LOG(ME, "sceMpegGetUserdataAu(%08x, %08x, %08x, %08x): bad mpeg handle", mpeg, streamUid, auAddr, resultAddr);
2220 return -1;
2221 }
2222
2223 DEBUG_LOG(ME, "sceMpegGetUserdataAu(%08x, %08x, %08x, %08x)", mpeg, streamUid, auAddr, resultAddr);
2224
2225 // TODO: Are these at all right? Seen in Phantasy Star Portable 2.
2226 Memory::Write_U32(0, resultAddr);
2227 Memory::Write_U32(0, resultAddr + 4);
2228
2229 // We currently can't demux userdata so this seems like the best thing to return in the meantime..
2230 // Then we probably shouldn't do the above writes? but it works...
2231 return ERROR_MPEG_NO_DATA;
2232 }
2233
sceMpegNextAvcRpAu(u32 mpeg,u32 streamUid)2234 static u32 sceMpegNextAvcRpAu(u32 mpeg, u32 streamUid)
2235 {
2236 MpegContext *ctx = getMpegCtx(mpeg);
2237 if (!ctx) {
2238 WARN_LOG(ME, "UNIMPL sceMpegNextAvcRpAu(%08x, %08x): bad mpeg handle", mpeg, streamUid);
2239 return -1;
2240 }
2241
2242 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegNextAvcRpAu(%08x, %08x)", mpeg, streamUid);
2243
2244 return 0;
2245 }
2246
sceMpegGetAvcNalAu(u32 mpeg)2247 static u32 sceMpegGetAvcNalAu(u32 mpeg)
2248 {
2249 MpegContext *ctx = getMpegCtx(mpeg);
2250 if (!ctx) {
2251 WARN_LOG(ME, "UNIMPL sceMpegGetAvcNalAu(%08x): bad mpeg handle", mpeg);
2252 return -1;
2253 }
2254
2255 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegGetAvcNalAu(%08x)", mpeg);
2256
2257 return 0;
2258 }
2259
sceMpegAvcDecodeDetailIndex(u32 mpeg)2260 static u32 sceMpegAvcDecodeDetailIndex(u32 mpeg)
2261 {
2262 MpegContext *ctx = getMpegCtx(mpeg);
2263 if (!ctx) {
2264 WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeDetailIndex(%08x): bad mpeg handle", mpeg);
2265 return -1;
2266 }
2267
2268 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcDecodeDetailIndex(%08x)", mpeg);
2269
2270 return 0;
2271 }
2272
sceMpegAvcDecodeDetail2(u32 mpeg)2273 static u32 sceMpegAvcDecodeDetail2(u32 mpeg)
2274 {
2275 MpegContext *ctx = getMpegCtx(mpeg);
2276 if (!ctx) {
2277 WARN_LOG(ME, "UNIMPL sceMpegAvcDecodeDetail2(%08x): bad mpeg handle", mpeg);
2278 return -1;
2279 }
2280
2281 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcDecodeDetail2(%08x)", mpeg);
2282
2283 return 0;
2284 }
2285
sceMpegGetAvcEsAu(u32 mpeg)2286 static u32 sceMpegGetAvcEsAu(u32 mpeg)
2287 {
2288 MpegContext *ctx = getMpegCtx(mpeg);
2289 if (!ctx) {
2290 WARN_LOG(ME, "UNIMPL sceMpegGetAvcEsAu(%08x): bad mpeg handle", mpeg);
2291 return -1;
2292 }
2293
2294 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegGetAvcEsAu(%08x)", mpeg);
2295
2296 return 0;
2297 }
2298
sceMpegAvcCscInfo(u32 mpeg)2299 static u32 sceMpegAvcCscInfo(u32 mpeg)
2300 {
2301 MpegContext *ctx = getMpegCtx(mpeg);
2302 if (!ctx) {
2303 WARN_LOG(ME, "UNIMPL sceMpegAvcCscInfo(%08x): bad mpeg handle", mpeg);
2304 return -1;
2305 }
2306
2307 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcCscInfo(%08x)", mpeg);
2308
2309 return 0;
2310 }
2311
sceMpegAvcCscMode(u32 mpeg)2312 static u32 sceMpegAvcCscMode(u32 mpeg)
2313 {
2314 MpegContext *ctx = getMpegCtx(mpeg);
2315 if (!ctx) {
2316 WARN_LOG(ME, "UNIMPL sceMpegAvcCscMode(%08x): bad mpeg handle", mpeg);
2317 return -1;
2318 }
2319
2320 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegAvcCscMode(%08x)", mpeg);
2321
2322 return 0;
2323 }
2324
sceMpegFlushAu(u32 mpeg)2325 static u32 sceMpegFlushAu(u32 mpeg)
2326 {
2327 MpegContext *ctx = getMpegCtx(mpeg);
2328 if (!ctx) {
2329 WARN_LOG(ME, "UNIMPL sceMpegFlushAu(%08x): bad mpeg handle", mpeg);
2330 return -1;
2331 }
2332
2333 ERROR_LOG_REPORT(ME, "UNIMPL sceMpegFlushAu(%08x)", mpeg);
2334
2335 return 0;
2336 }
2337
2338 const HLEFunction sceMpeg[] =
2339 {
2340 {0XE1CE83A7, &WrapI_UUUU<sceMpegGetAtracAu>, "sceMpegGetAtracAu", 'i', "xxxx" },
2341 {0XFE246728, &WrapI_UUUU<sceMpegGetAvcAu>, "sceMpegGetAvcAu", 'i', "xxxx" },
2342 {0XD8C5F121, &WrapU_UUUUUUU<sceMpegCreate>, "sceMpegCreate", 'x', "xxxxxxx" ,HLE_CLEAR_STACK_BYTES, 0xA8},
2343 {0XF8DCB679, &WrapI_UUU<sceMpegQueryAtracEsSize>, "sceMpegQueryAtracEsSize", 'i', "xxx" },
2344 {0XC132E22F, &WrapU_V<sceMpegQueryMemSize>, "sceMpegQueryMemSize", 'x', "" ,HLE_CLEAR_STACK_BYTES, 0x18},
2345 {0X21FF80E4, &WrapI_UUU<sceMpegQueryStreamOffset>, "sceMpegQueryStreamOffset", 'i', "xxx",HLE_CLEAR_STACK_BYTES, 0x18},
2346 {0X611E9E11, &WrapU_UU<sceMpegQueryStreamSize>, "sceMpegQueryStreamSize", 'x', "xx",HLE_CLEAR_STACK_BYTES, 0x8},
2347 {0X42560F23, &WrapI_UUU<sceMpegRegistStream>, "sceMpegRegistStream", 'i', "xxx" ,HLE_CLEAR_STACK_BYTES, 0x48},
2348 {0X591A4AA2, &WrapU_UI<sceMpegUnRegistStream>, "sceMpegUnRegistStream", 'x', "xi" ,HLE_CLEAR_STACK_BYTES, 0x18 },
2349 {0X707B7629, &WrapU_U<sceMpegFlushAllStream>, "sceMpegFlushAllStream", 'x', "x" },
2350 {0X500F0429, &WrapU_UI<sceMpegFlushStream>, "sceMpegFlushStream", 'x', "xi" },
2351 {0XA780CF7E, &WrapI_U<sceMpegMallocAvcEsBuf>, "sceMpegMallocAvcEsBuf", 'i', "x" },
2352 {0XCEB870B1, &WrapI_UI<sceMpegFreeAvcEsBuf>, "sceMpegFreeAvcEsBuf", 'i', "xi" },
2353 {0X167AFD9E, &WrapI_UUU<sceMpegInitAu>, "sceMpegInitAu", 'i', "xxx" },
2354 {0X682A619B, &WrapU_V<sceMpegInit>, "sceMpegInit", 'x', "" ,HLE_CLEAR_STACK_BYTES, 0x48},
2355 {0X606A4649, &WrapI_U<sceMpegDelete>, "sceMpegDelete", 'i', "x",HLE_CLEAR_STACK_BYTES, 0x18},
2356 {0X874624D6, &WrapU_V<sceMpegFinish>, "sceMpegFinish", 'x', "" ,HLE_CLEAR_STACK_BYTES, 0x18},
2357 {0X800C44DF, &WrapU_UUUI<sceMpegAtracDecode>, "sceMpegAtracDecode", 'x', "xxxi" },
2358 {0X0E3C2E9D, &WrapU_UUUUU<sceMpegAvcDecode>, "sceMpegAvcDecode", 'x', "xxxxx" },
2359 {0X740FCCD1, &WrapU_UUUU<sceMpegAvcDecodeStop>, "sceMpegAvcDecodeStop", 'x', "xxxx" },
2360 {0X4571CC64, &WrapU_U<sceMpegAvcDecodeFlush>, "sceMpegAvcDecodeFlush", 'x', "x" },
2361 {0X0F6C18D7, &WrapI_UU<sceMpegAvcDecodeDetail>, "sceMpegAvcDecodeDetail", 'i', "xx" },
2362 {0XA11C7026, &WrapI_UU<sceMpegAvcDecodeMode>, "sceMpegAvcDecodeMode", 'i', "xx" },
2363 {0X37295ED8, &WrapU_UUUUUU<sceMpegRingbufferConstruct>, "sceMpegRingbufferConstruct", 'x', "xxxxxx" },
2364 {0X13407F13, &WrapU_U<sceMpegRingbufferDestruct>, "sceMpegRingbufferDestruct", 'x', "x" },
2365 {0XB240A59E, &WrapU_UII<sceMpegRingbufferPut>, "sceMpegRingbufferPut", 'x', "xxx" },
2366 {0XB5F6DC87, &WrapI_U<sceMpegRingbufferAvailableSize>, "sceMpegRingbufferAvailableSize", 'i', "x" },
2367 {0XD7A29F46, &WrapU_I<sceMpegRingbufferQueryMemSize>, "sceMpegRingbufferQueryMemSize", 'x', "i" },
2368 {0X769BEBB6, &WrapI_U<sceMpegRingbufferQueryPackNum>, "sceMpegRingbufferQueryPackNum", 'i', "x" },
2369 {0X211A057C, &WrapI_UUUUU<sceMpegAvcQueryYCbCrSize>, "sceMpegAvcQueryYCbCrSize", 'i', "xxxxx" },
2370 {0XF0EB1125, &WrapI_UUUU<sceMpegAvcDecodeYCbCr>, "sceMpegAvcDecodeYCbCr", 'i', "xxxx" },
2371 {0XF2930C9C, &WrapU_UUU<sceMpegAvcDecodeStopYCbCr>, "sceMpegAvcDecodeStopYCbCr", 'x', "xxx" },
2372 {0X67179B1B, &WrapU_UIIIU<sceMpegAvcInitYCbCr>, "sceMpegAvcInitYCbCr", 'x', "xiiix" },
2373 {0X0558B075, &WrapU_UUU<sceMpegAvcCopyYCbCr>, "sceMpegAvcCopyYCbCr", 'x', "xxx" },
2374 {0X31BD0272, &WrapU_UUUIU<sceMpegAvcCsc>, "sceMpegAvcCsc", 'x', "xxxix" },
2375 {0X9DCFB7EA, &WrapU_UII<sceMpegChangeGetAuMode>, "sceMpegChangeGetAuMode", 'x', "xii" },
2376 {0X8C1E027D, &WrapU_UIUU<sceMpegGetPcmAu>, "sceMpegGetPcmAu", 'x', "xixx" },
2377 {0XC02CF6B5, &WrapI_UUU<sceMpegQueryPcmEsSize>, "sceMpegQueryPcmEsSize", 'i', "xxx" },
2378 {0XC45C99CC, &WrapU_UUU<sceMpegQueryUserdataEsSize>, "sceMpegQueryUserdataEsSize", 'x', "xxx" },
2379 {0X234586AE, &WrapU_UUI<sceMpegChangeGetAvcAuMode>, "sceMpegChangeGetAvcAuMode", 'x', "xxi" },
2380 {0X63B9536A, &WrapU_U<sceMpegAvcResourceGetAvcDecTopAddr>, "sceMpegAvcResourceGetAvcDecTopAddr", 'x', "x" },
2381 {0X8160A2FE, &WrapU_U<sceMpegAvcResourceFinish>, "sceMpegAvcResourceFinish", 'x', "x" },
2382 {0XAF26BB01, &WrapU_U<sceMpegAvcResourceGetAvcEsBuf>, "sceMpegAvcResourceGetAvcEsBuf", 'x', "x" },
2383 {0XFCBDB5AD, &WrapU_U<sceMpegAvcResourceInit>, "sceMpegAvcResourceInit", 'x', "x" },
2384 {0XF5E7EA31, &WrapI_UUUI<sceMpegAvcConvertToYuv420>, "sceMpegAvcConvertToYuv420", 'i', "xxxi" },
2385 {0X01977054, &WrapI_UUUU<sceMpegGetUserdataAu>, "sceMpegGetUserdataAu", 'i', "xxxx" },
2386 {0X3C37A7A6, &WrapU_UU<sceMpegNextAvcRpAu>, "sceMpegNextAvcRpAu", 'x', "xx" },
2387 {0X11F95CF1, &WrapU_U<sceMpegGetAvcNalAu>, "sceMpegGetAvcNalAu", 'x', "x" },
2388 {0XAB0E9556, &WrapU_U<sceMpegAvcDecodeDetailIndex>, "sceMpegAvcDecodeDetailIndex", 'x', "x" },
2389 {0XCF3547A2, &WrapU_U<sceMpegAvcDecodeDetail2>, "sceMpegAvcDecodeDetail2", 'x', "x" },
2390 {0X921FCCCF, &WrapU_U<sceMpegGetAvcEsAu>, "sceMpegGetAvcEsAu", 'x', "x" },
2391 {0XE95838F6, &WrapU_U<sceMpegAvcCscInfo>, "sceMpegAvcCscInfo", 'x', "x" },
2392 {0XD1CE4950, &WrapU_U<sceMpegAvcCscMode>, "sceMpegAvcCscMode", 'x', "x" },
2393 {0XDBB60658, &WrapU_U<sceMpegFlushAu>, "sceMpegFlushAu", 'x', "x" },
2394 {0XD4DD6E75, nullptr, "sceMpeg_D4DD6E75", '?', "" },
2395 {0X11CAB459, nullptr, "sceMpeg_11CAB459", '?', "" },
2396 {0XC345DED2, nullptr, "sceMpeg_C345DED2", '?', "" },
2397 {0XB27711A8, nullptr, "sceMpeg_B27711A8", '?', "" },
2398 {0X988E9E12, nullptr, "sceMpeg_988E9E12", '?', "" },
2399 };
2400
Register_sceMpeg()2401 void Register_sceMpeg()
2402 {
2403 RegisterModule("sceMpeg", ARRAY_SIZE(sceMpeg), sceMpeg);
2404 }
2405
2406 // This function is currently only been used for PMP videos
2407 // p pointing to a SceMpegLLI structure consists of video frame blocks.
sceMpegbase_BEA18F91(u32 p)2408 static u32 sceMpegbase_BEA18F91(u32 p)
2409 {
2410 pmp_videoSource = p;
2411 pmp_nBlocks = 0;
2412 SceMpegLLI lli;
2413 while (1){
2414 Memory::ReadStruct(p, &lli);
2415 pmp_nBlocks++;
2416 // lli.Next ==0 for last block
2417 if (lli.Next == 0){
2418 break;
2419 }
2420 p = p + sizeof(SceMpegLLI);
2421 }
2422
2423 DEBUG_LOG(ME, "sceMpegbase_BEA18F91(%08x), received %d block(s)", pmp_videoSource, pmp_nBlocks);
2424 return 0;
2425 }
2426
2427 const HLEFunction sceMpegbase[] =
2428 {
2429 {0XBEA18F91, &WrapU_U<sceMpegbase_BEA18F91>, "sceMpegbase_BEA18F91", 'x', "x" },
2430 {0X492B5E4B, nullptr, "sceMpegBaseCscInit", '?', "" },
2431 {0X0530BE4E, nullptr, "sceMpegbase_0530BE4E", '?', "" },
2432 {0X91929A21, nullptr, "sceMpegBaseCscAvc", '?', "" },
2433 {0X304882E1, nullptr, "sceMpegBaseCscAvcRange", '?', "" },
2434 {0X7AC0321A, nullptr, "sceMpegBaseYCrCbCopy", '?', "" }
2435 };
2436
Register_sceMpegbase()2437 void Register_sceMpegbase()
2438 {
2439 RegisterModule("sceMpegbase", ARRAY_SIZE(sceMpegbase), sceMpegbase);
2440 };
2441