haikuwebkit/PerformanceTests/Media/MSEPlaybackRate.html

192 lines
5.7 KiB
HTML
Raw Permalink Normal View History

Add some performance tests for various aspects of media loading and playback. https://bugs.webkit.org/show_bug.cgi?id=164977 Reviewed by Darin Adler. PerformanceTests: Add new tests for a few aspects of media playback; namely: how quickly media elements fire the "canplaythrough" event when all data is immediately available, how quickly HLS playback switches resolutions, and at what playback rate MSE-backed video can play without dropping frames. Skip these tests by default, as they're not runnable on all ports, and they require a webserver (run-webkit-httpd) to complete on macOS. * Media/HLSCanPlayThrough.html: Added. * Media/HLSGearChange.html: Added. * Media/MSECanPlayThrough.html: Added. * Media/MSEPlaybackRate.html: Added. * Media/StandardCanPlayThrough.html: Added. * Media/hls/1080p/iframe_index.m3u8: Added. * Media/hls/1080p/prog_index.m3u8: Added. * Media/hls/1080p/test.ts: Added. * Media/hls/480p/iframe_index.m3u8: Added. * Media/hls/480p/prog_index.m3u8: Added. * Media/hls/480p/test.ts: Added. * Media/hls/720p/iframe_index.m3u8: Added. * Media/hls/720p/prog_index.m3u8: Added. * Media/hls/720p/test.ts: Added. * Media/hls/720p/test.ts.back: Added. * Media/hls/index.m3u8: Added. * Media/media-source-loader.js: Added. (MediaSourceLoader): (MediaSourceLoader.prototype.loadManifest): (MediaSourceLoader.prototype.loadManifestSucceeded): (MediaSourceLoader.prototype.loadManifestFailed): (MediaSourceLoader.prototype.loadMediaData): (MediaSourceLoader.prototype.loadMediaDataSucceeded): (MediaSourceLoader.prototype.loadMediaDataFailed): (MediaSourceLoader.prototype.get type): (MediaSourceLoader.prototype.get duration): (MediaSourceLoader.prototype.get initSegment): (MediaSourceLoader.prototype.get mediaSegmentsLength): (MediaSourceLoader.prototype.mediaSegments): (MediaSourceLoader.prototype.get everyMediaSegment): * Media/test-fragmented-video.json: Added. * Media/test-fragmented-video.mp4: Added. * Media/test.mp4: Added. * Skipped: Tools: Allow callers to pass in extra alias/directory pairs to run-webkit-httpd. * Scripts/run-webkit-httpd: (parse_args): (main): Canonical link: https://commits.webkit.org/182707@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208999 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-28 17:22:30 +00:00
<!DOCTYPE html>
<html>
<head>
<script src="media-source-loader.js"></script>
<script src="../resources/runner.js"></script>
<script>
var loader;
window.addEventListener('load', () => {
loader = new MediaSourceLoader('test-fragmented-video.json');
loader.loadMediaData().then(runTest);
});
function *range(start, end) {
while (start < end)
yield(start++);
}
function addVideos(count, autoplay) {
return new Promise((resolve, reject) => {
var promises = [];
var videos = [];
for (var i of range(0, count)) {
var video = document.createElement('video');
video.controls = false;
video.loop = true;
video.muted = true;
document.body.appendChild(video);
promises.push(loadMediaDataIntoVideo(video));
videos.push(video);
}
document.getElementById('video-count').innerText = videoCount();
Promise.all(promises).then(() => {
resolve(videos);
});
});
}
function removeVideos(count) {
while (count > 0) {
--count;
var video = document.querySelector('video:last-child');
video.src = '';
video.load();
document.body.removeChild(video);
}
document.getElementById('video-count').innerText = videoCount();
}
function loadMediaDataIntoVideo(video) {
return new Promise((resolve, reject) => {
var source = new MediaSource();
source.addEventListener('sourceopen', (e) => {
var source = e.target;
var currentMediaSegment = 0;
var sourceBuffer = source.addSourceBuffer(loader.type);
var mediaSegments = loader.mediaSegments();
sourceBuffer.appendBuffer(loader.initSegment);
sourceBuffer.addEventListener('update', () => {
if (source.readyState === 'closed') {
resolve(video);
return;
}
var nextSegment = mediaSegments.next();
if (nextSegment.done) {
if (source.readyState !== 'ended') {
source.endOfStream();
resolve(video);
}
return;
}
sourceBuffer.appendBuffer(nextSegment.value);
});
sourceBuffer.addEventListener('error', (e) => {
reject();
});
});
video.src = URL.createObjectURL(source);
});
}
function videoCount() {
return document.querySelectorAll('video').length;
}
function totalDroppedFrames() {
var total = 0;
for (var video of document.querySelectorAll('video')) {
if (typeof(video.getVideoPlaybackQuality) !== 'undefined')
total += video.getVideoPlaybackQuality().droppedVideoFrames;
else if (typeof(video.webkitDroppedFrameCount) !== 'undefined')
total += video.webkitDroppedFrameCount;
}
return total;
}
function pauseAll() {
for (var video of document.querySelectorAll('video'))
video.pause();
}
function playVideos(videos) {
return new Promise((resolve, reject) => {
var promises = [];
for (var video of videos)
promises.push(video.play());
Promise.all(promises).then(() => { resolve(videos); });
});
}
function playAll() {
playVideos(document.querySelectorAll('video'));
}
function runTest() {
addVideos(initialVideoCount).then(playVideos);
trySeekingFaster(1.6);
}
function finishTest() {
pauseAll();
}
var initialVideoCount = 10;
var droppedFrameLimit = 1;
var initialPlaybackRate = 1;
function trySeekingFaster(value) {
initialPlaybackRate += value;
document.getElementById('video-speed').innerText = initialPlaybackRate;
for (var video of document.querySelectorAll('video'))
video.playbackRate = initialPlaybackRate;
setTimeout(() => {
var initialDroppedFrames = totalDroppedFrames();
setTimeout(() => {
var endingDroppedFrames = totalDroppedFrames();
document.getElementById('dropped-frame').innerText = endingDroppedFrames - initialDroppedFrames;
if (endingDroppedFrames - initialDroppedFrames <= droppedFrameLimit) {
if (value <= 0.05) {
finishTest();
return;
}
trySeekingFaster(value);
}
else
trySeekingSlower(value/2);
}, 1000);
}, 1000);
}
function trySeekingSlower(value) {
initialPlaybackRate -= value;
document.getElementById('video-speed').innerText = initialPlaybackRate;
for (var video of document.querySelectorAll('video'))
video.playbackRate = initialPlaybackRate;
setTimeout(() => {
var initialDroppedFrames = totalDroppedFrames();
setTimeout(() => {
var endingDroppedFrames = totalDroppedFrames();
document.getElementById('dropped-frame').innerText = endingDroppedFrames - initialDroppedFrames;
if (endingDroppedFrames - initialDroppedFrames <= droppedFrameLimit) {
if (value <= 0.05) {
finishTest();
return;
}
trySeekingFaster(value/2);
} else
trySeekingSlower(value);
}, 2000);
}, 2000);
}
</script>
</head>
<body>
<div>
Video Count: <span id="video-count">0</span> Speed: <span id="video-speed">0</span> Dropped Frame Delta: <span id="dropped-frame">0</span>
</div>
<div>
<button onclick="addVideos(1).then(playVideos)">add video</button><button onclick="removeVideos(1)">remove video</button><button onclick="pauseAll()">pause</button><button onclick="playAll()">play</button><br>
</div>
</body>
</html>