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>
This commit is contained in:
TIN TUN AUNG 2025-04-16 13:52:19 +08:00 committed by GitHub
parent 15199ba2ef
commit f5e6eb289a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 59 additions and 39 deletions

View file

@ -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();