Bug 1121774 - Split audio and video tracks in EME MSE tests. r=edwin

This commit is contained in:
Gerald Squelart 2015-03-11 20:40:00 -04:00
parent dc9e8a7592
commit c9deaaa539
22 changed files with 304 additions and 68 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to |bipbop-cenc*|. To
generate the bipbop-cenc files, run the following commands:
Encrypt bipbop-no-edts.mp4 with the keys specified in this file,
and output to |bipbop-cenc-{video,audio}.mp4|
MP4Box -crypt bipbop-frag-cenc.xml -rem 2 -out bipbop-cenc-video.mp4 bipbop-no-edts.mp4
MP4Box -crypt bipbop-frag-cenc.xml -rem 1 -out bipbop-cenc-audio.mp4 bipbop-no-edts.mp4
Fragment |bipbop-cenc-*.mp4| into 500ms segments:
MP4Box -dash 500 -rap -segment-name bipbop-cenc-video -subsegs-per-sidx 5 bipbop-cenc-video.mp4
MP4Box -dash 500 -rap -segment-name bipbop-cenc-audio -subsegs-per-sidx 5 bipbop-cenc-audio.mp4
The above command will generate a set of fragments in |bipbop-cenc-{video,audio}*.m4s
and |bipbop-cenc-{video,audio}init.mp4| containing just the init segment.
To cut down the duration, we throw out all but the first 3 audio & 2 video segments:
rm bipbop-cenc-audio{[^123],[123][^.]}.m4s
rm bipbop-cenc-video{[^12],[12][^.]}.m4s
MP4Box will also have generated some *.mpd files we don't need:
rm bipbop-cenc-*.mpd
Delete intermediate encrypted files:
rm bipbop-cenc-{audio,video}.mp4
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 2 -->
<BS bits="32" value="2" />
<!-- KeyID -->
<BS ID128="0x7e571d037e571d037e571d037e571d03" />
<BS ID128="0x7e571d047e571d047e571d047e571d04" />
</DRMInfo>
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d037e571d037e571d037e571d03"
value="0x7e5733337e5733337e5733337e573333" />
</CrypTrack>
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d047e571d047e571d047e571d04"
value="0x7e5744447e5744447e5744447e574444" />
</CrypTrack>
</GPACDRM>

Binary file not shown.

View File

@ -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 <video> element");
var firstEncrypted = true;
v.addEventListener("encrypted", function(ev) {
Log(token, "got encrypted event");
if (!firstEncrypted) {
// TODO: Better way to handle 'encrypted'?
// Maybe wait for metadataloaded and all expected 'encrypted's?
Log(token, "got encrypted event again, initDataType=" + ev.initDataType);
return;
}
firstEncrypted = false;
Log(token, "got encrypted event, initDataType=" + ev.initDataType);
var options = [
{
initDataType: ev.initDataType,
videoType: test.type,
audioType: test.type,
}
];

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This XML file describes the encryption applied to |gizmo-frag-cenc*|. To
generate the gizmo-frag-cenc files, run the following commands:
Encrypt gizmo.mp4 with the keys specified in this file, and output to |gizmo-cenc.mp4|
MP4Box -crypt gizmo-frag-cenc.xml -out gizmo-cenc.mp4 gizmo.mp4
Fragment |gizmo-cenc.mp4| into 1000ms segments:
MP4Box -dash 1000 -rap -segment-name gizmo-frag-cenc -subsegs-per-sidx 5 -rem 2 gizmo-cenc.mp4
The above command will generate a set of fragments in |gizmo-frag-cenc*.m4s|
and a single |gizmo-frag-cencinit.mp4| containing just the init segment.
To cut down the duration, we throw out all but the first two segments:
rm gizmo-frag-cenc[^12].m4s
-->
<GPACDRM type="CENC AES-CTR">
<DRMInfo type="pssh" version="1">
<!--
SystemID specified in
https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
-->
<BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
<!-- Number of KeyIDs = 2 -->
<BS bits="32" value="2" />
<!-- KeyID -->
<BS ID128="0x7e571d037e571d037e571d037e571d03" />
<BS ID128="0x7e571d047e571d047e571d047e571d04" />
</DRMInfo>
<CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d037e571d037e571d037e571d03"
value="0x7e5733337e5733337e5733337e573333" />
</CrypTrack>
<CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
first_IV="0x00000000000000000000000000000000">
<key KID="0x7e571d047e571d047e571d047e571d04"
value="0x7e5744447e5744447e5744447e574444" />
</CrypTrack>
</GPACDRM>

Binary file not shown.

Binary file not shown.

View File

@ -646,33 +646,100 @@ var gMetadataTests = [
// Test files for Encrypted Media Extensions
var gEMETests = [
{
name:"gizmo-frag-cencinit.mp4",
fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:2.00,
duration:1.60,
},
{
name:"gizmo-frag-cencinit.mp4",
fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:2.00,
crossOrigin:true,
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
tracks: [
{
name:"audio",
type:"audio/mp4; codecs=\"mp4a.40.2\"",
fragments:[ "bipbop-cenc-audioinit.mp4",
"bipbop-cenc-audio1.m4s",
"bipbop-cenc-audio2.m4s",
"bipbop-cenc-audio3.m4s",
],
},
{
name:"video",
type:"video/mp4; codecs=\"avc1.64000d\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
},
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
duration:1.60,
},
{
name:"bipbop-cenc-videoinit.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
tracks: [
{
name:"audio",
type:"audio/mp4; codecs=\"mp4a.40.2\"",
fragments:[ "bipbop-cenc-audioinit.mp4",
"bipbop-cenc-audio1.m4s",
"bipbop-cenc-audio2.m4s",
"bipbop-cenc-audio3.m4s",
],
},
{
name:"video",
type:"video/mp4; codecs=\"avc1.64000d\"",
fragments:[ "bipbop-cenc-videoinit.mp4",
"bipbop-cenc-video1.m4s",
"bipbop-cenc-video2.m4s",
],
},
],
keys: {
// "keyid" : "key"
"7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
"7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
},
sessionType:"temporary",
crossOrigin:true,
duration:1.60,
},
];
var gEMENonFragmentedTests = [
var gEMENonMSEFailTests = [
{
name:"short-cenc.mp4",
type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
@ -729,6 +796,10 @@ function getMajorMimeType(mimetype) {
// Force releasing decoder to avoid timeout in waiting for decoding resource.
function removeNodeAndSource(n) {
n.remove();
// Clearing mozSrcObject and/or src will actually set them to some default
// URI that will fail to load, so make sure we don't produce a spurious
// bailing error.
n.onerror = null;
// reset |mozSrcObject| first since it takes precedence over |src|.
n.mozSrcObject = null;
n.src = "";

View File

@ -45,6 +45,13 @@ support-files =
beta-phrasebook.ogg^headers^
big.wav
big.wav^headers^
bipbop-cenc-audio1.m4s
bipbop-cenc-audio2.m4s
bipbop-cenc-audio3.m4s
bipbop-cenc-audioinit.mp4
bipbop-cenc-video1.m4s
bipbop-cenc-video2.m4s
bipbop-cenc-videoinit.mp4
bogus.duh
bogus.ogv
bogus.ogv^headers^
@ -141,9 +148,6 @@ support-files =
dynamic_redirect.sjs
dynamic_resource.sjs
eme.js
gizmo-frag-cenc1.m4s
gizmo-frag-cenc2.m4s
gizmo-frag-cencinit.mp4
file_access_controls.html
fragment_noplay.js
fragment_play.js
@ -369,7 +373,7 @@ skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'go
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
[test_eme_canvas_blocked.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s || (os == 'win' && !debug) # bug 1043403, bug 1057908, bug 1140675
[test_eme_non_fragmented.html]
[test_eme_non_mse_fails.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
#[test_eme_obs_notification.html]
#skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908

View File

@ -38,7 +38,7 @@ function startTest(test, token)
manager.finished(token);
});
PlayFragmented(test, v, token);
LoadTest(test, v, token);
}
function beginTest() {

View File

@ -84,7 +84,7 @@ function startTest(test, token)
}
function beginTest() {
manager.runTests(gEMENonFragmentedTests, startTest);
manager.runTests(gEMENonMSEFailTests, startTest);
}
var prefs = [

View File

@ -52,7 +52,7 @@ function startTest(test, token)
manager.finished(token);
});
PlayFragmented(test, v, token);
LoadTest(test, v, token);
}
function beginTest() {

View File

@ -147,7 +147,7 @@ function startTest(test, token)
}
);
PlayFragmented(test, v, token);
LoadTest(test, v, token);
}
function beginTest() {

View File

@ -88,7 +88,7 @@ function startTest(test, token)
manager.finished(token);
});
PlayFragmented(test, v, token)
LoadTest(test, v, token)
.then(function() {
v.play();
}).catch(function() {

View File

@ -32,7 +32,7 @@ function startTest(test, token)
ok(false, TimeStamp(case1token) + " should never reach loadeddata, as setMediaKeys should fail");
});
manager.started(case1token);
PlayFragmented(test, v1, case1token);
LoadTest(test, v1, case1token);
// Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
@ -51,7 +51,7 @@ function startTest(test, token)
manager.finished(case2token);
});
manager.started(case2token);
PlayFragmented(test, v2, case2token);
LoadTest(test, v2, case2token);
// Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
@ -69,7 +69,7 @@ function startTest(test, token)
manager.finished(case3token);
});
manager.started(case3token);
PlayFragmented(test, v3, case3token);
LoadTest(test, v3, case3token);
}
function beginTest() {