Bug 1536766 - Switch test_streams_element_capture.html to test all gPlayTests. r=jya
☠☠ backed out by 41f1dcbe9caa ☠ ☠
authorAndreas Pehrson <apehrson@mozilla.com>
Thu, 18 Apr 2019 15:23:05 +0000
changeset 470092 3e0e3030314dbf9cc4be5bac8721c04dd78d63ed
parent 470091 24d0d307385d2cf5ce66854e40b92d7b15dc8428
child 470093 4f6d240c210d25b38d22d4c6b6474acfcda8c032
push id35888
push useraiakab@mozilla.com
push dateFri, 19 Apr 2019 09:47:45 +0000
treeherdermozilla-central@0160424142d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1536766
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1536766 - Switch test_streams_element_capture.html to test all gPlayTests. r=jya This tests HTMLMediaElement::MozCaptureStream on all of our play-tests, rather than just a single test, in order to test more corner cases in the capture code. Because this test checks that the media element that's playing the mozCaptureStream()-stream ends after at least the duration of the original media file, and because media elements playing a MediaStream have a `currentTime` based on the MediaStreamGraph's monotonically increasing clock, we need to have accurate metadata for how long the duration of the content of the original media file is. There are several cases among the play-tests where the duration metadata doesn't match what the decoder gives us -- the reason is often preroll or corrupt containers. This patch updates manifest.js with `contentDuration` for the tests among `gPlayTests` where try detected mismatches. Differential Revision: https://phabricator.services.mozilla.com/D27257
dom/media/test/manifest.js
dom/media/test/test_streams_element_capture.html
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -195,46 +195,46 @@ var gPlayTests = [
   // Ogg stream without eof marker
   { name:"bug461281.ogg", type:"application/ogg", duration:2.208 },
 
   // oggz-chop stream
   { name:"bug482461.ogv", type:"video/ogg", duration:4.34 },
   // Theora only oggz-chop stream
   { name:"bug482461-theora.ogv", type:"video/ogg", duration:4.138 },
   // With first frame a "duplicate" (empty) frame.
-  { name:"bug500311.ogv", type:"video/ogg", duration:1.96 },
+  { name:"bug500311.ogv", type:"video/ogg", duration:1.96, contentDuration:1.958 },
   // Small audio file
   { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
   // More audio in file than video.
   { name:"short-video.ogv", type:"video/ogg", duration:1.081 },
   // First Theora data packet is zero bytes.
   { name:"bug504613.ogv", type:"video/ogg", duration:Number.NaN },
   // Multiple audio streams.
   { name:"bug516323.ogv", type:"video/ogg", duration:4.208 },
   // oggz-chop with non-keyframe as first frame
-  { name:"bug556821.ogv", type:"video/ogg", duration:2.936 },
+  { name:"bug556821.ogv", type:"video/ogg", duration:2.936, contentDuration:2.903 },
 
   // Encoded with vorbis beta1, includes unusually sized codebooks
   { name:"beta-phrasebook.ogg", type:"audio/ogg", duration:4.01 },
   // Small file, only 1 frame with audio only.
   { name:"bug520493.ogg", type:"audio/ogg", duration:0.458 },
   // Small file with vorbis comments with 0 length values and names.
   { name:"bug520500.ogg", type:"audio/ogg", duration:0.123 },
 
   // Various weirdly formed Ogg files
-  { name:"bug499519.ogv", type:"video/ogg", duration:0.24 },
+  { name:"bug499519.ogv", type:"video/ogg", duration:0.24, contentDuration:0.22 },
   { name:"bug506094.ogv", type:"video/ogg", duration:0 },
   { name:"bug498855-1.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug498855-2.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug498855-3.ogv", type:"video/ogg", duration:0.24 },
-  { name:"bug504644.ogv", type:"video/ogg", duration:1.6 },
-  { name:"chain.ogv", type:"video/ogg", duration:Number.NaN },
-  { name:"bug523816.ogv", type:"video/ogg", duration:0.766 },
+  { name:"bug504644.ogv", type:"video/ogg", duration:1.6, contentDuration:1.52 },
+  { name:"chain.ogv", type:"video/ogg", duration:Number.NaN, contentDuration:0.266 },
+  { name:"bug523816.ogv", type:"video/ogg", duration:0.766, contentDuration:0 },
   { name:"bug495129.ogv", type:"video/ogg", duration:2.41 },
-  { name:"bug498380.ogv", type:"video/ogg", duration:0.7663 },
+  { name:"bug498380.ogv", type:"video/ogg", duration:0.7663, contentDuration:0 },
   { name:"bug495794.ogg", type:"audio/ogg", duration:0.3 },
   { name:"bug557094.ogv", type:"video/ogg", duration:0.24 },
   { name:"multiple-bos.ogg", type:"video/ogg", duration:0.431 },
   { name:"audio-overhang.ogg", type:"audio/ogg", duration:2.3 },
   { name:"video-overhang.ogg", type:"audio/ogg", duration:3.966 },
 
   // bug461281.ogg with the middle second chopped out.
   { name:"audio-gaps.ogg", type:"audio/ogg", duration:2.208 },
@@ -256,21 +256,21 @@ var gPlayTests = [
   { name:"resolution-change.webm", type:"video/webm", duration:6.533 },
 
   // A really short, low sample rate, single channel file. This tests whether
   // we can handle playing files when only push very little audio data to the
   // hardware.
   { name:"spacestorm-1000Hz-100ms.ogg", type:"audio/ogg", duration:0.099 },
 
   // Opus data in an ogg container
-  { name:"detodos-short.opus", type:"audio/ogg; codecs=opus", duration:0.22 },
+  { name:"detodos-short.opus", type:"audio/ogg; codecs=opus", duration:0.22, contentDuration:0.2135 },
   // Opus data in a webm container
-  { name:"detodos-short.webm", type:"audio/webm; codecs=opus", duration:0.26 },
+  { name:"detodos-short.webm", type:"audio/webm; codecs=opus", duration:0.26, contentDuration:0.2535 },
   // Opus in webm channel mapping=2 sample file
-  { name:"opus-mapping2.webm", type:"audio/webm; codecs=opus", duration:10.01 },
+  { name:"opus-mapping2.webm", type:"audio/webm; codecs=opus", duration:10.01, contentDuration:9.99 },
   { name:"bug1066943.webm", type:"audio/webm; codecs=opus", duration:1.383 },
 
   // Multichannel Opus in an ogg container
   { name:"test-1-mono.opus", type:"audio/ogg; codecs=opus", duration:1.044 },
   { name:"test-2-stereo.opus", type:"audio/ogg; codecs=opus", duration:2.925 },
   { name:"test-3-LCR.opus", type:"audio/ogg; codecs=opus", duration:4.214 },
   { name:"test-4-quad.opus", type:"audio/ogg; codecs=opus", duration:6.234 },
   { name:"test-5-5.0.opus", type:"audio/ogg; codecs=opus", duration:7.558 },
@@ -280,18 +280,18 @@ var gPlayTests = [
 
   { name:"gizmo-short.mp4", type:"video/mp4", duration:0.27 },
   // Test playback of a MP4 file with a non-zero start time (and audio starting
   // a second later).
   { name:"bipbop-lateaudio.mp4", type:"video/mp4" },
   // Ambisonics AAC, requires AAC extradata to be set when creating decoder (see bug 1431169)
   // Also test 4.0 decoding.
   { name:"ambisonics.mp4", type:"audio/mp4", duration:16.48 },
-  // Opus in MP4 channel mapping=0 sample file
-  { name:"opus-sample.mp4", type:"audio/mp4; codecs=opus", duration:10.92 },
+  // Opus in MP4 channel mapping=0 sample file (content shorter due to preskip)
+  { name:"opus-sample.mp4", type:"audio/mp4; codecs=opus", duration:10.92, contentDuration:10.09 },
   // Opus in MP4 channel mapping=2 sample file
   { name:"opus-mapping2.mp4", type:"audio/mp4; codecs=opus", duration:10.0 },
 
   { name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
   { name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
   { name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
   // owl.mp3 as above, but with something funny going on in the ID3v2 tag
   // that caused DirectShow to fail.
@@ -303,23 +303,23 @@ var gPlayTests = [
   // frame is at such a high offset into the file, MP3FrameParser will give up
   // and report that the stream is not MP3. However, it does not count ID3 tags
   // in that offset. This test case makes sure that ID3 exclusion holds.
   { name:"huge-id3.mp3", type:"audio/mpeg", duration:1.00 },
   // A truncated VBR MP3 with just enough frames to keep most decoders happy.
   // The Xing header reports the length of the file to be around 10 seconds, but
   // there is really only one second worth of data. We want MP3FrameParser to
   // trust the header, so this should be reported as 10 seconds.
-  { name:"vbr-head.mp3", type:"audio/mpeg", duration:10.00 },
+  { name:"vbr-head.mp3", type:"audio/mpeg", duration:10.00, contentDuration:1.019 },
 
   // A flac file where the STREAMINFO block was removed.
   // It is necessary to parse the file to find an audio frame instead.
   { name:"flac-noheader-s16.flac", type:"audio/flac", duration:4.0 },
   { name:"flac-s24.flac", type:"audio/flac", duration:4.04 },
-  { name:"flac-sample.mp4", type:"audio/mp4; codecs=flac", duration:4.95 },
+  { name:"flac-sample.mp4", type:"audio/mp4; codecs=flac", duration:4.95, contentDuration:5.03 },
   // Ogg with theora video and flac audio.
   { name:"A4.ogv", type:"video/ogg", width:320, height:240, duration:3.13 },
 
   // Invalid file
   { name:"bogus.duh", type:"bogus/duh", duration:Number.NaN },
 ];
 
 if (!(manifestNavigator().userAgent.includes("Windows") &&
@@ -349,17 +349,17 @@ var gSeekToNextFrameTests = [
   // Various weirdly formed Ogg files
   { name:"bug498855-1.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug498855-2.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug498855-3.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug504644.ogv", type:"video/ogg", duration:1.6 },
 
   { name:"bug523816.ogv", type:"video/ogg", duration:0.766 },
 
-  { name:"bug498380.ogv", type:"video/ogg", duration:0.766 },
+  { name:"bug498380.ogv", type:"video/ogg", duration:0.2 },
   { name:"bug557094.ogv", type:"video/ogg", duration:0.24 },
   { name:"multiple-bos.ogg", type:"video/ogg", duration:0.431 },
   // Test playback/metadata work after a redirect
   { name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
     type:"video/ogg", duration:0.266 },
   // Test playback of a webm file
   { name:"seek-short.webm", type:"video/webm", duration:0.23 },
   // Test playback of a WebM file with non-zero start time.
--- a/dom/media/test/test_streams_element_capture.html
+++ b/dom/media/test/test_streams_element_capture.html
@@ -4,97 +4,112 @@
   <title>Test that a MediaStream captured from one element plays back in another</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-SimpleTest.waitForExplicitFinish();
+let manager = new MediaTestManager();
 
-// longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(3);
-  SimpleTest.requestCompleteLog();
-}
-
-function checkDrawImage(vout) {
+function checkDrawImage(vout, msg) {
   var canvas = document.createElement("canvas");
   var ctx = canvas.getContext("2d");
   ctx.drawImage(vout, 0, 0);
   var imgData = ctx.getImageData(0, 0, 1, 1);
-  is(imgData.data[3], 255, "Check video frame pixel has been drawn");
+  is(imgData.data[3], 255, msg);
 }
 
 function isGreaterThanOrEqualEps(a, b, msg) {
-  ok(a >= b - 0.01,
-     "Got " + a + ", expected at least " + b + "; " + msg);
+  ok(a >= b, `Got ${a}, expected at least ${b}; ${msg}`);
 }
 
-function startTest(test) {
+function startTest(test, token) {
+  manager.started(token);
   var v = document.createElement('video');
   var vout = document.createElement('video');
 
+  v.id = "MediaDecoder";
+  vout.id = "MediaStream";
+
   v.src = test.name;
   var stream;
 
   var checkEnded = function() {
-    if (test.duration) {
-      isGreaterThanOrEqualEps(vout.currentTime, test.duration,
-         test.name + " current time at end");
+    let duration = test.duration;
+    if (typeof(test.contentDuration) == "number") {
+      duration = test.contentDuration;
+    }
+    if (duration) {
+      isGreaterThanOrEqualEps(vout.currentTime, duration,
+        `${token} current time at end`);
     }
-    is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
-    ok(vout.ended, test.name + " checking playback has ended");
-    if (test.type.match(/^video/)) {
-      checkDrawImage(vout);
+    is(vout.readyState, vout.HAVE_CURRENT_DATA,
+      `${token} checking readyState`);
+    ok(vout.ended, `${token} checking playback has ended`);
+    isnot(stream.getTracks().length, 0, `${token} results in some tracks`);
+    if (stream.getVideoTracks().length > 0) {
+      ok(test.type.match(/^video/), `${token} is a video resource`);
+      checkDrawImage(vout, `${token} checking video frame pixel has been drawn`);
     }
     vout.remove();
     removeNodeAndSource(v);
-    SimpleTest.finish();
+    manager.finished(token);
   };
-  vout.addEventListener("ended", checkEnded);
+	Promise.race([
+    Promise.all([
+      new Promise(r => vout.addEventListener("ended", r, {once:true})),
+      new Promise(r => v.addEventListener("ended", r, {once:true})),
+		]),
+		new Promise((res, rej) => vout.addEventListener("error", rej, {once:true})),
+		new Promise((res, rej) => v.addEventListener("error", rej, {once:true})),
+	]).then(() => checkEnded(), e => {
+		ok(false, `Error: ${e.target.id} ${token}, ${e.target.error.message}`);
+		manager.finished(token);
+	});
+
 
   document.body.appendChild(vout);
 
-  var onloadedmetadata = function (ev) {
+  var onloadedmetadata = async function (ev) {
     stream = v.mozCaptureStreamUntilEnded();
     vout.srcObject = stream;
-    is(vout.srcObject, stream, test.name + " set output element .srcObject correctly");
+    is(vout.srcObject, stream,
+      `${token} set output element .srcObject correctly`);
+    // Wait for the resource fetch algorithm to have run, so that the media
+    // element is hooked up to the MediaStream and ready to go. If we don't do
+    // this, we're not guaranteed to render the very first video frame, which
+    // can make this test fail the drawImage test when a video resource only
+    // contains one frame.
+    await new Promise(r => vout.addEventListener('loadstart', r));
     v.play();
     vout.play();
   }
 
   v.preload = 'metadata';
   v.addEventListener('loadedmetadata', onloadedmetadata);
 
   // Log events for debugging.
   var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
                 "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
                 "waiting", "pause"];
   function logEvent(e) {
-    Log(e.target.name, "got " + e.type);
+    Log(token, `${e.target.id} got ${e.type}`);
   }
   events.forEach(function(e) {
     v.addEventListener(e, logEvent);
     vout.addEventListener(e, logEvent);
   });
 
 }
 
-// We only test one playable video because for some of the audio files
-// --- small-shot.mp3.mp4 and small-shot.m4a --- GStreamer doesn't decode
-// as much data as indicated by the duration, causing this test to fail on
-// Linux. See bug 1084185.
-var testVideo = getPlayableVideo(gSmallTests);
-if (testVideo) {
-  SpecialPowers.pushPrefEnv(
-    { "set": [["privacy.reduceTimerPrecision", false]]},
-    function() {
-      startTest(testVideo);
-    });
-} else {
-  todo(false, "No playable video");
-}
+(async () => {
+  SimpleTest.waitForExplicitFinish();
+  await SpecialPowers.pushPrefEnv(
+    { "set": [["privacy.reduceTimerPrecision", false]]});
+  // Filter out bug1377278.webm due to bug 1541401.
+  manager.runTests(gPlayTests.filter(t => !t.name.includes("1377278")), startTest);
+})();
 </script>
 </pre>
 </body>
 </html>