diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp | 37 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp | 32 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/VideoTrack.cpp | 89 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/VideoTrack.h | 19 |
5 files changed, 87 insertions, 93 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index f155456d16..26dfe6740f 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -6,7 +6,7 @@ */ #include <LibJS/Runtime/Promise.h> -#include <LibVideo/Containers/Matroska/MatroskaDemuxer.h> +#include <LibVideo/PlaybackManager.h> #include <LibWeb/Bindings/HTMLMediaElementPrototype.h> #include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/DOM/Document.h> @@ -26,10 +26,31 @@ #include <LibWeb/HTML/VideoTrack.h> #include <LibWeb/HTML/VideoTrackList.h> #include <LibWeb/MimeSniff/MimeType.h> +#include <LibWeb/Platform/Timer.h> #include <LibWeb/WebIDL/Promise.h> namespace Web::HTML { +class MediaElementPlaybackTimer final : public Video::PlaybackTimer { +public: + static ErrorOr<NonnullOwnPtr<MediaElementPlaybackTimer>> create(int interval_ms, Function<void()> timeout_handler) + { + auto timer = Platform::Timer::create_single_shot(interval_ms, move(timeout_handler)); + return adopt_nonnull_own_or_enomem(new (nothrow) MediaElementPlaybackTimer(move(timer))); + } + + virtual void start() override { m_timer->start(); } + virtual void start(int interval_ms) override { m_timer->start(interval_ms); } + +private: + explicit MediaElementPlaybackTimer(NonnullRefPtr<Platform::Timer> timer) + : m_timer(move(timer)) + { + } + + NonnullRefPtr<Platform::Timer> m_timer; +}; + HTMLMediaElement::HTMLMediaElement(DOM::Document& document, DOM::QualifiedName qualified_name) : HTMLElement(document, move(qualified_name)) , m_pending_play_promises(heap()) @@ -579,10 +600,13 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::process_media_data(Function<void()> auto& realm = this->realm(); auto& vm = realm.vm(); + auto playback_manager = Video::PlaybackManager::from_data(m_media_data, [](auto interval_ms, auto timeout_handler) { + return MediaElementPlaybackTimer::create(interval_ms, move(timeout_handler)); + }); + // -> If the media data cannot be fetched at all, due to network errors, causing the user agent to give up trying to fetch the resource // -> If the media data can be fetched but is found by inspection to be in an unsupported format, or can otherwise not be rendered at all - auto demuxer = Video::Matroska::MatroskaDemuxer::from_data(m_media_data); - if (demuxer.is_error()) { + if (playback_manager.is_error()) { // 1. The user agent should cancel the fetching process. m_fetch_controller->terminate(); @@ -595,7 +619,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::process_media_data(Function<void()> JS::GCPtr<VideoTrack> video_track; // -> If the media resource is found to have an audio track - if (auto audio_tracks = demuxer.value()->get_tracks_for_type(Video::TrackType::Audio); !audio_tracks.is_error() && !audio_tracks.value().is_empty()) { + { // FIXME: 1. Create an AudioTrack object to represent the audio track. // FIXME: 2. Update the media element's audioTracks attribute's AudioTrackList object with the new AudioTrack object. // FIXME: 3. Let enable be unknown. @@ -609,9 +633,10 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::process_media_data(Function<void()> } // -> If the media resource is found to have a video track - if (auto video_tracks = demuxer.value()->get_tracks_for_type(Video::TrackType::Video); !video_tracks.is_error() && !video_tracks.value().is_empty()) { + // NOTE: Creating a Video::PlaybackManager above will have failed if there was not a video track. + { // 1. Create a VideoTrack object to represent the video track. - video_track = TRY(vm.heap().allocate<VideoTrack>(realm, realm, *this, demuxer.release_value(), video_tracks.value()[0])); + video_track = TRY(vm.heap().allocate<VideoTrack>(realm, realm, *this, playback_manager.release_value())); // 2. Update the media element's videoTracks attribute's VideoTrackList object with the new VideoTrack object. TRY_OR_THROW_OOM(vm, m_video_tracks->add_track({}, *video_track)); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp index 6f50bb5b55..d0ac5449ec 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp @@ -11,13 +11,9 @@ #include <LibWeb/HTML/HTMLVideoElement.h> #include <LibWeb/HTML/VideoTrack.h> #include <LibWeb/Layout/VideoBox.h> -#include <LibWeb/Platform/Timer.h> namespace Web::HTML { -// FIXME: Determine a reasonable framerate somehow. For now, this is roughly 24fps. -static constexpr int s_frame_delay_ms = 42; - HTMLVideoElement::HTMLVideoElement(DOM::Document& document, DOM::QualifiedName qualified_name) : HTMLMediaElement(document, move(qualified_name)) { @@ -81,32 +77,28 @@ void HTMLVideoElement::set_video_track(JS::GCPtr<HTML::VideoTrack> video_track) set_needs_style_update(true); document().set_needs_layout(); - if (m_video_timer) - m_video_timer->stop(); + if (m_video_track) + m_video_track->pause_video({}); m_video_track = video_track; } +void HTMLVideoElement::set_current_frame(Badge<VideoTrack>, RefPtr<Gfx::Bitmap> frame) +{ + m_current_frame = move(frame); + layout_node()->set_needs_display(); +} + void HTMLVideoElement::on_playing() { - if (!m_video_timer) { - m_video_timer = Platform::Timer::create_repeating(s_frame_delay_ms, [this]() { - if (auto frame = m_video_track->next_frame()) - m_current_frame = move(frame); - else - m_video_timer->stop(); - - layout_node()->set_needs_display(); - }); - } - - m_video_timer->start(); + if (m_video_track) + m_video_track->play_video({}); } void HTMLVideoElement::on_paused() { - if (m_video_timer) - m_video_timer->stop(); + if (m_video_track) + m_video_track->pause_video({}); } } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h index 51012a2b84..2c1c82cb47 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h @@ -28,6 +28,8 @@ public: u32 video_height() const; void set_video_track(JS::GCPtr<VideoTrack>); + + void set_current_frame(Badge<VideoTrack>, RefPtr<Gfx::Bitmap> frame); RefPtr<Gfx::Bitmap> const& current_frame() const { return m_current_frame; } private: @@ -42,7 +44,6 @@ private: virtual void on_paused() override; JS::GCPtr<HTML::VideoTrack> m_video_track; - RefPtr<Platform::Timer> m_video_timer; RefPtr<Gfx::Bitmap> m_current_frame; u32 m_video_width { 0 }; diff --git a/Userland/Libraries/LibWeb/HTML/VideoTrack.cpp b/Userland/Libraries/LibWeb/HTML/VideoTrack.cpp index 72dc4b5c72..c3e23dbbfc 100644 --- a/Userland/Libraries/LibWeb/HTML/VideoTrack.cpp +++ b/Userland/Libraries/LibWeb/HTML/VideoTrack.cpp @@ -8,6 +8,8 @@ #include <LibGfx/Bitmap.h> #include <LibJS/Runtime/Realm.h> #include <LibJS/Runtime/VM.h> +#include <LibVideo/PlaybackManager.h> +#include <LibVideo/Track.h> #include <LibWeb/Bindings/Intrinsics.h> #include <LibWeb/Bindings/VideoTrackPrototype.h> #include <LibWeb/DOM/Event.h> @@ -21,12 +23,23 @@ namespace Web::HTML { static IDAllocator s_video_track_id_allocator; -VideoTrack::VideoTrack(JS::Realm& realm, JS::NonnullGCPtr<HTMLMediaElement> media_element, NonnullOwnPtr<Video::Matroska::MatroskaDemuxer> demuxer, Video::Track track) +VideoTrack::VideoTrack(JS::Realm& realm, JS::NonnullGCPtr<HTMLMediaElement> media_element, NonnullOwnPtr<Video::PlaybackManager> playback_manager) : PlatformObject(realm) , m_media_element(media_element) - , m_demuxer(move(demuxer)) - , m_track(track) + , m_playback_manager(move(playback_manager)) { + m_playback_manager->on_video_frame = [this](auto frame) { + if (is<HTMLVideoElement>(*m_media_element)) + verify_cast<HTMLVideoElement>(*m_media_element).set_current_frame({}, move(frame)); + }; + + m_playback_manager->on_decoder_error = [](auto) { + // FIXME: Propagate this error to HTMLMediaElement's error attribute. + }; + + m_playback_manager->on_fatal_playback_error = [](auto) { + // FIXME: Propagate this error to HTMLMediaElement's error attribute. + }; } VideoTrack::~VideoTrack() @@ -54,63 +67,29 @@ void VideoTrack::visit_edges(Cell::Visitor& visitor) visitor.visit(m_video_track_list); } -RefPtr<Gfx::Bitmap> VideoTrack::next_frame() +void VideoTrack::play_video(Badge<HTMLVideoElement>) { - auto frame_sample = m_demuxer->get_next_video_sample_for_track(m_track); - if (frame_sample.is_error()) { - if (frame_sample.error().category() != Video::DecoderErrorCategory::EndOfStream) - dbgln("VideoTrack: Error getting next video sample: {}", frame_sample.error().description()); - return {}; - } - - OwnPtr<Video::VideoFrame> decoded_frame; - - while (!decoded_frame) { - auto result = m_decoder.receive_sample(frame_sample.value()->data()); - if (result.is_error()) { - dbgln("VideoTrack: Error receiving video sample data: {}", result.error().description()); - return {}; - } - - while (true) { - auto frame_result = m_decoder.get_decoded_frame(); - if (frame_result.is_error()) { - if (frame_result.error().category() == Video::DecoderErrorCategory::NeedsMoreInput) - break; - - dbgln("VideoTrack: Error decoding video frame: {}", frame_result.error().description()); - return {}; - } + m_playback_manager->resume_playback(); +} - decoded_frame = frame_result.release_value(); - VERIFY(decoded_frame); - } - } +void VideoTrack::pause_video(Badge<HTMLVideoElement>) +{ + m_playback_manager->pause_playback(); +} - auto& cicp = decoded_frame->cicp(); - cicp.adopt_specified_values(frame_sample.value()->container_cicp()); - cicp.default_code_points_if_unspecified({ Video::ColorPrimaries::BT709, Video::TransferCharacteristics::BT709, Video::MatrixCoefficients::BT709, Video::VideoFullRangeFlag::Studio }); - - // BT.601, BT.709 and BT.2020 have a similar transfer function to sRGB, so other applications - // (Chromium, VLC) forgo transfer characteristics conversion. We will emulate that behavior by - // handling those as sRGB instead, which causes no transfer function change in the output, - // unless display color management is later implemented. - switch (cicp.transfer_characteristics()) { - case Video::TransferCharacteristics::BT601: - case Video::TransferCharacteristics::BT709: - case Video::TransferCharacteristics::BT2020BitDepth10: - case Video::TransferCharacteristics::BT2020BitDepth12: - cicp.set_transfer_characteristics(Video::TransferCharacteristics::SRGB); - break; - default: - break; - } +Time VideoTrack::duration() const +{ + return m_playback_manager->selected_video_track().video_data().duration; +} - auto bitmap = decoded_frame->to_bitmap(); - if (bitmap.is_error()) - return {}; +u64 VideoTrack::pixel_width() const +{ + return m_playback_manager->selected_video_track().video_data().pixel_width; +} - return bitmap.release_value(); +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 diff --git a/Userland/Libraries/LibWeb/HTML/VideoTrack.h b/Userland/Libraries/LibWeb/HTML/VideoTrack.h index 5009271705..77e37cecf6 100644 --- a/Userland/Libraries/LibWeb/HTML/VideoTrack.h +++ b/Userland/Libraries/LibWeb/HTML/VideoTrack.h @@ -9,9 +9,7 @@ #include <AK/String.h> #include <AK/Time.h> #include <LibGfx/Forward.h> -#include <LibVideo/Containers/Matroska/MatroskaDemuxer.h> -#include <LibVideo/Track.h> -#include <LibVideo/VP9/Decoder.h> +#include <LibVideo/Forward.h> #include <LibWeb/Bindings/PlatformObject.h> namespace Web::HTML { @@ -24,11 +22,12 @@ public: void set_video_track_list(Badge<VideoTrackList>, JS::GCPtr<VideoTrackList> video_track_list) { m_video_track_list = video_track_list; } - RefPtr<Gfx::Bitmap> next_frame(); + void play_video(Badge<HTMLVideoElement>); + void pause_video(Badge<HTMLVideoElement>); - Time duration() const { return m_track.video_data().duration; } - u64 pixel_width() const { return m_track.video_data().pixel_width; } - u64 pixel_height() const { return m_track.video_data().pixel_height; } + Time duration() const; + u64 pixel_width() const; + u64 pixel_height() const; String const& id() const { return m_id; } String const& kind() const { return m_kind; } @@ -39,7 +38,7 @@ public: void set_selected(bool selected); private: - explicit VideoTrack(JS::Realm&, JS::NonnullGCPtr<HTMLMediaElement>, NonnullOwnPtr<Video::Matroska::MatroskaDemuxer>, Video::Track); + VideoTrack(JS::Realm&, JS::NonnullGCPtr<HTMLMediaElement>, NonnullOwnPtr<Video::PlaybackManager>); virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; @@ -62,9 +61,7 @@ private: JS::NonnullGCPtr<HTMLMediaElement> m_media_element; JS::GCPtr<VideoTrackList> m_video_track_list; - NonnullOwnPtr<Video::Matroska::MatroskaDemuxer> m_demuxer; - Video::VP9::Decoder m_decoder; - Video::Track m_track; + NonnullOwnPtr<Video::PlaybackManager> m_playback_manager; }; } |