OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // These must match with how the video and canvas tags are declared in html. | 5 // These must match with how the video and canvas tags are declared in html. |
6 const VIDEO_TAG_WIDTH = 320; | 6 const VIDEO_TAG_WIDTH = 320; |
7 const VIDEO_TAG_HEIGHT = 240; | 7 const VIDEO_TAG_HEIGHT = 240; |
8 | 8 |
9 // Fake video capture background green is of value 135. | 9 // Fake video capture background green is of value 135. |
10 const COLOR_BACKGROUND_GREEN = 135; | 10 const COLOR_BACKGROUND_GREEN = 135; |
11 | 11 |
12 // Number of test events to occur before the test pass. When the test pass, | 12 // Number of test events to occur before the test pass. When the test pass, |
13 // the function gAllEventsOccured is called. | 13 // the function gAllEventsOccured is called. |
14 var gNumberOfExpectedEvents = 0; | 14 var gNumberOfExpectedEvents = 0; |
15 | 15 |
16 // Number of events that currently have occurred. | 16 // Number of events that currently have occurred. |
17 var gNumberOfEvents = 0; | 17 var gNumberOfEvents = 0; |
18 | 18 |
19 var gAllEventsOccured = function () {}; | 19 var gAllEventsOccured = function () {}; |
20 | 20 |
21 // Use this function to set a function that will be called once all expected | 21 // Use this function to set a function that will be called once all expected |
22 // events has occurred. | 22 // events has occurred. |
23 function setAllEventsOccuredHandler(handler) { | 23 function setAllEventsOccuredHandler(handler) { |
24 gAllEventsOccured = handler; | 24 gAllEventsOccured = handler; |
25 } | 25 } |
26 | 26 |
27 // Tells the C++ code we succeeded, which will generally exit the test. | |
28 function reportTestSuccess() { | |
29 window.domAutomationController.send('OK'); | |
30 } | |
31 | |
32 // Returns a custom return value to the test. | |
33 function sendValueToTest(value) { | |
34 window.domAutomationController.send(value); | |
35 } | |
36 | |
37 // Immediately fails the test on the C++ side and throw an exception to | |
38 // stop execution on the javascript side. | |
39 function failTest(reason) { | |
40 var error = new Error(reason); | |
41 window.domAutomationController.send(error.stack); | |
phoglund_chromium
2014/03/07 13:41:18
This here gives a nice stack trace when the js det
| |
42 } | |
43 | |
27 function detectVideoPlaying(videoElementName, callback) { | 44 function detectVideoPlaying(videoElementName, callback) { |
28 detectVideo(videoElementName, isVideoPlaying, callback); | 45 detectVideo(videoElementName, isVideoPlaying, callback); |
29 } | 46 } |
30 | 47 |
31 function detectVideoStopped(videoElementName, callback) { | 48 function detectVideoStopped(videoElementName, callback) { |
32 detectVideo(videoElementName, | 49 detectVideo(videoElementName, |
33 function (pixels, previous_pixels) { | 50 function (pixels, previous_pixels) { |
34 return !isVideoPlaying(pixels, previous_pixels); | 51 return !isVideoPlaying(pixels, previous_pixels); |
35 }, | 52 }, |
36 callback); | 53 callback); |
(...skipping 18 matching lines...) Expand all Loading... | |
55 predicate(pixels, oldPixels)) { | 72 predicate(pixels, oldPixels)) { |
56 console.log('Done looking at video in element ' + videoElementName); | 73 console.log('Done looking at video in element ' + videoElementName); |
57 clearInterval(waitVideo); | 74 clearInterval(waitVideo); |
58 callback(); | 75 callback(); |
59 } | 76 } |
60 oldPixels = pixels; | 77 oldPixels = pixels; |
61 }, 200); | 78 }, 200); |
62 } | 79 } |
63 | 80 |
64 function waitForVideo(videoElement) { | 81 function waitForVideo(videoElement) { |
65 document.title = 'Waiting for video...'; | |
66 addExpectedEvent(); | 82 addExpectedEvent(); |
67 detectVideoPlaying(videoElement, function () { eventOccured(); }); | 83 detectVideoPlaying(videoElement, function () { eventOccured(); }); |
68 } | 84 } |
69 | 85 |
70 function waitForVideoToStop(videoElement) { | 86 function waitForVideoToStop(videoElement) { |
71 document.title = 'Waiting for video to stop...'; | |
72 addExpectedEvent(); | 87 addExpectedEvent(); |
73 detectVideoStopped(videoElement, function () { eventOccured(); }); | 88 detectVideoStopped(videoElement, function () { eventOccured(); }); |
74 } | 89 } |
75 | 90 |
76 function waitForConnectionToStabilize(peerConnection, callback) { | 91 function waitForConnectionToStabilize(peerConnection, callback) { |
77 var waitForStabilization = setInterval(function() { | 92 var waitForStabilization = setInterval(function() { |
78 if (peerConnection.signalingState == 'stable') { | 93 if (peerConnection.signalingState == 'stable') { |
79 clearInterval(waitForStabilization); | 94 clearInterval(waitForStabilization); |
80 callback(); | 95 callback(); |
81 } | 96 } |
82 }, 100); | 97 }, 100); |
83 } | 98 } |
84 | 99 |
100 // Adds an expected event. You may call this function many times to add more | |
101 // expected events. Each expected event must later be matched by a call to | |
102 // eventOccurred. When enough events have occurred, the "all events occurred | |
103 // handler" will be called. | |
85 function addExpectedEvent() { | 104 function addExpectedEvent() { |
86 ++gNumberOfExpectedEvents; | 105 ++gNumberOfExpectedEvents; |
87 } | 106 } |
88 | 107 |
108 // See addExpectedEvent. | |
89 function eventOccured() { | 109 function eventOccured() { |
90 ++gNumberOfEvents; | 110 ++gNumberOfEvents; |
91 if (gNumberOfEvents == gNumberOfExpectedEvents) { | 111 if (gNumberOfEvents == gNumberOfExpectedEvents) { |
92 gAllEventsOccured(); | 112 gAllEventsOccured(); |
93 } | 113 } |
94 } | 114 } |
95 | 115 |
96 // This very basic video verification algorithm will be satisfied if any | 116 // This very basic video verification algorithm will be satisfied if any |
97 // pixels are changed. | 117 // pixels are changed. |
98 function isVideoPlaying(pixels, previousPixels) { | 118 function isVideoPlaying(pixels, previousPixels) { |
99 for (var i = 0; i < pixels.length; i++) { | 119 for (var i = 0; i < pixels.length; i++) { |
100 if (pixels[i] != previousPixels[i]) { | 120 if (pixels[i] != previousPixels[i]) { |
101 return true; | 121 return true; |
102 } | 122 } |
103 } | 123 } |
104 return false; | 124 return false; |
105 } | 125 } |
106 | 126 |
107 // This function matches |left| and |right| and throws an exception if the | 127 // This function matches |left| and |right| and fails the test if the |
108 // values don't match. | 128 // values don't match using normal javascript equality (i.e. the hard |
109 function expectEquals(left, right) { | 129 // types of the operands aren't checked). |
110 if (left != right) { | 130 function assertEquals(expected, actual) { |
phoglund_chromium
2014/03/07 13:41:18
Renamed this to assertEquals since expectEquals ge
| |
111 var s = "expectEquals failed left: " + left + " right: " + right; | 131 if (actual != expected) { |
112 document.title = s; | 132 failTest("expected '" + expected + "', got '" + actual + "'."); |
113 throw s; | |
114 } | 133 } |
115 } | 134 } |
116 | |
117 // This function tries to calculate the aspect ratio shown by the fake capture | |
118 // device in the video tag. For this, we count the amount of light green pixels | |
119 // along |aperture| pixels on the positive X and Y axis starting from the | |
120 // center of the image. In this very center there should be a time-varying | |
121 // pacman; the algorithm counts for a couple of iterations and keeps the | |
122 // maximum amount of light green pixels on both directions. From this data | |
123 // the aspect ratio is calculated relative to a 320x240 window, so 4:3 would | |
124 // show as a 1. Furthermore, since an original non-4:3 might be letterboxed or | |
125 // cropped, the actual X and Y pixel amounts are compared with the fake video | |
126 // capture expected pacman radius (see further below). | |
127 function detectAspectRatio(callback) { | |
128 var width = VIDEO_TAG_WIDTH; | |
129 var height = VIDEO_TAG_HEIGHT; | |
130 var videoElement = $('local-view'); | |
131 var canvas = $('local-view-canvas'); | |
132 | |
133 var maxLightGreenPixelsX = 0; | |
134 var maxLightGreenPixelsY = 0; | |
135 | |
136 var aperture = Math.min(width, height) / 2; | |
137 var iterations = 0; | |
138 var maxIterations = 10; | |
139 | |
140 var waitVideo = setInterval(function() { | |
141 var context = canvas.getContext('2d'); | |
142 context.drawImage(videoElement, 0, 0, width, height); | |
143 | |
144 // We are interested in a window starting from the center of the image | |
145 // where we expect the circle from the fake video capture to be rolling. | |
146 var pixels = | |
147 context.getImageData(width / 2, height / 2, aperture, aperture); | |
148 | |
149 var lightGreenPixelsX = 0; | |
150 var lightGreenPixelsY = 0; | |
151 | |
152 // Walk horizontally counting light green pixels. | |
153 for (var x = 0; x < aperture; ++x) { | |
154 if (pixels.data[4 * x + 1] != COLOR_BACKGROUND_GREEN) | |
155 lightGreenPixelsX++; | |
156 } | |
157 // Walk vertically counting light green pixels. | |
158 for (var y = 0; y < aperture; ++y) { | |
159 if (pixels.data[4 * y * aperture + 1] != 135) | |
160 lightGreenPixelsY++; | |
161 } | |
162 if (lightGreenPixelsX > maxLightGreenPixelsX && | |
163 lightGreenPixelsX < aperture) | |
164 maxLightGreenPixelsX = lightGreenPixelsX; | |
165 if (lightGreenPixelsY > maxLightGreenPixelsY && | |
166 lightGreenPixelsY < aperture) | |
167 maxLightGreenPixelsY = lightGreenPixelsY; | |
168 | |
169 var detectedAspectRatioString = ""; | |
170 if (++iterations > maxIterations) { | |
171 clearInterval(waitVideo); | |
172 observedAspectRatio = maxLightGreenPixelsY / maxLightGreenPixelsX; | |
173 // At this point the observed aspect ratio is either 1, for undistorted | |
174 // 4:3, or some other aspect ratio that is seen as distorted. | |
175 if (Math.abs(observedAspectRatio - 1.333) < 0.1) | |
176 detectedAspectRatioString = "16:9"; | |
177 else if (Math.abs(observedAspectRatio - 1.20) < 0.1) | |
178 detectedAspectRatioString = "16:10"; | |
179 else if (Math.abs(observedAspectRatio - 1.0) < 0.1) | |
180 detectedAspectRatioString = "4:3"; | |
181 else | |
182 detectedAspectRatioString = "UNKNOWN aspect ratio"; | |
183 console.log(detectedAspectRatioString + " observed aspect ratio (" + | |
184 observedAspectRatio + ")"); | |
185 | |
186 // The FakeVideoCapture calculates the circle radius as | |
187 // std::min(capture_format_.width, capture_format_.height) / 4; | |
188 // we do the same and see if both dimensions are scaled, meaning | |
189 // we started from a cropped or stretched image. | |
190 var nonDistortedRadius = Math.min(width, height) / 4; | |
191 if ((maxLightGreenPixelsX != nonDistortedRadius) && | |
192 (maxLightGreenPixelsY != nonDistortedRadius)) { | |
193 detectedAspectRatioString += " cropped"; | |
194 } else | |
195 detectedAspectRatioString += " letterbox"; | |
196 | |
197 console.log("Original image is: " + detectedAspectRatioString); | |
198 callback(detectedAspectRatioString); | |
199 } | |
200 }, | |
201 50); | |
202 } | |
OLD | NEW |