1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2011 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.View;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.BranchFilter;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.FrameSlotSource;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.FrameSlotTarget;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.GraphInputSource;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.GraphOutputTarget;
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.ValueTarget;
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.ValueTarget.ValueListener;
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterpacks.base.VariableSource;
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Collection;
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashMap;
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashSet;
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Map.Entry;
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Set;
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * A graph of Filter nodes.
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * A FilterGraph instance contains a set of Filter instances connected by their output and input
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * ports. Every filter belongs to exactly one graph and cannot be moved to another graph.
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * FilterGraphs may contain sub-graphs that are dependent on the parent graph. These are typically
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * used when inserting sub-graphs into MetaFilters. When a parent graph is torn down so are its
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * sub-graphs. The same applies to flushing frames of a graph.
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class FilterGraph {
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static boolean DEBUG = false;
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** The context that this graph lives in */
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private MffContext mContext;
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Map from name of filter to the filter instance */
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private HashMap<String, Filter> mFilterMap = new HashMap<String, Filter>();
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Allows quick access to array of all filters. */
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Filter[] mAllFilters = null;
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** The GraphRunner currently attached to this graph */
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    GraphRunner mRunner;
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** The set of sub-graphs of this graph */
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    HashSet<FilterGraph> mSubGraphs = new HashSet<FilterGraph>();
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** The parent graph of this graph, or null it this graph is a root graph. */
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private FilterGraph mParentGraph;
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static class Builder {
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /** The context that this builder lives in */
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private MffContext mContext;
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /** Map from name of filter to the filter instance */
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private HashMap<String, Filter> mFilterMap = new HashMap<String, Filter>();
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Creates a new builder for specifying a graph structure.
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param context The context the graph will live in.
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public Builder(MffContext context) {
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mContext = context;
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Add a filter to the graph.
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Adds the specified filter to the set of filters of this graph. The filter must not be in
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * the graph already, and the filter's name must be unique within the graph.
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param filter the filter to add to the graph.
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @throws IllegalArgumentException if the filter is in the graph already, or its name is
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *                                  is already taken.
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void addFilter(Filter filter) {
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mFilterMap.values().contains(filter)) {
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Attempting to add filter " + filter + " that "
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "is in the graph already!");
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (mFilterMap.containsKey(filter.getName())) {
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Graph contains filter with name '"
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + filter.getName() + "' already!");
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mFilterMap.put(filter.getName(), filter);
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Adds a variable to the graph.
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * TODO: More documentation.
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param name the name of the variable.
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param value the value of the variable or null if no value is to be set yet.
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @return the VariableSource filter that holds the value of this variable.
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public VariableSource addVariable(String name, Object value) {
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (getFilter(name) != null) {
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Filter named '" + name + "' exists already!");
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            VariableSource valueSource = new VariableSource(mContext, name);
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            addFilter(valueSource);
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (value != null) {
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                valueSource.setValue(value);
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return valueSource;
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public FrameSlotSource addFrameSlotSource(String name, String slotName) {
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            FrameSlotSource filter = new FrameSlotSource(mContext, name, slotName);
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            addFilter(filter);
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return filter;
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public FrameSlotTarget addFrameSlotTarget(String name, String slotName) {
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            FrameSlotTarget filter = new FrameSlotTarget(mContext, name, slotName);
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            addFilter(filter);
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return filter;
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Connect two filters by their ports.
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * The filters specified must have been previously added to the graph builder.
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param sourceFilterName The name of the source filter.
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param sourcePort The name of the source port.
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param targetFilterName The name of the target filter.
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param targetPort The name of the target port.
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void connect(String sourceFilterName, String sourcePort,
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            String targetFilterName, String targetPort) {
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter sourceFilter = getFilter(sourceFilterName);
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter targetFilter = getFilter(targetFilterName);
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (sourceFilter == null) {
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unknown filter '" + sourceFilterName + "'!");
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (targetFilter == null) {
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unknown filter '" + targetFilterName + "'!");
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            connect(sourceFilter, sourcePort, targetFilter, targetPort);
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Connect two filters by their ports.
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * The filters specified must have been previously added to the graph builder.
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param sourceFilter The source filter.
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param sourcePort The name of the source port.
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param targetFilter The target filter.
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param targetPort The name of the target port.
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void connect(Filter sourceFilter, String sourcePort,
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            Filter targetFilter, String targetPort) {
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            sourceFilter.connect(sourcePort, targetFilter, targetPort);
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Returns the filter with the specified name.
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @return the filter with the specified name, or null if no such filter exists.
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public Filter getFilter(String name) {
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mFilterMap.get(name);
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Builds the graph and checks signatures.
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @return The new graph instance.
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public FilterGraph build() {
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            checkSignatures();
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return buildWithParent(null);
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Builds the sub-graph and checks signatures.
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param parentGraph the parent graph of the built sub-graph.
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @return The new graph instance.
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public FilterGraph buildSubGraph(FilterGraph parentGraph) {
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (parentGraph == null) {
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new NullPointerException("Parent graph must be non-null!");
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            checkSignatures();
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return buildWithParent(parentGraph);
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VariableSource assignValueToFilterInput(Object value, String filterName, String inputName) {
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Get filter to connect to
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter filter = getFilter(filterName);
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (filter == null) {
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unknown filter '" + filterName + "'!");
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Construct a name for our value source and make sure it does not exist already
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            String valueSourceName = filterName + "." + inputName;
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (getFilter(valueSourceName) != null) {
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("VariableSource for '" + filterName + "' and "
218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "input '" + inputName + "' exists already!");
219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Create new VariableSource and connect it to the target filter and port
222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            VariableSource valueSource = new VariableSource(mContext, valueSourceName);
223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            addFilter(valueSource);
224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            try {
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                ((Filter)valueSource).connect("value", filter, inputName);
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } catch (RuntimeException e) {
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Could not connect VariableSource to input '" + inputName
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "' of filter '" + filterName + "'!", e);
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Assign the value to the VariableSource
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (value != null) {
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                valueSource.setValue(value);
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return valueSource;
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        VariableSource assignVariableToFilterInput(String varName,
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                   String filterName,
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                                   String inputName) {
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Get filter to connect to
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter filter = getFilter(filterName);
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (filter == null) {
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unknown filter '" + filterName + "'!");
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Get variable
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter variable = getFilter(varName);
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (variable == null || !(variable instanceof VariableSource)) {
251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unknown variable '" + varName + "'!");
252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Connect variable (and possibly branch) variable to filter
255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            try {
256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                connectAndBranch(variable, "value", filter, inputName);
257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } catch (RuntimeException e) {
258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Could not connect VariableSource to input '" + inputName
259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "' of filter '" + filterName + "'!", e);
260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return (VariableSource)variable;
263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Builds the graph without checking signatures.
267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * If parent is non-null, build a sub-graph of the specified parent.
268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @return The new graph instance.
270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private FilterGraph buildWithParent(FilterGraph parent) {
272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            FilterGraph graph = new FilterGraph(mContext, parent);
273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            graph.mFilterMap = mFilterMap;
274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            graph.mAllFilters = mFilterMap.values().toArray(new Filter[0]);
275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (Entry<String, Filter> filterEntry : mFilterMap.entrySet()) {
276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                filterEntry.getValue().insertIntoFilterGraph(graph);
277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return graph;
279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void checkSignatures() {
282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            checkSignaturesForFilters(mFilterMap.values());
283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // TODO: Currently this always branches even if the connection is a 1:1 connection. Later
286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // we may optimize to pass through directly in the 1:1 case (may require disconnecting
287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // ports).
288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void connectAndBranch(Filter sourceFilter,
289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      String sourcePort,
290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      Filter targetFilter,
291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                      String targetPort) {
292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            String branchName = "__" + sourceFilter.getName() + "_" + sourcePort + "Branch";
293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter branch = getFilter(branchName);
294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (branch == null) {
295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                branch = new BranchFilter(mContext, branchName, false);
296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                addFilter(branch);
297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                sourceFilter.connect(sourcePort, branch, "input");
298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            String portName = "to" + targetFilter.getName() + "_" + targetPort;
300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            branch.connect(portName, targetFilter, targetPort);
301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Attach the graph and its subgraphs to a custom GraphRunner.
307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Call this if you want the graph to be executed by a specific GraphRunner. You must call
309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * this before any other runner is set. Note that calls to {@code getRunner()} and
310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@code run()} auto-create a GraphRunner.
311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param runner The GraphRunner instance that should execute this graph.
313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #getRunner()
314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #run()
315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void attachToRunner(GraphRunner runner) {
317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mRunner == null) {
318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (FilterGraph subGraph : mSubGraphs) {
319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                subGraph.attachToRunner(runner);
320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            runner.attachGraph(this);
322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mRunner = runner;
323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (mRunner != runner) {
324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Cannot attach FilterGraph to GraphRunner that is already "
325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "attached to another GraphRunner!");
326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Forcibly tear down a filter graph.
331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Call this to release any resources associated with the filter graph, its filters and any of
333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * its sub-graphs. This method must not be called if the graph (or any sub-graph) is running.
334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * You may no longer access this graph instance or any of its subgraphs after calling this
336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * method.
337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Tearing down of sub-graphs is not supported. You must tear down the root graph, which will
339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * tear down all of its sub-graphs.
340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalStateException if the graph is still running.
342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws RuntimeException if you attempt to tear down a sub-graph.
343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void tearDown() {
345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        assertNotRunning();
346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mParentGraph != null) {
347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Attempting to tear down sub-graph!");
348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mRunner != null) {
350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mRunner.tearDownGraph(this);
351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (FilterGraph subGraph : mSubGraphs) {
353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            subGraph.mParentGraph = null;
354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            subGraph.tearDown();
355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mSubGraphs.clear();
357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the context of the graph.
361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the MffContext instance that this graph is bound to.
363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public MffContext getContext() {
365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mContext;
366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the filter with the specified name.
370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the filter with the specified name, or null if no such filter exists.
372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Filter getFilter(String name) {
374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mFilterMap.get(name);
375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the VariableSource for the specified variable.
379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * TODO: More documentation.
381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * TODO: More specialized error handling.
382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param name The name of the VariableSource.
384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return The VariableSource filter instance with the specified name.
385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public VariableSource getVariable(String name) {
387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Filter result = mFilterMap.get(name);
388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result != null && result instanceof VariableSource) {
389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return (VariableSource)result;
390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Unknown variable '" + name + "' specified!");
392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the GraphOutputTarget with the specified name.
397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param name The name of the target.
399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return The GraphOutputTarget instance with the specified name.
400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public GraphOutputTarget getGraphOutput(String name) {
402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Filter result = mFilterMap.get(name);
403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result != null && result instanceof GraphOutputTarget) {
404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return (GraphOutputTarget)result;
405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Unknown target '" + name + "' specified!");
407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
411227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the GraphInputSource with the specified name.
412227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
413227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param name The name of the source.
414227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return The GraphInputSource instance with the specified name.
415227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
416227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public GraphInputSource getGraphInput(String name) {
417227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Filter result = mFilterMap.get(name);
418227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result != null && result instanceof GraphInputSource) {
419227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return (GraphInputSource)result;
420227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
421227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Unknown source '" + name + "' specified!");
422227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
423227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
424227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
425227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
426227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Binds a filter to a view.
427227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
428227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * ViewFilter instances support visualizing their data to a view. See the specific filter
429227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * documentation for details. Views may be bound only if the graph is not running.
430227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
431227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param filterName the name of the filter to bind.
432227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param view the view to bind to.
433227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalStateException if the filter is in an illegal state.
434227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalArgumentException if no such view-filter exists.
435227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
436227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void bindFilterToView(String filterName, View view) {
437227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Filter filter = mFilterMap.get(filterName);
438227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (filter != null && filter instanceof ViewFilter) {
439227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            ((ViewFilter)filter).bindToView(view);
440227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
441227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Unknown view filter '" + filterName + "'!");
442227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
443227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
444227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
445227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
446227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * TODO: Documentation.
447227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
448227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void bindValueTarget(String filterName, ValueListener listener, boolean onCallerThread) {
449227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Filter filter = mFilterMap.get(filterName);
450227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (filter != null && filter instanceof ValueTarget) {
451227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            ((ValueTarget)filter).setListener(listener, onCallerThread);
452227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
453227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Unknown ValueTarget filter '" + filterName + "'!");
454227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
455227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
456227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
457227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Running Graphs //////////////////////////////////////////////////////////////////////////////
458227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
459227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Convenience method to run the graph.
460227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
461227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Creates a new runner for this graph in the specified mode and executes it. Returns the
462227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * runner to allow control of execution.
463227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
464227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalStateException if the graph is already running.
465227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the GraphRunner instance that was used for execution.
466227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
467227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public GraphRunner run() {
468227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GraphRunner runner = getRunner();
469227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        runner.setIsVerbose(false);
470227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        runner.start(this);
471227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return runner;
472227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
473227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
474227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
475227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the GraphRunner for this graph.
476227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
477227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Every FilterGraph instance has a GraphRunner instance associated with it for executing the
478227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * graph.
479227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
480227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the GraphRunner instance for this graph.
481227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
482227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public GraphRunner getRunner() {
483227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mRunner == null) {
484227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            GraphRunner runner = new GraphRunner(mContext);
485227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            attachToRunner(runner);
486227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
487227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mRunner;
488227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
489227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
490227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
491227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the graph is currently running.
492227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
493227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true if the graph is currently running.
494227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
495227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isRunning() {
496227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mRunner != null && mRunner.isRunning();
497227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
498227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
499227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
500227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Check each filter's signatures if all requirements are fulfilled.
501227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
502227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This will throw a RuntimeException if any unfulfilled requirements are found.
503227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note that FilterGraph.Builder also has a function checkSignatures(), which allows
504227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * to do the same /before/ the FilterGraph is built.
505227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
506227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void checkSignatures() {
507227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        checkSignaturesForFilters(mFilterMap.values());
508227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
509227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
510227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // MFF Internal Methods ////////////////////////////////////////////////////////////////////////
511227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    Filter[] getAllFilters() {
512227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mAllFilters;
513227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
514227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
515227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    static void checkSignaturesForFilters(Collection<Filter> filters) {
516227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (Filter filter : filters) {
517227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (DEBUG) {
518227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.d("FilterGraph", "Checking filter " + filter.getName() + "...");
519227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
520227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Signature signature = filter.getSignature();
521227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            signature.checkInputPortsConform(filter);
522227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            signature.checkOutputPortsConform(filter);
523227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
524227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
525227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
526227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
527227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Wipes the filter references in this graph, so that they may be collected.
528227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
529227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This must be called only after a tearDown as this will make the FilterGraph invalid.
530227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
531227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void wipe() {
532227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mAllFilters = null;
533227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mFilterMap = null;
534227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
535227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
536227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void flushFrames() {
537227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (Filter filter : mFilterMap.values()) {
538227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (InputPort inputPort : filter.getConnectedInputPorts()) {
539227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                inputPort.clear();
540227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
541227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (OutputPort outputPort : filter.getConnectedOutputPorts()) {
542227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                outputPort.clear();
543227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
544227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
545227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
546227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
547227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    Set<FilterGraph> getSubGraphs() {
548227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mSubGraphs;
549227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
550227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
551227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Internal Methods ////////////////////////////////////////////////////////////////////////////
552227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private FilterGraph(MffContext context, FilterGraph parentGraph) {
553227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mContext = context;
554227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mContext.addGraph(this);
555227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (parentGraph != null) {
556227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mParentGraph = parentGraph;
557227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mParentGraph.mSubGraphs.add(this);
558227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
559227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
560227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
561227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void assertNotRunning() {
562227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (isRunning()) {
563227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalStateException("Attempting to modify running graph!");
564227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
565227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
566227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
567227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
568