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