1*b7c941bbSAndroid Build Coastguard Worker# Copyright 2014 The Android Open Source Project 2*b7c941bbSAndroid Build Coastguard Worker# 3*b7c941bbSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*b7c941bbSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*b7c941bbSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*b7c941bbSAndroid Build Coastguard Worker# 7*b7c941bbSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*b7c941bbSAndroid Build Coastguard Worker# 9*b7c941bbSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*b7c941bbSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*b7c941bbSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*b7c941bbSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*b7c941bbSAndroid Build Coastguard Worker# limitations under the License. 14*b7c941bbSAndroid Build Coastguard Worker"""CameraITS test to measure jitter in camera timestamps.""" 15*b7c941bbSAndroid Build Coastguard Worker 16*b7c941bbSAndroid Build Coastguard Workerimport logging 17*b7c941bbSAndroid Build Coastguard Workerimport os.path 18*b7c941bbSAndroid Build Coastguard Worker 19*b7c941bbSAndroid Build Coastguard Workerfrom matplotlib import pyplot as plt 20*b7c941bbSAndroid Build Coastguard Workerfrom mobly import test_runner 21*b7c941bbSAndroid Build Coastguard Worker 22*b7c941bbSAndroid Build Coastguard Workerimport its_base_test 23*b7c941bbSAndroid Build Coastguard Workerimport camera_properties_utils 24*b7c941bbSAndroid Build Coastguard Workerimport capture_request_utils 25*b7c941bbSAndroid Build Coastguard Workerimport its_session_utils 26*b7c941bbSAndroid Build Coastguard Worker 27*b7c941bbSAndroid Build Coastguard Worker_NS_TO_MS = 1.0E-6 28*b7c941bbSAndroid Build Coastguard Worker_NAME = os.path.basename(__file__).split('.')[0] 29*b7c941bbSAndroid Build Coastguard Worker_NUM_FRAMES = 50 30*b7c941bbSAndroid Build Coastguard Worker_START_FRAME = 2 # 1 frame delay to allow faster latency to 1st frame 31*b7c941bbSAndroid Build Coastguard Worker_TEST_FPS = 30 # frames per second 32*b7c941bbSAndroid Build Coastguard Worker# PASS/FAIL thresholds 33*b7c941bbSAndroid Build Coastguard Worker_MIN_AVG_FRAME_DELTA = 30 # at least 30ms delta between frames 34*b7c941bbSAndroid Build Coastguard Worker_MAX_INIT_FRAME_DELTA = 100 # no more than 100ms between first 2 frames 35*b7c941bbSAndroid Build Coastguard Worker_MAX_VAR_FRAME_DELTA = 0.01 # variance of frame deltas 36*b7c941bbSAndroid Build Coastguard Worker_MAX_FRAME_DELTA_JITTER = 0.3 # max ms gap from the average frame delta 37*b7c941bbSAndroid Build Coastguard Worker 38*b7c941bbSAndroid Build Coastguard Worker 39*b7c941bbSAndroid Build Coastguard Workerclass JitterTest(its_base_test.ItsBaseTest): 40*b7c941bbSAndroid Build Coastguard Worker """Measure jitter in camera timestamps.""" 41*b7c941bbSAndroid Build Coastguard Worker 42*b7c941bbSAndroid Build Coastguard Worker def test_jitter(self): 43*b7c941bbSAndroid Build Coastguard Worker with its_session_utils.ItsSession( 44*b7c941bbSAndroid Build Coastguard Worker device_id=self.dut.serial, 45*b7c941bbSAndroid Build Coastguard Worker camera_id=self.camera_id, 46*b7c941bbSAndroid Build Coastguard Worker hidden_physical_id=self.hidden_physical_id) as cam: 47*b7c941bbSAndroid Build Coastguard Worker props = cam.get_camera_properties() 48*b7c941bbSAndroid Build Coastguard Worker props = cam.override_with_hidden_physical_camera_props(props) 49*b7c941bbSAndroid Build Coastguard Worker camera_properties_utils.skip_unless( 50*b7c941bbSAndroid Build Coastguard Worker camera_properties_utils.manual_sensor(props) and 51*b7c941bbSAndroid Build Coastguard Worker camera_properties_utils.sensor_fusion(props)) 52*b7c941bbSAndroid Build Coastguard Worker 53*b7c941bbSAndroid Build Coastguard Worker req, fmt = capture_request_utils.get_fastest_manual_capture_settings( 54*b7c941bbSAndroid Build Coastguard Worker props) 55*b7c941bbSAndroid Build Coastguard Worker req['android.control.aeTargetFpsRange'] = [_TEST_FPS, _TEST_FPS] 56*b7c941bbSAndroid Build Coastguard Worker caps = cam.do_capture([req] * _NUM_FRAMES, [fmt]) 57*b7c941bbSAndroid Build Coastguard Worker 58*b7c941bbSAndroid Build Coastguard Worker # Log the millisecond delta between the start of each exposure 59*b7c941bbSAndroid Build Coastguard Worker tstamps = [c['metadata']['android.sensor.timestamp'] for c in caps] 60*b7c941bbSAndroid Build Coastguard Worker if (tstamps[1]-tstamps[0])*_NS_TO_MS > _MAX_INIT_FRAME_DELTA: 61*b7c941bbSAndroid Build Coastguard Worker raise AssertionError('Initial frame timestamp delta too great! ' 62*b7c941bbSAndroid Build Coastguard Worker f'tstamp[1]: {tstamps[1]}ms, ' 63*b7c941bbSAndroid Build Coastguard Worker f'tstamp[0]: {tstamps[0]}ms, ' 64*b7c941bbSAndroid Build Coastguard Worker f'ATOL: {_MAX_INIT_FRAME_DELTA}ms') 65*b7c941bbSAndroid Build Coastguard Worker deltas = [ 66*b7c941bbSAndroid Build Coastguard Worker tstamps[i] - tstamps[i-1] for i in range(_START_FRAME, len(tstamps)) 67*b7c941bbSAndroid Build Coastguard Worker ] 68*b7c941bbSAndroid Build Coastguard Worker deltas_ms = [d * _NS_TO_MS for d in deltas] 69*b7c941bbSAndroid Build Coastguard Worker avg = sum(deltas_ms) / len(deltas_ms) 70*b7c941bbSAndroid Build Coastguard Worker var = sum([d * d for d in deltas_ms]) / len(deltas_ms) - avg * avg 71*b7c941bbSAndroid Build Coastguard Worker range0 = min(deltas_ms) - avg 72*b7c941bbSAndroid Build Coastguard Worker range1 = max(deltas_ms) - avg 73*b7c941bbSAndroid Build Coastguard Worker 74*b7c941bbSAndroid Build Coastguard Worker logging.debug('Average: %s', avg) 75*b7c941bbSAndroid Build Coastguard Worker logging.debug('Variance: %s', var) 76*b7c941bbSAndroid Build Coastguard Worker logging.debug('Jitter range: %s to %s', range0, range1) 77*b7c941bbSAndroid Build Coastguard Worker 78*b7c941bbSAndroid Build Coastguard Worker # Draw a plot. 79*b7c941bbSAndroid Build Coastguard Worker plt.figure() 80*b7c941bbSAndroid Build Coastguard Worker plt.plot(range(len(deltas_ms)), deltas_ms, '-bo') 81*b7c941bbSAndroid Build Coastguard Worker plt.title(_NAME) 82*b7c941bbSAndroid Build Coastguard Worker plt.xlabel('frame number') 83*b7c941bbSAndroid Build Coastguard Worker plt.ylabel('jitter (ms)') 84*b7c941bbSAndroid Build Coastguard Worker name_with_log_path = os.path.join(self.log_path, _NAME) 85*b7c941bbSAndroid Build Coastguard Worker plt.savefig(f'{name_with_log_path}_deltas.png') 86*b7c941bbSAndroid Build Coastguard Worker 87*b7c941bbSAndroid Build Coastguard Worker # Test for pass/fail. 88*b7c941bbSAndroid Build Coastguard Worker if avg <= _MIN_AVG_FRAME_DELTA: 89*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 90*b7c941bbSAndroid Build Coastguard Worker f'avg: {avg:.4f}ms, ATOL: {_MIN_AVG_FRAME_DELTA}ms' 91*b7c941bbSAndroid Build Coastguard Worker ) 92*b7c941bbSAndroid Build Coastguard Worker if var >= _MAX_VAR_FRAME_DELTA: 93*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 94*b7c941bbSAndroid Build Coastguard Worker f'var: {var:.4f}ms, ATOL: {_MAX_VAR_FRAME_DELTA}ms' 95*b7c941bbSAndroid Build Coastguard Worker ) 96*b7c941bbSAndroid Build Coastguard Worker if (abs(range0) >= _MAX_FRAME_DELTA_JITTER or 97*b7c941bbSAndroid Build Coastguard Worker abs(range1) >= _MAX_FRAME_DELTA_JITTER): 98*b7c941bbSAndroid Build Coastguard Worker raise AssertionError( 99*b7c941bbSAndroid Build Coastguard Worker f'range0: {range0:.4f}ms, range1: {range1:.4f}ms, ' 100*b7c941bbSAndroid Build Coastguard Worker f'ATOL: {_MAX_FRAME_DELTA_JITTER}' 101*b7c941bbSAndroid Build Coastguard Worker ) 102*b7c941bbSAndroid Build Coastguard Worker 103*b7c941bbSAndroid Build Coastguard Worker 104*b7c941bbSAndroid Build Coastguard Workerif __name__ == '__main__': 105*b7c941bbSAndroid Build Coastguard Worker test_runner.main() 106