LibMedia+LibWeb: Rewrite PlaybackManager using the provider/sink model

With this commit, all PlaybackManager can do is autoplay a file from
start to finish, with no pausing or seeking functionality.

All audio playback functionality has been removed from HTMLMediaElement
and HTMLAudioElement in anticipation of PlaybackManager taking that
over, for both audio-only and audio/video.
This commit is contained in:
Zaggy1024 2025-10-03 00:39:39 -05:00 committed by Jelle Raaijmakers
parent 0f9fa47352
commit 6caa2f99aa
Notes: github-actions[bot] 2025-10-28 00:35:44 +00:00
15 changed files with 371 additions and 1234 deletions

View file

@ -6,17 +6,13 @@
#include <AK/IDAllocator.h>
#include <AK/Time.h>
#include <LibGfx/Bitmap.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/VM.h>
#include <LibMedia/PlaybackManager.h>
#include <LibMedia/Track.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/VideoTrackPrototype.h>
#include <LibWeb/DOM/Event.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/HTML/HTMLMediaElement.h>
#include <LibWeb/HTML/HTMLVideoElement.h>
#include <LibWeb/HTML/VideoTrack.h>
#include <LibWeb/HTML/VideoTrackList.h>
@ -26,42 +22,11 @@ GC_DEFINE_ALLOCATOR(VideoTrack);
static IDAllocator s_video_track_id_allocator;
VideoTrack::VideoTrack(JS::Realm& realm, GC::Ref<HTMLMediaElement> media_element, NonnullOwnPtr<Media::PlaybackManager> playback_manager)
VideoTrack::VideoTrack(JS::Realm& realm, GC::Ref<HTMLMediaElement> media_element, Media::Track const& track)
: PlatformObject(realm)
, m_media_element(media_element)
, m_playback_manager(move(playback_manager))
, m_track_in_playback_manager(track)
{
m_playback_manager->on_video_frame = [this](auto frame) {
auto playback_position = static_cast<double>(position().to_milliseconds()) / 1000.0;
if (is<HTMLVideoElement>(*m_media_element))
as<HTMLVideoElement>(*m_media_element).set_current_frame({}, move(frame), playback_position);
m_media_element->set_current_playback_position(playback_position);
};
m_playback_manager->on_playback_state_change = [this]() {
switch (m_playback_manager->get_state()) {
case Media::PlaybackState::Stopped: {
auto playback_position_ms = static_cast<double>(duration().to_milliseconds());
m_media_element->set_current_playback_position(playback_position_ms / 1000.0);
break;
}
default:
break;
}
};
m_playback_manager->on_decoder_error = [this](auto error) {
auto error_message = MUST(String::from_utf8(error.description()));
m_media_element->set_decoder_error(move(error_message));
};
m_playback_manager->on_fatal_playback_error = [this](auto error) {
auto error_message = MUST(String::from_utf8(error.string_literal()));
m_media_element->set_decoder_error(move(error_message));
};
}
VideoTrack::~VideoTrack()
@ -88,53 +53,6 @@ void VideoTrack::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_video_track_list);
}
void VideoTrack::play_video(Badge<HTMLVideoElement>)
{
m_playback_manager->resume_playback();
}
void VideoTrack::pause_video(Badge<HTMLVideoElement>)
{
m_playback_manager->pause_playback();
}
void VideoTrack::stop_video(Badge<HTMLVideoElement>)
{
m_playback_manager->terminate_playback();
}
AK::Duration VideoTrack::position() const
{
return m_playback_manager->current_playback_time();
}
AK::Duration VideoTrack::duration() const
{
return m_playback_manager->duration();
}
void VideoTrack::seek(AK::Duration position, MediaSeekMode seek_mode)
{
switch (seek_mode) {
case MediaSeekMode::Accurate:
m_playback_manager->seek_to_timestamp(position, Media::PlaybackManager::SeekMode::Accurate);
break;
case MediaSeekMode::ApproximateForSpeed:
m_playback_manager->seek_to_timestamp(position, Media::PlaybackManager::SeekMode::Fast);
break;
}
}
u64 VideoTrack::pixel_width() const
{
return m_playback_manager->selected_video_track().video_data().pixel_width;
}
u64 VideoTrack::pixel_height() const
{
return m_playback_manager->selected_video_track().video_data().pixel_height;
}
// https://html.spec.whatwg.org/multipage/media.html#dom-videotrack-selected
void VideoTrack::set_selected(bool selected)
{
@ -167,11 +85,8 @@ void VideoTrack::set_selected(bool selected)
m_selected = selected;
// AD-HOC: Inform the video element node that we have (un)selected a video track for layout.
if (is<HTMLVideoElement>(*m_media_element)) {
auto& video_element = as<HTMLVideoElement>(*m_media_element);
video_element.set_video_track(m_selected ? this : nullptr);
}
// AD-HOC: Inform the element node that we have (un)selected a video track for layout.
m_media_element->set_selected_video_track({}, m_selected ? this : nullptr);
}
}