/* * Copyright (C) 2011 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.filterfw.core; import android.filterfw.core.KeyValueMap; import android.filterfw.core.MutableFrameFormat; import java.util.Arrays; import java.util.Map.Entry; /** * @hide */ public class FrameFormat { public static final int TYPE_UNSPECIFIED = 0; public static final int TYPE_BIT = 1; public static final int TYPE_BYTE = 2; public static final int TYPE_INT16 = 3; public static final int TYPE_INT32 = 4; public static final int TYPE_FLOAT = 5; public static final int TYPE_DOUBLE = 6; public static final int TYPE_POINTER = 7; public static final int TYPE_OBJECT = 8; public static final int TARGET_UNSPECIFIED = 0; public static final int TARGET_SIMPLE = 1; public static final int TARGET_NATIVE = 2; public static final int TARGET_GPU = 3; public static final int TARGET_VERTEXBUFFER = 4; public static final int TARGET_RS = 5; public static final int SIZE_UNSPECIFIED = 0; // TODO: When convenience formats are used, consider changing this to 0 and have the convenience // intializers use a proper BPS. public static final int BYTES_PER_SAMPLE_UNSPECIFIED = 1; protected static final int SIZE_UNKNOWN = -1; protected int mBaseType = TYPE_UNSPECIFIED; protected int mBytesPerSample = 1; protected int mSize = SIZE_UNKNOWN; protected int mTarget = TARGET_UNSPECIFIED; protected int[] mDimensions; protected KeyValueMap mMetaData; protected Class mObjectClass; protected FrameFormat() { } public FrameFormat(int baseType, int target) { mBaseType = baseType; mTarget = target; initDefaults(); } public static FrameFormat unspecified() { return new FrameFormat(TYPE_UNSPECIFIED, TARGET_UNSPECIFIED); } public int getBaseType() { return mBaseType; } public boolean isBinaryDataType() { return mBaseType >= TYPE_BIT && mBaseType <= TYPE_DOUBLE; } public int getBytesPerSample() { return mBytesPerSample; } public int getValuesPerSample() { return mBytesPerSample / bytesPerSampleOf(mBaseType); } public int getTarget() { return mTarget; } public int[] getDimensions() { return mDimensions; } public int getDimension(int i) { return mDimensions[i]; } public int getDimensionCount() { return mDimensions == null ? 0 : mDimensions.length; } public boolean hasMetaKey(String key) { return mMetaData != null ? mMetaData.containsKey(key) : false; } public boolean hasMetaKey(String key, Class expectedClass) { if (mMetaData != null && mMetaData.containsKey(key)) { if (!expectedClass.isAssignableFrom(mMetaData.get(key).getClass())) { throw new RuntimeException( "FrameFormat meta-key '" + key + "' is of type " + mMetaData.get(key).getClass() + " but expected to be of type " + expectedClass + "!"); } return true; } return false; } public Object getMetaValue(String key) { return mMetaData != null ? mMetaData.get(key) : null; } public int getNumberOfDimensions() { return mDimensions != null ? mDimensions.length : 0; } public int getLength() { return (mDimensions != null && mDimensions.length >= 1) ? mDimensions[0] : -1; } public int getWidth() { return getLength(); } public int getHeight() { return (mDimensions != null && mDimensions.length >= 2) ? mDimensions[1] : -1; } public int getDepth() { return (mDimensions != null && mDimensions.length >= 3) ? mDimensions[2] : -1; } public int getSize() { if (mSize == SIZE_UNKNOWN) mSize = calcSize(mDimensions); return mSize; } public Class getObjectClass() { return mObjectClass; } public MutableFrameFormat mutableCopy() { MutableFrameFormat result = new MutableFrameFormat(); result.setBaseType(getBaseType()); result.setTarget(getTarget()); result.setBytesPerSample(getBytesPerSample()); result.setDimensions(getDimensions()); result.setObjectClass(getObjectClass()); result.mMetaData = mMetaData == null ? null : (KeyValueMap)mMetaData.clone(); return result; } @Override public boolean equals(Object object) { if (this == object) { return true; } if (!(object instanceof FrameFormat)) { return false; } FrameFormat format = (FrameFormat)object; return format.mBaseType == mBaseType && format.mTarget == mTarget && format.mBytesPerSample == mBytesPerSample && Arrays.equals(format.mDimensions, mDimensions) && format.mMetaData.equals(mMetaData); } @Override public int hashCode() { return 4211 ^ mBaseType ^ mBytesPerSample ^ getSize(); } public boolean isCompatibleWith(FrameFormat specification) { // Check base type if (specification.getBaseType() != TYPE_UNSPECIFIED && getBaseType() != specification.getBaseType()) { return false; } // Check target if (specification.getTarget() != TARGET_UNSPECIFIED && getTarget() != specification.getTarget()) { return false; } // Check bytes per sample if (specification.getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED && getBytesPerSample() != specification.getBytesPerSample()) { return false; } // Check number of dimensions if (specification.getDimensionCount() > 0 && getDimensionCount() != specification.getDimensionCount()) { return false; } // Check dimensions for (int i = 0; i < specification.getDimensionCount(); ++i) { int specDim = specification.getDimension(i); if (specDim != SIZE_UNSPECIFIED && getDimension(i) != specDim) { return false; } } // Check class if (specification.getObjectClass() != null) { if (getObjectClass() == null || !specification.getObjectClass().isAssignableFrom(getObjectClass())) { return false; } } // Check meta-data if (specification.mMetaData != null) { for (String specKey : specification.mMetaData.keySet()) { if (mMetaData == null || !mMetaData.containsKey(specKey) || !mMetaData.get(specKey).equals(specification.mMetaData.get(specKey))) { return false; } } } // Passed all the tests return true; } public boolean mayBeCompatibleWith(FrameFormat specification) { // Check base type if (specification.getBaseType() != TYPE_UNSPECIFIED && getBaseType() != TYPE_UNSPECIFIED && getBaseType() != specification.getBaseType()) { return false; } // Check target if (specification.getTarget() != TARGET_UNSPECIFIED && getTarget() != TARGET_UNSPECIFIED && getTarget() != specification.getTarget()) { return false; } // Check bytes per sample if (specification.getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED && getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED && getBytesPerSample() != specification.getBytesPerSample()) { return false; } // Check number of dimensions if (specification.getDimensionCount() > 0 && getDimensionCount() > 0 && getDimensionCount() != specification.getDimensionCount()) { return false; } // Check dimensions for (int i = 0; i < specification.getDimensionCount(); ++i) { int specDim = specification.getDimension(i); if (specDim != SIZE_UNSPECIFIED && getDimension(i) != SIZE_UNSPECIFIED && getDimension(i) != specDim) { return false; } } // Check class if (specification.getObjectClass() != null && getObjectClass() != null) { if (!specification.getObjectClass().isAssignableFrom(getObjectClass())) { return false; } } // Check meta-data if (specification.mMetaData != null && mMetaData != null) { for (String specKey : specification.mMetaData.keySet()) { if (mMetaData.containsKey(specKey) && !mMetaData.get(specKey).equals(specification.mMetaData.get(specKey))) { return false; } } } // Passed all the tests return true; } public static int bytesPerSampleOf(int baseType) { // Defaults based on base-type switch (baseType) { case TYPE_BIT: case TYPE_BYTE: return 1; case TYPE_INT16: return 2; case TYPE_INT32: case TYPE_FLOAT: case TYPE_POINTER: return 4; case TYPE_DOUBLE: return 8; default: return 1; } } public static String dimensionsToString(int[] dimensions) { StringBuffer buffer = new StringBuffer(); if (dimensions != null) { int n = dimensions.length; for (int i = 0; i < n; ++i) { if (dimensions[i] == SIZE_UNSPECIFIED) { buffer.append("[]"); } else { buffer.append("[" + String.valueOf(dimensions[i]) + "]"); } } } return buffer.toString(); } public static String baseTypeToString(int baseType) { switch (baseType) { case TYPE_UNSPECIFIED: return "unspecified"; case TYPE_BIT: return "bit"; case TYPE_BYTE: return "byte"; case TYPE_INT16: return "int"; case TYPE_INT32: return "int"; case TYPE_FLOAT: return "float"; case TYPE_DOUBLE: return "double"; case TYPE_POINTER: return "pointer"; case TYPE_OBJECT: return "object"; default: return "unknown"; } } public static String targetToString(int target) { switch (target) { case TARGET_UNSPECIFIED: return "unspecified"; case TARGET_SIMPLE: return "simple"; case TARGET_NATIVE: return "native"; case TARGET_GPU: return "gpu"; case TARGET_VERTEXBUFFER: return "vbo"; case TARGET_RS: return "renderscript"; default: return "unknown"; } } public static String metaDataToString(KeyValueMap metaData) { if (metaData == null) { return ""; } else { StringBuffer buffer = new StringBuffer(); buffer.append("{ "); for (Entry entry : metaData.entrySet()) { buffer.append(entry.getKey() + ": " + entry.getValue() + " "); } buffer.append("}"); return buffer.toString(); } } public static int readTargetString(String targetString) { if (targetString.equalsIgnoreCase("CPU") || targetString.equalsIgnoreCase("NATIVE")) { return FrameFormat.TARGET_NATIVE; } else if (targetString.equalsIgnoreCase("GPU")) { return FrameFormat.TARGET_GPU; } else if (targetString.equalsIgnoreCase("SIMPLE")) { return FrameFormat.TARGET_SIMPLE; } else if (targetString.equalsIgnoreCase("VERTEXBUFFER")) { return FrameFormat.TARGET_VERTEXBUFFER; } else if (targetString.equalsIgnoreCase("UNSPECIFIED")) { return FrameFormat.TARGET_UNSPECIFIED; } else { throw new RuntimeException("Unknown target type '" + targetString + "'!"); } } // TODO: FromString public String toString() { int valuesPerSample = getValuesPerSample(); String sampleCountString = valuesPerSample == 1 ? "" : String.valueOf(valuesPerSample); String targetString = mTarget == TARGET_UNSPECIFIED ? "" : (targetToString(mTarget) + " "); String classString = mObjectClass == null ? "" : (" class(" + mObjectClass.getSimpleName() + ") "); return targetString + baseTypeToString(mBaseType) + sampleCountString + dimensionsToString(mDimensions) + classString + metaDataToString(mMetaData); } private void initDefaults() { mBytesPerSample = bytesPerSampleOf(mBaseType); } // Core internal methods /////////////////////////////////////////////////////////////////////// int calcSize(int[] dimensions) { if (dimensions != null && dimensions.length > 0) { int size = getBytesPerSample(); for (int dim : dimensions) { size *= dim; } return size; } return 0; } boolean isReplaceableBy(FrameFormat format) { return mTarget == format.mTarget && getSize() == format.getSize() && Arrays.equals(format.mDimensions, mDimensions); } }