Skip to content

Commit

Permalink
Implemented timing based on FPS
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-mogilko committed Feb 22, 2024
1 parent 518b13a commit c1143fb
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 25 deletions.
3 changes: 2 additions & 1 deletion Engine/media/video/video_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ int video_core_slot_init(std::unique_ptr<AGS::Common::Stream> in,
auto player = create_video_player(ext_hint);
if (!player)
return -1;
if (!player->Open(std::move(in), name, params.Flags, params.TargetSize, params.TargetColorDepth))
if (!player->Open(std::move(in), name,
params.Flags, params.TargetSize, params.TargetColorDepth, params.FPS))
return -1;
return video_core_slot_init(std::move(player));
}
Expand Down
48 changes: 29 additions & 19 deletions Engine/media/video/videoplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ HError VideoPlayer::Open(std::unique_ptr<Common::Stream> data_stream,

HError VideoPlayer::Open(std::unique_ptr<Common::Stream> data_stream,
const String &name, int flags,
const Size &target_sz, int target_depth)
const Size &target_sz, int target_depth, int target_fps)
{
// We request a target depth from decoder, but it may ignore our request,
// so we have to check actual "native" frame's depth after
Expand All @@ -48,6 +48,7 @@ HError VideoPlayer::Open(std::unique_ptr<Common::Stream> data_stream,

_name = name;
_flags = flags;
_targetFPS = target_fps > 0 ? target_fps : _frameRate;
// Start the audio stream
if (HasAudio())
{
Expand All @@ -63,7 +64,8 @@ HError VideoPlayer::Open(std::unique_ptr<Common::Stream> data_stream,
SetTargetFrame(target_sz);
}

_frameTime = 1000 / _frameRate;
// TODO: actually support dynamic FPS, need to adjust audio speed
_frameTime = 1000 / _targetFPS;
return HError::None();
}

Expand Down Expand Up @@ -128,13 +130,15 @@ void VideoPlayer::Play()

switch (_playState)
{
case PlayStatePaused: Resume(); /* fall-through */
case PlayStateInitial: _playState = PlayStatePlaying; break;
default: break; // TODO: support rewind/replay from stop/finished state?
case PlayStateInitial:
case PlayStatePaused:
if (_audioOut)
_audioOut->Play();
_playState = PlayStatePlaying;
break;
default:
break; // TODO: support rewind/replay from stop/finished state?
}

if (_audioOut)
_audioOut->Play();
}

void VideoPlayer::Pause()
Expand All @@ -146,15 +150,6 @@ void VideoPlayer::Pause()
_playState = PlayStatePaused;
}

void VideoPlayer::Resume()
{
if (_playState != PlayStatePaused) return;

if (_audioOut)
_audioOut->Resume();
_playState = PlayStatePlaying;
}

void VideoPlayer::Seek(float pos_ms)
{
// TODO
Expand Down Expand Up @@ -254,10 +249,14 @@ void VideoPlayer::BufferAudio()

bool VideoPlayer::ProcessVideo()
{
const auto now = AGS_Clock::now();
const auto duration =
std::chrono::duration_cast<std::chrono::milliseconds>(now - _firstFrameTime).count();
// If has got a ready video frame, then test whether it's time to drop it
if (_videoReadyFrame)
{
if (true /* test timestamp! */)
// TODO: get frame's timestamp if available from decoder?
if (duration >= _framesPlayed * _frameTime)
{
_videoReadyFrame = nullptr;
}
Expand All @@ -267,10 +266,21 @@ bool VideoPlayer::ProcessVideo()
// a new one from queue
if (!_videoReadyFrame && _videoFrameQueue.size() > 0)
{
if (true /* test timestamp! */)
// TODO: get frame's timestamp if available from decoder?
if (_framesPlayed == 0u ||
duration >= _framesPlayed * _frameTime)
{
_videoReadyFrame = std::move(_videoFrameQueue.front());
_videoFrameQueue.pop_front();

_lastFrameTime = now;
// First frame: save timestamp
if (_framesPlayed == 0u)
{
_firstFrameTime = _lastFrameTime;
}

_framesPlayed++;
}
}

Expand Down
14 changes: 9 additions & 5 deletions Engine/media/video/videoplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <deque>
#include <memory>
#include <stack>
#include "ac/timer.h"
#include "gfx/bitmap.h"
#include "media/audio/audiodefines.h"
#include "media/audio/openalsource.h"
Expand Down Expand Up @@ -59,7 +60,7 @@ class VideoPlayer
const String &name, int flags);
Common::HError Open(std::unique_ptr<Common::Stream> data_stream,
const String &name, int flags,
const Size &target_sz, int target_depth);
const Size &target_sz, int target_depth = 0, int target_fps = 0);
// Tells if the videoplayer object is valid and ready to render
virtual bool IsValid() { return false; }
bool HasVideo() const { return (_flags & kVideo_EnableVideo) != 0; }
Expand Down Expand Up @@ -126,9 +127,6 @@ class VideoPlayer
uint32_t _frameRate = 0u;

private:
// Resumes after pausing
void Resume();

// Read and queue video frames
void BufferVideo();
// Read and queue audio frames
Expand All @@ -146,17 +144,23 @@ class VideoPlayer
// Output video frame's color depth and size
Size _targetSize;
int _targetDepth = 0;
int _targetFPS = 0;
size_t _videoQueueMax = 5u;
size_t _audioQueueMax = 0u; // we don't have a real queue atm
// Playback state
uint32_t _frameTime = 0u; // frame duration in ms
PlaybackState _playState = PlayStateInitial;
size_t _framesPlayed = 0u;
AGS_Clock::time_point _firstFrameTime; // time when the first frame was ready
AGS_Clock::time_point _lastFrameTime; // time when the previous frame was ready
// TODO: implement timing freeze/update on pause/resume
AGS_Clock::time_point _pauseTime; // time when the playback was paused
// Audio
// Audio queue (single frame for now, because output buffers too)
SoundBuffer _audioFrame{};
// Audio output object
std::unique_ptr<OpenAlSource> _audioOut;
// Video
uint32_t _frameTime = 0u; // frame duration in ms
// Helper buffer for retrieving video frames of different size/depth;
// should match "native" video frame size and color depth
std::unique_ptr<Common::Bitmap> _vframeBuf;
Expand Down

0 comments on commit c1143fb

Please sign in to comment.