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
15import math
16
17import its.caps
18import its.device
19import its.objects
20import its.target
21
22
23def main():
24    """Test the validity of some metadata entries.
25
26    Looks at capture results and at the camera characteristics objects.
27    """
28    global md, props, failed
29
30    with its.device.ItsSession() as cam:
31        # Arbitrary capture request exposure values; image content is not
32        # important for this test, only the metadata.
33        props = cam.get_camera_properties()
34        props = cam.override_with_hidden_physical_camera_props(props)
35        its.caps.skip_unless(its.caps.backward_compatible(props))
36        auto_req = its.objects.auto_capture_request()
37        cap = cam.do_capture(auto_req)
38        md = cap["metadata"]
39
40    print "Hardware level"
41    print "  Legacy:", its.caps.legacy(props)
42    print "  Limited:", its.caps.limited(props)
43    print "  Full or better:", its.caps.full_or_better(props)
44    print "Capabilities"
45    print "  Manual sensor:", its.caps.manual_sensor(props)
46    print "  Manual post-proc:", its.caps.manual_post_proc(props)
47    print "  Raw:", its.caps.raw(props)
48    print "  Sensor fusion:", its.caps.sensor_fusion(props)
49
50    # Test: hardware level should be a valid value.
51    check('props.has_key("android.info.supportedHardwareLevel")')
52    check('props["android.info.supportedHardwareLevel"] is not None')
53    check('props["android.info.supportedHardwareLevel"] in [0,1,2,3]')
54    manual_sensor = its.caps.manual_sensor(props)
55
56    # Test: rollingShutterSkew, and frameDuration tags must all be present,
57    # and rollingShutterSkew must be greater than zero and smaller than all
58    # of the possible frame durations.
59    if manual_sensor:
60        check('md.has_key("android.sensor.frameDuration")')
61        check('md["android.sensor.frameDuration"] is not None')
62    check('md.has_key("android.sensor.rollingShutterSkew")')
63    check('md["android.sensor.rollingShutterSkew"] is not None')
64    if manual_sensor:
65        check('md["android.sensor.rollingShutterSkew"] > 0')
66        check('md["android.sensor.frameDuration"] > 0')
67
68    # Test: timestampSource must be a valid value.
69    check('props.has_key("android.sensor.info.timestampSource")')
70    check('props["android.sensor.info.timestampSource"] is not None')
71    check('props["android.sensor.info.timestampSource"] in [0,1]')
72
73    # Test: croppingType must be a valid value, and for full devices, it
74    # must be FREEFORM=1.
75    check('props.has_key("android.scaler.croppingType")')
76    check('props["android.scaler.croppingType"] is not None')
77    check('props["android.scaler.croppingType"] in [0,1]')
78
79    # Test: android.sensor.blackLevelPattern exists for RAW and is not None
80    if its.caps.raw(props):
81        check('props.has_key("android.sensor.blackLevelPattern")')
82        check('props["android.sensor.blackLevelPattern"] is not None')
83
84    assert not failed
85
86    if not its.caps.legacy(props):
87        # Test: pixel_pitch, FOV, and hyperfocal distance are reasonable
88        fmts = props["android.scaler.streamConfigurationMap"]["availableStreamConfigurations"]
89        fmts = sorted(fmts, key=lambda k: k["width"]*k["height"], reverse=True)
90        sensor_size = props["android.sensor.info.physicalSize"]
91        pixel_pitch_h = (sensor_size["height"] / fmts[0]["height"] * 1E3)
92        pixel_pitch_w = (sensor_size["width"] / fmts[0]["width"] * 1E3)
93        print "Assert pixel_pitch WxH: %.2f um, %.2f um" % (pixel_pitch_w,
94                                                            pixel_pitch_h)
95        assert 0.7 <= pixel_pitch_w <= 10
96        assert 0.7 <= pixel_pitch_h <= 10
97        assert 0.333 <= pixel_pitch_w/pixel_pitch_h <= 3.0
98
99        diag = math.sqrt(sensor_size["height"] ** 2 +
100                         sensor_size["width"] ** 2)
101        fl = md["android.lens.focalLength"]
102        fov = 2 * math.degrees(math.atan(diag / (2 * fl)))
103        print "Assert field of view: %.1f degrees" % fov
104        assert 10 <= fov <= 130
105
106        if its.caps.lens_approx_calibrated(props):
107            diopter_hyperfocal = props["android.lens.info.hyperfocalDistance"]
108            if diopter_hyperfocal != 0.0:
109                hyperfocal = 1.0 / diopter_hyperfocal
110                print "Assert hyperfocal distance: %.2f m" % hyperfocal
111                assert 0.02 <= hyperfocal
112
113
114def getval(expr, default=None):
115    try:
116        return eval(expr)
117    except:
118        return default
119
120failed = False
121
122
123def check(expr):
124    global md, props, failed
125    try:
126        if eval(expr):
127            print "Passed>", expr
128        else:
129            print "Failed>>", expr
130            failed = True
131    except:
132        print "Failed>>", expr
133        failed = True
134
135if __name__ == '__main__':
136    main()
137
138