• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 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 os
16import os.path
17import sys
18import re
19import json
20import tempfile
21import time
22import unittest
23import subprocess
24import math
25
26def int_to_rational(i):
27    """Function to convert Python integers to Camera2 rationals.
28
29    Args:
30        i: Python integer or list of integers.
31
32    Returns:
33        Python dictionary or list of dictionaries representing the given int(s)
34        as rationals with denominator=1.
35    """
36    if isinstance(i, list):
37        return [{"numerator":val, "denominator":1} for val in i]
38    else:
39        return {"numerator":i, "denominator":1}
40
41def float_to_rational(f, denom=128):
42    """Function to convert Python floats to Camera2 rationals.
43
44    Args:
45        f: Python float or list of floats.
46        denom: (Optonal) the denominator to use in the output rationals.
47
48    Returns:
49        Python dictionary or list of dictionaries representing the given
50        float(s) as rationals.
51    """
52    if isinstance(f, list):
53        return [{"numerator":math.floor(val*denom+0.5), "denominator":denom}
54                for val in f]
55    else:
56        return {"numerator":math.floor(f*denom+0.5), "denominator":denom}
57
58def rational_to_float(r):
59    """Function to convert Camera2 rational objects to Python floats.
60
61    Args:
62        r: Rational or list of rationals, as Python dictionaries.
63
64    Returns:
65        Float or list of floats.
66    """
67    if isinstance(r, list):
68        return [float(val["numerator"]) / float(val["denominator"])
69                for val in r]
70    else:
71        return float(r["numerator"]) / float(r["denominator"])
72
73def manual_capture_request(sensitivity, exp_time, linear_tonemap=False):
74    """Return a capture request with everything set to manual.
75
76    Uses identity/unit color correction, and the default tonemap curve.
77    Optionally, the tonemap can be specified as being linear.
78
79    Args:
80        sensitivity: The sensitivity value to populate the request with.
81        exp_time: The exposure time, in nanoseconds, to populate the request
82            with.
83        linear_tonemap: [Optional] whether a linear tonemap should be used
84            in this request.
85
86    Returns:
87        The default manual capture request, ready to be passed to the
88        its.device.do_capture function.
89    """
90    req = {
91        "android.control.mode": 0,
92        "android.control.aeMode": 0,
93        "android.control.awbMode": 0,
94        "android.control.afMode": 0,
95        "android.control.effectMode": 0,
96        "android.sensor.frameDuration": 0,
97        "android.sensor.sensitivity": sensitivity,
98        "android.sensor.exposureTime": exp_time,
99        "android.colorCorrection.mode": 0,
100        "android.colorCorrection.transform":
101                int_to_rational([1,0,0, 0,1,0, 0,0,1]),
102        "android.colorCorrection.gains": [1,1,1,1],
103        "android.tonemap.mode": 1,
104        }
105    if linear_tonemap:
106        req["android.tonemap.mode"] = 0
107        req["android.tonemap.curveRed"] = [0.0,0.0, 1.0,1.0]
108        req["android.tonemap.curveGreen"] = [0.0,0.0, 1.0,1.0]
109        req["android.tonemap.curveBlue"] = [0.0,0.0, 1.0,1.0]
110    return req
111
112def auto_capture_request():
113    """Return a capture request with everything set to auto.
114    """
115    return {
116        "android.control.mode": 1,
117        "android.control.aeMode": 1,
118        "android.control.awbMode": 1,
119        "android.control.afMode": 1,
120        "android.colorCorrection.mode": 1,
121        "android.tonemap.mode": 1,
122        }
123
124def get_available_output_sizes(fmt, props):
125    """Return a sorted list of available output sizes for a given format.
126
127    Args:
128        fmt: the output format, as a string in ["jpg", "yuv", "raw"].
129        props: the object returned from its.device.get_camera_properties().
130
131    Returns:
132        A sorted list of (w,h) tuples (sorted large-to-small).
133    """
134    fmt_codes = {"raw":0x20, "raw10":0x25, "yuv":0x23, "jpg":0x100, "jpeg":0x100}
135    configs = props['android.scaler.streamConfigurationMap']\
136                   ['availableStreamConfigurations']
137    fmt_configs = [cfg for cfg in configs if cfg['format'] == fmt_codes[fmt]]
138    out_configs = [cfg for cfg in fmt_configs if cfg['input'] == False]
139    out_sizes = [(cfg['width'],cfg['height']) for cfg in out_configs]
140    out_sizes.sort(reverse=True)
141    return out_sizes
142
143def get_fastest_manual_capture_settings(props):
144    """Return a capture request and format spec for the fastest capture.
145
146    Args:
147        props: the object returned from its.device.get_camera_properties().
148
149    Returns:
150        Two values, the first is a capture request, and the second is an output
151        format specification, for the fastest possible (legal) capture that
152        can be performed on this device (with the smallest output size).
153    """
154    fmt = "yuv"
155    size = get_available_output_sizes(fmt, props)[-1]
156    out_spec = {"format":fmt, "width":size[0], "height":size[1]}
157    s = min(props['android.sensor.info.sensitivityRange'])
158    e = min(props['android.sensor.info.exposureTimeRange'])
159    req = manual_capture_request(s,e)
160    return req, out_spec
161
162class __UnitTest(unittest.TestCase):
163    """Run a suite of unit tests on this module.
164    """
165
166    def test_int_to_rational(self):
167        """Unit test for int_to_rational.
168        """
169        self.assertEqual(int_to_rational(10),
170                         {"numerator":10,"denominator":1})
171        self.assertEqual(int_to_rational([1,2]),
172                         [{"numerator":1,"denominator":1},
173                          {"numerator":2,"denominator":1}])
174
175    def test_float_to_rational(self):
176        """Unit test for float_to_rational.
177        """
178        self.assertEqual(float_to_rational(0.5001, 64),
179                        {"numerator":32, "denominator":64})
180
181    def test_rational_to_float(self):
182        """Unit test for rational_to_float.
183        """
184        self.assertTrue(
185                abs(rational_to_float({"numerator":32,"denominator":64})-0.5)
186                < 0.0001)
187
188if __name__ == '__main__':
189    unittest.main()
190
191