diff options
author | TIN TUN AUNG <62133983+rayguo17@users.noreply.github.com> | 2025-04-16 13:52:19 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-16 05:52:19 +0000 |
commit | f5e6eb289af2507fa01a7926eff77d46c773b2c1 (patch) | |
tree | f71fd904bb85e8edeff282fa1026dfc3681a4b4c | |
parent | 15199ba2efee3fb59661d63238bcd4fc7990ad0c (diff) | |
download | servo-f5e6eb289af2507fa01a7926eff77d46c773b2c1.tar.gz servo-f5e6eb289af2507fa01a7926eff77d46c773b2c1.zip |
media element: support seekable attribute (#36541)
support seekable attribute in `htmlmediaelement`, modify `seek`
algorithm to use `seekable` attribute.
related
[specs](https://html.spec.whatwg.org/multipage/media.html#dom-media-seekable)
Testing: Run WPT Test
Fixes: https://github.com/servo/servo/issues/22297
Will wait for https://github.com/servo/media/pull/435 before turning
this to ready for review.
cc @jdm @xiaochengh
Signed-off-by: rayguo17 <rayguo17@gmail.com>
5 files changed, 59 insertions, 39 deletions
diff --git a/Cargo.lock b/Cargo.lock index 4ffa4b4058c..e9af4b24fdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6600,7 +6600,7 @@ dependencies = [ [[package]] name = "servo-media" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "once_cell", "servo-media-audio", @@ -6613,7 +6613,7 @@ dependencies = [ [[package]] name = "servo-media-audio" version = "0.2.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "byte-slice-cast", "euclid", @@ -6634,7 +6634,7 @@ dependencies = [ [[package]] name = "servo-media-derive" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "proc-macro2", "quote", @@ -6644,7 +6644,7 @@ dependencies = [ [[package]] name = "servo-media-dummy" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "ipc-channel", "servo-media", @@ -6658,7 +6658,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "byte-slice-cast", "glib", @@ -6691,7 +6691,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer-render" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "gstreamer", "gstreamer-video", @@ -6701,7 +6701,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer-render-android" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "glib", "gstreamer", @@ -6715,7 +6715,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer-render-unix" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "glib", "gstreamer", @@ -6730,7 +6730,7 @@ dependencies = [ [[package]] name = "servo-media-player" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "ipc-channel", "serde", @@ -6742,7 +6742,7 @@ dependencies = [ [[package]] name = "servo-media-streams" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "uuid", ] @@ -6750,12 +6750,12 @@ dependencies = [ [[package]] name = "servo-media-traits" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" [[package]] name = "servo-media-webrtc" version = "0.1.0" -source = "git+https://github.com/servo/media#c7eab1ae326b8b95b938741660553342f7cd94b7" +source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" dependencies = [ "log", "servo-media-streams", diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index d1baab7d6d2..8ddef6d33cb 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -29,6 +29,7 @@ use net_traits::{ ResourceTimingType, }; use pixels::Image; +use script_bindings::codegen::GenericBindings::TimeRangesBinding::TimeRangesMethods; use script_bindings::codegen::InheritTypes::{ ElementTypeId, HTMLElementTypeId, HTMLMediaElementTypeId, NodeTypeId, }; @@ -1277,15 +1278,40 @@ impl HTMLMediaElement { let time = f64::max(time, 0.); // Step 8. - // XXX(ferjm) seekable attribute: we need to get the information about - // what's been decoded and buffered so far from servo-media - // and add the seekable attribute as a TimeRange. - if let Some(ref current_fetch_context) = *self.current_fetch_context.borrow() { - if !current_fetch_context.is_seekable() { - self.seeking.set(false); - return; + let seekable = self.Seekable(); + if seekable.Length() == 0 { + self.seeking.set(false); + return; + } + let mut nearest_seekable_position = 0.0; + let mut in_seekable_range = false; + let mut nearest_seekable_distance = f64::MAX; + for i in 0..seekable.Length() { + let start = seekable.Start(i).unwrap().abs(); + let end = seekable.End(i).unwrap().abs(); + if time >= start && time <= end { + nearest_seekable_position = time; + in_seekable_range = true; + break; + } else if time < start { + let distance = start - time; + if distance < nearest_seekable_distance { + nearest_seekable_distance = distance; + nearest_seekable_position = start; + } + } else { + let distance = time - end; + if distance < nearest_seekable_distance { + nearest_seekable_distance = distance; + nearest_seekable_position = end; + } } } + let time = if in_seekable_range { + time + } else { + nearest_seekable_position + }; // Step 9. // servo-media with gstreamer does not support inaccurate seeking for now. @@ -2402,6 +2428,19 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement { ) } + // https://html.spec.whatwg.org/multipage/#dom-media-seekable + fn Seekable(&self) -> DomRoot<TimeRanges> { + let mut seekable = TimeRangesContainer::default(); + if let Some(ref player) = *self.player.borrow() { + if let Ok(ranges) = player.lock().unwrap().seekable() { + for range in ranges { + let _ = seekable.add(range.start, range.end); + } + } + } + TimeRanges::new(self.global().as_window(), seekable, CanGc::note()) + } + // https://html.spec.whatwg.org/multipage/#dom-media-buffered fn Buffered(&self) -> DomRoot<TimeRanges> { let mut buffered = TimeRangesContainer::default(); diff --git a/components/script_bindings/webidls/HTMLMediaElement.webidl b/components/script_bindings/webidls/HTMLMediaElement.webidl index a2c7866a3fe..7ceae06f151 100644 --- a/components/script_bindings/webidls/HTMLMediaElement.webidl +++ b/components/script_bindings/webidls/HTMLMediaElement.webidl @@ -45,7 +45,7 @@ interface HTMLMediaElement : HTMLElement { [Throws] attribute double defaultPlaybackRate; [Throws] attribute double playbackRate; readonly attribute TimeRanges played; - // readonly attribute TimeRanges seekable; + readonly attribute TimeRanges seekable; readonly attribute boolean ended; [CEReactions] attribute boolean autoplay; [CEReactions] attribute boolean loop; diff --git a/tests/wpt/meta/html/dom/idlharness.https.html.ini b/tests/wpt/meta/html/dom/idlharness.https.html.ini index 7cc9f5ba321..a60e9fcd4af 100644 --- a/tests/wpt/meta/html/dom/idlharness.https.html.ini +++ b/tests/wpt/meta/html/dom/idlharness.https.html.ini @@ -2322,9 +2322,6 @@ [HTMLSelectElement interface: document.createElement("select") must inherit property "autocomplete" with the proper type] expected: FAIL - [HTMLMediaElement interface: attribute seekable] - expected: FAIL - [HTMLTableSectionElement interface: attribute align] expected: FAIL @@ -6487,36 +6484,24 @@ [HTMLMediaElement interface: document.createElement("video") must inherit property "preservesPitch" with the proper type] expected: FAIL - [HTMLMediaElement interface: document.createElement("video") must inherit property "seekable" with the proper type] - expected: FAIL - [HTMLMediaElement interface: document.createElement("audio") must inherit property "getStartDate()" with the proper type] expected: FAIL [HTMLMediaElement interface: document.createElement("audio") must inherit property "preservesPitch" with the proper type] expected: FAIL - [HTMLMediaElement interface: document.createElement("audio") must inherit property "seekable" with the proper type] - expected: FAIL - [HTMLMediaElement interface: new Audio() must inherit property "getStartDate()" with the proper type] expected: FAIL [HTMLMediaElement interface: new Audio() must inherit property "preservesPitch" with the proper type] expected: FAIL - [HTMLMediaElement interface: new Audio() must inherit property "seekable" with the proper type] - expected: FAIL - [HTMLMediaElement interface: operation getStartDate()] expected: FAIL [HTMLMediaElement interface: attribute preservesPitch] expected: FAIL - [HTMLMediaElement interface: attribute seekable] - expected: FAIL - [HTMLMapElement interface: attribute name] expected: FAIL diff --git a/tests/wpt/meta/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini b/tests/wpt/meta/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini deleted file mode 100644 index 589a58e234d..00000000000 --- a/tests/wpt/meta/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[seek-to-currentTime.html] - [seek to currentTime] - expected: FAIL - |