Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 <!DOCTYPE html> | |
| 2 <html> | |
| 3 <head> | |
| 4 <title>Canvas Capture FPS Test</title> | |
| 5 </head> | |
| 6 <body> | |
| 7 <div> Canvas capture FPS test.</div> | |
| 8 <video id='local-video' muted='true' hidden loop autoplay> | |
| 9 <source src='bear-640x360.webm' type='video/webm'> | |
| 10 </video> | |
| 11 <br></br> | |
| 12 <label>Canvas</label> | |
| 13 <canvas id='canvas' width=640 height=360></canvas> | |
| 14 <br></br> | |
| 15 <label>Captured canvas stream</label> | |
| 16 <video id='captured-video' autoplay></video> | |
| 17 <script> | |
| 18 | |
| 19 'use strict'; | |
| 20 | |
| 21 var DEFAULT_FRAME_RATE = 10; | |
| 22 var TOLERANCE_PERCENT = 15 / 100; | |
| 23 | |
| 24 // Define video event listener when window is loaded. | |
| 25 window.onload = function() { | |
| 26 var video = document.getElementById('local-video'); | |
| 27 var canvas = document.getElementById('canvas'); | |
| 28 var context = canvas.getContext('2d'); | |
| 29 video.addEventListener('play', function() { | |
| 30 draw(this, context, canvas.clientWidth, canvas.clientHeight); | |
| 31 }, false); | |
| 32 }; | |
| 33 | |
| 34 // This function draws the video frame on the canvas. | |
| 35 function draw(video, context, width, height) { | |
| 36 window.requestAnimationFrame(draw.bind(null, video, context, width, | |
| 37 height)); | |
| 38 if (video.paused || video.ended) return false; | |
| 39 context.drawImage(video, 0, 0, width, height); | |
| 40 } | |
| 41 | |
| 42 // Test class that measures the frame rate of a stream originated from | |
| 43 // canvas capture. | |
| 44 function CanvasFpsTest() { | |
| 45 this.theCanvasStream = null; | |
| 46 this.decodedFrames = 0; | |
| 47 this.droppedFrames = 0; | |
| 48 this.decodedFPS = []; | |
| 49 this.droppedFPS = []; | |
| 50 this.startTime = {}; | |
| 51 this.interval = {}; | |
| 52 this.targetFPS = 0; | |
| 53 } | |
| 54 | |
| 55 // This function starts the canvas capture of the local video stream. | |
| 56 CanvasFpsTest.prototype.startCanvasCapture = function(frameRate) { | |
| 57 var test = this; | |
| 58 test.targetFPS = frameRate ? frameRate : DEFAULT_FRAME_RATE; | |
| 59 test.theCanvasStream = document.getElementById('canvas').captureStream( | |
| 60 test.targetFPS); | |
| 61 var testVideo = document.getElementById('captured-video'); | |
| 62 testVideo.addEventListener('play', function(event) { | |
| 63 test.startTime = new Date().getTime(); | |
| 64 test.interval = setInterval(test.calculateStats.bind(test, testVideo), | |
| 65 1000); | |
| 66 }); | |
| 67 testVideo.src = URL.createObjectURL(test.theCanvasStream); | |
| 68 }; | |
| 69 | |
| 70 // This function calculates the FPS for decoded frames and dropped frames. | |
| 71 CanvasFpsTest.prototype.calculateStats = function(video) { | |
| 72 // We calculate stats on 6 seconds worth of video, that should be | |
| 73 // reasonable. | |
| 74 if (this.decodedFPS.length == 6) { | |
| 75 clearInterval(this.interval); | |
| 76 return this.validateResults(); | |
| 77 } | |
| 78 if (video.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA || | |
| 79 video.paused || video.ended) | |
| 80 return; | |
| 81 var currentTime = new Date().getTime(); | |
| 82 var deltaTime = (currentTime - this.startTime) / 1000; | |
| 83 | |
| 84 this.startTime = currentTime; | |
| 85 | |
| 86 // Calculate decoded frames per second. | |
| 87 var fps = (video.webkitDecodedFrameCount - this.decodedFrames) / deltaTime; | |
| 88 this.decodedFrames = video.webkitDecodedFrameCount; | |
| 89 this.decodedFPS.push(fps); | |
| 90 | |
| 91 // Calculate dropped frames per second. | |
| 92 fps = (video.webkitDroppedFrameCount - this.droppedFrames) / deltaTime; | |
| 93 this.droppedFrames = video.webkitDroppedFrameCount; | |
| 94 this.droppedFPS.push(fps); | |
| 95 }; | |
| 96 | |
| 97 // This function validates the frame rate against accepted error tolerance. | |
| 98 CanvasFpsTest.prototype.validateResults = function() { | |
| 99 // Pop out the first value as it could be a bit off. | |
| 100 this.decodedFPS.shift; | |
| 101 this.droppedFPS.shift; | |
| 102 var averageFPS = average(this.decodedFPS); | |
| 103 var averageDroppedFPS = average(this.droppedFPS); | |
| 104 var errorFPS = Math.abs(averageFPS - this.targetFPS) / this.targetFPS; | |
| 105 var minFPS = this.targetFPS * (1 - TOLERANCE_PERCENT); | |
| 106 var maxFPS = this.targetFPS * (1 + TOLERANCE_PERCENT); | |
| 107 if (errorFPS > TOLERANCE_PERCENT) { | |
| 108 reportResult('ERROR: Expected FPS between ' + minFPS + ' and ' + maxFPS + | |
| 109 ' (' + 100 * TOLERANCE_PERCENT + '% tolerance) but got ' + averageFPS + | |
| 110 ' instead'); | |
| 111 } else if (averageDroppedFPS != 0) { | |
| 112 reportResult('ERROR: Expected zero dropped frames per second, but got' + | |
| 113 averageDroppedFPS + ' instead'); | |
|
phoglund_chromium
2016/02/15 08:05:44
Nit: indent 4
emircan
2016/02/16 22:21:47
If there are many dropped frames by video, that do
cpaulin (no longer in chrome)
2016/02/16 23:48:29
Emircan, is it possible that dropped frames are du
| |
| 114 } else { | |
| 115 reportResult('OK'); | |
| 116 } | |
| 117 }; | |
| 118 | |
| 119 // This function calculates average of array values. | |
| 120 function average(array) { | |
| 121 var count = array.length; | |
| 122 var total = 0; | |
| 123 for (var i = 0; i < count; i++) { | |
| 124 total += parseInt(array[i]); | |
| 125 } | |
| 126 return Math.floor(total / count); | |
| 127 } | |
| 128 | |
| 129 // This function logs and reports result to Test Environment. | |
| 130 function reportResult(message) { | |
| 131 console.log(message); | |
| 132 if (!window.domAutomationController) | |
| 133 throw 'Expected to run in an automated context.'; | |
| 134 window.domAutomationController.send(message); | |
| 135 } | |
| 136 | |
| 137 // Tests that canvas capture will approximately honor the given frame rate. | |
| 138 function testFrameRateOfCanvasCapture(frameRate) { | |
| 139 var fpsTest = new CanvasFpsTest(); | |
| 140 fpsTest.startCanvasCapture(frameRate); | |
| 141 } | |
| 142 | |
| 143 </script> | |
| 144 </body> | |
| 145 </html> | |
| OLD | NEW |