<!DOCTYPE html> <html> <head><title>GetUserMedia test</title></head> <body> <script src="ssim.js"></script> <script src="blackframe.js"></script> <script> var resolutions = [[640, 480], [1280, 720]]; var results = {}; var isTestDone = 0; var durationMs = 20000; function testNextResolution() { var nextResolution = resolutions.shift(); if (nextResolution == undefined) { reportTestDone(); return; } var test = new CameraTest(nextResolution); test.start(); setTimeout( function() { test.stop(); testNextResolution(); }, durationMs); } function reportTestDone() { console.log('tests completed'); isTestDone = 1; } function getResults() { return results; } function resolutionMatchesIndependentOfRotation(aWidth, aHeight, bWidth, bHeight) { return (aWidth === bWidth && aHeight === bHeight) || (aWidth === bHeight && aHeight === bWidth); } function saveResult(resolution, verdict) { results[resolution] = verdict; } function CameraTest(resolution) { this.resolution = resolution; this.localVideo = document.createElement('video'); this.localVideo.id = 'local-video'; this.localVideo.autoplay = true; document.body.appendChild(this.localVideo); this.localStream = null; this.canvas = document.createElement('canvas'); this.context = this.canvas.getContext('2d'); this.previousFrame = []; this.identicalFrameSsimThreshold = 0.985; this.frameComparator = new Ssim(); this.results = {cameraErrors: [], frameStats: {numBlackFrames: 0, numFrozenFrames:0, numFrames: 0}}; this.constraints = { "audio": false, "video": { "mandatory" : { "maxWidth": this.resolution[0].toString(), "maxHeight": this.resolution[1].toString(), "minWidth": this.resolution[0].toString(), "minHeight": this.resolution[1].toString() }, } }; } CameraTest.prototype = { start: function() { this.localVideo.addEventListener('play', this.startCheckingVideoFrames.bind(this), false); navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia(this.constraints, this.gotLocalStream.bind(this), this.gotUserMediaError.bind(this)); }, gotLocalStream: function(stream) { this.localStream = stream; this.localVideo.src = window.URL.createObjectURL(stream); }, gotUserMediaError: function(error) { console.log('navigator.getUserMedia error: ', error); this.results.cameraErrors.push('GetUserMedia error: ' + error.toString()); }, startCheckingVideoFrames: function() { if (!resolutionMatchesIndependentOfRotation(this.localVideo.videoWidth, this.localVideo.videoHeight, this.resolution[0], this.resolution[1])) { this.results.cameraErrors.push('resolution', 'Got ' + this.localVideo.videoWidth + 'x' + this.localVideo.videoHeight + ', expected ' + this.resolution[0] + 'x' + this.resolution[1] + ' or rotated version thereof'); } this.videoFrameChecker = setInterval(this.checkVideoFrame.bind(this), 20); }, checkVideoFrame: function() { this.context.drawImage(this.localVideo, 0, 0, this.canvas.width, this.canvas.height); var imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); if (isBlackFrame(imageData.data, imageData.data.length)) { this.results.frameStats.numBlackFrames++; } if (this.frameComparator.calculate(this.previousFrame, imageData.data) > this.identicalFrameSsimThreshold) { this.results.frameStats.numFrozenFrames++; } this.previousFrame = imageData.data; this.results.frameStats.numFrames++; }, stop: function() { clearInterval(this.videoFrameChecker); saveResult(this.resolution, this.results); this.localStream.getTracks().forEach(function(track) { track.stop(); }); document.body.removeChild(this.localVideo); }, } window.onload = testNextResolution; window.onerror = function (message, filename, lineno, colno, error) { console.log("Something went wrong, here is the stack trace --> %s", error.stack); }; </script> </body> </html>