1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 07:18:13 +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:
Zaggy1024 2022-11-11 22:26:19 -06:00 committed by Andreas Kling
parent e216d1a65f
commit f31621b3f2
7 changed files with 84 additions and 13 deletions

View file

@ -38,6 +38,17 @@ VideoPlayerWidget::VideoPlayerWidget(GUI::Window& window)
m_seek_slider = player_controls_widget.add<GUI::HorizontalSlider>();
m_seek_slider->set_fixed_height(20);
m_seek_slider->set_enabled(false);
m_seek_slider->on_change = [&](int value) {
if (!m_playback_manager)
return;
update_seek_slider_max();
auto progress = value / static_cast<double>(m_seek_slider->max());
auto duration = m_playback_manager->duration().to_milliseconds();
Time timestamp = Time::from_milliseconds(static_cast<i64>(round(progress * static_cast<double>(duration))));
set_current_timestamp(timestamp);
m_playback_manager->seek_to_timestamp(timestamp);
};
m_seek_slider->set_jump_to_cursor(true);
auto& toolbar_container = player_controls_widget.add<GUI::ToolbarContainer>();
m_toolbar = toolbar_container.add<GUI::Toolbar>();
@ -56,7 +67,7 @@ VideoPlayerWidget::VideoPlayerWidget(GUI::Window& window)
m_toolbar->add_action(*m_play_pause_action);
m_toolbar->add<GUI::VerticalSeparator>();
m_timestamp_label = m_toolbar->add<GUI::Label>();
m_timestamp_label->set_fixed_width(50);
m_timestamp_label->set_autosize(true);
m_toolbar->add<GUI::Widget>(); // Filler widget
@ -89,6 +100,7 @@ void VideoPlayerWidget::open_file(StringView filename)
close_file();
m_playback_manager = load_file_result.release_value();
update_seek_slider_max();
resume_playback();
}
@ -162,6 +174,46 @@ void VideoPlayerWidget::on_decoding_error(Video::DecoderError const& error)
GUI::MessageBox::show(&m_window, String::formatted(text_format, error.string_literal()), "Video Player encountered an error"sv);
}
void VideoPlayerWidget::update_seek_slider_max()
{
if (!m_playback_manager) {
m_seek_slider->set_enabled(false);
return;
}
m_seek_slider->set_max(static_cast<int>(min(m_playback_manager->duration().to_milliseconds(), NumericLimits<int>::max())));
m_seek_slider->set_enabled(true);
}
void VideoPlayerWidget::set_current_timestamp(Time timestamp)
{
set_time_label(timestamp);
if (!m_playback_manager)
return;
auto progress = static_cast<double>(timestamp.to_milliseconds()) / static_cast<double>(m_playback_manager->duration().to_milliseconds());
m_seek_slider->set_value(static_cast<int>(round(progress * m_seek_slider->max())), GUI::AllowCallback::No);
}
void VideoPlayerWidget::set_time_label(Time timestamp)
{
StringBuilder string_builder;
auto append_time = [&](Time time) {
auto seconds = time.to_seconds();
string_builder.appendff("{:02}:{:02}:{:02}", seconds / 3600, seconds / 60, seconds % 60);
};
append_time(timestamp);
if (m_playback_manager) {
string_builder.append(" / "sv);
append_time(m_playback_manager->duration());
} else {
string_builder.append(" / --:--:--.---"sv);
}
m_timestamp_label->set_text(string_builder.string_view());
}
void VideoPlayerWidget::event(Core::Event& event)
{
if (event.type() == Video::EventType::DecoderErrorOccurred) {
@ -174,9 +226,8 @@ void VideoPlayerWidget::event(Core::Event& event)
m_video_display->set_bitmap(frame_event.frame());
m_video_display->repaint();
m_seek_slider->set_max(m_playback_manager->duration().to_milliseconds());
m_seek_slider->set_value(m_playback_manager->current_playback_time().to_milliseconds());
m_seek_slider->set_enabled(true);
update_seek_slider_max();
set_current_timestamp(m_playback_manager->current_playback_time());
frame_event.accept();
} else if (event.type() == Video::EventType::PlaybackStatusChange) {