def testIsScreenshotWithinDynamicContentThreshold(self): # TODO(lchoi): This unit test fails on Windows due to an apparent platform # dependent image decoding behavior that will need to be investigated in the # future if Cluster Telemetry ever becomes compatible with Windows. width = 2 height = 1 num_total_pixels = width * height content_pixels = bytearray([0, 0, 0, 128, 128, 128]) base_screenshot = image_util.FromRGBPixels(width, height, content_pixels) next_pixels = bytearray([1, 1, 1, 128, 128, 128]) next_screenshot = image_util.FromRGBPixels(width, height, next_pixels) expected_pixels = bytearray([0, 255, 255, 128, 128, 128]) self.assertTrue( screenshot.IsScreenshotWithinDynamicContentThreshold( base_screenshot, next_screenshot, content_pixels, num_total_pixels, 0.51)) self.assertTrue(expected_pixels == content_pixels) next_pixels = bytearray([0, 0, 0, 1, 1, 1]) next_screenshot = image_util.FromRGBPixels(2, 1, next_pixels) expected_pixels = bytearray([0, 255, 255, 0, 255, 255]) self.assertTrue( screenshot.IsScreenshotWithinDynamicContentThreshold( base_screenshot, next_screenshot, content_pixels, num_total_pixels, 0.51)) self.assertTrue(expected_pixels == content_pixels) self.assertFalse( screenshot.IsScreenshotWithinDynamicContentThreshold( base_screenshot, next_screenshot, content_pixels, num_total_pixels, 0.49))
def ValidateAndMeasurePage(self, page, tab, results): try: tab.WaitForDocumentReadyStateToBeComplete() except py_utils.TimeoutException: logging.warning("WaitForDocumentReadyStateToBeComplete() timeout, " "page: %s", page.name) return time.sleep(self._wait_time) if not os.path.exists(self._png_outdir): logging.info("Creating directory %s", self._png_outdir) try: os.makedirs(self._png_outdir) except OSError: logging.warning("Directory %s could not be created", self._png_outdir) raise outpath = os.path.abspath( os.path.join(self._png_outdir, page.file_safe_name)) + '.png' # Replace win32 path separator char '\' with '\\'. outpath = outpath.replace('\\', '\\\\') screenshot = tab.Screenshot() image_width = image_util.Width(screenshot) image_height = image_util.Height(screenshot) num_total_pixels = image_width * image_height content_pixels = image_util.Pixels(screenshot) # Dynamic content flag. if self._dc_detect: for i in range(self._dc_extra_screenshots): logging.info("Sleeping for %f seconds.", self._dc_wait_time) time.sleep(self._dc_wait_time) # After the specified wait time, take another screenshot of the page. logging.info("Taking extra screenshot %d of %d.", i+1, self._dc_extra_screenshots) next_screenshot = tab.Screenshot() # Compare this screenshot to the original to mark inconsistent pixels, # and check the percentage of dynamic content against the threshold. if not IsScreenshotWithinDynamicContentThreshold( screenshot, next_screenshot, content_pixels, num_total_pixels, self._dc_threshold): raise legacy_page_test.MeasurementFailure("Percentage of pixels " "with dynamic content is greater than threshold.") # Convert the pixel bytearray back into an image. image = image_util.FromRGBPixels(image_width, image_height, content_pixels) # TODO(lchoi): Add logging to image_util.py and/or augment error handling of # image_util.WritePngFile logging.info("Writing PNG file to %s. This may take awhile.", outpath) start = time.time() image_util.WritePngFile(image, outpath) logging.info("PNG file written successfully. (Took %f seconds)", time.time()-start)
def _FramesFromMp4(self, mp4_file): host_platform = platform.GetHostPlatform() if not host_platform.CanLaunchApplication('avconv'): host_platform.InstallApplication('avconv') def GetDimensions(video): proc = subprocess.Popen(['avconv', '-i', video], stderr=subprocess.PIPE) dimensions = None output = '' for line in proc.stderr.readlines(): output += line if 'Video:' in line: dimensions = line.split(',')[2] dimensions = map(int, dimensions.split()[0].split('x')) break proc.communicate() assert dimensions, ( 'Failed to determine video dimensions. output=%s' % output) return dimensions def GetFrameTimestampMs(stderr): """Returns the frame timestamp in integer milliseconds from the dump log. The expected line format is: ' dts=1.715 pts=1.715\n' We have to be careful to only read a single timestamp per call to avoid deadlock because avconv interleaves its writes to stdout and stderr. """ while True: line = '' next_char = '' while next_char != '\n': next_char = stderr.read(1) line += next_char if 'pts=' in line: return int(1000 * float(line.split('=')[-1])) dimensions = GetDimensions(mp4_file) frame_length = dimensions[0] * dimensions[1] * 3 frame_data = bytearray(frame_length) # Use rawvideo so that we don't need any external library to parse frames. proc = subprocess.Popen([ 'avconv', '-i', mp4_file, '-vcodec', 'rawvideo', '-pix_fmt', 'rgb24', '-dump', '-loglevel', 'debug', '-f', 'rawvideo', '-' ], stderr=subprocess.PIPE, stdout=subprocess.PIPE) while True: num_read = proc.stdout.readinto(frame_data) if not num_read: raise StopIteration assert num_read == len( frame_data), 'Unexpected frame size: %d' % num_read yield (GetFrameTimestampMs(proc.stderr), image_util.FromRGBPixels(dimensions[0], dimensions[1], frame_data))
def testWriteCroppedBmpToPngFile(self): pixels = [255, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 255, 0, 0, 0, 0] orig = image_util.FromRGBPixels(3, 2, pixels) orig = image_util.Crop(orig, 0, 0, 2, 2) temp_file = tempfile.NamedTemporaryFile(suffix='.png').name image_util.WritePngFile(orig, temp_file) new_file = image_util.FromPngFile(temp_file) self.assertTrue(image_util.AreEqual(orig, new_file, likely_equal=True))
def testHistogramDistanceIgnoreColor(self): pixels = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] bmp = image_util.FromRGBPixels(2, 2, pixels) hist1 = image_util.GetColorHistogram(bmp, ignore_color=rgba_color.RgbaColor( 1, 2, 3)) hist2 = image_util.GetColorHistogram(bmp) self.assertEquals(hist1.Distance(hist2), 0)
def testCrop(self): pixels = [0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 0, 1, 0, 1, 1, 0, 2, 1, 0, 3, 1, 0, 0, 2, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0] bmp = image_util.FromRGBPixels(4, 3, pixels) bmp = image_util.Crop(bmp, 1, 2, 2, 1) self.assertEquals(2, image_util.Width(bmp)) self.assertEquals(1, image_util.Height(bmp)) image_util.GetPixelColor(bmp, 0, 0).AssertIsRGB(1, 2, 0) image_util.GetPixelColor(bmp, 1, 0).AssertIsRGB(2, 2, 0) self.assertEquals(image_util.Pixels(bmp), bytearray([1, 2, 0, 2, 2, 0]))
def testGetBoundingBox(self): pixels = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] bmp = image_util.FromRGBPixels(4, 3, pixels) box, count = image_util.GetBoundingBox(bmp, rgba_color.RgbaColor(1, 0, 0)) self.assertEquals(box, (1, 1, 2, 1)) self.assertEquals(count, 2) box, count = image_util.GetBoundingBox(bmp, rgba_color.RgbaColor(0, 1, 0)) self.assertEquals(box, None) self.assertEquals(count, 0)
def testHistogramIgnoreColor(self): pixels = [ 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 8, 7, 6, 5, 4, 6, 1, 2, 3, 1, 2, 3, 8, 7, 6, 5, 4, 6, 1, 2, 3 ] bmp = image_util.FromRGBPixels(4, 3, pixels) hist = image_util.GetColorHistogram(bmp, ignore_color=rgba_color.RgbaColor( 1, 2, 3)) self.assertEquals(hist.r[1], 0) self.assertEquals(hist.r[5], 2) self.assertEquals(hist.r[8], 2) self.assertEquals(hist.g[2], 0) self.assertEquals(hist.g[4], 2) self.assertEquals(hist.g[7], 2) self.assertEquals(hist.b[3], 0) self.assertEquals(hist.b[6], 4)
def testHistogramIgnoreColorTolerance(self): pixels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6] bmp = image_util.FromRGBPixels(2, 2, pixels) hist = image_util.GetColorHistogram(bmp, ignore_color=rgba_color.RgbaColor( 0, 1, 2), tolerance=1) self.assertEquals(hist.r[1], 0) self.assertEquals(hist.r[4], 1) self.assertEquals(hist.r[7], 1) self.assertEquals(hist.r[8], 1) self.assertEquals(hist.g[2], 0) self.assertEquals(hist.g[5], 1) self.assertEquals(hist.g[7], 1) self.assertEquals(hist.g[8], 1) self.assertEquals(hist.b[3], 0) self.assertEquals(hist.b[6], 2) self.assertEquals(hist.b[9], 1)
def testHistogram(self): pixels = [ 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 8, 7, 6, 5, 4, 6, 1, 2, 3, 1, 2, 3, 8, 7, 6, 5, 4, 6, 1, 2, 3 ] bmp = image_util.FromRGBPixels(4, 3, pixels) bmp = image_util.Crop(bmp, 1, 1, 2, 2) hist = image_util.GetColorHistogram(bmp) for i in xrange(3): self.assertEquals(sum(hist[i]), image_util.Width(bmp) * image_util.Height(bmp)) self.assertEquals(hist.r[1], 0) self.assertEquals(hist.r[5], 2) self.assertEquals(hist.r[8], 2) self.assertEquals(hist.g[2], 0) self.assertEquals(hist.g[4], 2) self.assertEquals(hist.g[7], 2) self.assertEquals(hist.b[3], 0) self.assertEquals(hist.b[6], 4)