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 |