diff options
author | Igor Murashkin <iam@google.com> | 2013-07-18 20:11:17 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2013-07-19 12:04:48 -0700 |
commit | 3710db80d4b9e573d775790e4c9a2ab6e062201e (patch) | |
tree | 75ca64515cc2aba0f97c9334e454bf0d90636d78 /core/java/android/hardware | |
parent | 27b62ae8eb4623cef45d29c704aaf169f8c76025 (diff) | |
download | frameworks_base-3710db80d4b9e573d775790e4c9a2ab6e062201e.zip frameworks_base-3710db80d4b9e573d775790e4c9a2ab6e062201e.tar.gz frameworks_base-3710db80d4b9e573d775790e4c9a2ab6e062201e.tar.bz2 |
camera2 api: marshal rect, size, string for metadata
Change-Id: Iec2fd823bc92394da44abb32ca38a625d7638e3d
Diffstat (limited to 'core/java/android/hardware')
5 files changed, 361 insertions, 7 deletions
diff --git a/core/java/android/hardware/photography/CameraMetadata.java b/core/java/android/hardware/photography/CameraMetadata.java index 4633b2f..c024c05 100644 --- a/core/java/android/hardware/photography/CameraMetadata.java +++ b/core/java/android/hardware/photography/CameraMetadata.java @@ -16,6 +16,10 @@ package android.hardware.photography; +import android.hardware.photography.impl.MetadataMarshalClass; +import android.hardware.photography.impl.MetadataMarshalRect; +import android.hardware.photography.impl.MetadataMarshalSize; +import android.hardware.photography.impl.MetadataMarshalString; import android.os.Parcelable; import android.os.Parcel; import android.util.Log; @@ -85,6 +89,11 @@ public class CameraMetadata implements Parcelable, AutoCloseable { public <T> void set(Key<T> key, T value) { int tag = key.getTag(); + if (value == null) { + writeValues(tag, null); + return; + } + int nativeType = getNativeType(tag); int size = packSingle(value, null, key.mType, nativeType, /* sizeOnly */true); @@ -265,6 +274,11 @@ public class CameraMetadata implements Parcelable, AutoCloseable { private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType, boolean sizeOnly) { + MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); + if (marshaler != null) { + return marshaler.marshal(value, buffer, nativeType, sizeOnly); + } + /** * FIXME: This doesn't actually work because getFields() returns fields in an unordered * manner. Although we could sort and get the data to come out correctly on the *java* side, @@ -558,6 +572,11 @@ public class CameraMetadata implements Parcelable, AutoCloseable { private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) { + MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType); + if (marshaler != null) { + return marshaler.unmarshal(buffer, nativeType); + } + /** * FIXME: This doesn't actually work because getFields() returns fields in an unordered * manner. Although we could sort and get the data to come out correctly on the *java* side, @@ -611,14 +630,44 @@ public class CameraMetadata implements Parcelable, AutoCloseable { Class<?> componentType = type.getComponentType(); Object array; - int remaining = buffer.remaining(); - // FIXME: Assumes that the rest of the ByteBuffer is part of the array. - int arraySize = remaining / getTypeSize(nativeType); + int elementSize = getTypeSize(nativeType); + + MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType); + if (marshaler != null) { + elementSize = marshaler.getNativeSize(nativeType); + } + + if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) { + int remaining = buffer.remaining(); + int arraySize = remaining / elementSize; + + Log.v(TAG, + String.format( + "Attempting to unpack array (count = %d, element size = %d, bytes " + + "remaining = %d) for type %s", + arraySize, elementSize, remaining, type)); + + array = Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; ++i) { + Object elem = unpackSingle(buffer, componentType, nativeType); + Array.set(array, i, elem); + } + } else { + // Dynamic size, use an array list. + ArrayList<Object> arrayList = new ArrayList<Object>(); + + int primitiveSize = getTypeSize(nativeType); + while (buffer.remaining() >= primitiveSize) { + Object elem = unpackSingle(buffer, componentType, nativeType); + arrayList.add(elem); + } - array = Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; ++i) { - Object elem = unpackSingle(buffer, componentType, nativeType); - Array.set(array, i, elem); + array = arrayList.toArray((T[]) Array.newInstance(componentType, 0)); + } + + if (buffer.remaining() != 0) { + Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking " + + type); } return (T) array; @@ -927,11 +976,39 @@ public class CameraMetadata implements Parcelable, AutoCloseable { return values[ordinal]; } + static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new + HashMap<Class<?>, MetadataMarshalClass<?>>(); + + private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) { + sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler); + } + + @SuppressWarnings("unchecked") + private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) { + MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type); + + if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) { + throw new UnsupportedOperationException("Unsupported type " + nativeType + + " to be marshalled to/from a " + type); + } + + return marshaler; + } + /** * We use a class initializer to allow the native code to cache some field offsets */ static { System.loadLibrary("media_jni"); nativeClassInit(); + + Log.v(TAG, "Shall register metadata marshalers"); + + // load built-in marshallers + registerMarshaler(new MetadataMarshalRect()); + registerMarshaler(new MetadataMarshalSize()); + registerMarshaler(new MetadataMarshalString()); + + Log.v(TAG, "Registered metadata marshalers"); } } diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalClass.java b/core/java/android/hardware/photography/impl/MetadataMarshalClass.java new file mode 100644 index 0000000..a70784d --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalClass.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.photography.impl; + +import java.nio.ByteBuffer; + +public interface MetadataMarshalClass<T> { + + /** + * Marshal the specified object instance (value) into a byte buffer. + * + * @param value the value of type T that we wish to write into the byte buffer + * @param buffer the byte buffer into which the marshalled object will be written + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}. + * Guaranteed to be one for which isNativeTypeSupported returns true. + * @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only. + * @return the size that needs to be written to the byte buffer + */ + int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly); + + /** + * Unmarshal a new object instance from the byte buffer. + * @param buffer the byte buffer, from which we will read the object + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}. + * Guaranteed to be one for which isNativeTypeSupported returns true. + * @return a new instance of type T read from the byte buffer + */ + T unmarshal(ByteBuffer buffer, int nativeType); + + Class<T> getMarshalingClass(); + + /** + * Determines whether or not this marshaller supports this native type. Most marshallers + * will are likely to only support one type. + * + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE} + * @return true if it supports, false otherwise + */ + boolean isNativeTypeSupported(int nativeType); + + public static int NATIVE_SIZE_DYNAMIC = -1; + + /** + * How many bytes T will take up if marshalled to/from nativeType + * @param nativeType the native type, e.g. + * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE} + * @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic + */ + int getNativeSize(int nativeType); +} diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalRect.java b/core/java/android/hardware/photography/impl/MetadataMarshalRect.java new file mode 100644 index 0000000..d6636ac --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalRect.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.photography.impl; + +import android.graphics.Rect; +import android.hardware.photography.CameraMetadata; + +import java.nio.ByteBuffer; + +public class MetadataMarshalRect implements MetadataMarshalClass<Rect> { + private static final int SIZE = 16; + + @Override + public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) { + if (sizeOnly) { + return SIZE; + } + + buffer.putInt(value.left); + buffer.putInt(value.top); + buffer.putInt(value.width()); + buffer.putInt(value.height()); + + return SIZE; + } + + @Override + public Rect unmarshal(ByteBuffer buffer, int nativeType) { + + int left = buffer.getInt(); + int top = buffer.getInt(); + int width = buffer.getInt(); + int height = buffer.getInt(); + + int right = left + width; + int bottom = top + height; + + return new Rect(left, top, right, bottom); + } + + @Override + public Class<Rect> getMarshalingClass() { + return Rect.class; + } + + @Override + public boolean isNativeTypeSupported(int nativeType) { + return nativeType == CameraMetadata.TYPE_INT32; + } + + @Override + public int getNativeSize(int nativeType) { + return SIZE; + } +} diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalSize.java b/core/java/android/hardware/photography/impl/MetadataMarshalSize.java new file mode 100644 index 0000000..430219c --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalSize.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.photography.impl; + +import android.hardware.photography.CameraMetadata; +import android.hardware.photography.Size; + +import java.nio.ByteBuffer; + +public class MetadataMarshalSize implements MetadataMarshalClass<Size> { + + private static final int SIZE = 8; + + @Override + public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) { + if (sizeOnly) { + return SIZE; + } + + buffer.putInt(value.getWidth()); + buffer.putInt(value.getHeight()); + + return SIZE; + } + + @Override + public Size unmarshal(ByteBuffer buffer, int nativeType) { + int width = buffer.getInt(); + int height = buffer.getInt(); + + return new Size(width, height); + } + + @Override + public Class<Size> getMarshalingClass() { + return Size.class; + } + + @Override + public boolean isNativeTypeSupported(int nativeType) { + return nativeType == CameraMetadata.TYPE_INT32; + } + + @Override + public int getNativeSize(int nativeType) { + return SIZE; + } +} diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalString.java b/core/java/android/hardware/photography/impl/MetadataMarshalString.java new file mode 100644 index 0000000..81123ee --- /dev/null +++ b/core/java/android/hardware/photography/impl/MetadataMarshalString.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.photography.impl; + +import android.hardware.photography.CameraMetadata; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +public class MetadataMarshalString implements MetadataMarshalClass<String> { + + private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); + + @Override + public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) { + byte[] arr = value.getBytes(UTF8_CHARSET); + + if (!sizeOnly) { + buffer.put(arr); + buffer.put((byte)0); // metadata strings are NULL-terminated + } + + return arr.length + 1; + } + + @Override + public String unmarshal(ByteBuffer buffer, int nativeType) { + + buffer.mark(); // save the current position + + boolean foundNull = false; + int stringLength = 0; + while (buffer.hasRemaining()) { + if (buffer.get() == (byte)0) { + foundNull = true; + break; + } + + stringLength++; + } + if (!foundNull) { + throw new IllegalArgumentException("Strings must be null-terminated"); + } + + buffer.reset(); // go back to the previously marked position + + byte[] strBytes = new byte[stringLength + 1]; + buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character + + // not including null character + return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET); + } + + @Override + public Class<String> getMarshalingClass() { + return String.class; + } + + @Override + public boolean isNativeTypeSupported(int nativeType) { + return nativeType == CameraMetadata.TYPE_BYTE; + } + + @Override + public int getNativeSize(int nativeType) { + return NATIVE_SIZE_DYNAMIC; + } +} |