diff options
Diffstat (limited to 'components/script/dom/htmlmediaelement.rs')
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 213 |
1 files changed, 182 insertions, 31 deletions
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 690dd928f45..690692a2481 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -59,11 +59,13 @@ use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingLi use crate::script_thread::ScriptThread; use crate::task_source::TaskSource; use dom_struct::dom_struct; +use euclid::Size2D; use headers::{ContentLength, ContentRange, HeaderMapExt}; use html5ever::{LocalName, Prefix}; use http::header::{self, HeaderMap, HeaderValue}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; +use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward}; use net_traits::image::base::Image; use net_traits::image_cache::ImageResponse; use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder, RequestMode}; @@ -71,7 +73,6 @@ use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseLis use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType}; use script_layout_interface::HTMLMediaData; use servo_config::pref; -use servo_media::player::context::{GlContext, NativeDisplay, PlayerGLContext}; use servo_media::player::frame::{Frame, FrameRenderer}; use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType}; use servo_media::{ServoMedia, SupportsMediaType}; @@ -83,23 +84,72 @@ use std::mem; use std::rc::Rc; use std::sync::{Arc, Mutex}; use time::{self, Duration, Timespec}; +use webrender_api::{ExternalImageData, ExternalImageId, ExternalImageType, TextureTarget}; use webrender_api::{ImageData, ImageDescriptor, ImageFormat, ImageKey, RenderApi}; use webrender_api::{RenderApiSender, Transaction}; +#[derive(PartialEq)] +enum FrameStatus { + Locked, + Unlocked, +} + +struct FrameHolder(FrameStatus, Frame); + +impl FrameHolder { + fn new(frame: Frame) -> FrameHolder { + FrameHolder(FrameStatus::Unlocked, frame) + } + + fn lock(&mut self) { + if self.0 == FrameStatus::Unlocked { + self.0 = FrameStatus::Locked; + }; + } + + fn unlock(&mut self) { + if self.0 == FrameStatus::Locked { + self.0 = FrameStatus::Unlocked; + }; + } + + fn set(&mut self, new_frame: Frame) { + if self.0 == FrameStatus::Unlocked { + self.1 = new_frame + }; + } + + fn get(&self) -> (u32, Size2D<i32>, usize) { + if self.0 == FrameStatus::Locked { + ( + self.1.get_texture_id(), + Size2D::new(self.1.get_width(), self.1.get_height()), + 0, + ) + } else { + unreachable!(); + } + } +} + pub struct MediaFrameRenderer { + player_id: Option<u64>, api: RenderApi, current_frame: Option<(ImageKey, i32, i32)>, old_frame: Option<ImageKey>, very_old_frame: Option<ImageKey>, + current_frame_holder: Option<FrameHolder>, } impl MediaFrameRenderer { fn new(render_api_sender: RenderApiSender) -> Self { Self { + player_id: None, api: render_api_sender.create_api(), current_frame: None, old_frame: None, very_old_frame: None, + current_frame_holder: None, } } @@ -112,6 +162,12 @@ impl MediaFrameRenderer { impl FrameRenderer for MediaFrameRenderer { fn render(&mut self, frame: Frame) { + let mut txn = Transaction::new(); + + if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) { + txn.delete_image(old_image_key); + } + let descriptor = ImageDescriptor::new( frame.get_width(), frame.get_height(), @@ -120,24 +176,22 @@ impl FrameRenderer for MediaFrameRenderer { false, ); - let mut txn = Transaction::new(); - - let image_data = ImageData::Raw(frame.get_data()); - - if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) { - txn.delete_image(old_image_key); - } - match self.current_frame { Some((ref image_key, ref mut width, ref mut height)) if *width == frame.get_width() && *height == frame.get_height() => { - txn.update_image( - *image_key, - descriptor, - image_data, - &webrender_api::DirtyRect::All, - ); + if !frame.is_gl_texture() { + txn.update_image( + *image_key, + descriptor, + ImageData::Raw(frame.get_data()), + &webrender_api::DirtyRect::All, + ); + } else if self.player_id.is_some() { + self.current_frame_holder + .get_or_insert_with(|| FrameHolder::new(frame.clone())) + .set(frame); + } if let Some(old_image_key) = self.old_frame.take() { txn.delete_image(old_image_key); @@ -147,31 +201,47 @@ impl FrameRenderer for MediaFrameRenderer { self.old_frame = Some(*image_key); let new_image_key = self.api.generate_image_key(); - txn.add_image(new_image_key, descriptor, image_data, None); + + /* update current_frame */ *image_key = new_image_key; *width = frame.get_width(); *height = frame.get_height(); + + let image_data = if frame.is_gl_texture() && self.player_id.is_some() { + self.current_frame_holder + .get_or_insert_with(|| FrameHolder::new(frame.clone())) + .set(frame); + ImageData::External(ExternalImageData { + id: ExternalImageId(self.player_id.unwrap()), + channel_index: 0, + image_type: ExternalImageType::TextureHandle(TextureTarget::Default), + }) + } else { + ImageData::Raw(frame.get_data()) + }; + txn.add_image(new_image_key, descriptor, image_data, None); }, None => { let image_key = self.api.generate_image_key(); - txn.add_image(image_key, descriptor, image_data, None); self.current_frame = Some((image_key, frame.get_width(), frame.get_height())); + + let image_data = if frame.is_gl_texture() && self.player_id.is_some() { + self.current_frame_holder = Some(FrameHolder::new(frame)); + ImageData::External(ExternalImageData { + id: ExternalImageId(self.player_id.unwrap()), + channel_index: 0, + image_type: ExternalImageType::TextureHandle(TextureTarget::Default), + }) + } else { + ImageData::Raw(frame.get_data()) + }; + txn.add_image(image_key, descriptor, image_data, None); }, } self.api.update_resources(txn.resource_updates); } } -struct PlayerContextDummy(); -impl PlayerGLContext for PlayerContextDummy { - fn get_gl_context(&self) -> GlContext { - return GlContext::Unknown; - } - fn get_native_display(&self) -> NativeDisplay { - return NativeDisplay::Unknown; - } -} - #[must_root] #[derive(JSTraceable, MallocSizeOf)] enum SrcObject { @@ -263,6 +333,8 @@ pub struct HTMLMediaElement { next_timeupdate_event: Cell<Timespec>, /// Latest fetch request context. current_fetch_context: DomRefCell<Option<HTMLMediaElementFetchContext>>, + /// Player Id reported the player thread + id: Cell<u64>, } /// <https://html.spec.whatwg.org/multipage/#dom-media-networkstate> @@ -324,6 +396,7 @@ impl HTMLMediaElement { text_tracks_list: Default::default(), next_timeupdate_event: Cell::new(time::get_time() + Duration::milliseconds(250)), current_fetch_context: DomRefCell::new(None), + id: Cell::new(0), } } @@ -1222,29 +1295,30 @@ impl HTMLMediaElement { _ => StreamType::Seekable, }; - let (action_sender, action_receiver) = ipc::channel().unwrap(); + let window = window_from_node(self); + let (action_sender, action_receiver) = ipc::channel::<PlayerEvent>().unwrap(); let renderer: Option<Arc<Mutex<dyn FrameRenderer>>> = match self.media_type_id() { HTMLMediaElementTypeId::HTMLAudioElement => None, HTMLMediaElementTypeId::HTMLVideoElement => Some(self.frame_renderer.clone()), }; + let player = ServoMedia::get().unwrap().create_player( stream_type, action_sender, renderer, - Box::new(PlayerContextDummy()), + Box::new(window.get_player_context()), ); *self.player.borrow_mut() = Some(player); let trusted_node = Trusted::new(self); - let window = window_from_node(self); let (task_source, canceller) = window .task_manager() .media_element_task_source_with_canceller(); ROUTER.add_route( action_receiver.to_opaque(), Box::new(move |message| { - let event: PlayerEvent = message.to().unwrap(); + let event = message.to().unwrap(); trace!("Player event {:?}", event); let this = trusted_node.clone(); if let Err(err) = task_source.queue_with_canceller( @@ -1258,6 +1332,73 @@ impl HTMLMediaElement { }), ); + // GLPlayer thread setup + let (player_id, image_receiver) = window + .get_player_context() + .glplayer_chan + .map(|pipeline| { + let (image_sender, image_receiver) = + glplayer_channel::<GLPlayerMsgForward>().unwrap(); + pipeline + .channel() + .send(GLPlayerMsg::RegisterPlayer(image_sender)) + .unwrap(); + match image_receiver.recv().unwrap() { + GLPlayerMsgForward::PlayerId(id) => (id, Some(image_receiver)), + _ => unreachable!(), + } + }) + .unwrap_or((0, None)); + + self.id.set(player_id); + self.frame_renderer.lock().unwrap().player_id = Some(player_id); + + if let Some(image_receiver) = image_receiver { + let trusted_node = Trusted::new(self); + let (task_source, canceller) = window + .task_manager() + .media_element_task_source_with_canceller(); + ROUTER.add_route( + image_receiver.to_opaque(), + Box::new(move |message| { + let msg = message.to().unwrap(); + let this = trusted_node.clone(); + if let Err(err) = task_source.queue_with_canceller( + task!(handle_glplayer_message: move || { + trace!("GLPlayer message {:?}", msg); + let frame_renderer = this.root().frame_renderer.clone(); + + match msg { + GLPlayerMsgForward::Lock(sender) => { + frame_renderer + .lock() + .unwrap() + .current_frame_holder + .as_mut() + .map(|holder| { + holder.lock(); + sender.send(holder.get()).unwrap(); + }); + }, + GLPlayerMsgForward::Unlock() => { + frame_renderer + .lock() + .unwrap() + .current_frame_holder + .as_mut() + .map(|holder| holder.unlock()); + }, + _ => (), + } + }), + &canceller, + ) { + warn!("Could not queue GL player message handler task {:?}", err); + } + }), + ); + } + Ok(()) } @@ -1585,6 +1726,16 @@ impl HTMLMediaElement { impl Drop for HTMLMediaElement { fn drop(&mut self) { + let window = window_from_node(self); + window.get_player_context().glplayer_chan.map(|pipeline| { + if let Err(err) = pipeline + .channel() + .send(GLPlayerMsg::UnregisterPlayer(self.id.get())) + { + warn!("GLPlayer disappeared!: {:?}", err); + } + }); + if let Some(ref player) = *self.player.borrow() { if let Err(err) = player.shutdown() { warn!("Error shutting down player {:?}", err); |