13c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin/* 23c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Copyright (C) 2014 The Android Open Source Project 33c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * 43c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License"); 53c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * you may not use this file except in compliance with the License. 63c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * You may obtain a copy of the License at 73c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * 83c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * http://www.apache.org/licenses/LICENSE-2.0 93c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * 103c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Unless required by applicable law or agreed to in writing, software 113c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS, 123c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * See the License for the specific language governing permissions and 143c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * limitations under the License. 153c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */ 163c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinpackage android.hardware.camera2.marshal.impl; 173c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 183c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.Marshaler; 193c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.MarshalQueryable; 203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.marshal.MarshalRegistry; 213c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.utils.TypeReference; 223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.util.Log; 233c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 243c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.lang.reflect.Array; 253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.nio.ByteBuffer; 263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport java.util.ArrayList; 273c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 283c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport static android.hardware.camera2.impl.CameraMetadataNative.*; 293c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport static android.hardware.camera2.marshal.MarshalHelpers.*; 303c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 313c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin/** 323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Marshal any array {@code T}. 333c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * 343c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type 353c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * also has to exist.</p> 363c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * 373c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a 383c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * built-in primitive (e.g. int[], float[], etc).</p> 393c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 403c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * @param <T> the type of the array (e.g. T = int[], or T = Rational[]) 413c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */ 423c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinpublic class MarshalQueryableArray<T> implements MarshalQueryable<T> { 433c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 443c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private static final String TAG = MarshalQueryableArray.class.getSimpleName(); 453c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 463c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 473c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private class MarshalerArray extends Marshaler<T> { 483c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private final Class<T> mClass; 493c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private final Marshaler<?> mComponentMarshaler; 503c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private final Class<?> mComponentClass; 513c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 523c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @SuppressWarnings("unchecked") 533c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin protected MarshalerArray(TypeReference<T> typeReference, int nativeType) { 543c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin super(MarshalQueryableArray.this, typeReference, nativeType); 553c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 563c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin mClass = (Class<T>)typeReference.getRawType(); 573c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 583c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin TypeReference<?> componentToken = typeReference.getComponentType(); 593c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType); 603c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin mComponentClass = componentToken.getRawType(); 613c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 623c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 633c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @Override 643c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin public void marshal(T value, ByteBuffer buffer) { 653c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int length = Array.getLength(value); 663c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin for (int i = 0; i < length; ++i) { 673c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin marshalArrayElement(mComponentMarshaler, buffer, value, i); 683c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 693c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 703c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 713c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @Override 723c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin public T unmarshal(ByteBuffer buffer) { 733c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Object array; 743c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 753c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int elementSize = mComponentMarshaler.getNativeSize(); 763c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 773c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) { 783c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int remaining = buffer.remaining(); 793c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int arraySize = remaining / elementSize; 803c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 813c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin if (remaining % elementSize != 0) { 823c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin throw new UnsupportedOperationException("Arrays for " + mTypeReference 833c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin + " must be packed tighly into a multiple of " + elementSize 843c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin + "; but there are " + (remaining % elementSize) + " left over bytes"); 853c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 863c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 873c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin if (VERBOSE) { 883c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Log.v(TAG, String.format( 893c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin "Attempting to unpack array (count = %d, element size = %d, bytes " 903c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin + "remaining = %d) for type %s", 913c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin arraySize, elementSize, remaining, mClass)); 923c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 933c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 943c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin array = Array.newInstance(mComponentClass, arraySize); 953c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin for (int i = 0; i < arraySize; ++i) { 963c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Object elem = mComponentMarshaler.unmarshal(buffer); 973c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Array.set(array, i, elem); 983c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 993c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } else { 1003c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // Dynamic size, use an array list. 1013c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin ArrayList<Object> arrayList = new ArrayList<Object>(); 1023c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1033c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // Assumes array is packed tightly; no unused bytes allowed 1043c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin while (buffer.hasRemaining()) { 1053c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Object elem = mComponentMarshaler.unmarshal(buffer); 1063c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin arrayList.add(elem); 1073c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1083c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1093c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int arraySize = arrayList.size(); 1103c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize)); 1113c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1123c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1133c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin if (buffer.remaining() != 0) { 1143c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking " 1153c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin + mClass); 1163c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1173c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1183c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return mClass.cast(array); 1193c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1213c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @Override 1223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin public int getNativeSize() { 1233c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return NATIVE_SIZE_DYNAMIC; 1243c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1253c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @Override 1273c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin public int calculateMarshalSize(T value) { 1283c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int elementSize = mComponentMarshaler.getNativeSize(); 1293c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int arrayLength = Array.getLength(value); 1303c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1313c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) { 1323c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // The fast way. Every element size is uniform. 1333c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return elementSize * arrayLength; 1343c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } else { 1353c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // The slow way. Accumulate size for each element. 1363c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin int size = 0; 1373c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin for (int i = 0; i < arrayLength; ++i) { 1383c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin size += calculateElementMarshalSize(mComponentMarshaler, value, i); 1393c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1403c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1413c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return size; 1423c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1433c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1443c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1453c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin /* 1463c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin * Helpers to avoid compiler errors regarding types with wildcards (?) 1473c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin */ 1483c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1493c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @SuppressWarnings("unchecked") 1503c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler, 1513c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin ByteBuffer buffer, Object array, int index) { 1523c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin marshaler.marshal((TElem)Array.get(array, index), buffer); 1533c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1543c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1553c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @SuppressWarnings("unchecked") 1563c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) { 1573c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return arrayList.toArray((T[]) arrayDest); 1583c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1593c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1603c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @SuppressWarnings("unchecked") 1613c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler, 1623c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Object array, int index) { 1633c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin Object elem = Array.get(array, index); 1643c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1653c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return marshaler.calculateMarshalSize((TElem) elem); 1663c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1673c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1683c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1693c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @Override 1703c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) { 1713c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return new MarshalerArray(managedType, nativeType); 1723c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1733c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1743c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin @Override 1753c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) { 1763c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // support both ConcreteType[] and GenericType<ConcreteType>[] 1773c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin return managedType.getRawType().isArray(); 1783c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin 1793c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // TODO: Should this recurse deeper and check that there is 1803c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin // a valid marshaler for the ConcreteType as well? 1813c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin } 1823c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin} 183