diff --git a/Engine/media/video/video.cpp b/Engine/media/video/video.cpp index caefbf7fad2..f6eff9158c3 100644 --- a/Engine/media/video/video.cpp +++ b/Engine/media/video/video.cpp @@ -14,6 +14,9 @@ #include "media/video/video.h" #ifndef AGS_NO_VIDEO_PLAYER +#include +#include +#include #include "core/assetmanager.h" #include "ac/draw.h" #include "ac/game.h" @@ -53,8 +56,7 @@ class BlockingVideoPlayer : public GameState int video_flags, int state_flags, VideoSkipType skip); ~BlockingVideoPlayer(); - const VideoPlayer *GetVideoPlayer() const { return _player.get(); } - PlaybackState GetPlayState() const { return _player->GetPlayState(); } + PlaybackState GetPlayState() const { return _playbackState; } void Begin() override; void End() override; @@ -65,6 +67,10 @@ class BlockingVideoPlayer : public GameState void Resume() override; private: +#if !defined(AGS_DISABLE_THREADS) + static void PollVideo(BlockingVideoPlayer *self); +#endif + std::unique_ptr _player; const String _assetName; // for diagnostics int _videoFlags = 0; @@ -73,6 +79,9 @@ class BlockingVideoPlayer : public GameState Rect _dstRect; float _oldFps = 0.f; VideoSkipType _skip = VideoSkipNone; + std::thread _videoThread; + std::mutex _videoMutex; + PlaybackState _playbackState = PlayStateInvalid; }; BlockingVideoPlayer::BlockingVideoPlayer(std::unique_ptr player, @@ -140,10 +149,20 @@ void BlockingVideoPlayer::Begin() set_game_speed(_player->GetFramerate()); _player->Play(); + _playbackState = _player->GetPlayState(); + +#if !defined(AGS_DISABLE_THREADS) + _videoThread = std::thread(BlockingVideoPlayer::PollVideo, this); +#endif } void BlockingVideoPlayer::End() { +#if !defined(AGS_DISABLE_THREADS) + if (_videoThread.joinable()) + _videoThread.join(); +#endif + if (_videoDDB) gfxDriver->DestroyDDB(_videoDDB); _videoDDB = nullptr; @@ -168,12 +187,14 @@ void BlockingVideoPlayer::End() void BlockingVideoPlayer::Pause() { assert(_player); + std::lock_guard lk(_videoMutex); _player->Pause(); } void BlockingVideoPlayer::Resume() { assert(_player); + std::lock_guard lk(_videoMutex); _player->Play(); } @@ -190,19 +211,31 @@ bool BlockingVideoPlayer::Run() // Check user input skipping the video if (video_check_user_input(_skip)) return false; - + +#if defined(AGS_DISABLE_THREADS) if (!_player->Poll()) return false; +#endif // update/render next frame if ((_videoFlags & kVideo_EnableVideo) != 0) { - auto frame = _player->GetReadyFrame(); + std::unique_ptr frame; + { + std::lock_guard lk(_videoMutex); + frame = _player->GetReadyFrame(); + } + if (frame) { gfxDriver->UpdateDDBFromBitmap(_videoDDB, frame.get(), false); _videoDDB->SetStretch(_dstRect.GetWidth(), _dstRect.GetHeight(), false); - _player->ReleaseFrame(std::move(frame)); + + { + std::lock_guard lk(_videoMutex); + _player->ReleaseFrame(std::move(frame)); + _playbackState = _player->GetPlayState(); + } } } @@ -210,7 +243,7 @@ bool BlockingVideoPlayer::Run() // update the game and wait for next frame UpdateGameAudioOnly(); - return true; + return IsPlaybackReady(GetPlayState()); } void BlockingVideoPlayer::Draw() @@ -224,6 +257,27 @@ void BlockingVideoPlayer::Draw() render_to_screen(); } +#if !defined(AGS_DISABLE_THREADS) +using namespace std::chrono_literals; +/* static */ void BlockingVideoPlayer::PollVideo(BlockingVideoPlayer *self) +{ + assert(self && self->_player.get()); + if (!self || !self->_player.get()) + return; + + bool do_run = true; + while (do_run) + { + { + std::lock_guard lk(self->_videoMutex); + self->_player->Poll(); + do_run = IsPlaybackReady(self->_player->GetPlayState()); + } + std::this_thread::sleep_for(8ms); + } +} +#endif + std::unique_ptr gl_Video; } // namespace Engine @@ -260,7 +314,7 @@ static bool video_check_user_input(VideoSkipType skip) return false; } -static HError video_run(std::unique_ptr video, const String &asset_name, +static HError video_single_run(std::unique_ptr video, const String &asset_name, int video_flags, int state_flags, VideoSkipType skip) { assert(video); @@ -300,12 +354,12 @@ HError play_flc_video(int numb, int video_flags, int state_flags, VideoSkipType return new Error(String::FromFormat("FLIC animation flic%d.flc nor flic%d.fli were found", numb, numb)); } - return video_run(std::make_unique(), flicname, video_flags, state_flags, skip); + return video_single_run(std::make_unique(), flicname, video_flags, state_flags, skip); } HError play_theora_video(const char *name, int video_flags, int state_flags, VideoSkipType skip) { - return video_run(std::make_unique(), name, video_flags, state_flags, skip); + return video_single_run(std::make_unique(), name, video_flags, state_flags, skip); } void video_single_pause() diff --git a/Engine/media/video/videoplayer.cpp b/Engine/media/video/videoplayer.cpp index c96284a2427..71074271804 100644 --- a/Engine/media/video/videoplayer.cpp +++ b/Engine/media/video/videoplayer.cpp @@ -409,8 +409,4 @@ bool VideoPlayer::ProcessAudio() } // namespace Engine } // namespace AGS -#else // AGS_NO_VIDEO_PLAYER - - - -#endif // !AGS_NO_VIDEO_PLAYER +#endif // AGS_NO_VIDEO_PLAYER