ItsSerializer.java revision a04e462a07854595122f19b1df9f19c78e5dc030
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.camera2.its; 18 19import android.hardware.camera2.CameraDevice; 20import android.hardware.camera2.CameraMetadata; 21import android.hardware.camera2.CaptureRequest; 22import android.hardware.camera2.Rational; 23import android.util.Log; 24 25import org.json.JSONArray; 26import org.json.JSONObject; 27 28import java.lang.reflect.Array; 29import java.lang.reflect.Field; 30import java.lang.reflect.GenericArrayType; 31import java.lang.reflect.Modifier; 32import java.lang.reflect.ParameterizedType; 33import java.lang.reflect.Type; 34import java.util.Arrays; 35import java.util.LinkedList; 36import java.util.List; 37 38/** 39 * Class to deal with serializing and deserializing between JSON and Camera2 objects. 40 */ 41public class ItsSerializer { 42 public static final String TAG = ItsSerializer.class.getSimpleName(); 43 44 private static class MetadataEntry { 45 public MetadataEntry(String k, Object v) { 46 key = k; 47 value = v; 48 } 49 public String key; 50 public Object value; 51 } 52 53 @SuppressWarnings("unchecked") 54 private static MetadataEntry serializeEntry(Type keyType, Object keyObj, CameraMetadata md) 55 throws ItsException { 56 CameraMetadata.Key key = (CameraMetadata.Key)keyObj; 57 try { 58 if (md.get(key) == null) { 59 return new MetadataEntry(key.getName(), JSONObject.NULL); 60 } 61 if (keyType == Integer.class || keyType == Long.class || keyType == Byte.class || 62 keyType == Float.class || keyType == Boolean.class || keyType == String.class) { 63 return new MetadataEntry(key.getName(), md.get(key)); 64 } else if (keyType == Rational.class) { 65 CameraMetadata.Key<Rational> key2 = (CameraMetadata.Key<Rational>)keyObj; 66 JSONObject ratObj = new JSONObject(); 67 ratObj.put("numerator", md.get(key2).getNumerator()); 68 ratObj.put("denominator", md.get(key2).getDenominator()); 69 return new MetadataEntry(key.getName(), ratObj); 70 } else if (keyType == android.hardware.camera2.Size.class) { 71 CameraMetadata.Key<android.hardware.camera2.Size> key2 = 72 (CameraMetadata.Key<android.hardware.camera2.Size>)keyObj; 73 JSONObject sizeObj = new JSONObject(); 74 sizeObj.put("width", md.get(key2).getWidth()); 75 sizeObj.put("height", md.get(key2).getHeight()); 76 return new MetadataEntry(key.getName(), sizeObj); 77 } else if (keyType == android.graphics.Rect.class) { 78 CameraMetadata.Key<android.graphics.Rect> key2 = 79 (CameraMetadata.Key<android.graphics.Rect>)keyObj; 80 JSONObject rectObj = new JSONObject(); 81 rectObj.put("left", md.get(key2).left); 82 rectObj.put("right", md.get(key2).right); 83 rectObj.put("top", md.get(key2).top); 84 rectObj.put("bottom", md.get(key2).bottom); 85 return new MetadataEntry(key.getName(), rectObj); 86 } else { 87 throw new ItsException( 88 "Unsupported key type in metadata serializer: " + keyType); 89 } 90 } catch (org.json.JSONException e) { 91 throw new ItsException("JSON error for key: " + key.getName() + ": ", e); 92 } 93 } 94 95 @SuppressWarnings("unchecked") 96 private static MetadataEntry serializeArrayEntry(Type keyType, Object keyObj, CameraMetadata md) 97 throws ItsException { 98 CameraMetadata.Key key = (CameraMetadata.Key)keyObj; 99 try { 100 if (md.get(key) == null) { 101 return new MetadataEntry(key.getName(), JSONObject.NULL); 102 } 103 Type elmtType = ((GenericArrayType)keyType).getGenericComponentType(); 104 if (elmtType == int.class || elmtType == float.class || elmtType == byte.class || 105 elmtType == long.class || elmtType == double.class) { 106 return new MetadataEntry(key.getName(), new JSONArray(md.get(key))); 107 } else if (elmtType == Rational.class) { 108 CameraMetadata.Key<Rational[]> key2 = (CameraMetadata.Key<Rational[]>)keyObj; 109 JSONArray jsonArray = new JSONArray(); 110 for (int i = 0; i < Array.getLength(md.get(key)); i++) { 111 JSONObject ratObj = new JSONObject(); 112 ratObj.put("numerator", md.get(key2)[i].getNumerator()); 113 ratObj.put("denominator", md.get(key2)[i].getDenominator()); 114 jsonArray.put(ratObj); 115 } 116 return new MetadataEntry(key.getName(), jsonArray); 117 } else if (elmtType == android.hardware.camera2.Size.class) { 118 CameraMetadata.Key<android.hardware.camera2.Size[]> key2 = 119 (CameraMetadata.Key<android.hardware.camera2.Size[]>)keyObj; 120 JSONArray jsonArray = new JSONArray(); 121 for (int i = 0; i < Array.getLength(md.get(key)); i++) { 122 JSONObject sizeObj = new JSONObject(); 123 sizeObj.put("width", md.get(key2)[i].getWidth()); 124 sizeObj.put("height", md.get(key2)[i].getHeight()); 125 jsonArray.put(sizeObj); 126 } 127 return new MetadataEntry(key.getName(), jsonArray); 128 } else if (elmtType == android.graphics.Rect.class) { 129 CameraMetadata.Key<android.graphics.Rect[]> key2 = 130 (CameraMetadata.Key<android.graphics.Rect[]>)keyObj; 131 JSONArray jsonArray = new JSONArray(); 132 for (int i = 0; i < Array.getLength(md.get(key)); i++) { 133 JSONObject rectObj = new JSONObject(); 134 rectObj.put("left", md.get(key2)[i].left); 135 rectObj.put("right", md.get(key2)[i].right); 136 rectObj.put("top", md.get(key2)[i].top); 137 rectObj.put("bottom", md.get(key2)[i].bottom); 138 jsonArray.put(rectObj); 139 } 140 return new MetadataEntry(key.getName(), jsonArray); 141 } else { 142 throw new ItsException("Unsupported array type: " + elmtType); 143 } 144 } catch (org.json.JSONException e) { 145 throw new ItsException("JSON error for key: " + key.getName() + ": ", e); 146 } 147 } 148 149 @SuppressWarnings("unchecked") 150 public static JSONObject serialize(CameraMetadata md) 151 throws ItsException { 152 JSONObject jsonObj = new JSONObject(); 153 Field[] allFields = md.getClass().getDeclaredFields(); 154 for (Field field : allFields) { 155 if (Modifier.isPublic(field.getModifiers()) && 156 Modifier.isStatic(field.getModifiers()) && 157 field.getType() == CameraMetadata.Key.class && 158 field.getGenericType() instanceof ParameterizedType) { 159 ParameterizedType paramType = (ParameterizedType)field.getGenericType(); 160 Type[] argTypes = paramType.getActualTypeArguments(); 161 if (argTypes.length > 0) { 162 try { 163 Type keyType = argTypes[0]; 164 Object keyObj = field.get(md); 165 MetadataEntry entry; 166 if (keyType instanceof GenericArrayType) { 167 entry = serializeArrayEntry(keyType, keyObj, md); 168 } else { 169 entry = serializeEntry(keyType, keyObj, md); 170 } 171 if (entry != null) { 172 jsonObj.put(entry.key, entry.value); 173 } 174 } catch (IllegalAccessException e) { 175 throw new ItsException( 176 "Access error for field: " + field + ": ", e); 177 } catch (org.json.JSONException e) { 178 throw new ItsException( 179 "JSON error for field: " + field + ": ", e); 180 } 181 } 182 } 183 } 184 return jsonObj; 185 } 186 187 @SuppressWarnings("unchecked") 188 public static CaptureRequest.Builder deserialize(CaptureRequest.Builder mdDefault, 189 JSONObject jsonReq) throws ItsException { 190 try { 191 Log.i(TAG, "Parsing JSON capture request ..."); 192 193 // Iterate over the CameraMetadata reflected fields. 194 CaptureRequest.Builder md = mdDefault; 195 Field[] allFields = md.getClass().getDeclaredFields(); 196 for (Field field : allFields) { 197 if (Modifier.isPublic(field.getModifiers()) && 198 Modifier.isStatic(field.getModifiers()) && 199 field.getType() == CameraMetadata.Key.class && 200 field.getGenericType() instanceof ParameterizedType) { 201 ParameterizedType paramType = (ParameterizedType)field.getGenericType(); 202 Type[] argTypes = paramType.getActualTypeArguments(); 203 if (argTypes.length > 0) { 204 CameraMetadata.Key key = (CameraMetadata.Key)field.get(md); 205 String keyName = key.getName(); 206 Type keyType = argTypes[0]; 207 208 // For each reflected CameraMetadata entry, look inside the JSON object 209 // to see if it is being set. If it is found, remove the key from the 210 // JSON object. After this process, there should be no keys left in the 211 // JSON (otherwise an invalid key was specified). 212 213 if (jsonReq.has(keyName) && !jsonReq.isNull(keyName)) { 214 if (keyType instanceof GenericArrayType) { 215 Type elmtType = 216 ((GenericArrayType)keyType).getGenericComponentType(); 217 JSONArray ja = jsonReq.getJSONArray(keyName); 218 Object val[] = new Object[ja.length()]; 219 for (int i = 0; i < ja.length(); i++) { 220 if (elmtType == int.class) { 221 Array.set(val, i, ja.getInt(i)); 222 } else if (elmtType == byte.class) { 223 Array.set(val, i, (byte)ja.getInt(i)); 224 } else if (elmtType == float.class) { 225 Array.set(val, i, (float)ja.getDouble(i)); 226 } else if (elmtType == long.class) { 227 Array.set(val, i, ja.getLong(i)); 228 } else if (elmtType == double.class) { 229 Array.set(val, i, ja.getDouble(i)); 230 } else if (elmtType == boolean.class) { 231 Array.set(val, i, ja.getBoolean(i)); 232 } else if (elmtType == String.class) { 233 Array.set(val, i, ja.getString(i)); 234 } else if (elmtType == android.hardware.camera2.Size.class) { 235 JSONObject obj = ja.getJSONObject(i); 236 Array.set(val, i, new android.hardware.camera2.Size( 237 obj.getInt("width"), obj.getInt("height"))); 238 } else if (elmtType == android.graphics.Rect.class) { 239 JSONObject obj = ja.getJSONObject(i); 240 Array.set(val, i, new android.graphics.Rect( 241 obj.getInt("left"), obj.getInt("top"), 242 obj.getInt("bottom"), obj.getInt("right"))); 243 } else if (elmtType == Rational.class) { 244 JSONObject obj = ja.getJSONObject(i); 245 Array.set(val, i, new Rational( 246 obj.getInt("numerator"), 247 obj.getInt("denominator"))); 248 } else { 249 throw new ItsException( 250 "Failed to parse key from JSON: " + keyName); 251 } 252 } 253 if (val != null) { 254 Log.i(TAG, "Set: " + keyName + " -> " + Arrays.toString(val)); 255 md.set(key, val); 256 jsonReq.remove(keyName); 257 } 258 } else { 259 Object val = null; 260 if (keyType == Integer.class) { 261 val = jsonReq.getInt(keyName); 262 } else if (keyType == Byte.class) { 263 val = (byte)jsonReq.getInt(keyName); 264 } else if (keyType == Double.class) { 265 val = jsonReq.getDouble(keyName); 266 } else if (keyType == Long.class) { 267 val = jsonReq.getLong(keyName); 268 } else if (keyType == Float.class) { 269 val = (float)jsonReq.getDouble(keyName); 270 } else if (keyType == Boolean.class) { 271 val = jsonReq.getBoolean(keyName); 272 } else if (keyType == String.class) { 273 val = jsonReq.getString(keyName); 274 } else if (keyType == android.hardware.camera2.Size.class) { 275 JSONObject obj = jsonReq.getJSONObject(keyName); 276 val = new android.hardware.camera2.Size( 277 obj.getInt("width"), obj.getInt("height")); 278 } else if (keyType == android.graphics.Rect.class) { 279 JSONObject obj = jsonReq.getJSONObject(keyName); 280 val = new android.graphics.Rect( 281 obj.getInt("left"), obj.getInt("top"), 282 obj.getInt("right"), obj.getInt("bottom")); 283 } else if (keyType == Rational.class) { 284 JSONObject obj = jsonReq.getJSONObject(keyName); 285 val = new Rational(obj.getInt("numerator"), 286 obj.getInt("denominator")); 287 } else { 288 throw new ItsException( 289 "Failed to parse key from JSON: " + keyName); 290 } 291 if (val != null) { 292 Log.i(TAG, "Set: " + keyName + " -> " + val); 293 md.set(key ,val); 294 jsonReq.remove(keyName); 295 } 296 } 297 } 298 } 299 } 300 } 301 302 // Ensure that there were no invalid keys in the JSON request object. 303 if (jsonReq.length() != 0) { 304 throw new ItsException("Invalid JSON key(s): " + jsonReq.toString()); 305 } 306 307 Log.i(TAG, "Parsing JSON capture request completed"); 308 return md; 309 } catch (java.lang.IllegalAccessException e) { 310 throw new ItsException("Access error: ", e); 311 } catch (org.json.JSONException e) { 312 throw new ItsException("JSON error: ", e); 313 } 314 } 315 316 @SuppressWarnings("unchecked") 317 public static List<CaptureRequest.Builder> deserializeRequestList( 318 CameraDevice device, JSONObject jsonObjTop) 319 throws ItsException { 320 try { 321 List<CaptureRequest.Builder> requests = null; 322 if (jsonObjTop.has("captureRequest")) { 323 JSONObject jsonReq = jsonObjTop.getJSONObject("captureRequest"); 324 CaptureRequest.Builder templateReq = device.createCaptureRequest( 325 CameraDevice.TEMPLATE_STILL_CAPTURE); 326 requests = new LinkedList<CaptureRequest.Builder>(); 327 requests.add(deserialize(templateReq, jsonReq)); 328 } else if (jsonObjTop.has("captureRequestList")) { 329 JSONArray jsonReqs = jsonObjTop.getJSONArray("captureRequestList"); 330 requests = new LinkedList<CaptureRequest.Builder>(); 331 for (int i = 0; i < jsonReqs.length(); i++) { 332 CaptureRequest.Builder templateReq = device.createCaptureRequest( 333 CameraDevice.TEMPLATE_STILL_CAPTURE); 334 requests.add( 335 deserialize(templateReq, jsonReqs.getJSONObject(i))); 336 } 337 } 338 return requests; 339 } catch (org.json.JSONException e) { 340 throw new ItsException("JSON error: ", e); 341 } catch (android.hardware.camera2.CameraAccessException e) { 342 throw new ItsException("Access error: ", e); 343 } 344 } 345} 346