Home | History | Annotate | Download | only in core
      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 
     64     protected FrameFormat() {
     65     }
     66 
     67     public FrameFormat(int baseType, int target) {
     68         mBaseType = baseType;
     69         mTarget = target;
     70         initDefaults();
     71     }
     72 
     73     public static FrameFormat unspecified() {
     74         return new FrameFormat(TYPE_UNSPECIFIED, TARGET_UNSPECIFIED);
     75     }
     76 
     77     public int getBaseType() {
     78         return mBaseType;
     79     }
     80 
     81     public boolean isBinaryDataType() {
     82         return mBaseType >= TYPE_BIT && mBaseType <= TYPE_DOUBLE;
     83     }
     84 
     85     public int getBytesPerSample() {
     86         return mBytesPerSample;
     87     }
     88 
     89     public int getValuesPerSample() {
     90         return mBytesPerSample / bytesPerSampleOf(mBaseType);
     91     }
     92 
     93     public int getTarget() {
     94         return mTarget;
     95     }
     96 
     97     public int[] getDimensions() {
     98         return mDimensions;
     99     }
    100 
    101     public int getDimension(int i) {
    102         return mDimensions[i];
    103     }
    104 
    105     public int getDimensionCount() {
    106         return mDimensions == null ? 0 : mDimensions.length;
    107     }
    108 
    109     public boolean hasMetaKey(String key) {
    110         return mMetaData != null ? mMetaData.containsKey(key) : false;
    111     }
    112 
    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 
    126     public Object getMetaValue(String key) {
    127         return mMetaData != null ? mMetaData.get(key) : null;
    128     }
    129 
    130     public int getNumberOfDimensions() {
    131         return mDimensions != null ? mDimensions.length : 0;
    132     }
    133 
    134     public int getLength() {
    135         return (mDimensions != null && mDimensions.length >= 1) ? mDimensions[0] : -1;
    136     }
    137 
    138     public int getWidth() {
    139         return getLength();
    140     }
    141 
    142     public int getHeight() {
    143         return (mDimensions != null && mDimensions.length >= 2) ? mDimensions[1] : -1;
    144     }
    145 
    146     public int getDepth() {
    147         return (mDimensions != null && mDimensions.length >= 3) ? mDimensions[2] : -1;
    148     }
    149 
    150     public int getSize() {
    151         if (mSize == SIZE_UNKNOWN) mSize = calcSize(mDimensions);
    152         return mSize;
    153     }
    154 
    155     public Class getObjectClass() {
    156         return mObjectClass;
    157     }
    158 
    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
    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
    189     public int hashCode() {
    190         return 4211 ^ mBaseType ^ mBytesPerSample ^ getSize();
    191     }
    192 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    418     private void initDefaults() {
    419         mBytesPerSample = bytesPerSampleOf(mBaseType);
    420     }
    421 
    422     // Core internal methods ///////////////////////////////////////////////////////////////////////
    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 
    434     boolean isReplaceableBy(FrameFormat format) {
    435         return mTarget == format.mTarget
    436             && getSize() == format.getSize()
    437             && Arrays.equals(format.mDimensions, mDimensions);
    438     }
    439 }
    440