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