Skip to content

Commit

Permalink
Engine: implemented buffering thread for the blocking video state
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-mogilko committed Mar 7, 2024
1 parent 0719ff0 commit 906f905
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
71 changes: 62 additions & 9 deletions Engine/media/video/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include "media/video/video.h"

#ifndef AGS_NO_VIDEO_PLAYER
#include <chrono>
#include <mutex>
#include <thread>
#include "core/assetmanager.h"
#include "ac/draw.h"
#include "ac/game.h"
Expand Down Expand Up @@ -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;
Expand All @@ -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<VideoPlayer> _player;
const String _assetName; // for diagnostics
int _videoFlags = 0;
Expand All @@ -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<VideoPlayer> player,
Expand Down Expand Up @@ -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;
Expand All @@ -168,12 +187,14 @@ void BlockingVideoPlayer::End()
void BlockingVideoPlayer::Pause()
{
assert(_player);
std::lock_guard<std::mutex> lk(_videoMutex);
_player->Pause();
}

void BlockingVideoPlayer::Resume()
{
assert(_player);
std::lock_guard<std::mutex> lk(_videoMutex);
_player->Play();
}

Expand All @@ -190,27 +211,39 @@ 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<Bitmap> frame;
{
std::lock_guard<std::mutex> 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<std::mutex> lk(_videoMutex);
_player->ReleaseFrame(std::move(frame));
_playbackState = _player->GetPlayState();
}
}
}

Draw();

// update the game and wait for next frame
UpdateGameAudioOnly();
return true;
return IsPlaybackReady(GetPlayState());
}

void BlockingVideoPlayer::Draw()
Expand All @@ -224,6 +257,26 @@ void BlockingVideoPlayer::Draw()
render_to_screen();
}

#if !defined(AGS_DISABLE_THREADS)
/* 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<std::mutex> lk(self->_videoMutex);
self->_player->Poll();
do_run = IsPlaybackReady(self->_player->GetPlayState());
}
std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
}
#endif

std::unique_ptr<BlockingVideoPlayer> gl_Video;

} // namespace Engine
Expand Down Expand Up @@ -260,7 +313,7 @@ static bool video_check_user_input(VideoSkipType skip)
return false;
}

static HError video_run(std::unique_ptr<VideoPlayer> video, const String &asset_name,
static HError video_single_run(std::unique_ptr<VideoPlayer> video, const String &asset_name,
int video_flags, int state_flags, VideoSkipType skip)
{
assert(video);
Expand Down Expand Up @@ -300,12 +353,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<FlicPlayer>(), flicname, video_flags, state_flags, skip);
return video_single_run(std::make_unique<FlicPlayer>(), 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<TheoraPlayer>(), name, video_flags, state_flags, skip);
return video_single_run(std::make_unique<TheoraPlayer>(), name, video_flags, state_flags, skip);
}

void video_single_pause()
Expand Down
6 changes: 1 addition & 5 deletions Engine/media/video/videoplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 906f905

Please sign in to comment.