1 /* 2 * Copyright (C) 2011 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 17 18 package android.filterfw.core; 19 20 import android.annotation.UnsupportedAppUsage; 21 import android.filterfw.core.KeyValueMap; 22 import android.filterfw.core.MutableFrameFormat; 23 24 import java.util.Arrays; 25 import java.util.Map.Entry; 26 27 /** 28 * @hide 29 */ 30 public class FrameFormat { 31 32 public static final int TYPE_UNSPECIFIED = 0; 33 public static final int TYPE_BIT = 1; 34 public static final int TYPE_BYTE = 2; 35 public static final int TYPE_INT16 = 3; 36 public static final int TYPE_INT32 = 4; 37 public static final int TYPE_FLOAT = 5; 38 public static final int TYPE_DOUBLE = 6; 39 public static final int TYPE_POINTER = 7; 40 public static final int TYPE_OBJECT = 8; 41 42 public static final int TARGET_UNSPECIFIED = 0; 43 public static final int TARGET_SIMPLE = 1; 44 public static final int TARGET_NATIVE = 2; 45 public static final int TARGET_GPU = 3; 46 public static final int TARGET_VERTEXBUFFER = 4; 47 public static final int TARGET_RS = 5; 48 49 public static final int SIZE_UNSPECIFIED = 0; 50 51 // TODO: When convenience formats are used, consider changing this to 0 and have the convenience 52 // intializers use a proper BPS. 53 public static final int BYTES_PER_SAMPLE_UNSPECIFIED = 1; 54 55 protected static final int SIZE_UNKNOWN = -1; 56 57 protected int mBaseType = TYPE_UNSPECIFIED; 58 protected int mBytesPerSample = 1; 59 protected int mSize = SIZE_UNKNOWN; 60 protected int mTarget = TARGET_UNSPECIFIED; 61 protected int[] mDimensions; 62 protected KeyValueMap mMetaData; 63 protected Class mObjectClass; 64 FrameFormat()65 protected FrameFormat() { 66 } 67 FrameFormat(int baseType, int target)68 public FrameFormat(int baseType, int target) { 69 mBaseType = baseType; 70 mTarget = target; 71 initDefaults(); 72 } 73 unspecified()74 public static FrameFormat unspecified() { 75 return new FrameFormat(TYPE_UNSPECIFIED, TARGET_UNSPECIFIED); 76 } 77 getBaseType()78 public int getBaseType() { 79 return mBaseType; 80 } 81 isBinaryDataType()82 public boolean isBinaryDataType() { 83 return mBaseType >= TYPE_BIT && mBaseType <= TYPE_DOUBLE; 84 } 85 getBytesPerSample()86 public int getBytesPerSample() { 87 return mBytesPerSample; 88 } 89 getValuesPerSample()90 public int getValuesPerSample() { 91 return mBytesPerSample / bytesPerSampleOf(mBaseType); 92 } 93 94 @UnsupportedAppUsage getTarget()95 public int getTarget() { 96 return mTarget; 97 } 98 getDimensions()99 public int[] getDimensions() { 100 return mDimensions; 101 } 102 getDimension(int i)103 public int getDimension(int i) { 104 return mDimensions[i]; 105 } 106 getDimensionCount()107 public int getDimensionCount() { 108 return mDimensions == null ? 0 : mDimensions.length; 109 } 110 hasMetaKey(String key)111 public boolean hasMetaKey(String key) { 112 return mMetaData != null ? mMetaData.containsKey(key) : false; 113 } 114 hasMetaKey(String key, Class expectedClass)115 public boolean hasMetaKey(String key, Class expectedClass) { 116 if (mMetaData != null && mMetaData.containsKey(key)) { 117 if (!expectedClass.isAssignableFrom(mMetaData.get(key).getClass())) { 118 throw new RuntimeException( 119 "FrameFormat meta-key '" + key + "' is of type " + 120 mMetaData.get(key).getClass() + " but expected to be of type " + 121 expectedClass + "!"); 122 } 123 return true; 124 } 125 return false; 126 } 127 getMetaValue(String key)128 public Object getMetaValue(String key) { 129 return mMetaData != null ? mMetaData.get(key) : null; 130 } 131 getNumberOfDimensions()132 public int getNumberOfDimensions() { 133 return mDimensions != null ? mDimensions.length : 0; 134 } 135 getLength()136 public int getLength() { 137 return (mDimensions != null && mDimensions.length >= 1) ? mDimensions[0] : -1; 138 } 139 140 @UnsupportedAppUsage getWidth()141 public int getWidth() { 142 return getLength(); 143 } 144 145 @UnsupportedAppUsage getHeight()146 public int getHeight() { 147 return (mDimensions != null && mDimensions.length >= 2) ? mDimensions[1] : -1; 148 } 149 getDepth()150 public int getDepth() { 151 return (mDimensions != null && mDimensions.length >= 3) ? mDimensions[2] : -1; 152 } 153 getSize()154 public int getSize() { 155 if (mSize == SIZE_UNKNOWN) mSize = calcSize(mDimensions); 156 return mSize; 157 } 158 getObjectClass()159 public Class getObjectClass() { 160 return mObjectClass; 161 } 162 163 @UnsupportedAppUsage mutableCopy()164 public MutableFrameFormat mutableCopy() { 165 MutableFrameFormat result = new MutableFrameFormat(); 166 result.setBaseType(getBaseType()); 167 result.setTarget(getTarget()); 168 result.setBytesPerSample(getBytesPerSample()); 169 result.setDimensions(getDimensions()); 170 result.setObjectClass(getObjectClass()); 171 result.mMetaData = mMetaData == null ? null : (KeyValueMap)mMetaData.clone(); 172 return result; 173 } 174 175 @Override equals(Object object)176 public boolean equals(Object object) { 177 if (this == object) { 178 return true; 179 } 180 181 if (!(object instanceof FrameFormat)) { 182 return false; 183 } 184 185 FrameFormat format = (FrameFormat)object; 186 return format.mBaseType == mBaseType && 187 format.mTarget == mTarget && 188 format.mBytesPerSample == mBytesPerSample && 189 Arrays.equals(format.mDimensions, mDimensions) && 190 format.mMetaData.equals(mMetaData); 191 } 192 193 @Override hashCode()194 public int hashCode() { 195 return 4211 ^ mBaseType ^ mBytesPerSample ^ getSize(); 196 } 197 isCompatibleWith(FrameFormat specification)198 public boolean isCompatibleWith(FrameFormat specification) { 199 // Check base type 200 if (specification.getBaseType() != TYPE_UNSPECIFIED 201 && getBaseType() != specification.getBaseType()) { 202 return false; 203 } 204 205 // Check target 206 if (specification.getTarget() != TARGET_UNSPECIFIED 207 && getTarget() != specification.getTarget()) { 208 return false; 209 } 210 211 // Check bytes per sample 212 if (specification.getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED 213 && getBytesPerSample() != specification.getBytesPerSample()) { 214 return false; 215 } 216 217 // Check number of dimensions 218 if (specification.getDimensionCount() > 0 219 && getDimensionCount() != specification.getDimensionCount()) { 220 return false; 221 } 222 223 // Check dimensions 224 for (int i = 0; i < specification.getDimensionCount(); ++i) { 225 int specDim = specification.getDimension(i); 226 if (specDim != SIZE_UNSPECIFIED && getDimension(i) != specDim) { 227 return false; 228 } 229 } 230 231 // Check class 232 if (specification.getObjectClass() != null) { 233 if (getObjectClass() == null 234 || !specification.getObjectClass().isAssignableFrom(getObjectClass())) { 235 return false; 236 } 237 } 238 239 // Check meta-data 240 if (specification.mMetaData != null) { 241 for (String specKey : specification.mMetaData.keySet()) { 242 if (mMetaData == null 243 || !mMetaData.containsKey(specKey) 244 || !mMetaData.get(specKey).equals(specification.mMetaData.get(specKey))) { 245 return false; 246 } 247 } 248 } 249 250 // Passed all the tests 251 return true; 252 } 253 mayBeCompatibleWith(FrameFormat specification)254 public boolean mayBeCompatibleWith(FrameFormat specification) { 255 // Check base type 256 if (specification.getBaseType() != TYPE_UNSPECIFIED 257 && getBaseType() != TYPE_UNSPECIFIED 258 && getBaseType() != specification.getBaseType()) { 259 return false; 260 } 261 262 // Check target 263 if (specification.getTarget() != TARGET_UNSPECIFIED 264 && getTarget() != TARGET_UNSPECIFIED 265 && getTarget() != specification.getTarget()) { 266 return false; 267 } 268 269 // Check bytes per sample 270 if (specification.getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED 271 && getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED 272 && getBytesPerSample() != specification.getBytesPerSample()) { 273 return false; 274 } 275 276 // Check number of dimensions 277 if (specification.getDimensionCount() > 0 278 && getDimensionCount() > 0 279 && getDimensionCount() != specification.getDimensionCount()) { 280 return false; 281 } 282 283 // Check dimensions 284 for (int i = 0; i < specification.getDimensionCount(); ++i) { 285 int specDim = specification.getDimension(i); 286 if (specDim != SIZE_UNSPECIFIED 287 && getDimension(i) != SIZE_UNSPECIFIED 288 && getDimension(i) != specDim) { 289 return false; 290 } 291 } 292 293 // Check class 294 if (specification.getObjectClass() != null && getObjectClass() != null) { 295 if (!specification.getObjectClass().isAssignableFrom(getObjectClass())) { 296 return false; 297 } 298 } 299 300 // Check meta-data 301 if (specification.mMetaData != null && mMetaData != null) { 302 for (String specKey : specification.mMetaData.keySet()) { 303 if (mMetaData.containsKey(specKey) 304 && !mMetaData.get(specKey).equals(specification.mMetaData.get(specKey))) { 305 return false; 306 } 307 } 308 } 309 310 // Passed all the tests 311 return true; 312 } 313 bytesPerSampleOf(int baseType)314 public static int bytesPerSampleOf(int baseType) { 315 // Defaults based on base-type 316 switch (baseType) { 317 case TYPE_BIT: 318 case TYPE_BYTE: 319 return 1; 320 case TYPE_INT16: 321 return 2; 322 case TYPE_INT32: 323 case TYPE_FLOAT: 324 case TYPE_POINTER: 325 return 4; 326 case TYPE_DOUBLE: 327 return 8; 328 default: 329 return 1; 330 } 331 } 332 dimensionsToString(int[] dimensions)333 public static String dimensionsToString(int[] dimensions) { 334 StringBuffer buffer = new StringBuffer(); 335 if (dimensions != null) { 336 int n = dimensions.length; 337 for (int i = 0; i < n; ++i) { 338 if (dimensions[i] == SIZE_UNSPECIFIED) { 339 buffer.append("[]"); 340 } else { 341 buffer.append("[" + String.valueOf(dimensions[i]) + "]"); 342 } 343 } 344 } 345 return buffer.toString(); 346 } 347 baseTypeToString(int baseType)348 public static String baseTypeToString(int baseType) { 349 switch (baseType) { 350 case TYPE_UNSPECIFIED: return "unspecified"; 351 case TYPE_BIT: return "bit"; 352 case TYPE_BYTE: return "byte"; 353 case TYPE_INT16: return "int"; 354 case TYPE_INT32: return "int"; 355 case TYPE_FLOAT: return "float"; 356 case TYPE_DOUBLE: return "double"; 357 case TYPE_POINTER: return "pointer"; 358 case TYPE_OBJECT: return "object"; 359 default: return "unknown"; 360 } 361 } 362 targetToString(int target)363 public static String targetToString(int target) { 364 switch (target) { 365 case TARGET_UNSPECIFIED: return "unspecified"; 366 case TARGET_SIMPLE: return "simple"; 367 case TARGET_NATIVE: return "native"; 368 case TARGET_GPU: return "gpu"; 369 case TARGET_VERTEXBUFFER: return "vbo"; 370 case TARGET_RS: return "renderscript"; 371 default: return "unknown"; 372 } 373 } 374 metaDataToString(KeyValueMap metaData)375 public static String metaDataToString(KeyValueMap metaData) { 376 if (metaData == null) { 377 return ""; 378 } else { 379 StringBuffer buffer = new StringBuffer(); 380 buffer.append("{ "); 381 for (Entry<String, Object> entry : metaData.entrySet()) { 382 buffer.append(entry.getKey() + ": " + entry.getValue() + " "); 383 } 384 buffer.append("}"); 385 return buffer.toString(); 386 } 387 } 388 readTargetString(String targetString)389 public static int readTargetString(String targetString) { 390 if (targetString.equalsIgnoreCase("CPU") || targetString.equalsIgnoreCase("NATIVE")) { 391 return FrameFormat.TARGET_NATIVE; 392 } else if (targetString.equalsIgnoreCase("GPU")) { 393 return FrameFormat.TARGET_GPU; 394 } else if (targetString.equalsIgnoreCase("SIMPLE")) { 395 return FrameFormat.TARGET_SIMPLE; 396 } else if (targetString.equalsIgnoreCase("VERTEXBUFFER")) { 397 return FrameFormat.TARGET_VERTEXBUFFER; 398 } else if (targetString.equalsIgnoreCase("UNSPECIFIED")) { 399 return FrameFormat.TARGET_UNSPECIFIED; 400 } else { 401 throw new RuntimeException("Unknown target type '" + targetString + "'!"); 402 } 403 } 404 405 // TODO: FromString 406 toString()407 public String toString() { 408 int valuesPerSample = getValuesPerSample(); 409 String sampleCountString = valuesPerSample == 1 ? "" : String.valueOf(valuesPerSample); 410 String targetString = mTarget == TARGET_UNSPECIFIED ? "" : (targetToString(mTarget) + " "); 411 String classString = mObjectClass == null 412 ? "" 413 : (" class(" + mObjectClass.getSimpleName() + ") "); 414 415 return targetString 416 + baseTypeToString(mBaseType) 417 + sampleCountString 418 + dimensionsToString(mDimensions) 419 + classString 420 + metaDataToString(mMetaData); 421 } 422 initDefaults()423 private void initDefaults() { 424 mBytesPerSample = bytesPerSampleOf(mBaseType); 425 } 426 427 // Core internal methods /////////////////////////////////////////////////////////////////////// calcSize(int[] dimensions)428 int calcSize(int[] dimensions) { 429 if (dimensions != null && dimensions.length > 0) { 430 int size = getBytesPerSample(); 431 for (int dim : dimensions) { 432 size *= dim; 433 } 434 return size; 435 } 436 return 0; 437 } 438 isReplaceableBy(FrameFormat format)439 boolean isReplaceableBy(FrameFormat format) { 440 return mTarget == format.mTarget 441 && getSize() == format.getSize() 442 && Arrays.equals(format.mDimensions, mDimensions); 443 } 444 } 445