mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 14:57:34 +00:00
VideoPlayer/LibVideo: Implement the UI functionality for seeking
With these changes, the seek bar can be used, but only to seek to the start of the file. Seeking to anywhere else in the file will cause an error in the demuxer. The timestamp label that was previously invisible now has its text set according to either the playback or seek slider's position.
This commit is contained in:
parent
e216d1a65f
commit
f31621b3f2
7 changed files with 84 additions and 13 deletions
|
@ -28,7 +28,7 @@ public:
|
|||
return sample.release_nonnull<VideoSample>();
|
||||
}
|
||||
|
||||
virtual DecoderErrorOr<void> seek_to_most_recent_keyframe(Track track, size_t timestamp) = 0;
|
||||
virtual DecoderErrorOr<void> seek_to_most_recent_keyframe(Track track, Time timestamp) = 0;
|
||||
|
||||
virtual DecoderErrorOr<Time> duration() = 0;
|
||||
|
||||
|
|
|
@ -53,9 +53,9 @@ DecoderErrorOr<MatroskaDemuxer::TrackStatus*> MatroskaDemuxer::get_track_status(
|
|||
return &m_track_statuses.get(track).release_value();
|
||||
}
|
||||
|
||||
DecoderErrorOr<void> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, size_t timestamp)
|
||||
DecoderErrorOr<void> MatroskaDemuxer::seek_to_most_recent_keyframe(Track track, Time timestamp)
|
||||
{
|
||||
if (timestamp == 0) {
|
||||
if (timestamp.is_zero()) {
|
||||
// Removing the track status will cause us to start from the beginning.
|
||||
m_track_statuses.remove(track);
|
||||
return {};
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
|
||||
DecoderErrorOr<Vector<Track>> get_tracks_for_type(TrackType type) override;
|
||||
|
||||
DecoderErrorOr<void> seek_to_most_recent_keyframe(Track track, size_t timestamp) override;
|
||||
DecoderErrorOr<void> seek_to_most_recent_keyframe(Track track, Time timestamp) override;
|
||||
|
||||
DecoderErrorOr<Time> duration() override;
|
||||
|
||||
|
|
|
@ -55,8 +55,6 @@ void PlaybackManager::set_playback_status(PlaybackStatus status)
|
|||
if (status == PlaybackStatus::Playing) {
|
||||
if (old_status == PlaybackStatus::Stopped || old_status == PlaybackStatus::Corrupted) {
|
||||
restart_playback();
|
||||
m_frame_queue->clear();
|
||||
m_skipped_frames = 0;
|
||||
}
|
||||
m_last_present_in_real_time = Time::now_monotonic();
|
||||
m_present_timer->start(0);
|
||||
|
@ -94,6 +92,8 @@ bool PlaybackManager::prepare_next_frame()
|
|||
|
||||
Time PlaybackManager::current_playback_time()
|
||||
{
|
||||
if (m_last_present_in_media_time.is_negative())
|
||||
return Time::zero();
|
||||
if (is_playing())
|
||||
return m_last_present_in_media_time + (Time::now_monotonic() - m_last_present_in_real_time);
|
||||
return m_last_present_in_media_time;
|
||||
|
@ -165,6 +165,11 @@ void PlaybackManager::update_presented_frame()
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_last_present_in_media_time.is_negative()) {
|
||||
m_last_present_in_media_time = m_next_frame->timestamp();
|
||||
dbgln_if(PLAYBACK_MANAGER_DEBUG, "We've seeked, set last media time to the next frame {}ms", m_last_present_in_media_time.to_milliseconds());
|
||||
}
|
||||
|
||||
auto frame_time_ms = (m_next_frame->timestamp() - current_playback_time()).to_milliseconds();
|
||||
VERIFY(frame_time_ms <= NumericLimits<int>::max());
|
||||
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Time until next frame is {}ms", frame_time_ms);
|
||||
|
@ -176,15 +181,26 @@ void PlaybackManager::update_presented_frame()
|
|||
m_decode_timer->start(0);
|
||||
}
|
||||
|
||||
void PlaybackManager::restart_playback()
|
||||
void PlaybackManager::seek_to_timestamp(Time timestamp)
|
||||
{
|
||||
m_last_present_in_media_time = Time::zero();
|
||||
dbgln_if(PLAYBACK_MANAGER_DEBUG, "Seeking to {}ms", timestamp.to_milliseconds());
|
||||
m_last_present_in_media_time = Time::min();
|
||||
m_last_present_in_real_time = Time::zero();
|
||||
auto result = m_demuxer->seek_to_most_recent_keyframe(m_selected_video_track, 0);
|
||||
m_frame_queue->clear();
|
||||
m_next_frame.clear();
|
||||
m_skipped_frames = 0;
|
||||
// FIXME: When the demuxer is getting samples off the main thread in the future, this needs to
|
||||
// mutex so that seeking can't happen while that thread is getting a sample.
|
||||
auto result = m_demuxer->seek_to_most_recent_keyframe(m_selected_video_track, timestamp);
|
||||
if (result.is_error())
|
||||
on_decoder_error(result.release_error());
|
||||
}
|
||||
|
||||
void PlaybackManager::restart_playback()
|
||||
{
|
||||
seek_to_timestamp(Time::zero());
|
||||
}
|
||||
|
||||
void PlaybackManager::post_decoder_error(DecoderError error)
|
||||
{
|
||||
m_main_loop.post_event(m_event_handler, make<DecoderErrorEvent>(error));
|
||||
|
|
|
@ -101,6 +101,7 @@ public:
|
|||
void resume_playback();
|
||||
void pause_playback();
|
||||
void restart_playback();
|
||||
void seek_to_timestamp(Time);
|
||||
bool is_playing() const { return m_status == PlaybackStatus::Playing; }
|
||||
bool is_buffering() const { return m_status == PlaybackStatus::Buffering; }
|
||||
bool is_stopped() const { return m_status == PlaybackStatus::Stopped; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue