1<!DOCTYPE html> 2<html> 3<head><title>GetUserMedia test</title></head> 4<body> 5 <script src="ssim.js"></script> 6 <script src="blackframe.js"></script> 7<script> 8 9var resolutions = [[640, 480], 10 [1280, 720]]; 11var isVideoInputFound = false; 12var results = {}; 13var isTestDone = false; 14var durationMs = 20000; 15 16function testNextResolution() { 17 var nextResolution = resolutions.shift(); 18 if (nextResolution == undefined) { 19 reportTestDone(); 20 return; 21 } 22 var test = new CameraTest(nextResolution); 23 test.start(); 24 setTimeout( 25 function() { 26 test.stop(); 27 testNextResolution(); 28 }, 29 durationMs); 30} 31 32function reportTestDone() { 33 console.log('tests completed'); 34 isTestDone = true; 35} 36 37function getResults() { 38 return results; 39} 40 41function resolutionMatchesIndependentOfRotation(aWidth, aHeight, 42 bWidth, bHeight) { 43 return (aWidth === bWidth && aHeight === bHeight) || 44 (aWidth === bHeight && aHeight === bWidth); 45} 46 47function saveResult(resolution, verdict) { 48 results[resolution] = verdict; 49} 50 51// Check if a video input exists 52function checkVideoInput() { 53 navigator.mediaDevices.enumerateDevices() 54 .then(findVideoInput) 55 .catch(gotEnumerateDevicesError); 56} 57 58function findVideoInput(devices) { 59 isVideoInputFound = devices.some(dev => dev.kind == 'videoinput'); 60} 61 62function gotEnumerateDevicesError(error) { 63 console.log('navigator.mediaDevices.enumerateDevices error: ', error); 64 results.cameraErrors.push('EnumerateDevices error: ' + error.toString()); 65} 66 67function CameraTest(resolution) { 68 this.resolution = resolution; 69 this.localVideo = document.createElement('video'); 70 this.localVideo.id = 'local-video'; 71 this.localVideo.autoplay = true; 72 document.body.appendChild(this.localVideo); 73 this.localStream = null; 74 this.canvas = document.createElement('canvas'); 75 this.context = this.canvas.getContext('2d'); 76 this.previousFrame = []; 77 this.identicalFrameSsimThreshold = 0.985; 78 this.frameComparator = new Ssim(); 79 this.results = {cameraErrors: [], 80 frameStats: {numBlackFrames: 0, numFrozenFrames:0, numFrames: 0}}; 81 82 this.constraints = { 83 "audio": false, 84 "video": { 85 "mandatory" : { 86 "maxWidth": this.resolution[0].toString(), 87 "maxHeight": this.resolution[1].toString(), 88 "minWidth": this.resolution[0].toString(), 89 "minHeight": this.resolution[1].toString() 90 }, 91 } 92 }; 93} 94 95CameraTest.prototype = { 96 97 start: function() { 98 this.localVideo.addEventListener('play', 99 this.startCheckingVideoFrames.bind(this), false); 100 101 navigator.mediaDevices.getUserMedia(this.constraints) 102 .then(this.gotLocalStream.bind(this)) 103 .catch(this.gotUserMediaError.bind(this)); 104 }, 105 106 gotLocalStream: function(stream) { 107 this.localStream = stream; 108 this.localVideo.srcObject = stream; 109 }, 110 111 gotUserMediaError: function(error) { 112 console.log('navigator.mediaDevices.getUserMedia error: ', error); 113 this.results.cameraErrors.push('GetUserMedia error: ' + error.toString()); 114 }, 115 116 startCheckingVideoFrames: function() { 117 if (!resolutionMatchesIndependentOfRotation(this.localVideo.videoWidth, 118 this.localVideo.videoHeight, this.resolution[0], this.resolution[1])) { 119 this.results.cameraErrors.push('resolution', 'Got ' + 120 this.localVideo.videoWidth + 'x' + this.localVideo.videoHeight + 121 ', expected ' + this.resolution[0] + 'x' + this.resolution[1] + 122 ' or rotated version thereof'); 123 } 124 125 this.videoFrameChecker = setInterval(this.checkVideoFrame.bind(this), 20); 126 }, 127 128 checkVideoFrame: function() { 129 this.context.drawImage(this.localVideo, 0, 0, this.canvas.width, 130 this.canvas.height); 131 var imageData = this.context.getImageData(0, 0, this.canvas.width, 132 this.canvas.height); 133 134 if (isBlackFrame(imageData.data, imageData.data.length)) { 135 this.results.frameStats.numBlackFrames++; 136 } 137 138 if (this.frameComparator.calculate(this.previousFrame, imageData.data) > 139 this.identicalFrameSsimThreshold) { 140 this.results.frameStats.numFrozenFrames++; 141 } 142 143 this.previousFrame = imageData.data; 144 this.results.frameStats.numFrames++; 145 }, 146 147 stop: function() { 148 clearInterval(this.videoFrameChecker); 149 saveResult(this.resolution, this.results); 150 this.localStream.getTracks().forEach(function(track) { 151 track.stop(); 152 }); 153 document.body.removeChild(this.localVideo); 154 }, 155} 156 157window.onload = testNextResolution; 158window.onerror = function (message, filename, lineno, colno, error) { 159 console.log("Something went wrong, here is the stack trace --> %s", 160 error.stack); 161}; 162</script> 163</body> 164</html> 165