aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTIN TUN AUNG <62133983+rayguo17@users.noreply.github.com>2025-04-16 13:52:19 +0800
committerGitHub <noreply@github.com>2025-04-16 05:52:19 +0000
commitf5e6eb289af2507fa01a7926eff77d46c773b2c1 (patch)
treef71fd904bb85e8edeff282fa1026dfc3681a4b4c
parent15199ba2efee3fb59661d63238bcd4fc7990ad0c (diff)
downloadservo-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>
-rw-r--r--Cargo.lock24
-rw-r--r--components/script/dom/htmlmediaelement.rs53
-rw-r--r--components/script_bindings/webidls/HTMLMediaElement.webidl2
-rw-r--r--tests/wpt/meta/html/dom/idlharness.https.html.ini15
-rw-r--r--tests/wpt/meta/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini4
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
-