diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-04-03 05:05:32 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-03 05:05:32 -0400 |
commit | b9b729caa06229695e25bde8d5a735e713003c3d (patch) | |
tree | 48a8df00c811f2d549ee156d6c4d851ecbbdf781 | |
parent | 1ff56aa84ff73b4e14861e70a1b9e8cc957efa39 (diff) | |
parent | d15640081cadbdb8c26a4ba0fdc8c39742ffbdcc (diff) | |
download | servo-b9b729caa06229695e25bde8d5a735e713003c3d.tar.gz servo-b9b729caa06229695e25bde8d5a735e713003c3d.zip |
Auto merge of #23103 - ferjm:srcObject, r=Manishearth
Implement srcObject logic for Blob media providers
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] There are tests for these changes
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23103)
<!-- Reviewable:end -->
4 files changed, 115 insertions, 14 deletions
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<MediaStream>), + Blob(Dom<Blob>), +} + +impl From<MediaStreamOrBlob> 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 { /// <https://html.spec.whatwg.org/multipage/#dom-media-readystate> ready_state: Cell<ReadyState>, /// <https://html.spec.whatwg.org/multipage/#dom-media-srcobject> - src_object: MutNullableDom<Blob>, + src_object: DomRefCell<Option<SrcObject>>, /// <https://html.spec.whatwg.org/multipage/#dom-media-currentsrc> current_src: DomRefCell<String>, /// Incremented whenever tasks associated with this element are cancelled. @@ -211,6 +234,9 @@ pub struct HTMLMediaElement { muted: Cell<bool>, /// URL of the media resource, if any. resource_url: DomRefCell<Option<ServoUrl>>, + /// URL of the media resource, if the resource is set through the src_object attribute and it + /// is a blob. + blob_url: DomRefCell<Option<ServoUrl>>, /// https://html.spec.whatwg.org/multipage/#dom-media-played #[ignore_malloc_size_of = "Rc"] played: DomRefCell<TimeRangesContainer>, @@ -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<HTMLSourceElement>), } fn mode(media: &HTMLMediaElement) -> Option<Mode> { - 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<u64>) { - 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<DomRoot<Blob>> { - self.src_object.get() + fn GetSrcObject(&self) -> Option<MediaStreamOrBlob> { + 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<MediaStreamOrBlob>) { + *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 0239cbc7ccc..9860287c707 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": [ [ @@ -12763,6 +12766,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", @@ -194943,6 +194947,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", @@ -202191,6 +202196,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "infrastructure/assumptions/ahem-ref.html": [ [ "infrastructure/assumptions/ahem-ref.html", @@ -202289,6 +202295,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", @@ -300951,6 +300958,7 @@ {} ] ], + "html/semantics/embedded-content/media-elements/src_object_blob.html": [], "html/semantics/embedded-content/media-elements/track/track-element/cors/support/common.js": [ [ {} @@ -389289,6 +389297,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", @@ -472882,6 +472896,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", @@ -472932,6 +472947,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", @@ -658947,6 +658963,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 @@ +<!doctype html> +<meta charset="utf-8"> +<title>HTMLMediaElement.srcObject blob</title> +<script src='/common/media.js'></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<video></video> +<script> + async_test(function(t) { + t.step(function() { + fetch(getVideoURI('/media/movie_5')) + .then(function(response) { + return response.blob(); + }) + .then(function(blob) { + let video = document.querySelector("video"); + video.srcObject = blob; + video.addEventListener('ended', function() { + t.done(); + }); + video.play().catch(function(error) { + assert(false, error); + }); + }) + .catch(function(error) { + assert(false, error); + }); + }); + }); +</script> + |