165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/* 265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project 365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License"); 565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License. 665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at 765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * http://www.apache.org/licenses/LICENSE-2.0 965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software 1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS, 1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and 1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License. 1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpackage android.filterfw.core; 1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.HashMap; 2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.HashSet; 2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Iterator; 2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.LinkedList; 2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Map.Entry; 2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Set; 2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Stack; 2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterContext; 2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.KeyValueMap; 3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterpacks.base.FrameBranch; 3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterpacks.base.NullFilter; 3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.util.Log; 3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/** 3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide 3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic class FilterGraph { 3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private HashSet<Filter> mFilters = new HashSet<Filter>(); 4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private HashMap<String, Filter> mNameMap = new HashMap<String, Filter>(); 4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private HashMap<OutputPort, LinkedList<InputPort>> mPreconnections = new 4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn HashMap<OutputPort, LinkedList<InputPort>>(); 4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public static final int AUTOBRANCH_OFF = 0; 4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public static final int AUTOBRANCH_SYNCED = 1; 4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public static final int AUTOBRANCH_UNSYNCED = 2; 4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public static final int TYPECHECK_OFF = 0; 5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public static final int TYPECHECK_DYNAMIC = 1; 5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public static final int TYPECHECK_STRICT = 2; 5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mIsReady = false; 5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mAutoBranchMode = AUTOBRANCH_OFF; 5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mTypeCheckMode = TYPECHECK_STRICT; 5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mDiscardUnconnectedOutputs = false; 5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mLogVerbose; 5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private String TAG = "FilterGraph"; 6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public FilterGraph() { 6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public boolean addFilter(Filter filter) { 6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!containsFilter(filter)) { 6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFilters.add(filter); 6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNameMap.put(filter.getName(), filter); 6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public boolean containsFilter(Filter filter) { 7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return mFilters.contains(filter); 7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public Filter getFilter(String name) { 7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return mNameMap.get(name); 8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void connect(Filter source, 8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String outputName, 8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Filter target, 8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String inputName) { 8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (source == null || target == null) { 8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new IllegalArgumentException("Passing null Filter in connect()!"); 8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (!containsFilter(source) || !containsFilter(target)) { 8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Attempting to connect filter not in graph!"); 9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn OutputPort outPort = source.getOutputPort(outputName); 9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn InputPort inPort = target.getInputPort(inputName); 9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (outPort == null) { 9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Unknown output port '" + outputName + "' on Filter " + 9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn source + "!"); 9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (inPort == null) { 9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Unknown input port '" + inputName + "' on Filter " + 9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn target + "!"); 10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn preconnect(outPort, inPort); 10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void connect(String sourceName, 10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String outputName, 10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String targetName, 10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String inputName) { 10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Filter source = getFilter(sourceName); 11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Filter target = getFilter(targetName); 11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (source == null) { 11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException( 11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "Attempting to connect unknown source filter '" + sourceName + "'!"); 11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (target == null) { 11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException( 11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "Attempting to connect unknown target filter '" + targetName + "'!"); 11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn connect(source, outputName, target, inputName); 11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public Set<Filter> getFilters() { 12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return mFilters; 12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void beginProcessing() { 12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening all filter connections..."); 12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : mFilters) { 12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn filter.openOutputs(); 12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mIsReady = true; 13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void flushFrames() { 13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : mFilters) { 13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn filter.clearOutputs(); 13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void closeFilters(FilterContext context) { 14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Closing all filters..."); 14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : mFilters) { 14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn filter.performClose(context); 14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mIsReady = false; 14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public boolean isReady() { 14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return mIsReady; 14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void setAutoBranchMode(int autoBranchMode) { 15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mAutoBranchMode = autoBranchMode; 15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void setDiscardUnconnectedOutputs(boolean discard) { 15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mDiscardUnconnectedOutputs = discard; 15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void setTypeCheckMode(int typeCheckMode) { 16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mTypeCheckMode = typeCheckMode; 16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void tearDown(FilterContext context) { 16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mFilters.isEmpty()) { 16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn flushFrames(); 16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : mFilters) { 16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn filter.performTearDown(context); 16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFilters.clear(); 17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNameMap.clear(); 17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mIsReady = false; 17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean readyForProcessing(Filter filter, Set<Filter> processed) { 17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Check if this has been already processed 17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (processed.contains(filter)) { 17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Check if all dependencies have been processed 18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (InputPort port : filter.getInputPorts()) { 18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Filter dependency = port.getSourceFilter(); 18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (dependency != null && !processed.contains(dependency)) { 18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void runTypeCheck() { 19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Stack<Filter> filterStack = new Stack<Filter>(); 19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Set<Filter> processedFilters = new HashSet<Filter>(); 19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn filterStack.addAll(getSourceFilters()); 19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn while (!filterStack.empty()) { 19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Get current filter and mark as processed 19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Filter filter = filterStack.pop(); 19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn processedFilters.add(filter); 20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Anchor output formats 20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn updateOutputs(filter); 20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Perform type check 20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Running type check on " + filter + "..."); 20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn runTypeCheckOn(filter); 20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Push connected filters onto stack 20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (OutputPort port : filter.getOutputPorts()) { 21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Filter target = port.getTargetFilter(); 21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (target != null && readyForProcessing(target, processedFilters)) { 21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn filterStack.push(target); 21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Make sure all ports were setup 21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (processedFilters.size() != getFilters().size()) { 21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Could not schedule all filters! Is your graph malformed?"); 22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void updateOutputs(Filter filter) { 22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (OutputPort outputPort : filter.getOutputPorts()) { 22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn InputPort inputPort = outputPort.getBasePort(); 22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (inputPort != null) { 22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat inputFormat = inputPort.getSourceFormat(); 22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat outputFormat = filter.getOutputFormat(outputPort.getName(), 22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn inputFormat); 23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (outputFormat == null) { 23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Filter did not return an output format for " 23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + outputPort + "!"); 23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn outputPort.setPortFormat(outputFormat); 23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void runTypeCheckOn(Filter filter) { 24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (InputPort inputPort : filter.getInputPorts()) { 24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Type checking port " + inputPort); 24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat sourceFormat = inputPort.getSourceFormat(); 24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat targetFormat = inputPort.getPortFormat(); 24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (sourceFormat != null && targetFormat != null) { 24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Checking " + sourceFormat + " against " + targetFormat + "."); 24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn boolean compatible = true; 24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn switch (mTypeCheckMode) { 24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case TYPECHECK_OFF: 25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn inputPort.setChecksType(false); 25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case TYPECHECK_DYNAMIC: 25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn compatible = sourceFormat.mayBeCompatibleWith(targetFormat); 25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn inputPort.setChecksType(true); 25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case TYPECHECK_STRICT: 25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn compatible = sourceFormat.isCompatibleWith(targetFormat); 25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn inputPort.setChecksType(false); 25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!compatible) { 26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Type mismatch: Filter " + filter + " expects a " 26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + "format of type " + targetFormat + " but got a format of type " 26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + sourceFormat + "!"); 26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void checkConnections() { 27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // TODO 27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void discardUnconnectedOutputs() { 27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Connect unconnected ports to Null filters 27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn LinkedList<Filter> addedFilters = new LinkedList<Filter>(); 27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : mFilters) { 27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int id = 0; 28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (OutputPort port : filter.getOutputPorts()) { 28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!port.isConnected()) { 28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Autoconnecting unconnected " + port + " to Null filter."); 28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn NullFilter nullFilter = new NullFilter(filter.getName() + "ToNull" + id); 28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn nullFilter.init(); 28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn addedFilters.add(nullFilter); 28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn port.connectTo(nullFilter.getInputPort("frame")); 28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ++id; 28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Add all added filters to this graph 29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : addedFilters) { 29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn addFilter(filter); 29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void removeFilter(Filter filter) { 29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFilters.remove(filter); 29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNameMap.remove(filter.getName()); 30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void preconnect(OutputPort outPort, InputPort inPort) { 30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn LinkedList<InputPort> targets; 30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn targets = mPreconnections.get(outPort); 30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (targets == null) { 30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn targets = new LinkedList<InputPort>(); 30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPreconnections.put(outPort, targets); 30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn targets.add(inPort); 31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void connectPorts() { 31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int branchId = 1; 31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Entry<OutputPort, LinkedList<InputPort>> connection : mPreconnections.entrySet()) { 31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn OutputPort outputPort = connection.getKey(); 31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn LinkedList<InputPort> inputPorts = connection.getValue(); 31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (inputPorts.size() == 1) { 31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn outputPort.connectTo(inputPorts.get(0)); 31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (mAutoBranchMode == AUTOBRANCH_OFF) { 32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Attempting to connect " + outputPort + " to multiple " 32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn + "filter ports! Enable auto-branching to allow this."); 32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Creating branch for " + outputPort + "!"); 32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameBranch branch = null; 32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mAutoBranchMode == AUTOBRANCH_SYNCED) { 32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn branch = new FrameBranch("branch" + branchId++); 32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("TODO: Unsynced branches not implemented yet!"); 32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn KeyValueMap branchParams = new KeyValueMap(); 33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn branch.initWithAssignmentList("outputs", inputPorts.size()); 33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn addFilter(branch); 33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn outputPort.connectTo(branch.getInputPort("in")); 33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Iterator<InputPort> inputPortIter = inputPorts.iterator(); 33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (OutputPort branchOutPort : ((Filter)branch).getOutputPorts()) { 33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn branchOutPort.connectTo(inputPortIter.next()); 33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPreconnections.clear(); 34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private HashSet<Filter> getSourceFilters() { 34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn HashSet<Filter> sourceFilters = new HashSet<Filter>(); 34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (Filter filter : getFilters()) { 34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (filter.getNumberOfConnectedInputs() == 0) { 34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Found source filter: " + filter); 34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceFilters.add(filter); 34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return sourceFilters; 35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Core internal methods ///////////////////////////////////////////////////////////////////////// 35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn void setupFilters() { 35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mDiscardUnconnectedOutputs) { 35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn discardUnconnectedOutputs(); 35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn connectPorts(); 36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn checkConnections(); 36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn runTypeCheck(); 36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 364