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 from telemetry.core import bitmap | 5 from telemetry.core import bitmap |
6 from telemetry.core import web_contents | 6 from telemetry.core import web_contents |
7 | 7 |
8 DEFAULT_TAB_TIMEOUT = 60 | 8 DEFAULT_TAB_TIMEOUT = 60 |
9 | 9 |
10 | 10 |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 | 135 |
136 Args: | 136 Args: |
137 min_bitrate_mbps: The minimum caputre bitrate in MegaBits Per Second. | 137 min_bitrate_mbps: The minimum caputre bitrate in MegaBits Per Second. |
138 The platform is free to deliver a higher bitrate if it can do so | 138 The platform is free to deliver a higher bitrate if it can do so |
139 without increasing overhead. | 139 without increasing overhead. |
140 """ | 140 """ |
141 self.Highlight(bitmap.WEB_PAGE_TEST_ORANGE) | 141 self.Highlight(bitmap.WEB_PAGE_TEST_ORANGE) |
142 self.browser.platform.StartVideoCapture(min_bitrate_mbps) | 142 self.browser.platform.StartVideoCapture(min_bitrate_mbps) |
143 self.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE) | 143 self.ClearHighlight(bitmap.WEB_PAGE_TEST_ORANGE) |
144 | 144 |
145 def _FindHighlightBoundingBox(self, bmp, color): | 145 def _FindHighlightBoundingBox(self, bmp, color, bounds_tolerance=4, |
| 146 color_tolerance=8): |
146 """Returns the bounding box of the content highlight of the given color. | 147 """Returns the bounding box of the content highlight of the given color. |
147 | 148 |
148 Raises: | 149 Raises: |
149 BoundingBoxNotFoundException if the hightlight could not be found. | 150 BoundingBoxNotFoundException if the hightlight could not be found. |
150 """ | 151 """ |
151 content_box, pixel_count = bmp.GetBoundingBox(color, tolerance=8) | 152 content_box, pixel_count = bmp.GetBoundingBox(color, |
| 153 tolerance=color_tolerance) |
152 | 154 |
153 if not content_box: | 155 if not content_box: |
154 raise BoundingBoxNotFoundException('Failed to find tab contents.') | 156 return None |
155 | 157 |
156 # We assume arbitrarily that tabs are all larger than 200x200. If this | 158 # We assume arbitrarily that tabs are all larger than 200x200. If this |
157 # fails it either means that assumption has changed or something is | 159 # fails it either means that assumption has changed or something is |
158 # awry with our bounding box calculation. | 160 # awry with our bounding box calculation. |
159 if content_box[2] < 200 or content_box[3] < 200: | 161 if content_box[2] < 200 or content_box[3] < 200: |
160 raise BoundingBoxNotFoundException('Unexpectedly small tab contents.') | 162 raise BoundingBoxNotFoundException('Unexpectedly small tab contents.') |
161 | 163 |
162 # TODO(tonyg): Can this threshold be increased? | 164 # TODO(tonyg): Can this threshold be increased? |
163 if pixel_count < 0.9 * content_box[2] * content_box[3]: | 165 if pixel_count < 0.9 * content_box[2] * content_box[3]: |
164 raise BoundingBoxNotFoundException( | 166 raise BoundingBoxNotFoundException( |
165 'Low count of pixels in tab contents matching expected color.') | 167 'Low count of pixels in tab contents matching expected color.') |
166 | 168 |
167 # Since Telemetry doesn't know how to resize the window, we assume | 169 # Since Telemetry doesn't know how to resize the window, we assume |
168 # that we should always get the same content box for a tab. If this | 170 # that we should always get the same content box for a tab. If this |
169 # fails, it means either that assumption has changed or something is | 171 # fails, it means either that assumption has changed or something is |
170 # awry with our bounding box calculation. If this assumption changes, | 172 # awry with our bounding box calculation. If this assumption changes, |
171 # this can be removed. | 173 # this can be removed. |
172 # | 174 # |
173 # TODO(tonyg): This assert doesn't seem to work. | 175 # TODO(tonyg): This assert doesn't seem to work. |
174 if (self._previous_tab_contents_bounding_box and | 176 if (self._previous_tab_contents_bounding_box and |
175 self._previous_tab_contents_bounding_box != content_box): | 177 self._previous_tab_contents_bounding_box != content_box): |
176 raise BoundingBoxNotFoundException( | 178 # Check if there's just a minor variation on the bounding box. If it's |
177 'Unexpected change in tab contents box.') | 179 # just a few pixels, we can assume it's probably due to |
| 180 # compression artifacts. |
| 181 for i in xrange(len(content_box)): |
| 182 bounds_difference = abs(content_box[i] - |
| 183 self._previous_tab_contents_bounding_box[i]) |
| 184 if bounds_difference > bounds_tolerance: |
| 185 raise BoundingBoxNotFoundException( |
| 186 'Unexpected change in tab contents box.') |
178 self._previous_tab_contents_bounding_box = content_box | 187 self._previous_tab_contents_bounding_box = content_box |
179 | 188 |
180 return content_box | 189 return content_box |
181 | 190 |
182 def StopVideoCapture(self): | 191 def StopVideoCapture(self): |
183 """Stops recording video of the tab's contents. | 192 """Stops recording video of the tab's contents. |
184 | 193 |
185 This looks for the initial color flash in the first frame to establish the | 194 This looks for the initial color flash in the first frame to establish the |
186 tab content boundaries and then omits all frames displaying the flash. | 195 tab content boundaries and then omits all frames displaying the flash. |
187 | 196 |
188 Yields: | 197 Yields: |
189 (time_ms, bitmap) tuples representing each video keyframe. Only the first | 198 (time_ms, bitmap) tuples representing each video keyframe. Only the first |
190 frame in a run of sequential duplicate bitmaps is typically included. | 199 frame in a run of sequential duplicate bitmaps is typically included. |
191 time_ms is milliseconds since navigationStart. | 200 time_ms is milliseconds since navigationStart. |
192 bitmap is a telemetry.core.Bitmap. | 201 bitmap is a telemetry.core.Bitmap. |
193 """ | 202 """ |
194 frame_generator = self.browser.platform.StopVideoCapture() | 203 frame_generator = self.browser.platform.StopVideoCapture() |
195 | 204 |
196 # Flip through frames until we find the initial tab contents flash. | 205 # Flip through frames until we find the initial tab contents flash. |
197 content_box = None | 206 content_box = None |
198 for _, bmp in frame_generator: | 207 for _, bmp in frame_generator: |
199 try: | 208 content_box = self._FindHighlightBoundingBox( |
200 content_box = self._FindHighlightBoundingBox( | 209 bmp, bitmap.WEB_PAGE_TEST_ORANGE) |
201 bmp, bitmap.WEB_PAGE_TEST_ORANGE) | 210 if content_box: |
202 break | 211 break |
203 except BoundingBoxNotFoundException: | |
204 pass | |
205 | 212 |
206 if not content_box: | 213 if not content_box: |
207 raise BoundingBoxNotFoundException( | 214 raise BoundingBoxNotFoundException( |
208 'Failed to identify tab contents in video capture.') | 215 'Failed to identify tab contents in video capture.') |
209 | 216 |
210 # Flip through frames until the flash goes away and emit that as frame 0. | 217 # Flip through frames until the flash goes away and emit that as frame 0. |
211 timestamp = 0 | 218 timestamp = 0 |
212 for timestamp, bmp in frame_generator: | 219 for timestamp, bmp in frame_generator: |
213 try: | 220 if not self._FindHighlightBoundingBox(bmp, bitmap.WEB_PAGE_TEST_ORANGE): |
214 self._FindHighlightBoundingBox(bmp, bitmap.WEB_PAGE_TEST_ORANGE) | |
215 except BoundingBoxNotFoundException: | |
216 yield 0, bmp.Crop(*content_box) | 221 yield 0, bmp.Crop(*content_box) |
217 break | 222 break |
218 | 223 |
219 start_time = timestamp | 224 start_time = timestamp |
220 for timestamp, bmp in frame_generator: | 225 for timestamp, bmp in frame_generator: |
221 yield timestamp - start_time, bmp.Crop(*content_box) | 226 yield timestamp - start_time, bmp.Crop(*content_box) |
222 | 227 |
223 def PerformActionAndWaitForNavigate( | 228 def PerformActionAndWaitForNavigate( |
224 self, action_function, timeout=DEFAULT_TAB_TIMEOUT): | 229 self, action_function, timeout=DEFAULT_TAB_TIMEOUT): |
225 """Executes action_function, and waits for the navigation to complete. | 230 """Executes action_function, and waits for the navigation to complete. |
(...skipping 18 matching lines...) Expand all Loading... |
244 def GetCookieByName(self, name, timeout=DEFAULT_TAB_TIMEOUT): | 249 def GetCookieByName(self, name, timeout=DEFAULT_TAB_TIMEOUT): |
245 """Returns the value of the cookie by the given |name|.""" | 250 """Returns the value of the cookie by the given |name|.""" |
246 return self._inspector_backend.GetCookieByName(name, timeout) | 251 return self._inspector_backend.GetCookieByName(name, timeout) |
247 | 252 |
248 def CollectGarbage(self): | 253 def CollectGarbage(self): |
249 self._inspector_backend.CollectGarbage() | 254 self._inspector_backend.CollectGarbage() |
250 | 255 |
251 def ClearCache(self): | 256 def ClearCache(self): |
252 """Clears the browser's HTTP disk cache and the tab's HTTP memory cache.""" | 257 """Clears the browser's HTTP disk cache and the tab's HTTP memory cache.""" |
253 self._inspector_backend.ClearCache() | 258 self._inspector_backend.ClearCache() |
OLD | NEW |