aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2019-04-03 05:05:32 -0400
committerGitHub <noreply@github.com>2019-04-03 05:05:32 -0400
commitb9b729caa06229695e25bde8d5a735e713003c3d (patch)
tree48a8df00c811f2d549ee156d6c4d851ecbbdf781
parent1ff56aa84ff73b4e14861e70a1b9e8cc957efa39 (diff)
parentd15640081cadbdb8c26a4ba0fdc8c39742ffbdcc (diff)
downloadservo-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 -->
-rw-r--r--components/script/dom/htmlmediaelement.rs76
-rw-r--r--components/script/dom/webidls/HTMLMediaElement.webidl2
-rw-r--r--tests/wpt/metadata/MANIFEST.json20
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/embedded-content/media-elements/src_object_blob.html31
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>
+