| <!DOCTYPE html> |
| <html lang="en" class="reftest-wait"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>HTML MSE test: video is shown</title> |
| <link rel="author" title="Alicia Boya GarcĂa" href="mailto:aboya@igalia.com"> |
| <link rel="match" href="mediasource-video-is-visible-expected.html"> |
| <meta name="fuzzy" content="maxDifference=30;totalPixels=76800"> |
| <meta name="assert" content="Video is rendered in the MSE player."> |
| <style> |
| html, body { |
| margin: 0; |
| padding: 0; |
| overflow: hidden; |
| background: white; |
| } |
| body { |
| position: absolute; |
| top: 0; |
| bottom: 0; |
| left: 0; |
| right: 0; |
| } |
| #video { |
| width: 320px; |
| height: 240px; |
| } |
| #explanation { |
| position: absolute; |
| top: 260px; |
| } |
| </style> |
| </head> |
| <body> |
| <video id="video"></video> |
| <div id="explanation">A video containing a blue static image should be visible above.</div> |
| <script> |
| if ("testRunner" in window) |
| // WebKit reftests use a different mechanism for delaying the test finish. |
| testRunner.waitUntilDone(); |
| |
| const mediaElement = document.getElementById("video"); |
| |
| class NetworkError extends Error { |
| constructor(message) { |
| super(message); |
| } |
| } |
| |
| function requestJSON(url) { |
| return new Promise((resolve, reject) => { |
| const xhr = new XMLHttpRequest(); |
| xhr.open("GET", url, true); |
| xhr.responseType = "text"; |
| xhr.onreadystatechange = () => { |
| if (xhr.readyState === 4) { |
| if (xhr.status >= 200 && xhr.status < 300) { |
| resolve(JSON.parse(xhr.responseText)); |
| } else { |
| reject(new NetworkError(`Error ${xhr.status}`)); |
| } |
| } |
| }; |
| xhr.send(null); |
| }); |
| } |
| |
| function requestBinaryMedia(url) { |
| return new Promise((resolve, reject) => { |
| const xhr = new XMLHttpRequest(); |
| xhr.open("GET", url, true); |
| xhr.responseType = "arraybuffer"; |
| xhr.onreadystatechange = () => { |
| if (xhr.readyState === 4) { |
| if (xhr.status >= 200 && xhr.status < 300) { |
| resolve(xhr.response); |
| } else { |
| reject(new NetworkError(`Error ${xhr.status}`)); |
| } |
| } |
| }; |
| xhr.send(null); |
| }) |
| } |
| |
| function waitForEvent(element, eventName) { |
| return new Promise(resolve => { |
| element.addEventListener(eventName, function handler() { |
| element.removeEventListener(eventName, handler); |
| resolve(); |
| }) |
| }); |
| } |
| |
| function waitForAppend(sourceBuffer, data) { |
| return new Promise(resolve => { |
| const listener = () => { |
| sourceBuffer.removeEventListener("update", listener); |
| resolve(); |
| }; |
| sourceBuffer.addEventListener("update", listener); |
| sourceBuffer.appendBuffer(data); |
| }); |
| } |
| |
| let mediaSource; |
| let audioSB; |
| let videoSB; |
| |
| async function main(audioType, audioUrl, videoType, videoUrl) { |
| const audioManifest = await requestJSON(audioUrl); |
| const videoManifest = await requestJSON(videoUrl); |
| const audioData = await requestBinaryMedia(audioManifest.url); |
| const videoData = await requestBinaryMedia(videoManifest.url); |
| |
| mediaSource = new MediaSource(); |
| mediaElement.src = window.URL.createObjectURL(mediaSource); |
| mediaElement.volume = 0.1; |
| await waitForEvent(mediaSource, "sourceopen"); |
| |
| audioSB = mediaSource.addSourceBuffer(audioType); |
| videoSB = mediaSource.addSourceBuffer(videoType); |
| |
| await waitForAppend(audioSB, audioData.slice(0, audioManifest.init.size)); |
| await waitForAppend(videoSB, videoData.slice(0, videoManifest.init.size)); |
| |
| await waitForAppend(audioSB, audioData.slice(audioManifest.init.size)); |
| await waitForAppend(videoSB, videoData.slice(videoManifest.init.size)); |
| |
| mediaSource.endOfStream(); |
| mediaElement.play(); |
| await waitForEvent(mediaElement, "ended"); |
| |
| if ("testRunner" in window) |
| testRunner.notifyDone(); |
| document.documentElement.classList.remove("reftest-wait"); |
| } |
| |
| function selectAlternative(alternatives) { |
| for (let alternative of alternatives) { |
| if (MediaSource.isTypeSupported(alternative.mimeType)) |
| return [alternative.mimeType, alternative.url]; |
| } |
| throw new Error("Could not find suitable alternative"); |
| } |
| |
| const [audioType, audioUrl] = selectAlternative([ |
| {mimeType: 'audio/mp4; codecs="mp4a.40.2"', url: "mp4/test-a-1s.mp4-manifest.json"}, |
| {mimeType: 'audio/webm; codecs="opus"', url: "webm/test-a-1s.webm-manifest.json"}, |
| ]); |
| const [videoType, videoUrl] = selectAlternative([ |
| {mimeType: 'video/mp4; codecs="avc1.42C015"', url: "mp4/test-v-1s-blue.mp4-manifest.json"}, |
| {mimeType: 'video/webm; codecs="vp9"', url: "webm/test-v-1s-blue.webm-manifest.json"}, |
| ]); |
| |
| main(audioType, audioUrl, videoType, videoUrl); |
| </script> |
| </body> |
| </html> |