Home | History | Annotate | Download | only in chameleon
      1 # Copyright 2015 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 import os
      7 
      8 from autotest_lib.client.bin import utils
      9 from autotest_lib.client.common_lib import error
     10 
     11 
     12 class ChameleonVideoCapturer(object):
     13     """
     14     Wraps around chameleon APIs to provide an easy way to capture video frames.
     15 
     16     """
     17 
     18 
     19     def __init__(self, chameleon_port, display_facade,
     20                  timeout_get_all_frames_s=60):
     21 
     22         self.chameleon_port = chameleon_port
     23         self.display_facade = display_facade
     24         self.timeout_get_all_frames_s = timeout_get_all_frames_s
     25         self._checksums = []
     26 
     27         self.was_plugged = None
     28 
     29 
     30     def __enter__(self):
     31         self.was_plugged = self.chameleon_port.plugged
     32 
     33         if not self.was_plugged:
     34             self.chameleon_port.plug()
     35             self.chameleon_port.wait_video_input_stable()
     36 
     37         return self
     38 
     39 
     40     def capture(self, player, max_frame_count, box=None):
     41         """
     42         Captures frames upto max_frame_count, saves the image with filename
     43         same as the index of the frame in the frame buffer.
     44 
     45         @param player: object, VimeoPlayer or NativeHTML5Player
     46         @param max_frame_count: int, maximum total number of frames to capture.
     47         @param box: int tuple, left, upper, right, lower pixel coordinates.
     48                     Defines the rectangular boundary within which to compare.
     49         @return: list of paths of captured images.
     50 
     51         """
     52 
     53         self.capture_only(player, max_frame_count, box)
     54         # each checksum should be saved with a filename that is its index
     55         ind_paths = {i : str(i) for i in self.checksums}
     56         return self.write_images(ind_paths)
     57 
     58 
     59     def capture_only(self, player, max_frame_count, box=None):
     60         """
     61         Asynchronously begins capturing video frames. Stops capturing when the
     62         number of frames captured is equal or more than max_frame_count. Does
     63         save the images, gets only the checksums.
     64 
     65         @param player: VimeoPlayer or NativeHTML5Player.
     66         @param max_frame_count: int, the maximum number of frames we want.
     67         @param box: int tuple, left, upper, right, lower pixel coordinates.
     68                     Defines the rectangular boundary within which to compare.
     69         @return: list of checksums
     70 
     71         """
     72 
     73         if not box:
     74             box = self.box
     75 
     76         self.chameleon_port.start_capturing_video(box)
     77 
     78         player.play()
     79 
     80         error_msg = "Expected current time to be > 1 seconds"
     81 
     82         utils.poll_for_condition(lambda : player.currentTime() > 1,
     83                                  timeout=5,
     84                                  sleep_interval=0.01,
     85                                  exception=error.TestError(error_msg))
     86 
     87         error_msg = "Couldn't get the right number of frames"
     88 
     89         utils.poll_for_condition(
     90                 lambda: self.chameleon_port.get_captured_frame_count() >=
     91                         max_frame_count,
     92                 error.TestError(error_msg),
     93                 self.timeout_get_all_frames_s,
     94                 sleep_interval=0.01)
     95 
     96         self.chameleon_port.stop_capturing_video()
     97 
     98         self.checksums = self.chameleon_port.get_captured_checksums()
     99         count = self.chameleon_port.get_captured_frame_count()
    100 
    101         # Due to the polling and asychronous calls we might get too many frames
    102         # cap at max
    103         del self.checksums[max_frame_count:]
    104 
    105         logging.debug("***# of frames received %s", count)
    106         logging.debug("Checksums before chopping repeated ones")
    107         for c in self.checksums:
    108             logging.debug(c)
    109 
    110         # Find the first frame that is different from previous ones. This
    111         # represents the start of 'interesting' frames
    112         first_index = 0
    113         for i in xrange(1, count):
    114             if self.checksums[0] != self.checksums[i]:
    115                 first_index = i
    116                 break
    117 
    118         logging.debug("*** First interesting frame at index = %s", first_index)
    119         self.checksums = self.checksums[first_index:]
    120         return self.checksums
    121 
    122 
    123 
    124     def write_images(self, frame_indices, dest_dir, image_format):
    125         """
    126         Saves frames of given indices to disk. The filename of the frame will be
    127         index in the list.
    128         @param frame_indices: list of frame indices to save.
    129         @param dest_dir: path to the desired destination dir.
    130         @param image_format: string, format to save the image as. e.g; PNG
    131         @return: list of file paths
    132 
    133         """
    134         if type(frame_indices) is not list:
    135             frame_indices = [frame_indices]
    136 
    137         test_images = []
    138         curr_checksum = None
    139         for i, frame_index in enumerate(frame_indices):
    140             path = os.path.join(dest_dir, str(i) + '.' + image_format)
    141             # previous is what was current in the previous iteration
    142             prev_checksum = curr_checksum
    143             curr_checksum = self.checksums[frame_index]
    144             if curr_checksum == prev_checksum:
    145                 logging.debug("Image the same as previous image, copy it.")
    146             else:
    147                 logging.debug("Read frame %d, store as %s.", i, path)
    148                 curr_img = self.chameleon_port.read_captured_frame(frame_index)
    149             curr_img.save(path)
    150             test_images.append(path)
    151         return test_images
    152 
    153 
    154     def __exit__(self, exc_type, exc_val, exc_tb):
    155         if not self.was_plugged:
    156             self.chameleon_port.unplug()