blob: 809a98a0945337a0b2b9735a1f493a70a19dd322 [file] [log] [blame]
Ruben Brunk370e2432014-10-14 18:33:23 -07001# 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
Chien-Yu Chen0feea4a2014-10-20 11:04:11 -0700162def get_max_digital_zoom(props):
163 """Returns the maximum amount of zooming possible by the camera device.
164
165 Args:
166 props: the object returned from its.device.get_camera_properties().
167
168 Return:
169 A float indicating the maximum amount of zooming possible by the
170 camera device.
171 """
172
173 maxz = 1.0
174
175 if props.has_key("android.scaler.availableMaxDigitalZoom"):
176 maxz = props["android.scaler.availableMaxDigitalZoom"]
177
178 return maxz
179
180
Ruben Brunk370e2432014-10-14 18:33:23 -0700181class __UnitTest(unittest.TestCase):
182 """Run a suite of unit tests on this module.
183 """
184
185 def test_int_to_rational(self):
186 """Unit test for int_to_rational.
187 """
188 self.assertEqual(int_to_rational(10),
189 {"numerator":10,"denominator":1})
190 self.assertEqual(int_to_rational([1,2]),
191 [{"numerator":1,"denominator":1},
192 {"numerator":2,"denominator":1}])
193
194 def test_float_to_rational(self):
195 """Unit test for float_to_rational.
196 """
197 self.assertEqual(float_to_rational(0.5001, 64),
198 {"numerator":32, "denominator":64})
199
200 def test_rational_to_float(self):
201 """Unit test for rational_to_float.
202 """
203 self.assertTrue(
204 abs(rational_to_float({"numerator":32,"denominator":64})-0.5)
205 < 0.0001)
206
207if __name__ == '__main__':
208 unittest.main()
209