// VideoState.h #pragma once #include "State.h" #include #include #include #include #include class VideoPlayer; class VideoState : public State { public: explicit VideoState(StateContext& ctx); ~VideoState() override; void onEnter() override; void onExit() override; void handleEvent(const SDL_Event& e) override; void update(double frameMs) override; void render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logicalVP) override; // Called from the App's on-enter hook so we can create textures. bool begin(SDL_Renderer* renderer, const std::string& path); private: enum class Phase { FadeInFirstFrame, Playing, FadeOutToBlack, Done }; void startAudioIfReady(); void stopAudio(); static bool decodeAudioPcm16Stereo44100( const std::string& path, std::vector& outPcm, int& outRate, int& outChannels ); std::unique_ptr m_player; std::string m_path; Phase m_phase = Phase::FadeInFirstFrame; double m_phaseClockMs = 0.0; static constexpr double FADE_IN_MS = 900.0; static constexpr double FADE_OUT_MS = 450.0; // Audio decoding runs in the background while we fade in. std::atomic m_audioDecoded{false}; std::atomic m_audioDecodeFailed{false}; std::vector m_audioPcm; int m_audioRate = 44100; int m_audioChannels = 2; bool m_audioStarted = false; std::unique_ptr m_audioThread; // Render-time overlay alpha (0..1) for fade stages. float m_blackOverlayAlpha = 1.0f; };