summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp37
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLVideoElement.cpp32
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLVideoElement.h3
-rw-r--r--Userland/Libraries/LibWeb/HTML/VideoTrack.cpp89
-rw-r--r--Userland/Libraries/LibWeb/HTML/VideoTrack.h19
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;
};
}