mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Five of the six functions in this module were registered as nullptr, so any
caller reaching them got nothing. mpeg.prx needs all of them, and this is the
first of the pieces required before the real module can run in place of our
sceMpeg HLE.
The module gets its own file at the same time. It was a tail of sceMpeg.cpp,
which is long enough already, and everything below is new code for it.
sceMpegBaseCscAvc and sceMpegBaseCscAvcRange convert the ME's decoded output to
RGB. The 48-byte descriptor holds the frame size in macroblocks at 0x10 and
0x14 - it appears at 0x00/0x04 too, but scaled differently depending on which
path built it, so the second pair is the one every caller agrees on - and the
four luma buffers at 0x20. What they point at is not planar: luma arrives as
16-pixel-wide vertical strips alternating between buffers on every other line,
and chroma as Cb/Cr pairs interleaved across four more. All eight are untangled
into planes once per frame before converting, which keeps the pixel loop
readable.
sceMpegBaseCscInit carries the default buffer width for callers that pass zero.
sceMpegBaseCscSetPixelMode (0x0530BE4E - the official name isn't known) carries
the output format, in mpegbase's own numbering rather than the GE's: mpeg.prx
gets it by indexing a table of {1, 2, 3, 0} with the pixel mode the game gave
sceMpegAvcDecodeMode, making 0 ABGR8888 and 2 ABGR5551. Read as a GE mode it
turned Thrillville's black into blue.
sceMpegBaseYCrCbCopy copies the descriptor but not the buffers it points at,
and says so in its log - nothing seen so far needs more, and inventing the
buffer copy without something to test it against seemed worse than a note.
Behaviour is cross-checked against JPCSP, which implements all of these.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
161 lines
4.1 KiB
C++
161 lines
4.1 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/Swap.h"
|
|
|
|
class PointerWrap;
|
|
|
|
// MPEG statics.
|
|
static const u32 PSMF_MAGIC = 0x464D5350;
|
|
static const int PSMF_STREAM_VERSION_OFFSET = 0x4;
|
|
static const int PSMF_STREAM_OFFSET_OFFSET = 0x8;
|
|
static const int PSMF_STREAM_SIZE_OFFSET = 0xC;
|
|
static const int PSMF_FIRST_TIMESTAMP_OFFSET = 0x54;
|
|
static const int PSMF_LAST_TIMESTAMP_OFFSET = 0x5A;
|
|
|
|
static const int PSMF_VIDEO_STREAM_ID = 0xE0;
|
|
static const int PSMF_AUDIO_STREAM_ID = 0xBD;
|
|
|
|
struct SceMpegAu {
|
|
s64_le pts; // presentation time stamp
|
|
s64_le dts; // decode time stamp
|
|
u32_le esBuffer; // WARNING: We abuse this to keep track of the stream number!
|
|
u32_le esSize;
|
|
|
|
void read(u32 addr);
|
|
void write(u32 addr);
|
|
};
|
|
|
|
// As native in PSP ram
|
|
struct SceMpegRingBuffer {
|
|
// PSP info
|
|
s32_le packets;
|
|
// Misused: this is used as total read, but should be read offset (within ring.)
|
|
s32_le packetsRead;
|
|
s32_le packetsWritePos;
|
|
s32_le packetsAvail; // pspsdk: unk2, noxa: iUnk0
|
|
s32_le packetSize; // 2048
|
|
u32_le data; // address, ring buffer
|
|
u32_le callback_addr; // see sceMpegRingbufferPut
|
|
s32_le callback_args;
|
|
s32_le dataUpperBound;
|
|
s32_le semaID; // unused? No, probably not, see #20084. Though when should we signal it? create it?
|
|
u32_le mpeg; // pointer to mpeg struct, fixed up in sceMpegCreate
|
|
// Note: not available in all versions.
|
|
u32_le gp;
|
|
};
|
|
|
|
// Internal structure
|
|
struct AvcContext {
|
|
int avcDetailFrameWidth;
|
|
int avcDetailFrameHeight;
|
|
int avcDecodeResult;
|
|
int avcFrameStatus;
|
|
};
|
|
|
|
struct StreamInfo {
|
|
int type;
|
|
int num;
|
|
int sid;
|
|
bool needsReset;
|
|
};
|
|
|
|
static const int MPEG_DATA_ES_BUFFERS = 2;
|
|
typedef std::map<u32, StreamInfo> StreamInfoMap;
|
|
class MediaEngine;
|
|
|
|
// Internal structure
|
|
struct MpegContext {
|
|
MpegContext();
|
|
~MpegContext();
|
|
|
|
MpegContext(const MpegContext &) = delete;
|
|
void operator=(const MpegContext &) = delete;
|
|
|
|
void DoState(PointerWrap &p);
|
|
|
|
u8 mpegheader[2048];
|
|
u32 defaultFrameWidth;
|
|
int videoFrameCount;
|
|
int audioFrameCount;
|
|
bool endOfAudioReached;
|
|
bool endOfVideoReached;
|
|
int videoPixelMode;
|
|
u32 mpegMagic;
|
|
int mpegVersion;
|
|
u32 mpegRawVersion;
|
|
u32 mpegOffset;
|
|
u32 mpegStreamSize;
|
|
s64 mpegFirstTimestamp;
|
|
s64 mpegLastTimestamp;
|
|
u32 mpegFirstDate;
|
|
u32 mpegLastDate;
|
|
u32 mpegRingbufferAddr;
|
|
int mpegwarmUp;
|
|
bool esBuffers[MPEG_DATA_ES_BUFFERS];
|
|
AvcContext avc;
|
|
|
|
bool avcRegistered;
|
|
bool atracRegistered;
|
|
bool pcmRegistered;
|
|
bool dataRegistered;
|
|
|
|
bool ignoreAtrac;
|
|
bool ignorePcm;
|
|
bool ignoreAvc;
|
|
|
|
bool isAnalyzed = false;
|
|
bool ringbufferNeedsReverse = false;
|
|
|
|
StreamInfoMap streamMap;
|
|
std::map<u32, bool> streamIgnoreMap;
|
|
MediaEngine *mediaengine = nullptr;
|
|
};
|
|
|
|
void __MpegInit();
|
|
void __MpegDoState(PointerWrap &p);
|
|
void __MpegShutdown();
|
|
|
|
void __MpegLoadModule(int version, u32 crc);
|
|
|
|
void Register_sceMpeg();
|
|
|
|
// One block of the scatter-gather list sceMpegBasePESpacketCopy walks. Shared because the PMP
|
|
// video path reads the same list back.
|
|
struct SceMpegLLI {
|
|
u32 pSrc;
|
|
u32 pDst;
|
|
u32 Next;
|
|
int iSize;
|
|
};
|
|
|
|
// sceMpegBasePESpacketCopy hands the list it just walked to the PMP path, which decodes from it.
|
|
// The two values live in sceMpeg.cpp rather than with the copy itself because __VideoPmpDoState
|
|
// serializes them as part of sceMpeg's savestate section.
|
|
void MpegSetPmpVideoSource(u32 addr, int blocks);
|
|
|
|
void __VideoPmpInit();
|
|
void __VideoPmpDoState(PointerWrap &p);
|
|
void __VideoPmpShutdown();
|
|
|
|
const std::map<u32, MpegContext *> &__MpegGetContexts();
|