diff --git a/dom/media/test/bipbop-cenc-audio1.m4s b/dom/media/test/bipbop-cenc-audio1.m4s new file mode 100644 index 00000000000..63cfd66f7ef Binary files /dev/null and b/dom/media/test/bipbop-cenc-audio1.m4s differ diff --git a/dom/media/test/bipbop-cenc-audio2.m4s b/dom/media/test/bipbop-cenc-audio2.m4s new file mode 100644 index 00000000000..04a6cb6ff9c Binary files /dev/null and b/dom/media/test/bipbop-cenc-audio2.m4s differ diff --git a/dom/media/test/bipbop-cenc-audio3.m4s b/dom/media/test/bipbop-cenc-audio3.m4s new file mode 100644 index 00000000000..ad0cd72f903 Binary files /dev/null and b/dom/media/test/bipbop-cenc-audio3.m4s differ diff --git a/dom/media/test/bipbop-cenc-audioinit.mp4 b/dom/media/test/bipbop-cenc-audioinit.mp4 new file mode 100644 index 00000000000..b827aa49aac Binary files /dev/null and b/dom/media/test/bipbop-cenc-audioinit.mp4 differ diff --git a/dom/media/test/bipbop-cenc-video1.m4s b/dom/media/test/bipbop-cenc-video1.m4s new file mode 100644 index 00000000000..755013c11c8 Binary files /dev/null and b/dom/media/test/bipbop-cenc-video1.m4s differ diff --git a/dom/media/test/bipbop-cenc-video2.m4s b/dom/media/test/bipbop-cenc-video2.m4s new file mode 100644 index 00000000000..c884bd95fc4 Binary files /dev/null and b/dom/media/test/bipbop-cenc-video2.m4s differ diff --git a/dom/media/test/bipbop-cenc-videoinit.mp4 b/dom/media/test/bipbop-cenc-videoinit.mp4 new file mode 100644 index 00000000000..aa87d0bbe6c Binary files /dev/null and b/dom/media/test/bipbop-cenc-videoinit.mp4 differ diff --git a/dom/media/test/bipbop-frag-cenc.xml b/dom/media/test/bipbop-frag-cenc.xml new file mode 100644 index 00000000000..6f6a4d90a91 --- /dev/null +++ b/dom/media/test/bipbop-frag-cenc.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dom/media/test/bipbop-no-edts.mp4 b/dom/media/test/bipbop-no-edts.mp4 new file mode 100644 index 00000000000..63435887df1 Binary files /dev/null and b/dom/media/test/bipbop-no-edts.mp4 differ diff --git a/dom/media/test/eme.js b/dom/media/test/eme.js index 56baa0e996c..4190030e8a8 100644 --- a/dom/media/test/eme.js +++ b/dom/media/test/eme.js @@ -73,6 +73,35 @@ function Log(token, msg) { info(TimeStamp(token) + " " + msg); } +function TimeRangesToString(trs) +{ + var l = trs.length; + if (l === 0) { return "-"; } + var s = ""; + var i = 0; + for (;;) { + s += trs.start(i) + "-" + trs.end(i); + if (++i === l) { return s; } + s += ","; + } +} + +function SourceBufferToString(sb) +{ + return ("SourceBuffer{" + + "AppendMode=" + (sb.AppendMode || "-") + + ", updating=" + (sb.updating ? "true" : "false") + + ", buffered=" + TimeRangesToString(sb.buffered) + + ", audioTracks=" + (sb.audioTracks ? sb.audioTracks.length : "-") + + ", videoTracks=" + (sb.videoTracks ? sb.videoTracks.length : "-") + + "}"); +} + +function SourceBufferListToString(sbl) +{ + return "SourceBufferList[" + sbl.map(SourceBufferToString).join(", ") + "]"; +} + function UpdateSessionFunc(test, token, sessionType, resolve, reject) { return function(ev) { var msgStr = ArrayBufferToString(ev.message); @@ -186,6 +215,118 @@ function PlayFragmented(test, elem, token) }); } +function AppendTrack(test, ms, track, token) +{ + return new Promise(function(resolve, reject) { + var sb; + var curFragment = 0; + var resolved = false; + var fragmentFile; + + function addNextFragment() { + if (curFragment >= track.fragments.length) { + Log(token, track.name + ": end of track"); + resolve(); + resolved = true; + return; + } + + fragmentFile = MaybeCrossOriginURI(test, track.fragments[curFragment++]); + + var req = new XMLHttpRequest(); + req.open("GET", fragmentFile); + req.responseType = "arraybuffer"; + + req.addEventListener("load", function() { + Log(token, track.name + ": fetch of " + fragmentFile + " complete, appending"); + sb.appendBuffer(new Uint8Array(req.response)); + }); + + req.addEventListener("error", function(){info(token + " error fetching " + fragmentFile);}); + req.addEventListener("abort", function(){info(token + " aborted fetching " + fragmentFile);}); + + Log(token, track.name + ": addNextFragment() fetching next fragment " + fragmentFile); + req.send(null); + } + + Log(token, track.name + ": addSourceBuffer(" + track.type + ")"); + sb = ms.addSourceBuffer(track.type); + sb.addEventListener("updateend", function() { + if (ms.readyState == "ended") { + /* We can get another updateevent as a result of calling ms.endOfStream() if + the highest end time of our source buffers is different from that of the + media source duration. Due to bug 1065207 this can happen because of + inaccuracies in the frame duration calculations. Check if we are already + "ended" and ignore the update event */ + Log(token, track.name + ": updateend when readyState already 'ended'"); + if (!resolved) { + // Needed if decoder knows this was the last fragment and ended by itself. + Log(token, track.name + ": but promise not resolved yet -> end of track"); + resolve(); + resolved = true; + } + return; + } + Log(token, track.name + ": updateend for " + fragmentFile + ", " + SourceBufferToString(sb)); + addNextFragment(); + }); + + addNextFragment(); + }); +} + +function PlayMultiTrack(test, elem, token) +{ + if (!test.tracks) { + ok(false, token + " test does not have a tracks list"); + return Promise.reject(); + } + + var ms = new MediaSource(); + elem.src = URL.createObjectURL(ms); + + return new Promise(function (resolve, reject) { + var firstOpen = true; + ms.addEventListener("sourceopen", function () { + if (!firstOpen) { + Log(token, "sourceopen again?"); + return; + } + + firstOpen = false; + Log(token, "sourceopen"); + return Promise.all(test.tracks.map(function(track) { + return AppendTrack(test, ms, track, token); + })).then(function(){ + Log(token, "end of stream"); + ms.endOfStream(); + resolve(); + }); + }) + }); +} + +// Returns a promise that is resolved when the media element is ready to have +// its play() function called; when it's loaded MSE fragments, or once the load +// has started for non-MSE video. +function LoadTest(test, elem, token) +{ + if (test.fragments) { + // A |fragments| array indicates that this is an MSE test case with one track. + return PlayFragmented(test, elem, token); + } + + if (test.tracks) { + // A |tracks| array indicates that this is an MSE test case with multiple tracks. + return PlayMultiTrack(test, elem, token); + } + + // This file isn't fragmented; won't set the media source normally because + // EME doesn't support non-MSE source. + ok(false, token + " test does not have a fragments or tracks list"); + return Promise.reject(); +} + function SetupEME(test, token, params) { var v = document.createElement("video"); @@ -208,12 +349,23 @@ function SetupEME(test, token, params) ? params.onSetKeysFail : bail(token + " Failed to set MediaKeys on