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.os.SystemClock;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.ArrayList;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashMap;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Map;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.atomic.AtomicBoolean;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Filters are the processing nodes of the filter graphs.
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Filters may have any number of input and output ports, through which the data frames flow.
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * TODO: More documentation on filter life-cycle, port and type checking, GL and RenderScript, ...
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic abstract class Filter {
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static class State {
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private static final int STATE_UNPREPARED = 1;
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private static final int STATE_PREPARED = 2;
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private static final int STATE_OPEN = 3;
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private static final int STATE_CLOSED = 4;
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private static final int STATE_DESTROYED = 5;
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int current = STATE_UNPREPARED;
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public synchronized boolean check(int state) {
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return current == state;
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final int REQUEST_FLAG_NONE = 0;
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final int REQUEST_FLAG_CLOSE = 1;
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private String mName;
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private MffContext mContext;
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private FilterGraph mFilterGraph;
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private State mState = new State();
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mRequests = REQUEST_FLAG_NONE;
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mMinimumAvailableInputs = 1;
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mMinimumAvailableOutputs = 1;
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private int mScheduleCount = 0;
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private long mLastScheduleTime = 0;
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private boolean mIsActive = true;
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private AtomicBoolean mIsSleeping = new AtomicBoolean(false);
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private long mCurrentTimestamp = Frame.TIMESTAMP_NOT_SET;
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private HashMap<String, InputPort> mConnectedInputPorts = new HashMap<String, InputPort>();
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private HashMap<String, OutputPort> mConnectedOutputPorts = new HashMap<String, OutputPort>();
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private InputPort[] mConnectedInputPortArray = null;
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private OutputPort[] mConnectedOutputPortArray = null;
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ArrayList<Frame> mAutoReleaseFrames = new ArrayList<Frame>();
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Constructs a new filter.
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * A filter is bound to a specific MffContext. Its name can be any String value, but it must
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * be unique within the filter graph.
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note that names starting with "$" are reserved for internal use, and should not be used.
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param context The MffContext in which the filter will live.
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param name The name of the filter.
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected Filter(MffContext context, String name) {
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mName = name;
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mContext = context;
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Checks whether the filter class is available on this platform.
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Some filters may not be installed on all platforms and can therefore not be instantiated.
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Before instantiating a filter, check if it is available by using this method.
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This method uses the shared FilterFactory to check whether the filter class is available.
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param filterClassName The fully qualified class name of the Filter class.
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if filters of the specified class name are available.
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static final boolean isAvailable(String filterClassName) {
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return FilterFactory.sharedFactory().isFilterAvailable(filterClassName);
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the name of this filter.
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the name of the filter (specified during construction).
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public String getName() {
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mName;
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the signature of this filter.
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Subclasses should override this and return their filter signature. The default
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * implementation returns a generic signature with no constraints.
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This method may be called at any time.
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the Signature instance for this filter.
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Signature getSignature() {
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Signature();
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the MffContext that the filter resides in.
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the MffContext of the filter.
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public MffContext getContext() {
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mContext;
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns true, if the filter is active.
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * TODO: thread safety?
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the filter is active.
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isActive() {
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mIsActive;
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Activates the current filter.
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Only active filters can be scheduled for execution. This method can only be called if the
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * GraphRunner that is executing the filter is stopped or paused.
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void activate() {
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        assertIsPaused();
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (!mIsActive) {
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mIsActive = true;
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Deactivates the current filter.
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Only active filters can be scheduled for execution. This method can only be called if the
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * GraphRunner that is executing the filter is stopped or paused.
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void deactivate() {
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // TODO: Support close-on-deactivate (must happen in processing thread).
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        assertIsPaused();
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mIsActive) {
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mIsActive = false;
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the filter's set of input ports.
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note that this contains only the *connected* input ports. To retrieve all
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * input ports that this filter accepts, one has to go via the filter's Signature.
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return An array containing all connected input ports.
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public final InputPort[] getConnectedInputPorts() {
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mConnectedInputPortArray;
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the filter's set of output ports.
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note that this contains only the *connected* output ports. To retrieve all
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * output ports that this filter provides, one has to go via the filter's Signature.
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return An array containing all connected output ports.
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public final OutputPort[] getConnectedOutputPorts() {
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mConnectedOutputPortArray;
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the input port with the given name.
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note that this can only access the *connected* input ports. To retrieve all
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * input ports that this filter accepts, one has to go via the filter's Signature.
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the input port with the specified name, or null if no connected input port
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *  with this name exists.
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public final InputPort getConnectedInputPort(String name) {
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mConnectedInputPorts.get(name);
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the output port with the given name.
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note that this can only access the *connected* output ports. To retrieve all
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * output ports that this filter provides, one has to go via the filter's Signature.
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the output port with the specified name, or null if no connected output port
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *  with this name exists.
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public final OutputPort getConnectedOutputPort(String name) {
218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mConnectedOutputPorts.get(name);
219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when an input port has been attached in the graph.
223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Override this method, in case you want to be informed of any connected input ports, or make
224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * modifications to them. Note that you may not assume that any other ports have been attached
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * already. If you have dependencies on other ports, override
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@link #onInputPortOpen(InputPort)}. The default implementation does nothing.
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param port The InputPort instance that was attached.
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onInputPortAttached(InputPort port) {
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when an output port has been attached in the graph.
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Override this method, in case you want to be informed of any connected output ports, or make
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * modifications to them. Note that you may not assume that any other ports have been attached
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * already. If you have dependencies on other ports, override
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@link #onOutputPortOpen(OutputPort)}. The default implementation does nothing.
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param port The OutputPort instance that was attached.
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onOutputPortAttached(OutputPort port) {
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when an input port is opened on this filter.
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Input ports are opened by the data produce, that is the filter that is connected to an
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * input port. Override this if you need to make modifications to the port before processing
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * begins. Note, that this is only called if the connected filter is scheduled. You may assume
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * that all ports are attached when this is called.
251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param port The InputPort instance that was opened.
253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onInputPortOpen(InputPort port) {
255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when an output port is opened on this filter.
259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Output ports are opened when the filter they are attached to is opened. Override this if you
260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * need to make modifications to the port before processing begins. Note, that this is only
261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * called if the filter is scheduled. You may assume that all ports are attached when this is
262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * called.
263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param port The OutputPort instance that was opened.
265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onOutputPortOpen(OutputPort port) {
267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns true, if the filter is currently open.
271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the filter is currently open.
272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public final boolean isOpen() {
274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mState.check(State.STATE_OPEN);
275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public String toString() {
279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mName + " (" + getClass().getSimpleName() + ")";
280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when filter is prepared.
284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Subclasses can override this to prepare the filter for processing. This method gets called
285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * once only just before the filter is scheduled for processing the first time.
286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #onTearDown()
288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onPrepare() {
290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when the filter is opened.
294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Subclasses can override this to perform any kind of initialization just before processing
295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * starts. This method may be called any number of times, but is always balanced with an
296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@link #onClose()} call.
297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #onClose()
299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onOpen() {
301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called to perform processing on Frame data.
305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is the only method subclasses must override. It is called every time the filter is
306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * ready for processing. Typically this is when there is input data to process and available
307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * output ports, but may differ depending on the port configuration.
308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected abstract void onProcess();
310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when the filter is closed.
313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Subclasses can override this to perform any kind of post-processing steps. Processing will
314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * not resume until {@link #onOpen()} is called again. This method is only called if the filter
315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * is open.
316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #onOpen()
318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onClose() {
320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Called when the filter is torn down.
324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Subclasses can override this to perform clean-up tasks just before the filter is disposed of.
325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * It is called when the filter graph that the filter belongs to is disposed.
326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #onPrepare()
328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onTearDown() {
330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Check if the input conditions are met in order to schedule this filter.
334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is used by {@link #canSchedule()} to determine if the input-port conditions given by
336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * the filter are met. Subclasses that override scheduling behavior can make use of this
337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * function.
338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the filter's input conditions are met.
340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected boolean inputConditionsMet() {
342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mConnectedInputPortArray.length > 0) {
343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int inputFrames = 0;
344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // [Non-iterator looping]
345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (int i = 0; i < mConnectedInputPortArray.length; ++i) {
346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (!mConnectedInputPortArray[i].conditionsMet()) {
347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    return false;
348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                } else if (mConnectedInputPortArray[i].hasFrame()) {
349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    ++inputFrames;
350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (inputFrames < mMinimumAvailableInputs) {
353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return false;
354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return true;
357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Check if the output conditions are met in order to schedule this filter.
361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is used by {@link #canSchedule()} to determine if the output-port conditions given by
363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * the filter are met. Subclasses that override scheduling behavior can make use of this
364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * function.
365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the filter's output conditions are met.
367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected boolean outputConditionsMet() {
369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mConnectedOutputPortArray.length > 0) {
370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int availableOutputs = 0;
371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (int i = 0; i < mConnectedOutputPortArray.length; ++i) {
372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (!mConnectedOutputPortArray[i].conditionsMet()) {
373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    return false;
374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                } else if (mConnectedOutputPortArray[i].isAvailable()) {
375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    ++availableOutputs;
376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (availableOutputs < mMinimumAvailableOutputs) {
379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return false;
380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return true;
383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Check if the Filter is in a state so that it can be scheduled.
387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * When overriding the filter's {@link #canSchedule()} method, you should never allow
389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * scheduling a filter that is not in a schedulable state. This will result in undefined
390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * behavior.
391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the filter is in a schedulable state.
393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected boolean inSchedulableState() {
395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return (mIsActive && !mState.check(State.STATE_CLOSED));
396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns true if the filter can be currently scheduled.
400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Filters may override this method if they depend on custom factors that determine whether
402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * they can be scheduled or not. The scheduler calls this method to determine whether or not
403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * a filter can be scheduled for execution. It does not guarantee that it will be executed.
404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * It is strongly recommended to call super's implementation to make sure your filter can be
405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * scheduled based on its state, input and output ports.
406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the filter can be scheduled.
408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected boolean canSchedule() {
410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return inSchedulableState() && inputConditionsMet() && outputConditionsMet();
411227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
412227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
413227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
414227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the current FrameManager instance.
415227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the current FrameManager instance or null if there is no FrameManager set up yet.
416227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
417227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final FrameManager getFrameManager() {
418227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mFilterGraph.mRunner != null ? mFilterGraph.mRunner.getFrameManager() : null;
419227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
420227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
421227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
422227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the GraphRunner for this filter is running.
423227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
424227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Generally, this method should not be used for performing operations that need to be carried
425227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * out before running begins. Use {@link #performPreparation(Runnable)} for this.
426227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
427227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the GraphRunner for this filter is running.
428227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
429227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final boolean isRunning() {
430227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mFilterGraph != null && mFilterGraph.mRunner != null
431227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                && mFilterGraph.mRunner.isRunning();
432227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
433227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
434227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
435227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Performs operations before the filter is running.
436227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
437227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Use this method when your filter requires to perform operations while the graph is not
438227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * running. The filter will not be scheduled for execution until your method has completed
439227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * execution.
440227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
441227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final boolean performPreparation(Runnable runnable) {
442227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mState) {
443227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_OPEN) {
444227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return false;
445227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
446227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                runnable.run();
447227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return true;
448227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
449227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
450227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
451227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
452227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
453227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Request that this filter be closed after the current processing step.
454227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
455227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Implementations may call this within their {@link #onProcess()} calls to indicate that the
456227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * filter is done processing and wishes to be closed. After such a request the filter will be
457227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * closed and no longer receive {@link #onProcess()} calls.
458227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
459227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #onClose()
460227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #onProcess()
461227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
462227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final void requestClose() {
463227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRequests |= REQUEST_FLAG_CLOSE;
464227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
465227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
466227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
467227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Sets the minimum number of input frames required to process.
468227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * A filter will not be scheduled unless at least a certain number of input frames are available
469227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * on the input ports. This is only relevant if the filter has input ports and is not waiting on
470227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * all ports.
471227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The default value is 1.
472227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
473227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param count the minimum number of frames required to process.
474227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #getMinimumAvailableInputs()
475227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setMinimumAvailableOutputs(int)
476227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see InputPort#setWaitsForFrame(boolean)
477227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
478227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final void setMinimumAvailableInputs(int count) {
479227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mMinimumAvailableInputs = count;
480227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
481227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
482227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
483227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the minimum number of input frames required to process this filter.
484227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The default value is 1.
485227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
486227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the minimum number of input frames required to process.
487227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setMinimumAvailableInputs(int)
488227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
489227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final int getMinimumAvailableInputs() {
490227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mMinimumAvailableInputs;
491227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
492227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
493227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
494227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Sets the minimum number of available output ports required to process.
495227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * A filter will not be scheduled unless atleast a certain number of output ports are available.
496227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is only relevant if the filter has output ports and is not waiting on all ports. The
497227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * default value is 1.
498227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
499227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param count the minimum number of frames required to process.
500227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #getMinimumAvailableOutputs()
501227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setMinimumAvailableInputs(int)
502227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see OutputPort#setWaitsUntilAvailable(boolean)
503227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
504227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final void setMinimumAvailableOutputs(int count) {
505227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mMinimumAvailableOutputs = count;
506227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
507227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
508227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
509227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the minimum number of available outputs required to process this filter.
510227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The default value is 1.
511227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
512227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the minimum number of available outputs required to process.
513227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setMinimumAvailableOutputs(int)
514227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
515227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final int getMinimumAvailableOutputs() {
516227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mMinimumAvailableOutputs;
517227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
518227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
519227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
520227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Puts the filter to sleep so that it is no longer scheduled.
521227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * To resume scheduling the filter another thread must call wakeUp() on this filter.
522227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
523227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final void enterSleepState() {
524227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mIsSleeping.set(true);
525227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
526227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
527227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
528227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Wakes the filter and resumes scheduling.
529227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is generally called from another thread to signal that this filter should resume
530227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * processing. Does nothing if filter is not sleeping.
531227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
532227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected final void wakeUp() {
533227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (mIsSleeping.getAndSet(false)) {
534227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (isRunning()) {
535227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mFilterGraph.mRunner.signalWakeUp();
536227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
537227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
538227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
539227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
540227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
541227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether this Filter is allowed to use OpenGL.
542227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
543227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Filters may use OpenGL if the MffContext supports OpenGL and its GraphRunner allows it.
544227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
545227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if this Filter is allowed to use OpenGL.
546227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
547227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks   protected final boolean isOpenGLSupported() {
548227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mFilterGraph.mRunner.isOpenGLSupported();
549227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
550227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
551227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
552227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Connect an output port to an input port of another filter.
553227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Connects the output port with the specified name to the input port with the specified name
554227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * of the specified filter. If the input or output ports do not exist already, they are
555227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * automatically created and added to the respective filter.
556227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
557227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void connect(String outputName, Filter targetFilter, String inputName) {
558227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Make sure not connected already
559227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (getConnectedOutputPort(outputName) != null) {
560227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Attempting to connect already connected output port '"
561227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + outputName + "' of filter " + this + "'!");
562227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else if (targetFilter.getConnectedInputPort(inputName) != null) {
563227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Attempting to connect already connected input port '"
564227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + inputName + "' of filter " + targetFilter + "'!");
565227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
566227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
567227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Establish connection
568227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        InputPort inputPort = targetFilter.newInputPort(inputName);
569227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        OutputPort outputPort = newOutputPort(outputName);
570227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outputPort.setTarget(inputPort);
571227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
572227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Fire attachment callbacks
573227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        targetFilter.onInputPortAttached(inputPort);
574227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        onOutputPortAttached(outputPort);
575227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
576227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Update array of ports (which is maintained for more efficient access)
577227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        updatePortArrays();
578227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
579227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
580227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final Map<String, InputPort> getConnectedInputPortMap() {
581227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mConnectedInputPorts;
582227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
583227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
584227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final Map<String, OutputPort> getConnectedOutputPortMap() {
585227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mConnectedOutputPorts;
586227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
587227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
588227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void execute() {
589227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mState) {
590227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            autoPullInputs();
591227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mLastScheduleTime = SystemClock.elapsedRealtime();
592227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_UNPREPARED) {
593227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onPrepare();
594227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.current = State.STATE_PREPARED;
595227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
596227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_PREPARED) {
597227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                openPorts();
598227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onOpen();
599227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.current = State.STATE_OPEN;
600227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
601227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_OPEN) {
602227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onProcess();
603227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (mRequests != REQUEST_FLAG_NONE) {
604227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    processRequests();
605227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
606227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
607227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
608227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        autoReleaseFrames();
609227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ++mScheduleCount;
610227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
611227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
612227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void performClose() {
613227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mState) {
614227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_OPEN) {
615227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onClose();
616227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mIsSleeping.set(false);
617227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.current = State.STATE_CLOSED;
618227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mCurrentTimestamp = Frame.TIMESTAMP_NOT_SET;
619227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
620227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
621227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
622227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
623227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void softReset() {
624227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mState) {
625227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            performClose();
626227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_CLOSED) {
627227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.current = State.STATE_PREPARED;
628227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
629227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
630227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
631227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
632227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void performTearDown() {
633227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mState) {
634227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current == State.STATE_OPEN) {
635227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Attempting to tear-down filter " + this + " which is "
636227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "in an open state!");
637227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (mState.current != State.STATE_DESTROYED
638227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    && mState.current != State.STATE_UNPREPARED) {
639227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onTearDown();
640227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.current = State.STATE_DESTROYED;
641227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
642227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
643227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
644227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
645227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void insertIntoFilterGraph(FilterGraph graph) {
646227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mFilterGraph = graph;
647227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        updatePortArrays();
648227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
649227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
650227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final int getScheduleCount() {
651227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mScheduleCount;
652227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
653227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
654227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void resetScheduleCount() {
655227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mScheduleCount = 0;
656227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
657227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
658227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void openPorts() {
659227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Opening the output ports will open the connected input ports
660227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (OutputPort outputPort : mConnectedOutputPorts.values()) {
661227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            openOutputPort(outputPort);
662227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
663227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
664227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
665227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void addAutoReleaseFrame(Frame frame) {
666227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mAutoReleaseFrames.add(frame);
667227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
668227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
669227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final long getCurrentTimestamp() {
670227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mCurrentTimestamp;
671227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
672227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
673227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void onPulledFrameWithTimestamp(long timestamp) {
674227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (timestamp > mCurrentTimestamp || mCurrentTimestamp == Frame.TIMESTAMP_NOT_SET) {
675227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mCurrentTimestamp = timestamp;
676227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
677227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
678227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
679227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final void openOutputPort(OutputPort outPort) {
680227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (outPort.getQueue() == null) {
681227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            try {
682227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                FrameQueue.Builder builder = new FrameQueue.Builder();
683227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                InputPort inPort = outPort.getTarget();
684227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                outPort.onOpen(builder);
685227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                inPort.onOpen(builder);
686227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Filter targetFilter = inPort.getFilter();
687227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                String queueName = mName + "[" + outPort.getName() + "] -> " + targetFilter.mName
688227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        + "[" + inPort.getName() + "]";
689227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                FrameQueue queue = builder.build(queueName);
690227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                outPort.setQueue(queue);
691227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                inPort.setQueue(queue);
692227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } catch (RuntimeException e) {
693227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException("Could not open output port " + outPort + "!", e);
694227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
695227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
696227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
697227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
698227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final boolean isSleeping() {
699227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mIsSleeping.get();
700227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
701227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
702227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    final long getLastScheduleTime() {
703227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mLastScheduleTime ;
704227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
705227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
706227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final void autoPullInputs() {
707227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // [Non-iterator looping]
708227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < mConnectedInputPortArray.length; ++i) {
709227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            InputPort port = mConnectedInputPortArray[i];
710227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (port.hasFrame() && port.isAutoPullEnabled()) {
711227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mConnectedInputPortArray[i].pullFrame();
712227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
713227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
714227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
715227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
716227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final void autoReleaseFrames() {
717227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // [Non-iterator looping]
718227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        for (int i = 0; i < mAutoReleaseFrames.size(); ++i) {
719227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mAutoReleaseFrames.get(i).release();
720227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
721227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mAutoReleaseFrames.clear();
722227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
723227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
724227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final InputPort newInputPort(String name) {
725227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        InputPort result = mConnectedInputPorts.get(name);
726227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result == null) {
727227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Signature.PortInfo info = getSignature().getInputPortInfo(name);
728227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            result = new InputPort(this, name, info);
729227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mConnectedInputPorts.put(name, result);
730227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
731227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
732227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
733227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
734227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final OutputPort newOutputPort(String name) {
735227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        OutputPort result = mConnectedOutputPorts.get(name);
736227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (result == null) {
737227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Signature.PortInfo info = getSignature().getOutputPortInfo(name);
738227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            result = new OutputPort(this, name, info);
739227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mConnectedOutputPorts.put(name, result);
740227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
741227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
742227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
743227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
744227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final void processRequests() {
745227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if ((mRequests & REQUEST_FLAG_CLOSE) != 0) {
746227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            performClose();
747227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mRequests = REQUEST_FLAG_NONE;
748227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
749227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
750227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
751227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void assertIsPaused() {
752227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        GraphRunner runner = GraphRunner.current();
753227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (runner != null && !runner.isPaused() && !runner.isStopped()) {
754227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("Attempting to modify filter state while runner is "
755227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                + "executing. Please pause or stop the runner first!");
756227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
757227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
758227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
759227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final void updatePortArrays() {
760227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Copy our port-maps to arrays for faster non-iterator access
761227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mConnectedInputPortArray = mConnectedInputPorts.values().toArray(new InputPort[0]);
762227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mConnectedOutputPortArray = mConnectedOutputPorts.values().toArray(new OutputPort[0]);
763227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
764227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
765227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
766227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
767