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