1 # Copyright (c) 2014 The Chromium 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 errno 6 import fnmatch 7 import hashlib 8 import logging 9 import os 10 import re 11 import subprocess 12 13 from autotest_lib.client.bin import utils 14 from autotest_lib.client.common_lib import error 15 from autotest_lib.client.common_lib import file_utils 16 from autotest_lib.client.cros import chrome_binary_test 17 from autotest_lib.client.cros.video import device_capability 18 from autotest_lib.client.cros.video import helper_logger 19 20 DOWNLOAD_BASE = 'http://commondatastorage.googleapis.com/chromiumos-test-assets-public/' 21 BINARY = 'video_encode_accelerator_unittest' 22 23 # These default values are from video_encode_accelerator_unittest. 24 # The value of |requested_frame_rate| and |requested_subsequent_frame_rate|. 25 DEFAULT_FRAME_RATE = 30 26 # The ratio of |requested_subsequent_bit_rate| to |requested_bit_rate|. 27 DEFAULT_SUBSEQUENT_BIT_RATE_RATIO = 2 28 # The values of pixel formats //media/base/video_types.h. 29 PIXEL_FORMAT_NV12 = 6 30 31 def _remove_if_exists(filepath): 32 try: 33 os.remove(filepath) 34 except OSError, e: 35 if e.errno != errno.ENOENT: # no such file 36 raise 37 38 39 def _download_video(download_path, local_file): 40 url = '%s%s' % (DOWNLOAD_BASE, download_path) 41 logging.info('download "%s" to "%s"', url, local_file) 42 43 file_utils.download_file(url, local_file) 44 45 with open(local_file, 'r') as r: 46 md5sum = hashlib.md5(r.read()).hexdigest() 47 if md5sum not in download_path: 48 raise error.TestError('unmatched md5 sum: %s' % md5sum) 49 50 def _run_on_intel_cpu(): 51 try: 52 lscpu_result = subprocess.check_output(['lscpu']) 53 except subprocess.CalledProcessError: 54 logging.warning('lscpu failed.') 55 return False 56 for cpu_info in lscpu_result.splitlines(): 57 key, _, value = cpu_info.partition(':') 58 if key == 'Model name': 59 return value.strip().startswith('Intel(R)') 60 logging.warning("%s", lscpu_result) 61 return False 62 63 64 def _can_switch_bitrate(): 65 """Determine whether the board can switch the bitrate. 66 67 The bitrate switch test case is mainly for ARC++. We don't have much control 68 over some devices that do not run ARC++. Therefore we whitelist the boards 69 that should pass the bitrate switch test. (crbug.com/890125) 70 """ 71 # Most Intel chipsets are able to switch bitrate except these two old 72 # chipsets, so we blacklist the devices. 73 intel_blacklist = [ 74 # Rambi Bay Trial 75 'cranky', 'banjo', 'candy', 'clapper', 'enguarde', 'expresso', 76 'glimmer', 'gnawty', 'heli', 'hoofer', 'kip', 'kip14', 'ninja', 77 'orco', 'quawks', 'squawks', 'sumo', 'swanky', 'winky', 78 79 # Haswell 80 'falco', 'leon', 'mccloud', 'monroe', 'panther', 'peppy', 'tricky', 81 'wolf', 'zako', 82 ] 83 return (_run_on_intel_cpu() and 84 utils.get_current_board() not in intel_blacklist) 85 86 87 def _can_encode_nv12(): 88 """ 89 Determine whether the board can encode NV12. 90 91 NV12 format is a mostly common input format driver supports in video 92 encoding. 93 There are devices that cannot encode NV12 input buffer because of chromium 94 code base or driver issue. 95 """ 96 # Although V4L2VEA supports NV12, some devices cannot encode NV12 probably 97 # due to a driver issue. 98 nv12_black_list = [ 99 r'^daisy.*', 100 r'^nyan.*', 101 r'^peach.*', 102 r'^veyron.*', 103 ] 104 105 board = utils.get_current_board() 106 for p in nv12_black_list: 107 if re.match(p, board): 108 return False 109 return True 110 111 112 class video_VideoEncodeAccelerator(chrome_binary_test.ChromeBinaryTest): 113 """ 114 This test is a wrapper of the chrome unittest binary: 115 video_encode_accelerator_unittest. 116 """ 117 118 version = 1 119 120 def get_filter_option(self, profile, size): 121 """Get option of filtering test. 122 123 @param profile: The profile to encode into. 124 @param size: The size of test stream in pair format (width, height). 125 """ 126 127 # Profiles used in blacklist to filter test for specific profiles. 128 H264 = 1 129 VP8 = 11 130 VP9 = 12 131 132 blacklist = { 133 # (board, profile, size): [tests to skip...] 134 135 # "board" supports Unix shell-type wildcards. 136 137 # Use None for "profile" or "size" to indicate no filter on it. 138 139 # It is possible to match multiple keys for board/profile/size 140 # in the blacklist, e.g. veyron_minnie could match both 141 # "veyron_*" and "veyron_minnie". 142 143 # rk3399 doesn't support HW encode for plane sizes not multiple 144 # of cache line. 145 ('kevin', None, None): ['CacheLineUnalignedInputTest/*'], 146 ('bob', None, None): ['CacheLineUnalignedInputTest/*'], 147 ('scarlet', None, None): ['CacheLineUnalignedInputTest/*'], 148 149 # Still high failure rate of VP8 EncoderPerf for veyrons, 150 # disable it for now. crbug/720386 151 ('veyron_*', VP8, None): ['EncoderPerf/*'], 152 153 # Disable mid_stream_bitrate_switch test cases for elm/hana. 154 # crbug/725087 155 ('elm', None, None): ['MidStreamParamSwitchBitrate/*', 156 'MultipleEncoders/*'], 157 ('hana', None, None): ['MidStreamParamSwitchBitrate/*', 158 'MultipleEncoders/*'], 159 160 # Around 40% failure on elm and hana 320x180 test stream. 161 # crbug/728906 162 ('elm', H264, (320, 180)): ['ForceBitrate/*'], 163 ('elm', VP8, (320, 180)): ['ForceBitrate/*'], 164 ('hana', H264, (320, 180)): ['ForceBitrate/*'], 165 ('hana', VP8, (320, 180)): ['ForceBitrate/*'], 166 } 167 168 board = utils.get_current_board() 169 170 # Disable 320x180 test case. Bitrate of vp8 encoder on the test case is 171 # out of expected range. b/110059922 172 # TODO(hiroh): Remove this once b/110059922 is fixed. 173 if _run_on_intel_cpu(): 174 blacklist[(board, VP8, (320, 180))] = ['*'] 175 176 filter_list = [] 177 for (board_key, profile_key, size_key), value in blacklist.items(): 178 if (fnmatch.fnmatch(board, board_key) and 179 (profile_key is None or profile == profile_key) and 180 (size_key is None or size == size_key)): 181 filter_list += value 182 183 if filter_list: 184 return '-' + ':'.join(filter_list) 185 186 return '' 187 188 @helper_logger.video_log_wrapper 189 @chrome_binary_test.nuke_chrome 190 def run_once(self, in_cloud, streams, profile, capability): 191 """Runs video_encode_accelerator_unittest on the streams. 192 193 @param in_cloud: Input file needs to be downloaded first. 194 @param streams: The test streams for video_encode_accelerator_unittest. 195 @param profile: The profile to encode into. 196 197 @raises error.TestFail for video_encode_accelerator_unittest failures. 198 """ 199 device_capability.DeviceCapability().ensure_capability(capability) 200 201 last_test_failure = None 202 for (path, width, height, bit_rate, frame_rate, subsequent_bit_rate, 203 subsequent_frame_rate, pixel_format) in streams: 204 # Skip the bitrate test if the board cannot switch bitrate. 205 if subsequent_bit_rate is not None and not _can_switch_bitrate(): 206 logging.info('Skip the bitrate switch test: %s => %s', 207 bit_rate, subsequent_bit_rate) 208 continue 209 210 if pixel_format == PIXEL_FORMAT_NV12 and not _can_encode_nv12(): 211 logging.info('Skip the NV12 input buffer case.') 212 continue 213 214 # Set the default value for None. 215 frame_rate = frame_rate or DEFAULT_FRAME_RATE 216 subsequent_bit_rate = (subsequent_bit_rate or 217 bit_rate * DEFAULT_SUBSEQUENT_BIT_RATE_RATIO) 218 subsequent_frame_rate = subsequent_frame_rate or DEFAULT_FRAME_RATE 219 220 if in_cloud: 221 input_path = os.path.join(self.tmpdir, path.split('/')[-1]) 222 _download_video(path, input_path) 223 else: 224 input_path = os.path.join(self.cr_source_dir, path) 225 226 output_path = os.path.join(self.tmpdir, 227 '%s.out' % input_path.split('/')[-1]) 228 229 test_stream_list = map( 230 str, [input_path, width, height, profile, output_path, 231 bit_rate, frame_rate, subsequent_bit_rate, 232 subsequent_frame_rate, pixel_format]) 233 cmd_line_list = [ 234 '--test_stream_data="%s"' % ':'.join(test_stream_list), 235 '--ozone-platform=gbm', 236 helper_logger.chrome_vmodule_flag()] 237 238 # Command line |gtest_filter| can override get_filter_option(). 239 predefined_filter = self.get_filter_option(profile, (width, height)) 240 if predefined_filter: 241 cmd_line_list.append('--gtest_filter="%s"' % predefined_filter) 242 243 cmd_line = ' '.join(cmd_line_list) 244 logging.debug('Executing with argument: %s', cmd_line) 245 try: 246 self.run_chrome_test_binary(BINARY, cmd_line, as_chronos=False) 247 except error.TestFail as test_failure: 248 # Continue to run the remaining test streams and raise 249 # the last failure after finishing all streams. 250 logging.exception('error while encoding %s', input_path) 251 last_test_failure = test_failure 252 finally: 253 # Remove the downloaded video 254 if in_cloud: 255 _remove_if_exists(input_path) 256 _remove_if_exists(output_path) 257 258 if last_test_failure: 259 raise last_test_failure 260