From 7ac562c77bc26cdf2f7717d4c249822ed4ee51c5 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Wed, 6 Mar 2024 21:30:01 +0300 Subject: [PATCH] Engine: implement video's FrameRate, Duration and Position properties --- Engine/media/video/flic_player.cpp | 3 +++ Engine/media/video/theora_player.cpp | 5 ++++- Engine/media/video/videoplayer.cpp | 15 +++++++++------ Engine/media/video/videoplayer.h | 10 +++++++--- libsrc/allegro/include/allegro/fli.h | 1 + libsrc/allegro/src/fli.c | 3 +++ 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Engine/media/video/flic_player.cpp b/Engine/media/video/flic_player.cpp index 6d191357f11..bc7ce172ad5 100644 --- a/Engine/media/video/flic_player.cpp +++ b/Engine/media/video/flic_player.cpp @@ -49,6 +49,9 @@ HError FlicPlayer::OpenImpl(std::unique_ptr data_stream, _frameDepth = 8; _frameSize = Size(fliwidth, fliheight); _frameRate = 1000.f / fli_speed; + _frameTime = fli_speed; + _frameCount = fli_frame_count; + _durationMs = fli_frame_count * fli_speed; return HError::None(); } diff --git a/Engine/media/video/theora_player.cpp b/Engine/media/video/theora_player.cpp index cc0f38ae7c1..56b9ee23f52 100644 --- a/Engine/media/video/theora_player.cpp +++ b/Engine/media/video/theora_player.cpp @@ -101,8 +101,11 @@ HError TheoraPlayer::OpenAPEGStream(Stream *data_stream, const Common::String &n _usedDepth = target_depth; _frameDepth = target_depth; - _frameRate = _apegStream->frame_rate; _frameSize = Size(video_w, video_h); + _frameRate = _apegStream->frame_rate; + _frameTime = 1000.f / _apegStream->frame_rate; + _frameCount = _apegStream->length / _frameTime; + _durationMs = _apegStream->length; // According to the documentation: // encoded theora frames must be a multiple of 16 in width and height. // Which means that the original content may end up positioned on a larger frame. diff --git a/Engine/media/video/videoplayer.cpp b/Engine/media/video/videoplayer.cpp index f0d7f7d9566..255e4dd92bf 100644 --- a/Engine/media/video/videoplayer.cpp +++ b/Engine/media/video/videoplayer.cpp @@ -62,7 +62,7 @@ HError VideoPlayer::Open(std::unique_ptr data_stream, } // TODO: actually support dynamic FPS, need to adjust audio speed - _frameTime = 1000.f / _targetFPS; + _targetFrameTime = 1000.f / _targetFPS; return HError::None(); } @@ -216,13 +216,13 @@ void VideoPlayer::SetSpeed(float speed) break; } - auto old_frametime = _frameTime; + auto old_frametime = _targetFrameTime; _targetFPS = _frameRate * speed; - _frameTime = 1000.f / _targetFPS; + _targetFrameTime = 1000.f / _targetFPS; // Adjust our virtual timestamps by the difference between // previous play duration, and new duration calculated from the new speed. - float ft_rel = _frameTime / old_frametime; + float ft_rel = _targetFrameTime / old_frametime; AGS_Clock::duration virtual_play_dur = AGS_Clock::duration((int64_t)(play_dur.count() * ft_rel)); _firstFrameTime = now - virtual_play_dur; @@ -360,7 +360,7 @@ bool VideoPlayer::ProcessVideo(bool force_next) // TODO: get frame's timestamp if available from decoder? if (force_next || ((_videoFrameQueue.size() > 0) && - duration >= _framesPlayed * _frameTime)) + duration >= _framesPlayed * _targetFrameTime)) { _videoFramePool.push(std::move(_videoReadyFrame)); } @@ -372,7 +372,7 @@ bool VideoPlayer::ProcessVideo(bool force_next) { // TODO: get frame's timestamp if available from decoder? if (force_next || _framesPlayed == 0u || - duration >= _framesPlayed * _frameTime) + duration >= _framesPlayed * _targetFrameTime) { _videoReadyFrame = std::move(_videoFrameQueue.front()); _videoFrameQueue.pop_front(); @@ -387,6 +387,9 @@ bool VideoPlayer::ProcessVideo(bool force_next) } } + // TODO: get frame's timestamp if available from decoder? + _posMs = _framesPlayed * _frameTime; + // We are good so long as there's either a ready frame, or frames left in queue return _videoReadyFrame || !_videoFrameQueue.empty(); } diff --git a/Engine/media/video/videoplayer.h b/Engine/media/video/videoplayer.h index 10f6459a17c..fa7b5285c5d 100644 --- a/Engine/media/video/videoplayer.h +++ b/Engine/media/video/videoplayer.h @@ -101,9 +101,9 @@ class VideoPlayer // Get current playback state PlaybackState GetPlayState() const { return _playState; } // Gets duration, in ms - float GetDurationMs() const { return 0 /* TODO */; } + float GetDurationMs() const { return _durationMs; } // Gets playback position, in ms - float GetPositionMs() const { return 0 /* TODO */; } + float GetPositionMs() const { return _posMs; } void SetSpeed(float speed); void SetVolume(float volume); @@ -144,6 +144,9 @@ class VideoPlayer int _frameDepth = 0; // bits per pixel Size _frameSize{}; float _frameRate = 0.f; + float _frameTime = 0.f; + uint32_t _frameCount = 0; + float _durationMs = 0.f; private: // Resume after pause @@ -166,10 +169,12 @@ class VideoPlayer Size _targetSize; int _targetDepth = 0; float _targetFPS = 0.f; + float _targetFrameTime = 0.f; // frame duration in ms for "target fps" uint32_t _videoQueueMax = 5u; uint32_t _audioQueueMax = 0u; // we don't have a real queue atm // Playback state PlaybackState _playState = PlayStateInitial; + float _posMs = 0.f; // Frames counter, increments with playback, resets on rewind or seek uint32_t _framesPlayed = 0u; // Stage timestamps, used to calculate the next frame timing; @@ -183,7 +188,6 @@ class VideoPlayer // Audio output object std::unique_ptr _audioOut; // Video - float _frameTime = 0.f; // 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 _vframeBuf; diff --git a/libsrc/allegro/include/allegro/fli.h b/libsrc/allegro/include/allegro/fli.h index e4fea52c1fd..9c554de42f1 100644 --- a/libsrc/allegro/include/allegro/fli.h +++ b/libsrc/allegro/include/allegro/fli.h @@ -49,6 +49,7 @@ AL_VAR(int, fli_pal_dirty_from); /* what part of fli_palette is dirty */ AL_VAR(int, fli_pal_dirty_to); AL_VAR(int, fli_frame); /* current frame number */ +AL_VAR(int, fli_frame_count); /* total number of frames */ AL_VAR(int, fli_speed); /* FLI playback speed factor, in milliseconds */ diff --git a/libsrc/allegro/src/fli.c b/libsrc/allegro/src/fli.c index 18bca3fdc14..925b135af1b 100644 --- a/libsrc/allegro/src/fli.c +++ b/libsrc/allegro/src/fli.c @@ -84,6 +84,7 @@ int fli_pal_dirty_from = INT_MAX; /* what part of fli_palette is dirty */ int fli_pal_dirty_to = INT_MIN; int fli_frame = 0; /* current frame number in the FLI */ +int fli_frame_count = 0; /* total number of frames in the FLI */ int fli_speed = 0; /* speed of the fli playback */ @@ -857,6 +858,7 @@ static int do_open_fli(void) } reset_fli_variables(); + fli_frame_count = fli_header.frame_count; fli_frame = 0; fli_status = FLI_OK; @@ -921,6 +923,7 @@ int open_memory_fli(void *fli_data) */ void close_fli(void) { + fli_frame_count = 0; fli_speed = 0; if (fli_file) {