diff --git a/Cargo.lock b/Cargo.lock index 3c0f09bcdc5..4cbee3861f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3025,7 +3025,7 @@ dependencies = [ "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-media 0.1.0 (git+https://github.com/servo/media)", + "servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", "servo_allocator 0.0.1", "servo_arc 0.1.1", "servo_atoms 0.0.1", @@ -3261,9 +3261,9 @@ name = "servo-media" version = "0.1.0" source = "git+https://github.com/servo/media#3b347d7b0431c58611e2bd7b22d34062b64cda26" dependencies = [ - "servo-media-audio 0.1.0 (git+https://github.com/servo/media)", - "servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)", - "servo-media-player 0.1.0 (git+https://github.com/servo/media)", + "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", ] [[package]] @@ -3279,7 +3279,7 @@ dependencies = [ "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "servo_media_derive 0.1.0 (git+https://github.com/servo/media)", + "servo_media_derive 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3296,8 +3296,8 @@ dependencies = [ "gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-media-audio 0.1.0 (git+https://github.com/servo/media)", - "servo-media-player 0.1.0 (git+https://github.com/servo/media)", + "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4586,12 +4586,12 @@ dependencies = [ "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262" "checksum servo-fontconfig-sys 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b46d201addcfbd25c1798ad1281d98c40743824e0b0f1e611bd3d5d0d31a7b8d" "checksum servo-freetype-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d00ab791f66cd2ec58e72c91b6076cee20fac560463aa871404eb31dfc9c4ff" -"checksum servo-media 0.1.0 (git+https://github.com/servo/media)" = "" -"checksum servo-media-audio 0.1.0 (git+https://github.com/servo/media)" = "" -"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)" = "" -"checksum servo-media-player 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" "checksum servo-skia 0.30000019.1 (registry+https://github.com/rust-lang/crates.io-index)" = "82eddddcf9512dd7c60eccdb486e60e5bd4930afaa4da2d7d4afdff75950fb88" -"checksum servo_media_derive 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo_media_derive 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" "checksum shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8254bf098ce4d8d7cc7cc6de438c5488adc5297e5b7ffef88816c0a91bd289c1" "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5" diff --git a/Cargo.toml b/Cargo.toml index bb452af5fa6..93aa92630cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,5 @@ opt-level = 3 # # [patch."https://github.com/servo/"] # = { path = "/path/to/local/checkout" } +[patch."https://github.com/servo/media"] +servo-media = { git = "https://github.com/ferjm/media", branch = "seek" } diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index f123a2b66c5..d3e7bf26f11 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -74,6 +74,8 @@ scan screen scroll-position search +seeked +seeking select serif statechange diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index f594608563c..0f67d7a6fd2 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -170,10 +170,12 @@ pub struct HTMLMediaElement { show_poster: Cell, /// https://html.spec.whatwg.org/multipage/#dom-media-duration duration: Cell, - /// https://html.spec.whatwg.org/multipage/media.html#official-playback-position + /// https://html.spec.whatwg.org/multipage/#official-playback-position playback_position: Cell, - /// https://html.spec.whatwg.org/multipage/media.html#default-playback-start-position + /// https://html.spec.whatwg.org/multipage/#default-playback-start-position default_playback_start_position: Cell, + /// https://html.spec.whatwg.org/multipage/#dom-media-seeking + seeking: Cell, } /// @@ -223,6 +225,7 @@ impl HTMLMediaElement { duration: Cell::new(f64::NAN), playback_position: Cell::new(0.), default_playback_start_position: Cell::new(0.), + seeking: Cell::new(false), } } @@ -969,8 +972,69 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-seek - fn seek(&self, _time: f64, _approximate_for_speed: bool) { - // XXX + fn seek(&self, time: f64, approximate_for_speed: bool) { + // Step 1. + self.show_poster.set(false); + + // Step 2. + if self.ready_state.get() == ReadyState::HaveNothing { + return; + } + + // Step 3. + if self.seeking.get() { + // This will cancel only the sync part of the seek algorithm. + self.generation_id.set(self.generation_id.get() + 1); + } + + // Step 4. + // The flag will be cleared when the media engine tells us the seek was done. + self.seeking.set(true); + + // Step 5. + // XXX(ferjm) The rest of the steps should be run in parallel, so seeking cancelation + // can be done properly. No other browser does it yet anyway. + + // Step 6. + let time = f64::min(time, self.Duration()); + + // Step 7. + let time = f64::max(time, 0.); + + // Step 8. + // XXX(ferjm) seekable attribute. + + // Step 9. + let accurate = !approximate_for_speed; + + // Step 10. + let window = window_from_node(self); + let task_source = window.media_element_task_source(); + task_source.queue_simple_event(self.upcast(), atom!("seeking"), &window); + + // Step 11. + // XXX self.player.seek(time, accurate); + + // The rest of the steps are handled when the media engine signals a + // ready state change or otherwise satisfies seek completion and signals + // a position change. + } + + // https://html.spec.whatwg.org/multipage/#dom-media-seek + fn seek_sync(&self) { + // Step 14. + self.seeking.set(false); + + // Step 15. + self.time_marches_on(); + + // Step 16. + let window = window_from_node(self); + let task_source = window.media_element_task_source(); + task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); + + // Step 17. + task_source.queue_simple_event(self.upcast(), atom!("seeked"), &window); } fn setup_media_player(&self) -> Result<(), ServoMediaError> { @@ -1043,7 +1107,10 @@ impl HTMLMediaElement { // Step 8. if self.default_playback_start_position.get() > 0. { - self.seek(self.default_playback_start_position.get(), /* approximate_for_speed*/ false); + self.seek( + self.default_playback_start_position.get(), + /* approximate_for_speed*/ false, + ); _jumped = true; } @@ -1084,6 +1151,20 @@ impl HTMLMediaElement { PlayerEvent::FrameUpdated => { self.upcast::().dirty(NodeDamage::OtherNodeDamage); }, + PlayerEvent::SeekData(_) => { + // XXX byte-range request + }, + PlayerEvent::SeekDone(_) => { + // Continuation of + // https://html.spec.whatwg.org/multipage/#dom-media-seek + + // Step 13. + let task = MediaElementMicrotask::SeekedTask { + elem: DomRoot::from_ref(self), + generation_id: self.generation_id.get(), + }; + ScriptThread::await_stable_state(Microtask::MediaElement(task)); + }, PlayerEvent::Error => { self.error.set(Some(&*MediaError::new( &*window_from_node(self), @@ -1206,6 +1287,14 @@ impl HTMLMediaElementMethods for HTMLMediaElement { self.seek(*time, /* approximate_for_speed */ false); } } + + fn Seeking(&self) -> bool { + self.seeking.get() + } + + fn FastSeek(&self, time: Finite) { + self.seek(*time, /* approximat_for_speed */ true); + } } impl VirtualMethods for HTMLMediaElement { @@ -1263,6 +1352,10 @@ pub enum MediaElementMicrotask { PauseIfNotInDocumentTask { elem: DomRoot, }, + SeekedTask { + elem: DomRoot, + generation_id: u32, + }, } impl MicrotaskRunnable for MediaElementMicrotask { @@ -1282,6 +1375,14 @@ impl MicrotaskRunnable for MediaElementMicrotask { elem.internal_pause_steps(); } }, + &MediaElementMicrotask::SeekedTask { + ref elem, + generation_id, + } => { + if generation_id == elem.generation_id.get() { + elem.seek_sync(); + } + }, } } } diff --git a/components/script/dom/webidls/HTMLMediaElement.webidl b/components/script/dom/webidls/HTMLMediaElement.webidl index a8b9241c54d..f258f1ffb83 100644 --- a/components/script/dom/webidls/HTMLMediaElement.webidl +++ b/components/script/dom/webidls/HTMLMediaElement.webidl @@ -34,11 +34,11 @@ interface HTMLMediaElement : HTMLElement { const unsigned short HAVE_FUTURE_DATA = 3; const unsigned short HAVE_ENOUGH_DATA = 4; readonly attribute unsigned short readyState; - // readonly attribute boolean seeking; + readonly attribute boolean seeking; // playback state attribute double currentTime; - // void fastSeek(double time); + void fastSeek(double time); readonly attribute unrestricted double duration; // Date getStartDate(); readonly attribute boolean paused;