mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Implement srcObject logic for Blob media providers
This commit is contained in:
parent
3c27dc993d
commit
d15640081c
4 changed files with 115 additions and 14 deletions
|
@ -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::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode};
|
||||||
use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
|
use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
|
||||||
use crate::dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId};
|
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::error::{Error, ErrorResult, Fallible};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::num::Finite;
|
use crate::dom::bindings::num::Finite;
|
||||||
use crate::dom::bindings::refcounted::Trusted;
|
use crate::dom::bindings::refcounted::Trusted;
|
||||||
use crate::dom::bindings::reflector::DomObject;
|
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::bindings::str::{DOMString, USVString};
|
||||||
use crate::dom::blob::Blob;
|
use crate::dom::blob::Blob;
|
||||||
use crate::dom::document::Document;
|
use crate::dom::document::Document;
|
||||||
|
@ -35,6 +37,7 @@ use crate::dom::htmlelement::HTMLElement;
|
||||||
use crate::dom::htmlsourceelement::HTMLSourceElement;
|
use crate::dom::htmlsourceelement::HTMLSourceElement;
|
||||||
use crate::dom::htmlvideoelement::HTMLVideoElement;
|
use crate::dom::htmlvideoelement::HTMLVideoElement;
|
||||||
use crate::dom::mediaerror::MediaError;
|
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::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
|
||||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||||
use crate::dom::promise::Promise;
|
use crate::dom::promise::Promise;
|
||||||
|
@ -42,6 +45,7 @@ use crate::dom::texttrack::TextTrack;
|
||||||
use crate::dom::texttracklist::TextTrackList;
|
use crate::dom::texttracklist::TextTrackList;
|
||||||
use crate::dom::timeranges::{TimeRanges, TimeRangesContainer};
|
use crate::dom::timeranges::{TimeRanges, TimeRangesContainer};
|
||||||
use crate::dom::trackevent::TrackEvent;
|
use crate::dom::trackevent::TrackEvent;
|
||||||
|
use crate::dom::url::URL;
|
||||||
use crate::dom::videotrack::VideoTrack;
|
use crate::dom::videotrack::VideoTrack;
|
||||||
use crate::dom::videotracklist::VideoTrackList;
|
use crate::dom::videotracklist::VideoTrackList;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
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]
|
#[dom_struct]
|
||||||
pub struct HTMLMediaElement {
|
pub struct HTMLMediaElement {
|
||||||
htmlelement: HTMLElement,
|
htmlelement: HTMLElement,
|
||||||
|
@ -164,7 +187,7 @@ pub struct HTMLMediaElement {
|
||||||
/// <https://html.spec.whatwg.org/multipage/#dom-media-readystate>
|
/// <https://html.spec.whatwg.org/multipage/#dom-media-readystate>
|
||||||
ready_state: Cell<ReadyState>,
|
ready_state: Cell<ReadyState>,
|
||||||
/// <https://html.spec.whatwg.org/multipage/#dom-media-srcobject>
|
/// <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>
|
/// <https://html.spec.whatwg.org/multipage/#dom-media-currentsrc>
|
||||||
current_src: DomRefCell<String>,
|
current_src: DomRefCell<String>,
|
||||||
/// Incremented whenever tasks associated with this element are cancelled.
|
/// Incremented whenever tasks associated with this element are cancelled.
|
||||||
|
@ -211,6 +234,9 @@ pub struct HTMLMediaElement {
|
||||||
muted: Cell<bool>,
|
muted: Cell<bool>,
|
||||||
/// URL of the media resource, if any.
|
/// URL of the media resource, if any.
|
||||||
resource_url: DomRefCell<Option<ServoUrl>>,
|
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
|
/// https://html.spec.whatwg.org/multipage/#dom-media-played
|
||||||
#[ignore_malloc_size_of = "Rc"]
|
#[ignore_malloc_size_of = "Rc"]
|
||||||
played: DomRefCell<TimeRangesContainer>,
|
played: DomRefCell<TimeRangesContainer>,
|
||||||
|
@ -280,6 +306,7 @@ impl HTMLMediaElement {
|
||||||
volume: Cell::new(1.0),
|
volume: Cell::new(1.0),
|
||||||
seeking: Cell::new(false),
|
seeking: Cell::new(false),
|
||||||
resource_url: DomRefCell::new(None),
|
resource_url: DomRefCell::new(None),
|
||||||
|
blob_url: DomRefCell::new(None),
|
||||||
played: DomRefCell::new(TimeRangesContainer::new()),
|
played: DomRefCell::new(TimeRangesContainer::new()),
|
||||||
audio_tracks_list: Default::default(),
|
audio_tracks_list: Default::default(),
|
||||||
video_tracks_list: Default::default(),
|
video_tracks_list: Default::default(),
|
||||||
|
@ -557,7 +584,7 @@ impl HTMLMediaElement {
|
||||||
Children(DomRoot<HTMLSourceElement>),
|
Children(DomRoot<HTMLSourceElement>),
|
||||||
}
|
}
|
||||||
fn mode(media: &HTMLMediaElement) -> Option<Mode> {
|
fn mode(media: &HTMLMediaElement) -> Option<Mode> {
|
||||||
if media.src_object.get().is_some() {
|
if media.src_object.borrow().is_some() {
|
||||||
return Some(Mode::Object);
|
return Some(Mode::Object);
|
||||||
}
|
}
|
||||||
if let Some(attr) = media
|
if let Some(attr) = media
|
||||||
|
@ -661,7 +688,7 @@ impl HTMLMediaElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_request(&self, offset: Option<u64>) {
|
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");
|
eprintln!("Missing request url");
|
||||||
self.queue_dedicated_media_source_failure_steps();
|
self.queue_dedicated_media_source_failure_steps();
|
||||||
return;
|
return;
|
||||||
|
@ -679,8 +706,12 @@ impl HTMLMediaElement {
|
||||||
header::RANGE,
|
header::RANGE,
|
||||||
HeaderValue::from_str(&format!("bytes={}-", offset.unwrap_or(0))).unwrap(),
|
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 {
|
let request = RequestInit {
|
||||||
url: self.resource_url.borrow().as_ref().unwrap().clone(),
|
url: url.clone(),
|
||||||
headers,
|
headers,
|
||||||
destination,
|
destination,
|
||||||
credentials_mode: CredentialsMode::Include,
|
credentials_mode: CredentialsMode::Include,
|
||||||
|
@ -700,7 +731,7 @@ impl HTMLMediaElement {
|
||||||
*current_fetch_context = Some(fetch_context);
|
*current_fetch_context = Some(fetch_context);
|
||||||
let fetch_listener = Arc::new(Mutex::new(HTMLMediaElementFetchListener::new(
|
let fetch_listener = Arc::new(Mutex::new(HTMLMediaElementFetchListener::new(
|
||||||
self,
|
self,
|
||||||
self.resource_url.borrow().as_ref().unwrap().clone(),
|
url.clone(),
|
||||||
offset.unwrap_or(0),
|
offset.unwrap_or(0),
|
||||||
)));
|
)));
|
||||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||||
|
@ -788,11 +819,22 @@ impl HTMLMediaElement {
|
||||||
self.fetch_request(None);
|
self.fetch_request(None);
|
||||||
},
|
},
|
||||||
Resource::Object => {
|
Resource::Object => {
|
||||||
// FIXME(nox): Actually do something with the object.
|
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();
|
self.queue_dedicated_media_source_failure_steps();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Queues a task to run the [dedicated media source failure steps][steps].
|
/// Queues a task to run the [dedicated media source failure steps][steps].
|
||||||
///
|
///
|
||||||
|
@ -1550,13 +1592,21 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-media-srcobject
|
// https://html.spec.whatwg.org/multipage/#dom-media-srcobject
|
||||||
fn GetSrcObject(&self) -> Option<DomRoot<Blob>> {
|
fn GetSrcObject(&self) -> Option<MediaStreamOrBlob> {
|
||||||
self.src_object.get()
|
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
|
// https://html.spec.whatwg.org/multipage/#dom-media-srcobject
|
||||||
fn SetSrcObject(&self, value: Option<&Blob>) {
|
fn SetSrcObject(&self, value: Option<MediaStreamOrBlob>) {
|
||||||
self.src_object.set(value);
|
*self.src_object.borrow_mut() = value.map(|value| value.into());
|
||||||
self.media_element_load_algorithm();
|
self.media_element_load_algorithm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// https://html.spec.whatwg.org/multipage/#htmlmediaelement
|
// https://html.spec.whatwg.org/multipage/#htmlmediaelement
|
||||||
|
|
||||||
enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" };
|
enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" };
|
||||||
typedef /* (MediaStream or MediaSource or */ Blob /* ) */ MediaProvider;
|
typedef (MediaStream /*or MediaSource */ or Blob) MediaProvider;
|
||||||
|
|
||||||
[Abstract]
|
[Abstract]
|
||||||
interface HTMLMediaElement : HTMLElement {
|
interface HTMLMediaElement : HTMLElement {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
{
|
{
|
||||||
"items": {
|
"items": {
|
||||||
|
"conformancechecker": {
|
||||||
|
"html/semantics/embedded-content/media-elements/src_object_blob.html": []
|
||||||
|
},
|
||||||
"manual": {
|
"manual": {
|
||||||
"2dcontext/conformance-requirements/2d.coordinatespace-manual.html": [
|
"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": [
|
||||||
[
|
[
|
||||||
"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": [
|
||||||
[
|
[
|
||||||
"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": [
|
||||||
[
|
[
|
||||||
"infrastructure/assumptions/ahem-ref.html",
|
"infrastructure/assumptions/ahem-ref.html",
|
||||||
|
@ -201809,6 +201815,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"stub": {
|
"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": [
|
||||||
[
|
[
|
||||||
"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": [
|
"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": [
|
||||||
[
|
[
|
||||||
"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": [
|
||||||
[
|
[
|
||||||
"svg/text/visualtests/text-inline-size-001-visual.svg",
|
"svg/text/visualtests/text-inline-size-001-visual.svg",
|
||||||
|
@ -474362,6 +474377,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"wdspec": {
|
"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": [
|
||||||
[
|
[
|
||||||
"infrastructure/webdriver/tests/test_load_file.py",
|
"infrastructure/webdriver/tests/test_load_file.py",
|
||||||
|
@ -660109,6 +660125,10 @@
|
||||||
"56a99028deb273359f32fc14b53b9317a4b9c76d",
|
"56a99028deb273359f32fc14b53b9317a4b9c76d",
|
||||||
"testharness"
|
"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": [
|
"html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [
|
||||||
"3dd43cc3f5524a32b7438e33481552653076cbe8",
|
"3dd43cc3f5524a32b7438e33481552653076cbe8",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue