1# Copyright 2014 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""CameraITS test to verify metadata entries.""" 15 16import logging 17import math 18 19from mobly import test_runner 20 21import its_base_test 22import camera_properties_utils 23import capture_request_utils 24import its_session_utils 25 26 27class MetadataTest(its_base_test.ItsBaseTest): 28 """Test the validity of some metadata entries. 29 30 Looks at the capture results and at the camera characteristics objects. 31 """ 32 33 def test_metadata(self): 34 with its_session_utils.ItsSession( 35 device_id=self.dut.serial, 36 camera_id=self.camera_id, 37 hidden_physical_id=self.hidden_physical_id) as cam: 38 # Arbitrary capture request exposure values; image content is not 39 # important for this test, only the metadata. 40 props = cam.get_camera_properties() 41 props = cam.override_with_hidden_physical_camera_props(props) 42 camera_properties_utils.skip_unless( 43 camera_properties_utils.backward_compatible(props)) 44 auto_req = capture_request_utils.auto_capture_request() 45 cap = cam.do_capture(auto_req) 46 md = cap['metadata'] 47 self.failed = False 48 logging.debug('Hardware level') 49 logging.debug('Legacy: %s', camera_properties_utils.legacy(props)) 50 51 logging.debug('Limited: %s', camera_properties_utils.limited(props)) 52 logging.debug('Full or better: %s', 53 camera_properties_utils.full_or_better(props)) 54 logging.debug('Level 3: %s', camera_properties_utils.level3(props)) 55 logging.debug('Capabilities') 56 logging.debug('Manual sensor: %s', 57 camera_properties_utils.manual_sensor(props)) 58 logging.debug('Manual post-proc: %s', 59 camera_properties_utils.manual_post_proc(props)) 60 logging.debug('Raw: %s', camera_properties_utils.raw(props)) 61 logging.debug('Sensor fusion: %s', 62 camera_properties_utils.sensor_fusion(props)) 63 64 check(self, 'android.info.supportedHardwareLevel' in props, 65 'android.info.supportedHardwareLevel in props') 66 check(self, props['android.info.supportedHardwareLevel'] is not None, 67 'props[android.info.supportedHardwareLevel] is not None') 68 check(self, props['android.info.supportedHardwareLevel'] in [0, 1, 2, 3], 69 'props[android.info.supportedHardwareLevel] in [0, 1, 2, 3]') 70 manual_sensor = camera_properties_utils.manual_sensor(props) 71 # Test: rollingShutterSkew, and frameDuration tags must all be present, 72 # and rollingShutterSkew must be greater than zero and smaller than all 73 # of the possible frame durations. 74 if manual_sensor: 75 check(self, 'android.sensor.frameDuration' in md, 76 'md.has_key("android.sensor.frameDuration")') 77 check(self, md['android.sensor.frameDuration'] is not None, 78 'md["android.sensor.frameDuration"] is not None') 79 check(self, md['android.sensor.rollingShutterSkew'] > 0, 80 'md["android.sensor.rollingShutterSkew"] > 0') 81 check(self, md['android.sensor.frameDuration'] > 0, 82 'md["android.sensor.frameDuration"] > 0') 83 check( 84 self, md['android.sensor.rollingShutterSkew'] <= 85 md['android.sensor.frameDuration'], 86 ('md["android.sensor.rollingShutterSkew"] <= ' 87 'md["android.sensor.frameDuration"]')) 88 logging.debug('frameDuration: %d ns', 89 md['android.sensor.frameDuration']) 90 91 check(self, 'android.sensor.rollingShutterSkew' in md, 92 'md.has_key("android.sensor.rollingShutterSkew")') 93 check(self, md['android.sensor.rollingShutterSkew'] is not None, 94 'md["android.sensor.rollingShutterSkew"] is not None') 95 logging.debug('rollingShutterSkew: %d ns', 96 md['android.sensor.rollingShutterSkew']) 97 98 # Test: timestampSource must be a valid value. 99 check(self, 'android.sensor.info.timestampSource' in props, 100 'props.has_key("android.sensor.info.timestampSource")') 101 check(self, props['android.sensor.info.timestampSource'] is not None, 102 'props["android.sensor.info.timestampSource"] is not None') 103 check(self, props['android.sensor.info.timestampSource'] in [0, 1], 104 'props["android.sensor.info.timestampSource"] in [0,1]') 105 106 # Test: croppingType must be a valid value, and for full devices, it 107 # must be FREEFORM=1. 108 check(self, 'android.scaler.croppingType' in props, 109 'props.has_key("android.scaler.croppingType")') 110 check(self, props['android.scaler.croppingType'] is not None, 111 'props["android.scaler.croppingType"] is not None') 112 check(self, props['android.scaler.croppingType'] in [0, 1], 113 'props["android.scaler.croppingType"] in [0,1]') 114 115 # Test: android.sensor.blackLevelPattern exists for RAW and is not None 116 if camera_properties_utils.raw(props): 117 check(self, 'android.sensor.blackLevelPattern' in props, 118 'props.has_key("android.sensor.blackLevelPattern")') 119 check(self, props['android.sensor.blackLevelPattern'] is not None, 120 'props["android.sensor.blackLevelPattern"] is not None') 121 122 assert not self.failed 123 124 if not camera_properties_utils.legacy(props): 125 # Test: pixel_pitch, FOV, and hyperfocal distance are reasonable 126 fmts = props['android.scaler.streamConfigurationMap'][ 127 'availableStreamConfigurations'] 128 fmts = sorted( 129 fmts, key=lambda k: k['width'] * k['height'], reverse=True) 130 sensor_size = props['android.sensor.info.physicalSize'] 131 pixel_pitch_h = (sensor_size['height'] / fmts[0]['height'] * 1E3) 132 pixel_pitch_w = (sensor_size['width'] / fmts[0]['width'] * 1E3) 133 logging.debug('Assert pixel_pitch WxH: %.2f um, %.2f um', pixel_pitch_w, 134 pixel_pitch_h) 135 assert 0.7 <= pixel_pitch_w <= 10 136 assert 0.7 <= pixel_pitch_h <= 10 137 assert 0.333 <= pixel_pitch_w/pixel_pitch_h <= 3.0 138 139 diag = math.sqrt(sensor_size['height']**2 + sensor_size['width']**2) 140 fl = md['android.lens.focalLength'] 141 logging.debug('Focal length: %.3f', fl) 142 fov = 2 * math.degrees(math.atan(diag / (2 * fl))) 143 logging.debug('Assert field of view: %.1f degrees', fov) 144 assert 10 <= fov <= 130 145 146 if camera_properties_utils.lens_approx_calibrated(props): 147 diopter_hyperfocal = props['android.lens.info.hyperfocalDistance'] 148 if diopter_hyperfocal != 0.0: 149 hyperfocal = 1.0 / diopter_hyperfocal 150 logging.debug('Assert hyperfocal distance: %.2f m', hyperfocal) 151 assert 0.02 <= hyperfocal 152 153 logging.debug('Minimum focus distance: %3.f', 154 props['android.lens.info.minimumFocusDistance']) 155 156 157def check(self, expr, msg): 158 if expr: 159 logging.debug('Passed>>%s', msg) 160 else: 161 logging.debug('Failed>>%s', msg) 162 self.failed = True 163 164 165if __name__ == '__main__': 166 test_runner.main() 167