diff options
author | Víctor Manuel Jáquez Leal <vjaquez@igalia.com> | 2018-08-02 14:09:45 +0200 |
---|---|---|
committer | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-10-08 16:11:59 +0200 |
commit | ce76b5780a45a9e00ae3a235185d2ea15c6b688b (patch) | |
tree | 086ea8a7eb2fd5e9c05d2cec6da7b5ac337793c2 /components/script/dom | |
parent | 0ff9ecc18ac0fadf45f2e64192fe2e1d86760806 (diff) | |
download | servo-ce76b5780a45a9e00ae3a235185d2ea15c6b688b.tar.gz servo-ce76b5780a45a9e00ae3a235185d2ea15c6b688b.zip |
dom: htmlmediaelement: add initial player bits
Also removes the usage of audio-video-metadata crate (?)
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 129 |
1 files changed, 101 insertions, 28 deletions
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 6a89500e3fb..f726648f5d2 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use audio_video_metadata; use document_loader::{LoadBlocker, LoadType}; use dom::attr::Attr; use dom::bindings::cell::DomRefCell; @@ -40,6 +39,8 @@ use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; use network_listener::{NetworkListener, PreInvoke}; use script_thread::ScriptThread; +use servo_media::player::{PlaybackState, Player, PlayerEvent}; +use servo_media::ServoMedia; use servo_url::ServoUrl; use std::cell::Cell; use std::collections::VecDeque; @@ -49,6 +50,8 @@ use std::sync::{Arc, Mutex}; use task_source::{TaskSource, TaskSourceName}; use time::{self, Timespec, Duration}; +unsafe_no_jsmanaged_fields!(Arc<Mutex<Box<Player>>>); + #[dom_struct] // FIXME(nox): A lot of tasks queued for this element should probably be in the // media element event task source. @@ -82,6 +85,10 @@ pub struct HTMLMediaElement { /// Play promises which are soon to be fulfilled by a queued task. #[ignore_malloc_size_of = "promises are hard"] in_flight_play_promises_queue: DomRefCell<VecDeque<(Box<[Rc<Promise>]>, ErrorResult)>>, + /// Whether the media metadata has been completely received. + have_metadata: Cell<bool>, + #[ignore_malloc_size_of = "servo_media"] + player: Arc<Mutex<Box<Player>>>, } /// <https://html.spec.whatwg.org/multipage/#dom-media-networkstate> @@ -122,6 +129,10 @@ impl HTMLMediaElement { delaying_the_load_event_flag: Default::default(), pending_play_promises: Default::default(), in_flight_play_promises_queue: Default::default(), + have_metadata: Cell::new(false), + player: Arc::new(Mutex::new( + ServoMedia::get().unwrap().create_player().unwrap(), + )), } } @@ -217,7 +228,9 @@ impl HTMLMediaElement { return; } - this.fulfill_in_flight_play_promises(|| ()); + this.fulfill_in_flight_play_promises(|| { + this.player.lock().unwrap().play(); + }); }), window.upcast(), ).unwrap(); @@ -263,6 +276,9 @@ impl HTMLMediaElement { // Step 2.3.2. this.upcast::<EventTarget>().fire_event(atom!("pause")); + //FIXME(victor) + //this.player.lock().unwrap().pause(); + // Step 2.3.3. // Done after running this closure in // `fulfill_in_flight_play_promises`. @@ -298,6 +314,7 @@ impl HTMLMediaElement { this.fulfill_in_flight_play_promises(|| { // Step 2.1. this.upcast::<EventTarget>().fire_event(atom!("playing")); + this.player.lock().unwrap().play(); // Step 2.2. // Done after running this closure in @@ -587,6 +604,7 @@ impl HTMLMediaElement { ..RequestInit::default() }; + self.setup_media_player(); let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); let (action_sender, action_receiver) = ipc::channel().unwrap(); let window = window_from_node(self); @@ -648,6 +666,8 @@ impl HTMLMediaElement { // Step 5. this.upcast::<EventTarget>().fire_event(atom!("error")); + this.player.lock().unwrap().stop(); + // Step 6. // Done after running this closure in // `fulfill_in_flight_play_promises`. @@ -806,6 +826,72 @@ impl HTMLMediaElement { } self.media_element_load_algorithm(); } + + // servo media player + fn setup_media_player(&self) { + let (action_sender, action_receiver) = ipc::channel().unwrap(); + + self.player + .lock() + .unwrap() + .register_event_handler(action_sender); + self.player.lock().unwrap().setup().unwrap(); + + let trusted_node = Trusted::new(self); + let window = window_from_node(self); + let task_source = window.dom_manipulation_task_source(); + let task_canceller = window.task_canceller(TaskSourceName::DOMManipulation); + ROUTER.add_route( + action_receiver.to_opaque(), + Box::new(move |message| { + let event: PlayerEvent = message.to().unwrap(); + let this = trusted_node.clone(); + task_source + .queue_with_canceller( + task!(handle_player_event: move || { + this.root().handle_player_event(&event); + }), + &task_canceller, + ).unwrap(); + }), + ); + } + + fn handle_player_event(&self, event: &PlayerEvent) { + match *event { + PlayerEvent::MetadataUpdated(ref metadata) => { + if !self.have_metadata.get() { + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => "Once enough of the media data has been fetched to determine the duration..." + if let Some(_dur) = metadata.duration { + // Setp 6. + self.change_ready_state(ReadyState::HaveMetadata); + self.have_metadata.set(true); + } + } else { + // => set the element's delaying-the-load-event flag to false + self.change_ready_state(ReadyState::HaveCurrentData); + } + } + PlayerEvent::StateChanged(ref state) => match *state { + PlaybackState::Paused => { + if self.ready_state.get() == ReadyState::HaveMetadata { + self.change_ready_state(ReadyState::HaveEnoughData); + } + } + _ => {} + }, + PlayerEvent::EndOfStream => {} + PlayerEvent::FrameUpdated => {} + PlayerEvent::Error => { + self.error.set(Some(&*MediaError::new( + &*window_from_node(self), + MEDIA_ERR_DECODE, + ))); + self.upcast::<EventTarget>().fire_event(atom!("error")); + } + } + } } impl HTMLMediaElementMethods for HTMLMediaElement { @@ -969,16 +1055,12 @@ enum Resource { struct HTMLMediaElementContext { /// The element that initiated the request. elem: Trusted<HTMLMediaElement>, - /// The response body received to date. - data: Vec<u8>, /// The response metadata received to date. metadata: Option<Metadata>, /// The generation of the media element when this fetch started. generation_id: u32, /// Time of last progress notification. next_progress_event: Timespec, - /// Whether the media metadata has been completely received. - have_metadata: bool, /// True if this response is invalid and should be ignored. ignore_response: bool, } @@ -1012,22 +1094,17 @@ impl FetchResponseListener for HTMLMediaElementContext { } } - fn process_response_chunk(&mut self, mut payload: Vec<u8>) { + fn process_response_chunk(&mut self, payload: Vec<u8>) { if self.ignore_response { // An error was received previously, skip processing the payload. return; } - self.data.append(&mut payload); - let elem = self.elem.root(); - // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list - // => "Once enough of the media data has been fetched to determine the duration..." - if !self.have_metadata { - self.check_metadata(&elem); - } else { - elem.change_ready_state(ReadyState::HaveCurrentData); + // push input data into the player + if let Err(_) = elem.player.lock().unwrap().push_data(payload) { + eprintln!("Couldn't push input data to player"); } // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, @@ -1050,14 +1127,20 @@ impl FetchResponseListener for HTMLMediaElementContext { return; } let elem = self.elem.root(); + let player = elem.player.lock().unwrap(); + + // signal the eos to player + if let Err(_) = player.end_of_stream() { + eprintln!("Couldn't signal EOS to player"); + } // => "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" - if !self.have_metadata { + if !elem.have_metadata.get() { + // FIXME(victor): adjust player's max-size (or buffering) elem.queue_dedicated_media_source_failure_steps(); - } // => "Once the entire media resource has been fetched..." - else if status.is_ok() { + } else if status.is_ok() { elem.change_ready_state(ReadyState::HaveEnoughData); elem.upcast::<EventTarget>().fire_event(atom!("progress")); @@ -1100,20 +1183,10 @@ impl HTMLMediaElementContext { fn new(elem: &HTMLMediaElement) -> HTMLMediaElementContext { HTMLMediaElementContext { elem: Trusted::new(elem), - data: vec![], metadata: None, generation_id: elem.generation_id.get(), next_progress_event: time::get_time() + Duration::milliseconds(350), - have_metadata: false, ignore_response: false, } } - - fn check_metadata(&mut self, elem: &HTMLMediaElement) { - if audio_video_metadata::get_format_from_slice(&self.data).is_ok() { - // Step 6. - elem.change_ready_state(ReadyState::HaveMetadata); - self.have_metadata = true; - } - } } |