diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index de84ae42b4f..dbc952688b1 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -17,13 +17,15 @@ use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethod use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode}; use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId}; use crate::dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId}; -use crate::dom::bindings::codegen::UnionTypes::VideoTrackOrAudioTrackOrTextTrack; +use crate::dom::bindings::codegen::UnionTypes::{ + MediaStreamOrBlob, VideoTrackOrAudioTrackOrTextTrack, +}; use crate::dom::bindings::error::{Error, ErrorResult, Fallible}; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::DomObject; -use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::blob::Blob; use crate::dom::document::Document; @@ -35,6 +37,7 @@ use crate::dom::htmlelement::HTMLElement; use crate::dom::htmlsourceelement::HTMLSourceElement; use crate::dom::htmlvideoelement::HTMLVideoElement; use crate::dom::mediaerror::MediaError; +use crate::dom::mediastream::MediaStream; use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext}; use crate::dom::performanceresourcetiming::InitiatorType; use crate::dom::promise::Promise; @@ -42,6 +45,7 @@ use crate::dom::texttrack::TextTrack; use crate::dom::texttracklist::TextTrackList; use crate::dom::timeranges::{TimeRanges, TimeRangesContainer}; use crate::dom::trackevent::TrackEvent; +use crate::dom::url::URL; use crate::dom::videotrack::VideoTrack; use crate::dom::videotracklist::VideoTrackList; use crate::dom::virtualmethods::VirtualMethods; @@ -156,6 +160,25 @@ impl FrameRenderer for MediaFrameRenderer { } } +#[must_root] +#[derive(JSTraceable, MallocSizeOf)] +enum SrcObject { + MediaStream(Dom), + Blob(Dom), +} + +impl From for SrcObject { + #[allow(unrooted_must_root)] + fn from(src_object: MediaStreamOrBlob) -> SrcObject { + match src_object { + MediaStreamOrBlob::Blob(blob) => SrcObject::Blob(Dom::from_ref(&*blob)), + MediaStreamOrBlob::MediaStream(stream) => { + SrcObject::MediaStream(Dom::from_ref(&*stream)) + }, + } + } +} + #[dom_struct] pub struct HTMLMediaElement { htmlelement: HTMLElement, @@ -164,7 +187,7 @@ pub struct HTMLMediaElement { /// ready_state: Cell, /// - src_object: MutNullableDom, + src_object: DomRefCell>, /// current_src: DomRefCell, /// Incremented whenever tasks associated with this element are cancelled. @@ -211,6 +234,9 @@ pub struct HTMLMediaElement { muted: Cell, /// URL of the media resource, if any. resource_url: DomRefCell>, + /// URL of the media resource, if the resource is set through the src_object attribute and it + /// is a blob. + blob_url: DomRefCell>, /// https://html.spec.whatwg.org/multipage/#dom-media-played #[ignore_malloc_size_of = "Rc"] played: DomRefCell, @@ -280,6 +306,7 @@ impl HTMLMediaElement { volume: Cell::new(1.0), seeking: Cell::new(false), resource_url: DomRefCell::new(None), + blob_url: DomRefCell::new(None), played: DomRefCell::new(TimeRangesContainer::new()), audio_tracks_list: Default::default(), video_tracks_list: Default::default(), @@ -557,7 +584,7 @@ impl HTMLMediaElement { Children(DomRoot), } fn mode(media: &HTMLMediaElement) -> Option { - if media.src_object.get().is_some() { + if media.src_object.borrow().is_some() { return Some(Mode::Object); } if let Some(attr) = media @@ -661,7 +688,7 @@ impl HTMLMediaElement { } fn fetch_request(&self, offset: Option) { - if self.resource_url.borrow().is_none() { + if self.resource_url.borrow().is_none() && self.blob_url.borrow().is_none() { eprintln!("Missing request url"); self.queue_dedicated_media_source_failure_steps(); return; @@ -679,8 +706,12 @@ impl HTMLMediaElement { header::RANGE, HeaderValue::from_str(&format!("bytes={}-", offset.unwrap_or(0))).unwrap(), ); + let url = match self.resource_url.borrow().as_ref() { + Some(url) => url.clone(), + None => self.blob_url.borrow().as_ref().unwrap().clone(), + }; let request = RequestInit { - url: self.resource_url.borrow().as_ref().unwrap().clone(), + url: url.clone(), headers, destination, credentials_mode: CredentialsMode::Include, @@ -700,7 +731,7 @@ impl HTMLMediaElement { *current_fetch_context = Some(fetch_context); let fetch_listener = Arc::new(Mutex::new(HTMLMediaElementFetchListener::new( self, - self.resource_url.borrow().as_ref().unwrap().clone(), + url.clone(), offset.unwrap_or(0), ))); let (action_sender, action_receiver) = ipc::channel().unwrap(); @@ -788,8 +819,19 @@ impl HTMLMediaElement { self.fetch_request(None); }, Resource::Object => { - // FIXME(nox): Actually do something with the object. - self.queue_dedicated_media_source_failure_steps(); + if let Some(ref src_object) = *self.src_object.borrow() { + match src_object { + SrcObject::Blob(blob) => { + let blob_url = URL::CreateObjectURL(&self.global(), &*blob); + *self.blob_url.borrow_mut() = + Some(ServoUrl::parse(&blob_url).expect("infallible")); + self.fetch_request(None); + }, + SrcObject::MediaStream(_) => { + self.queue_dedicated_media_source_failure_steps(); + }, + } + } }, } } @@ -1550,13 +1592,21 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-srcobject - fn GetSrcObject(&self) -> Option> { - self.src_object.get() + fn GetSrcObject(&self) -> Option { + match *self.src_object.borrow() { + Some(ref src_object) => Some(match src_object { + SrcObject::Blob(blob) => MediaStreamOrBlob::Blob(DomRoot::from_ref(&*blob)), + SrcObject::MediaStream(stream) => { + MediaStreamOrBlob::MediaStream(DomRoot::from_ref(&*stream)) + }, + }), + None => None, + } } // https://html.spec.whatwg.org/multipage/#dom-media-srcobject - fn SetSrcObject(&self, value: Option<&Blob>) { - self.src_object.set(value); + fn SetSrcObject(&self, value: Option) { + *self.src_object.borrow_mut() = value.map(|value| value.into()); self.media_element_load_algorithm(); } diff --git a/components/script/dom/webidls/HTMLMediaElement.webidl b/components/script/dom/webidls/HTMLMediaElement.webidl index ba5669315d8..ee15d4b0dc3 100644 --- a/components/script/dom/webidls/HTMLMediaElement.webidl +++ b/components/script/dom/webidls/HTMLMediaElement.webidl @@ -5,7 +5,7 @@ // https://html.spec.whatwg.org/multipage/#htmlmediaelement enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" }; -typedef /* (MediaStream or MediaSource or */ Blob /* ) */ MediaProvider; +typedef (MediaStream /*or MediaSource */ or Blob) MediaProvider; [Abstract] interface HTMLMediaElement : HTMLElement { diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index adff757c06f..fe490276ddc 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -1,5 +1,8 @@ { "items": { + "conformancechecker": { + "html/semantics/embedded-content/media-elements/src_object_blob.html": [] + }, "manual": { "2dcontext/conformance-requirements/2d.coordinatespace-manual.html": [ [ @@ -12775,6 +12778,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "html/semantics/embedded-content/media-elements/video_controls_present-manual.html": [ [ "html/semantics/embedded-content/media-elements/video_controls_present-manual.html", @@ -194571,6 +194575,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-after-controls-added.html": [ [ "html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-after-controls-added.html", @@ -201711,6 +201716,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "infrastructure/assumptions/ahem-ref.html": [ [ "infrastructure/assumptions/ahem-ref.html", @@ -201809,6 +201815,7 @@ ] }, "stub": { + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "service-workers/stub-3.1-service-worker-obj.html": [ [ "service-workers/stub-3.1-service-worker-obj.html", @@ -300426,6 +300433,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "html/semantics/embedded-content/media-elements/track/track-element/cors/support/common.js": [ [ {} @@ -388893,6 +388901,12 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [ + [ + "html/semantics/embedded-content/media-elements/src_object_blob.html", + {} + ] + ], "html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [ [ "html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html", @@ -474312,6 +474326,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "svg/text/visualtests/text-inline-size-001-visual.svg": [ [ "svg/text/visualtests/text-inline-size-001-visual.svg", @@ -474362,6 +474377,7 @@ ] }, "wdspec": { + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "infrastructure/webdriver/tests/test_load_file.py": [ [ "infrastructure/webdriver/tests/test_load_file.py", @@ -660109,6 +660125,10 @@ "56a99028deb273359f32fc14b53b9317a4b9c76d", "testharness" ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [ + "481a8184ea2fdc6220b147d43a653ed510cfd104", + "testharness" + ], "html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [ "3dd43cc3f5524a32b7438e33481552653076cbe8", "testharness" diff --git a/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/src_object_blob.html b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/src_object_blob.html new file mode 100644 index 00000000000..481a8184ea2 --- /dev/null +++ b/tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/src_object_blob.html @@ -0,0 +1,31 @@ + + +HTMLMediaElement.srcObject blob + + + + + +