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