• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 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 that the device will write/read correct exp/gain values.
15"""
16
17import logging
18import os.path
19
20from mobly import test_runner
21
22import its_base_test
23import camera_properties_utils
24import capture_request_utils
25import its_session_utils
26
27
28_NAME = os.path.basename(__file__).split('.')[0]
29# Spec to be within 3% but not over for exposure in capture vs exposure request.
30_RTOL_EXP_GAIN = 0.97
31_TEST_EXP_RANGE = [6E6, 1E9]  # ns [6ms, 1s]
32
33
34class ReadWriteTest(its_base_test.ItsBaseTest):
35  """Test that the device will write/read correct exp/gain values.
36  """
37
38  def test_read_write(self):
39    with its_session_utils.ItsSession(
40        device_id=self.dut.serial,
41        camera_id=self.camera_id,
42        hidden_physical_id=self.hidden_physical_id) as cam:
43      props = cam.get_camera_properties()
44      props = cam.override_with_hidden_physical_camera_props(props)
45      camera_properties_utils.skip_unless(
46          camera_properties_utils.manual_sensor(props) and
47          camera_properties_utils.per_frame_control(props))
48      vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial)
49
50      valid_formats = ['yuv', 'jpg']
51      if camera_properties_utils.raw16(props):
52        valid_formats.insert(0, 'raw')
53      # grab exp/gain ranges from camera
54      sensor_exp_range = props['android.sensor.info.exposureTimeRange']
55      sens_range = props['android.sensor.info.sensitivityRange']
56      logging.debug('sensor exposure time range: %s', sensor_exp_range)
57      logging.debug('sensor sensitivity range: %s', sens_range)
58
59      # determine if exposure test range is within sensor reported range
60      if sensor_exp_range[0] == 0:
61        raise AssertionError('Min expsoure == 0')
62      exp_range = []
63      if sensor_exp_range[0] < _TEST_EXP_RANGE[0]:
64        exp_range.append(_TEST_EXP_RANGE[0])
65      else:
66        exp_range.append(sensor_exp_range[0])
67      if sensor_exp_range[1] > _TEST_EXP_RANGE[1]:
68        exp_range.append(_TEST_EXP_RANGE[1])
69      else:
70        exp_range.append(sensor_exp_range[1])
71
72      data = {}
73      # build requests
74      for fmt in valid_formats:
75        logging.debug('format: %s', fmt)
76        size = capture_request_utils.get_available_output_sizes(fmt, props)[-1]
77        out_surface = {'width': size[0], 'height': size[1], 'format': fmt}
78        # pylint: disable=protected-access
79        if cam._hidden_physical_id:
80          out_surface['physicalCamera'] = cam._hidden_physical_id
81        reqs = []
82        index_list = []
83        for exp in exp_range:
84          for sens in sens_range:
85            reqs.append(capture_request_utils.manual_capture_request(sens, exp))
86            index_list.append((fmt, exp, sens))
87            logging.debug('exp_write: %d, sens_write: %d', exp, sens)
88
89        # take shots
90        caps = cam.do_capture(reqs, out_surface)
91
92        # extract exp/sensitivity data
93        for i, cap in enumerate(caps):
94          exposure_read = cap['metadata']['android.sensor.exposureTime']
95          sensitivity_read = cap['metadata']['android.sensor.sensitivity']
96          data[index_list[i]] = (fmt, exposure_read, sensitivity_read)
97
98      # check read/write match across all shots
99      e_failed = []  # exposure time FAILs
100      s_failed = []  # sensitivity FAILs
101      r_failed = []  # sensitivity range FAILs
102      for fmt_write in valid_formats:
103        for e_write in exp_range:
104          for s_write in sens_range:
105            fmt_read, e_read, s_read = data[(fmt_write, e_write, s_write)]
106            if (e_write < e_read or e_read / float(e_write) <= _RTOL_EXP_GAIN):
107              e_failed.append({
108                  'format': fmt_read,
109                  'e_write': e_write,
110                  'e_read': e_read,
111                  's_write': s_write,
112                  's_read': s_read
113              })
114            if (s_write < s_read or s_read / float(s_write) <= _RTOL_EXP_GAIN):
115              s_failed.append({
116                  'format': fmt_read,
117                  'e_write': e_write,
118                  'e_read': e_read,
119                  's_write': s_write,
120                  's_read': s_read
121              })
122            if (vendor_api_level >= its_session_utils.ANDROID14_API_LEVEL and
123                s_read < sens_range[0]):
124              r_failed.append({
125                  'format': fmt_read,
126                  'e_write': e_write,
127                  'e_read': e_read,
128                  's_write': s_write,
129                  's_read': s_read
130              })
131
132        # print results
133        if e_failed:
134          logging.debug('FAILs for exposure time')
135          for fail in e_failed:
136            logging.debug('format: %s, e_write: %d, e_read: %d, RTOL: %.2f, ',
137                          fail['format'], fail['e_write'], fail['e_read'],
138                          _RTOL_EXP_GAIN)
139            logging.debug('s_write: %d, s_read: %d, RTOL: %.2f',
140                          fail['s_write'], fail['s_read'], _RTOL_EXP_GAIN)
141        if s_failed:
142          logging.debug('FAILs for sensitivity(ISO)')
143          for fail in s_failed:
144            logging.debug('format: %s, s_write: %d, s_read: %d, RTOL: %.2f, ',
145                          fail['format'], fail['s_write'], fail['s_read'],
146                          _RTOL_EXP_GAIN)
147            logging.debug('e_write: %d, e_read: %d, RTOL: %.2f',
148                          fail['e_write'], fail['e_read'], _RTOL_EXP_GAIN)
149        if r_failed:
150          logging.debug('FAILs for sensitivity(ISO) range')
151          for fail in r_failed:
152            logging.debug('format: %s, s_write: %d, s_read: %d, RTOL: %.2f, ',
153                          fail['format'], fail['s_write'], fail['s_read'],
154                          _RTOL_EXP_GAIN)
155            logging.debug('e_write: %d, e_read: %d, RTOL: %.2f',
156                          fail['e_write'], fail['e_read'], _RTOL_EXP_GAIN)
157
158        # PASS/FAIL
159        if e_failed:
160          raise AssertionError(f'Exposure fails: {e_failed}')
161        if s_failed:
162          raise AssertionError(f'Sensitivity fails: {s_failed}')
163        if r_failed:
164          raise AssertionError(f'Sensitivity range FAILs: {r_failed}')
165
166
167if __name__ == '__main__':
168  test_runner.main()
169