Home | History | Annotate | Download | only in filterfw
      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 androidx.media.filterfw;
     19 
     20 import java.util.HashMap;
     21 import java.util.HashSet;
     22 import java.util.Map.Entry;
     23 import java.util.Set;
     24 
     25 /**
     26  * A Signature holds the specification for a filter's input and output ports.
     27  *
     28  * A Signature instance must be returned by the filter's {@link Filter#getSignature()} method. It
     29  * specifies the number and names of the filter's input and output ports, whether or not they
     30  * are required, how data for those ports are accessed, and more. A Signature does not change over
     31  * time. This makes Signatures useful for understanding how a filter can be integrated into a
     32  * graph.
     33  *
     34  * There are a number of flags that can be specified for each input and output port. The flag
     35  * {@code PORT_REQUIRED} indicates that the user must connect the specified port. On the other hand,
     36  * {@code PORT_OPTIONAL} indicates that a port may be connected by the user.
     37  *
     38  * If ports other than the ones in the Signature are allowed, they default to the most generic
     39  * format, that allows passing in any type of Frame. Thus, if more granular access is needed to
     40  * a frame's data, it must be specified in the Signature.
     41  */
     42 public class Signature {
     43 
     44     private HashMap<String, PortInfo> mInputPorts = null;
     45     private HashMap<String, PortInfo> mOutputPorts = null;
     46     private boolean mAllowOtherInputs = true;
     47     private boolean mAllowOtherOutputs = true;
     48 
     49     static class PortInfo {
     50         public int flags;
     51         public FrameType type;
     52 
     53         public PortInfo() {
     54             flags = 0;
     55             type = FrameType.any();
     56         }
     57 
     58         public PortInfo(int flags, FrameType type) {
     59             this.flags = flags;
     60             this.type = type;
     61         }
     62 
     63         public boolean isRequired() {
     64             return (flags & PORT_REQUIRED) != 0;
     65         }
     66 
     67         public String toString(String ioMode, String name) {
     68             String ioName = ioMode + " " + name;
     69             String modeName = isRequired() ? "required" : "optional";
     70             return modeName + " " + ioName + ": " + type.toString();
     71         }
     72     }
     73 
     74     /** Indicates that the port must be connected in the graph. */
     75     public static final int PORT_REQUIRED = 0x02;
     76     /** Indicates that the port may be connected in the graph . */
     77     public static final int PORT_OPTIONAL = 0x01;
     78 
     79     /**
     80      * Creates a new empty Signature.
     81      */
     82     public Signature() {
     83     }
     84 
     85     /**
     86      * Adds an input port to the Signature.
     87      *
     88      * @param name the name of the input port. Must be unique among input port names.
     89      * @param flags a combination of port flags.
     90      * @param type the type of the input frame.
     91      * @return this Signature instance.
     92      */
     93     public Signature addInputPort(String name, int flags, FrameType type) {
     94         addInputPort(name, new PortInfo(flags, type));
     95         return this;
     96     }
     97 
     98     /**
     99      * Adds an output port to the Signature.
    100      *
    101      * @param name the name of the output port. Must be unique among output port names.
    102      * @param flags a combination of port flags.
    103      * @param type the type of the output frame.
    104      * @return this Signature instance.
    105      */
    106     public Signature addOutputPort(String name, int flags, FrameType type) {
    107         addOutputPort(name, new PortInfo(flags, type));
    108         return this;
    109     }
    110 
    111     /**
    112      * Disallows the user from adding any other input ports.
    113      * Adding any input port not explicitly specified in this Signature will cause an error.
    114      * @return this Signature instance.
    115      */
    116     public Signature disallowOtherInputs() {
    117         mAllowOtherInputs = false;
    118         return this;
    119     }
    120 
    121     /**
    122      * Disallows the user from adding any other output ports.
    123      * Adding any output port not explicitly specified in this Signature will cause an error.
    124      * @return this Signature instance.
    125      */
    126     public Signature disallowOtherOutputs() {
    127         mAllowOtherOutputs = false;
    128         return this;
    129     }
    130 
    131     /**
    132      * Disallows the user from adding any other ports.
    133      * Adding any input or output port not explicitly specified in this Signature will cause an
    134      * error.
    135      * @return this Signature instance.
    136      */
    137     public Signature disallowOtherPorts() {
    138         mAllowOtherInputs = false;
    139         mAllowOtherOutputs = false;
    140         return this;
    141     }
    142 
    143     @Override
    144     public String toString() {
    145         StringBuffer stringBuffer = new StringBuffer();
    146         for (Entry<String, PortInfo> entry : mInputPorts.entrySet()) {
    147             stringBuffer.append(entry.getValue().toString("input", entry.getKey()) + "\n");
    148         }
    149         for (Entry<String, PortInfo> entry : mOutputPorts.entrySet()) {
    150             stringBuffer.append(entry.getValue().toString("output", entry.getKey()) + "\n");
    151         }
    152         if (!mAllowOtherInputs) {
    153             stringBuffer.append("disallow other inputs\n");
    154         }
    155         if (!mAllowOtherOutputs) {
    156             stringBuffer.append("disallow other outputs\n");
    157         }
    158         return stringBuffer.toString();
    159     }
    160 
    161     PortInfo getInputPortInfo(String name) {
    162         PortInfo result = mInputPorts != null ? mInputPorts.get(name) : null;
    163         return result != null ? result : new PortInfo();
    164     }
    165 
    166     PortInfo getOutputPortInfo(String name) {
    167         PortInfo result = mOutputPorts != null ? mOutputPorts.get(name) : null;
    168         return result != null ? result : new PortInfo();
    169     }
    170 
    171     void checkInputPortsConform(Filter filter) {
    172         Set<String> filterInputs = new HashSet<String>();
    173         filterInputs.addAll(filter.getConnectedInputPortMap().keySet());
    174         if (mInputPorts != null) {
    175             for (Entry<String, PortInfo> entry : mInputPorts.entrySet()) {
    176                 String portName = entry.getKey();
    177                 PortInfo portInfo = entry.getValue();
    178                 InputPort inputPort = filter.getConnectedInputPort(portName);
    179                 if (inputPort == null && portInfo.isRequired()) {
    180                     throw new RuntimeException("Filter " + filter + " does not have required "
    181                         + "input port '" + portName + "'!");
    182                 }
    183                 filterInputs.remove(portName);
    184             }
    185         }
    186         if (!mAllowOtherInputs && !filterInputs.isEmpty()) {
    187             throw new RuntimeException("Filter " + filter + " has invalid input ports: "
    188                 + filterInputs + "!");
    189         }
    190     }
    191 
    192     void checkOutputPortsConform(Filter filter) {
    193         Set<String> filterOutputs = new HashSet<String>();
    194         filterOutputs.addAll(filter.getConnectedOutputPortMap().keySet());
    195         if (mOutputPorts != null) {
    196             for (Entry<String, PortInfo> entry : mOutputPorts.entrySet()) {
    197                 String portName = entry.getKey();
    198                 PortInfo portInfo = entry.getValue();
    199                 OutputPort outputPort = filter.getConnectedOutputPort(portName);
    200                 if (outputPort == null && portInfo.isRequired()) {
    201                     throw new RuntimeException("Filter " + filter + " does not have required "
    202                         + "output port '" + portName + "'!");
    203                 }
    204                 filterOutputs.remove(portName);
    205             }
    206         }
    207         if (!mAllowOtherOutputs && !filterOutputs.isEmpty()) {
    208             throw new RuntimeException("Filter " + filter + " has invalid output ports: "
    209                 + filterOutputs + "!");
    210         }
    211     }
    212 
    213     HashMap<String, PortInfo> getInputPorts() {
    214         return mInputPorts;
    215     }
    216 
    217     HashMap<String, PortInfo> getOutputPorts() {
    218         return mOutputPorts;
    219     }
    220 
    221     private void addInputPort(String name, PortInfo portInfo) {
    222         if (mInputPorts == null) {
    223             mInputPorts = new HashMap<String, PortInfo>();
    224         }
    225         if (mInputPorts.containsKey(name)) {
    226             throw new RuntimeException("Attempting to add duplicate input port '" + name + "'!");
    227         }
    228         mInputPorts.put(name, portInfo);
    229     }
    230 
    231     private void addOutputPort(String name, PortInfo portInfo) {
    232         if (mOutputPorts == null) {
    233             mOutputPorts = new HashMap<String, PortInfo>();
    234         }
    235         if (mOutputPorts.containsKey(name)) {
    236             throw new RuntimeException("Attempting to add duplicate output port '" + name + "'!");
    237         }
    238         mOutputPorts.put(name, portInfo);
    239     }
    240 }
    241 
    242