#pragma once #include #include #include "Runtime/CDvdFile.hpp" #include "Runtime/RetroTypes.hpp" #include "Runtime/Graphics/CGraphics.hpp" #include #include namespace metaforce { class CMoviePlayer : public CDvdFile { public: enum class EPlayMode { Stopped, Playing }; private: struct THPHeader { u32 magic; u32 version; u32 maxBufferSize; u32 maxAudioSamples; float fps; u32 numFrames; u32 firstFrameSize; u32 dataSize; u32 componentDataOffset; u32 offsetsDataOffset; u32 firstFrameOffset; u32 lastFrameOffset; void swapBig(); } x28_thpHead{}; struct THPComponents { u32 numComponents; enum class Type : u8 { Video = 0x0, Audio = 0x1, None = 0xff } comps[16]; void swapBig(); } x58_thpComponents{}; struct THPVideoInfo { u32 width; u32 height; void swapBig(); } x6c_videoInfo{}; struct THPAudioInfo { u32 numChannels; u32 sampleRate; u32 numSamples; void swapBig(); } x74_audioInfo{}; struct THPFrameHeader { u32 nextSize; u32 prevSize; u32 imageSize; u32 audioSize; void swapBig(); }; struct THPAudioFrameHeader { u32 channelSize; u32 numSamples; s16 channelCoefs[2][8][2]; s16 channelPrevs[2][2]; void swapBig(); }; struct CTHPTextureSet { std::shared_ptr Y[2]; std::shared_ptr U; std::shared_ptr V; u32 playedSamples = 0; u32 audioSamples = 0; std::unique_ptr audioBuf; }; std::vector x80_textures; std::unique_ptr x90_requestBuf; std::shared_ptr x98_request; std::vector> xa0_bufferQueue; u32 xb0_nextReadSize = 0; u32 xb4_nextReadOff = 0; u32 xb8_readSizeWrapped = 0; u32 xbc_readOffWrapped = 0; u32 xc0_curLoadFrame = 0; u32 xc4_requestFrameWrapped = 0; u32 xc8_curFrame = 0; u32 xcc_decodedTexSlot = 0; u32 xd0_drawTexSlot = -1; u32 xd4_audioSlot = -1; s32 xd8_decodedTexCount = 0; float xdc_frameRem = 0.f; EPlayMode xe0_playMode = EPlayMode::Playing; float xe4_totalSeconds = 0.f; float xe8_curSeconds = 0.f; float xec_preLoadSeconds; u32 xf0_preLoadFrames = 0; bool xf4_24_loop : 1; bool xf4_25_hasAudio : 1 = false; bool xf4_26_fieldFlip : 1 = false; bool m_deinterlace : 1; u32 xf8_ = 0; u32 xfc_fieldIndex = 0; std::unique_ptr m_yuvBuf; float m_hpad; float m_vpad; static u32 THPAudioDecode(s16* buffer, const u8* audioFrame, bool stereo); void DecodeFromRead(const void* data); void ReadCompleted(); void PostDVDReadRequestIfNeeded(); public: CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bool deinterlace); static void DisableStaticAudio() { SetStaticAudio(nullptr, 0, 0, 0); } static void SetStaticAudioVolume(int vol); static void SetStaticAudio(const void* data, u32 size, u32 loopBegin, u32 loopEnd); static void SetSfxVolume(u8 volume); static void MixStaticAudio(s16* out, const s16* in, u32 samples); void MixAudio(s16* out, const s16* in, u32 samples); void Rewind(); bool GetIsMovieFinishedPlaying() const { if (xf4_24_loop) return false; return xc8_curFrame == x28_thpHead.numFrames; } bool IsLooping() const { return xf4_24_loop; } bool GetIsFullyCached() const { return xa0_bufferQueue.size() >= xf0_preLoadFrames; } float GetPlayedSeconds() const { return xdc_frameRem + xe8_curSeconds; } float GetTotalSeconds() const { return xe4_totalSeconds; } void SetPlayMode(EPlayMode mode) { xe0_playMode = mode; } void SetFrame(float hpad, float vpad); void DrawFrame(); void Update(float dt); std::pair GetVideoDimensions() const { return {x6c_videoInfo.width, x6c_videoInfo.height}; } static void Initialize(); static void Shutdown(); }; } // namespace metaforce