Skip to content

Commit d156400

Browse files
committed
Implement srcObject logic for Blob media providers
1 parent 3c27dc9 commit d156400

File tree

4 files changed

+115
-14
lines changed

4 files changed

+115
-14
lines changed

components/script/dom/htmlmediaelement.rs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethod
1717
use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode};
1818
use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
1919
use crate::dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId};
20-
use crate::dom::bindings::codegen::UnionTypes::VideoTrackOrAudioTrackOrTextTrack;
20+
use crate::dom::bindings::codegen::UnionTypes::{
21+
MediaStreamOrBlob, VideoTrackOrAudioTrackOrTextTrack,
22+
};
2123
use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
2224
use crate::dom::bindings::inheritance::Castable;
2325
use crate::dom::bindings::num::Finite;
2426
use crate::dom::bindings::refcounted::Trusted;
2527
use crate::dom::bindings::reflector::DomObject;
26-
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
28+
use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
2729
use crate::dom::bindings::str::{DOMString, USVString};
2830
use crate::dom::blob::Blob;
2931
use crate::dom::document::Document;
@@ -35,13 +37,15 @@ use crate::dom::htmlelement::HTMLElement;
3537
use crate::dom::htmlsourceelement::HTMLSourceElement;
3638
use crate::dom::htmlvideoelement::HTMLVideoElement;
3739
use crate::dom::mediaerror::MediaError;
40+
use crate::dom::mediastream::MediaStream;
3841
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
3942
use crate::dom::performanceresourcetiming::InitiatorType;
4043
use crate::dom::promise::Promise;
4144
use crate::dom::texttrack::TextTrack;
4245
use crate::dom::texttracklist::TextTrackList;
4346
use crate::dom::timeranges::{TimeRanges, TimeRangesContainer};
4447
use crate::dom::trackevent::TrackEvent;
48+
use crate::dom::url::URL;
4549
use crate::dom::videotrack::VideoTrack;
4650
use crate::dom::videotracklist::VideoTrackList;
4751
use crate::dom::virtualmethods::VirtualMethods;
@@ -156,6 +160,25 @@ impl FrameRenderer for MediaFrameRenderer {
156160
}
157161
}
158162

163+
#[must_root]
164+
#[derive(JSTraceable, MallocSizeOf)]
165+
enum SrcObject {
166+
MediaStream(Dom<MediaStream>),
167+
Blob(Dom<Blob>),
168+
}
169+
170+
impl From<MediaStreamOrBlob> for SrcObject {
171+
#[allow(unrooted_must_root)]
172+
fn from(src_object: MediaStreamOrBlob) -> SrcObject {
173+
match src_object {
174+
MediaStreamOrBlob::Blob(blob) => SrcObject::Blob(Dom::from_ref(&*blob)),
175+
MediaStreamOrBlob::MediaStream(stream) => {
176+
SrcObject::MediaStream(Dom::from_ref(&*stream))
177+
},
178+
}
179+
}
180+
}
181+
159182
#[dom_struct]
160183
pub struct HTMLMediaElement {
161184
htmlelement: HTMLElement,
@@ -164,7 +187,7 @@ pub struct HTMLMediaElement {
164187
/// <https://html.spec.whatwg.org/multipage/#dom-media-readystate>
165188
ready_state: Cell<ReadyState>,
166189
/// <https://html.spec.whatwg.org/multipage/#dom-media-srcobject>
167-
src_object: MutNullableDom<Blob>,
190+
src_object: DomRefCell<Option<SrcObject>>,
168191
/// <https://html.spec.whatwg.org/multipage/#dom-media-currentsrc>
169192
current_src: DomRefCell<String>,
170193
/// Incremented whenever tasks associated with this element are cancelled.
@@ -211,6 +234,9 @@ pub struct HTMLMediaElement {
211234
muted: Cell<bool>,
212235
/// URL of the media resource, if any.
213236
resource_url: DomRefCell<Option<ServoUrl>>,
237+
/// URL of the media resource, if the resource is set through the src_object attribute and it
238+
/// is a blob.
239+
blob_url: DomRefCell<Option<ServoUrl>>,
214240
/// https://html.spec.whatwg.org/multipage/#dom-media-played
215241
#[ignore_malloc_size_of = "Rc"]
216242
played: DomRefCell<TimeRangesContainer>,
@@ -280,6 +306,7 @@ impl HTMLMediaElement {
280306
volume: Cell::new(1.0),
281307
seeking: Cell::new(false),
282308
resource_url: DomRefCell::new(None),
309+
blob_url: DomRefCell::new(None),
283310
played: DomRefCell::new(TimeRangesContainer::new()),
284311
audio_tracks_list: Default::default(),
285312
video_tracks_list: Default::default(),
@@ -557,7 +584,7 @@ impl HTMLMediaElement {
557584
Children(DomRoot<HTMLSourceElement>),
558585
}
559586
fn mode(media: &HTMLMediaElement) -> Option<Mode> {
560-
if media.src_object.get().is_some() {
587+
if media.src_object.borrow().is_some() {
561588
return Some(Mode::Object);
562589
}
563590
if let Some(attr) = media
@@ -661,7 +688,7 @@ impl HTMLMediaElement {
661688
}
662689

663690
fn fetch_request(&self, offset: Option<u64>) {
664-
if self.resource_url.borrow().is_none() {
691+
if self.resource_url.borrow().is_none() && self.blob_url.borrow().is_none() {
665692
eprintln!("Missing request url");
666693
self.queue_dedicated_media_source_failure_steps();
667694
return;
@@ -679,8 +706,12 @@ impl HTMLMediaElement {
679706
header::RANGE,
680707
HeaderValue::from_str(&format!("bytes={}-", offset.unwrap_or(0))).unwrap(),
681708
);
709+
let url = match self.resource_url.borrow().as_ref() {
710+
Some(url) => url.clone(),
711+
None => self.blob_url.borrow().as_ref().unwrap().clone(),
712+
};
682713
let request = RequestInit {
683-
url: self.resource_url.borrow().as_ref().unwrap().clone(),
714+
url: url.clone(),
684715
headers,
685716
destination,
686717
credentials_mode: CredentialsMode::Include,
@@ -700,7 +731,7 @@ impl HTMLMediaElement {
700731
*current_fetch_context = Some(fetch_context);
701732
let fetch_listener = Arc::new(Mutex::new(HTMLMediaElementFetchListener::new(
702733
self,
703-
self.resource_url.borrow().as_ref().unwrap().clone(),
734+
url.clone(),
704735
offset.unwrap_or(0),
705736
)));
706737
let (action_sender, action_receiver) = ipc::channel().unwrap();
@@ -788,8 +819,19 @@ impl HTMLMediaElement {
788819
self.fetch_request(None);
789820
},
790821
Resource::Object => {
791-
// FIXME(nox): Actually do something with the object.
792-
self.queue_dedicated_media_source_failure_steps();
822+
if let Some(ref src_object) = *self.src_object.borrow() {
823+
match src_object {
824+
SrcObject::Blob(blob) => {
825+
let blob_url = URL::CreateObjectURL(&self.global(), &*blob);
826+
*self.blob_url.borrow_mut() =
827+
Some(ServoUrl::parse(&blob_url).expect("infallible"));
828+
self.fetch_request(None);
829+
},
830+
SrcObject::MediaStream(_) => {
831+
self.queue_dedicated_media_source_failure_steps();
832+
},
833+
}
834+
}
793835
},
794836
}
795837
}
@@ -1550,13 +1592,21 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
15501592
}
15511593

15521594
// https://html.spec.whatwg.org/multipage/#dom-media-srcobject
1553-
fn GetSrcObject(&self) -> Option<DomRoot<Blob>> {
1554-
self.src_object.get()
1595+
fn GetSrcObject(&self) -> Option<MediaStreamOrBlob> {
1596+
match *self.src_object.borrow() {
1597+
Some(ref src_object) => Some(match src_object {
1598+
SrcObject::Blob(blob) => MediaStreamOrBlob::Blob(DomRoot::from_ref(&*blob)),
1599+
SrcObject::MediaStream(stream) => {
1600+
MediaStreamOrBlob::MediaStream(DomRoot::from_ref(&*stream))
1601+
},
1602+
}),
1603+
None => None,
1604+
}
15551605
}
15561606

15571607
// https://html.spec.whatwg.org/multipage/#dom-media-srcobject
1558-
fn SetSrcObject(&self, value: Option<&Blob>) {
1559-
self.src_object.set(value);
1608+
fn SetSrcObject(&self, value: Option<MediaStreamOrBlob>) {
1609+
*self.src_object.borrow_mut() = value.map(|value| value.into());
15601610
self.media_element_load_algorithm();
15611611
}
15621612

components/script/dom/webidls/HTMLMediaElement.webidl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// https://html.spec.whatwg.org/multipage/#htmlmediaelement
66

77
enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" };
8-
typedef /* (MediaStream or MediaSource or */ Blob /* ) */ MediaProvider;
8+
typedef (MediaStream /*or MediaSource */ or Blob) MediaProvider;
99

1010
[Abstract]
1111
interface HTMLMediaElement : HTMLElement {

tests/wpt/metadata/MANIFEST.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{
22
"items": {
3+
"conformancechecker": {
4+
"html/semantics/embedded-content/media-elements/src_object_blob.html": []
5+
},
36
"manual": {
47
"2dcontext/conformance-requirements/2d.coordinatespace-manual.html": [
58
[
@@ -12775,6 +12778,7 @@
1277512778
{}
1277612779
]
1277712780
],
12781+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
1277812782
"html/semantics/embedded-content/media-elements/video_controls_present-manual.html": [
1277912783
[
1278012784
"html/semantics/embedded-content/media-elements/video_controls_present-manual.html",
@@ -194571,6 +194575,7 @@
194571194575
{}
194572194576
]
194573194577
],
194578+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
194574194579
"html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-after-controls-added.html": [
194575194580
[
194576194581
"html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-after-controls-added.html",
@@ -201711,6 +201716,7 @@
201711201716
{}
201712201717
]
201713201718
],
201719+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
201714201720
"infrastructure/assumptions/ahem-ref.html": [
201715201721
[
201716201722
"infrastructure/assumptions/ahem-ref.html",
@@ -201809,6 +201815,7 @@
201809201815
]
201810201816
},
201811201817
"stub": {
201818+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
201812201819
"service-workers/stub-3.1-service-worker-obj.html": [
201813201820
[
201814201821
"service-workers/stub-3.1-service-worker-obj.html",
@@ -300426,6 +300433,7 @@
300426300433
{}
300427300434
]
300428300435
],
300436+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
300429300437
"html/semantics/embedded-content/media-elements/track/track-element/cors/support/common.js": [
300430300438
[
300431300439
{}
@@ -388893,6 +388901,12 @@
388893388901
{}
388894388902
]
388895388903
],
388904+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [
388905+
[
388906+
"html/semantics/embedded-content/media-elements/src_object_blob.html",
388907+
{}
388908+
]
388909+
],
388896388910
"html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [
388897388911
[
388898388912
"html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html",
@@ -474312,6 +474326,7 @@
474312474326
{}
474313474327
]
474314474328
],
474329+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
474315474330
"svg/text/visualtests/text-inline-size-001-visual.svg": [
474316474331
[
474317474332
"svg/text/visualtests/text-inline-size-001-visual.svg",
@@ -474362,6 +474377,7 @@
474362474377
]
474363474378
},
474364474379
"wdspec": {
474380+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [],
474365474381
"infrastructure/webdriver/tests/test_load_file.py": [
474366474382
[
474367474383
"infrastructure/webdriver/tests/test_load_file.py",
@@ -660109,6 +660125,10 @@
660109660125
"56a99028deb273359f32fc14b53b9317a4b9c76d",
660110660126
"testharness"
660111660127
],
660128+
"html/semantics/embedded-content/media-elements/src_object_blob.html": [
660129+
"481a8184ea2fdc6220b147d43a653ed510cfd104",
660130+
"testharness"
660131+
],
660112660132
"html/semantics/embedded-content/media-elements/src_reflects_attribute_not_source_elements.html": [
660113660133
"3dd43cc3f5524a32b7438e33481552653076cbe8",
660114660134
"testharness"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!doctype html>
2+
<meta charset="utf-8">
3+
<title>HTMLMediaElement.srcObject blob</title>
4+
<script src='/common/media.js'></script>
5+
<script src="/resources/testharness.js"></script>
6+
<script src="/resources/testharnessreport.js"></script>
7+
<video></video>
8+
<script>
9+
async_test(function(t) {
10+
t.step(function() {
11+
fetch(getVideoURI('/media/movie_5'))
12+
.then(function(response) {
13+
return response.blob();
14+
})
15+
.then(function(blob) {
16+
let video = document.querySelector("video");
17+
video.srcObject = blob;
18+
video.addEventListener('ended', function() {
19+
t.done();
20+
});
21+
video.play().catch(function(error) {
22+
assert(false, error);
23+
});
24+
})
25+
.catch(function(error) {
26+
assert(false, error);
27+
});
28+
});
29+
});
30+
</script>
31+

0 commit comments

Comments
 (0)