mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
LibWeb: Implement media element seeking through PlaybackManager
Including the behavior to conditionally seek forward when fast seeking!
This commit is contained in:
parent
ccf4b3f6e9
commit
e9495d0ba0
Notes:
github-actions[bot]
2025-10-28 00:32:54 +00:00
Author: https://github.com/Zaggy1024
Commit: e9495d0ba0
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6410
Reviewed-by: https://github.com/R-Goc
Reviewed-by: https://github.com/gmta ✅
3 changed files with 72 additions and 25 deletions
|
|
@ -1170,10 +1170,13 @@ void HTMLMediaElement::update_video_frame_and_timeline()
|
|||
needs_display = sink_update_result == Media::DisplayingVideoSinkUpdateResult::NewFrameAvailable;
|
||||
}
|
||||
|
||||
// FIXME: It might not be the best idea to send time updates at 60Hz, but this is a convenient place for this
|
||||
// for now.
|
||||
// Wait for the seek to complete before updating the timestamp, otherwise we'll display the timestamp from
|
||||
// before the seek when the user lets go of the left mouse button.
|
||||
if (seeking())
|
||||
return;
|
||||
|
||||
auto new_position = m_playback_manager->current_time().to_seconds_f64();
|
||||
if (new_position != m_official_playback_position) {
|
||||
if (new_position != m_current_playback_position) {
|
||||
set_current_playback_position(new_position);
|
||||
needs_display = true;
|
||||
}
|
||||
|
|
@ -1208,6 +1211,11 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::process_media_data(Function<void(Str
|
|||
|
||||
m_playback_manager = playback_manager_result.release_value();
|
||||
|
||||
m_playback_manager->on_playback_state_change = [weak_self = GC::Weak(*this)] {
|
||||
if (weak_self)
|
||||
weak_self->on_playback_manager_state_change();
|
||||
};
|
||||
|
||||
// -> If the media resource is found to have an audio track
|
||||
auto preferred_audio_track = m_playback_manager->preferred_audio_track();
|
||||
auto has_enabled_preferred_audio_track = false;
|
||||
|
|
@ -1560,6 +1568,14 @@ void HTMLMediaElement::set_ready_state(ReadyState ready_state)
|
|||
}
|
||||
}
|
||||
|
||||
void HTMLMediaElement::on_playback_manager_state_change()
|
||||
{
|
||||
if (!m_playback_manager)
|
||||
return;
|
||||
if (seeking() && m_playback_manager->state() != Media::PlaybackState::Seeking)
|
||||
finish_seeking_element();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#internal-play-steps
|
||||
WebIDL::ExceptionOr<void> HTMLMediaElement::play_element()
|
||||
{
|
||||
|
|
@ -1667,17 +1683,19 @@ void HTMLMediaElement::seek_element(double playback_position, MediaSeekMode seek
|
|||
if (m_ready_state == ReadyState::HaveNothing)
|
||||
return;
|
||||
|
||||
// FIXME: 3. If the element's seeking IDL attribute is true, then another instance of this algorithm is already running.
|
||||
// Abort that other instance of the algorithm without waiting for the step that it is running to complete.
|
||||
if (m_seeking) {
|
||||
}
|
||||
// 3. If the element's seeking IDL attribute is true, then another instance of this algorithm is already running.
|
||||
// Abort that other instance of the algorithm without waiting for the step that it is running to complete.
|
||||
// NOTE: PlaybackManager will restart any ongoing seek, and only exit the seeking state once, so we don't need to
|
||||
// check the seeking attribute here.
|
||||
|
||||
// 4. Set the seeking IDL attribute to true.
|
||||
set_seeking(true);
|
||||
|
||||
// FIXME: 5. If the seek was in response to a DOM method call or setting of an IDL attribute, then continue the script. The
|
||||
// remainder of these steps must be run in parallel. With the exception of the steps marked with ⌛, they could be
|
||||
// aborted at any time by another instance of this algorithm being invoked.
|
||||
// 5. If the seek was in response to a DOM method call or setting of an IDL attribute, then continue the script. The
|
||||
// remainder of these steps must be run in parallel. With the exception of the steps marked with ⌛, they could be
|
||||
// aborted at any time by another instance of this algorithm being invoked.
|
||||
// NOTE: We implement the async nature of seeking through PlaybackManager, and the steps here are implemented as options
|
||||
// that define how PlaybackManager's seeking behaves.
|
||||
|
||||
// 6. If the new playback position is later than the end of the media resource, then let it be the end of the media resource instead.
|
||||
playback_position = min(playback_position, m_duration);
|
||||
|
|
@ -1726,11 +1744,22 @@ void HTMLMediaElement::seek_element(double playback_position, MediaSeekMode seek
|
|||
}
|
||||
}
|
||||
|
||||
// AD-HOC: Ensure that currentTime returns the new playback position on the timeline immediately, as other
|
||||
// browsers do.
|
||||
// See https://github.com/whatwg/html/issues/11773
|
||||
m_official_playback_position = playback_position;
|
||||
|
||||
// 9. If the approximate-for-speed flag is set, adjust the new playback position to a value that will allow for playback to resume
|
||||
// promptly. If new playback position before this step is before current playback position, then the adjusted new playback position
|
||||
// must also be before the current playback position. Similarly, if the new playback position before this step is after current
|
||||
// playback position, then the adjusted new playback position must also be after the current playback position.
|
||||
// NOTE: LibVideo handles approximation for speed internally.
|
||||
auto manager_seek_mode = Media::SeekMode::Accurate;
|
||||
if (seek_mode == MediaSeekMode::ApproximateForSpeed) {
|
||||
if (playback_position <= current_playback_position())
|
||||
manager_seek_mode = Media::SeekMode::FastBefore;
|
||||
else
|
||||
manager_seek_mode = Media::SeekMode::FastAfter;
|
||||
}
|
||||
|
||||
// 10. Queue a media element task given the media element to fire an event named seeking at the element.
|
||||
queue_a_media_element_task([this]() {
|
||||
|
|
@ -1738,20 +1767,34 @@ void HTMLMediaElement::seek_element(double playback_position, MediaSeekMode seek
|
|||
});
|
||||
|
||||
// 11. Set the current playback position to the new playback position.
|
||||
set_current_playback_position(playback_position);
|
||||
// NOTE: We set the playback position in finish_seeking_element(), once we've established the new playback position using
|
||||
// the seek mode we've been provided.
|
||||
|
||||
// 12. Wait until the user agent has established whether or not the media data for the new playback position is
|
||||
// available, and, if it is, until it has decoded enough data to play back that position.
|
||||
// FIXME: Implement seeking in PlaybackManager.
|
||||
(void)seek_mode;
|
||||
if (m_playback_manager)
|
||||
m_playback_manager->seek(AK::Duration::from_seconds_f64(playback_position), manager_seek_mode);
|
||||
|
||||
// FIXME: 13. Await a stable state. The synchronous section consists of all the remaining steps of this algorithm. (Steps in the
|
||||
// synchronous section are marked with ⌛.)
|
||||
// The following steps should be executed within the success callback of a seek promise from PlaybackManager.
|
||||
// 13. Await a stable state. The synchronous section consists of all the remaining steps of this algorithm. (Steps in the
|
||||
// synchronous section are marked with ⌛.)
|
||||
if (m_playback_manager) {
|
||||
// NOTE: The final steps are triggered by our playback manager exiting the seeking state its playing/paused state.
|
||||
} else {
|
||||
finish_seeking_element();
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/media.html#dom-media-seek
|
||||
void HTMLMediaElement::finish_seeking_element()
|
||||
{
|
||||
// 14. ⌛ Set the seeking IDL attribute to false.
|
||||
set_seeking(false);
|
||||
|
||||
// NOTE: We deferred setting the current playback position until the async steps have completed.
|
||||
// This fulfills step 11. This will also update the displayed frame to ensure that the user immediately
|
||||
// sees the frame that we've seeked to.
|
||||
update_video_frame_and_timeline();
|
||||
|
||||
// 15. ⌛ Run the time marches on steps.
|
||||
time_marches_on(TimeMarchesOnReason::Other);
|
||||
|
||||
|
|
@ -2167,15 +2210,15 @@ WebIDL::ExceptionOr<bool> HTMLMediaElement::handle_keydown(Badge<Web::EventHandl
|
|||
|
||||
void HTMLMediaElement::set_layout_display_time(Badge<Painting::MediaPaintable>, Optional<double> display_time)
|
||||
{
|
||||
if (display_time.has_value() && !m_display_time.has_value()) {
|
||||
if (potentially_playing()) {
|
||||
if (display_time.has_value()) {
|
||||
if (potentially_playing() && !m_tracking_mouse_position_while_playing) {
|
||||
m_tracking_mouse_position_while_playing = true;
|
||||
// FIXME: Pause the PlaybackManager.
|
||||
m_playback_manager->pause();
|
||||
}
|
||||
} else if (!display_time.has_value() && m_display_time.has_value()) {
|
||||
} else if (!display_time.has_value()) {
|
||||
if (m_tracking_mouse_position_while_playing) {
|
||||
m_tracking_mouse_position_while_playing = false;
|
||||
// FIXME: Resume the PlaybackManager.
|
||||
m_playback_manager->play();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue