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"); you may not use this file except
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * in compliance with the License. You may obtain a copy of the License at
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software distributed under the License
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * or implied. See the License for the specific language governing permissions and limitations under
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the License.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw;
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.os.ConditionVariable;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.os.SystemClock;
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashSet;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Set;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Stack;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.LinkedBlockingQueue;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * A GraphRunner schedules and executes the filter nodes of a graph.
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Typically, you create a GraphRunner given a FilterGraph instance, and execute it by calling
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #start(FilterGraph)}.
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The scheduling strategy determines how the filter nodes are selected
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * for scheduling. More precisely, given the set of nodes that can be scheduled, the scheduling
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * strategy determines which node of this set to select for execution. For instance, an LFU
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * scheduler (the default) chooses the node that has been executed the least amount of times.
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic final class GraphRunner {
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static int PRIORITY_SLEEP = -1;
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static int PRIORITY_STOP = -2;
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event BEGIN_EVENT = new Event(Event.BEGIN, null);
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event FLUSH_EVENT = new Event(Event.FLUSH, null);
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event HALT_EVENT = new Event(Event.HALT, null);
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event KILL_EVENT = new Event(Event.KILL, null);
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event PAUSE_EVENT = new Event(Event.PAUSE, null);
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event RELEASE_FRAMES_EVENT = new Event(Event.RELEASE_FRAMES, null);
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event RESTART_EVENT = new Event(Event.RESTART, null);
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event RESUME_EVENT = new Event(Event.RESUME, null);
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event STEP_EVENT = new Event(Event.STEP, null);
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static final Event STOP_EVENT = new Event(Event.STOP, null);
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static class State {
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int STOPPED = 1;
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int PREPARING = 2;
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int RUNNING = 4;
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int PAUSED = 8;
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int HALTED = 16;
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mCurrent = STOPPED;
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public synchronized void setState(int newState) {
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mCurrent = newState;
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public synchronized boolean check(int state) {
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return ((mCurrent & state) == state);
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public synchronized boolean addState(int state) {
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if ((mCurrent & state) != state) {
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mCurrent |= state;
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return true;
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return false;
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public synchronized boolean removeState(int state) {
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            boolean result = (mCurrent & state) == state;
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mCurrent &= (~state);
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return result;
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public synchronized int current() {
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mCurrent;
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static class Event {
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int PREPARE = 1;
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int BEGIN = 2;
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int STEP = 3;
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int STOP = 4;
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int PAUSE = 6;
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int HALT = 7;
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int RESUME = 8;
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int RESTART = 9;
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int FLUSH = 10;
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int TEARDOWN = 11;
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int KILL = 12;
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public static final int RELEASE_FRAMES = 13;
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int code;
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public Object object;
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public Event(int code, Object object) {
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            this.code = code;
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            this.object = object;
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final class GraphRunLoop implements Runnable {
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private State mState = new State();
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private final boolean mAllowOpenGL;
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private RenderTarget mRenderTarget = null;
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private LinkedBlockingQueue<Event> mEventQueue = new LinkedBlockingQueue<Event>();
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Exception mCaughtException = null;
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private boolean mClosedSuccessfully = true;
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Stack<Filter[]> mFilters = new Stack<Filter[]>();
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Stack<SubListener> mSubListeners = new Stack<SubListener>();
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Set<FilterGraph> mOpenedGraphs = new HashSet<FilterGraph>();
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public ConditionVariable mStopCondition = new ConditionVariable(true);
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void loop() {
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            boolean killed = false;
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            while (!killed) {
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                try {
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    Event event = nextEvent();
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    if (event == null) continue;
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    switch (event.code) {
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.PREPARE:
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onPrepare((FilterGraph)event.object);
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.BEGIN:
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onBegin();
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.STEP:
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onStep();
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.STOP:
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onStop();
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.PAUSE:
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onPause();
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.HALT:
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onHalt();
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.RESUME:
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onResume();
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.RESTART:
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onRestart();
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.FLUSH:
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onFlush();
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.TEARDOWN:
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onTearDown((FilterGraph)event.object);
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.KILL:
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            killed = true;
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        case Event.RELEASE_FRAMES:
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            onReleaseFrames();
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            break;
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    }
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                } catch (Exception e) {
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    if (mCaughtException == null) {
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mCaughtException = e;
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mClosedSuccessfully = true;
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        e.printStackTrace();
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        pushEvent(STOP_EVENT);
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    } else {
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        // Exception during exception recovery? Abort all processing. Do not
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        // overwrite the original exception.
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mClosedSuccessfully = false;
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mEventQueue.clear();
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        cleanUp();
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    }
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public GraphRunLoop(boolean allowOpenGL) {
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mAllowOpenGL = allowOpenGL;
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void run() {
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            onInit();
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            loop();
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            onDestroy();
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void enterSubGraph(FilterGraph graph, SubListener listener) {
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.check(State.RUNNING)) {
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onOpenGraph(graph);
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mSubListeners.push(listener);
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void pushWakeEvent(Event event) {
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // This is of course not race-condition proof. The worst case is that the event
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // is pushed even though the queue was not empty, which is acceptible for our cases.
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mEventQueue.isEmpty()) {
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pushEvent(event);
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void pushEvent(Event event) {
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mEventQueue.offer(event);
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void pushEvent(int eventId, Object object) {
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mEventQueue.offer(new Event(eventId, object));
218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public boolean checkState(int state) {
221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mState.check(state);
222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public ConditionVariable getStopCondition() {
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mStopCondition;
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public boolean isOpenGLAllowed() {
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // Does not need synchronization as mAllowOpenGL flag is final.
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mAllowOpenGL;
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Event nextEvent() {
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            try {
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return mEventQueue.take();
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } catch (InterruptedException e) {
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                // Ignore and keep going.
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.w("GraphRunner", "Event queue processing was interrupted.");
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return null;
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onPause() {
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mState.addState(State.PAUSED);
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onResume() {
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.removeState(State.PAUSED)) {
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (mState.current() == State.RUNNING) {
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    pushEvent(STEP_EVENT);
251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onHalt() {
256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.addState(State.HALTED) && mState.check(State.RUNNING)) {
257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                closeAllFilters();
258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onRestart() {
262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.removeState(State.HALTED)) {
263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (mState.current() == State.RUNNING) {
264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    pushEvent(STEP_EVENT);
265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onDestroy() {
270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mFrameManager.destroyBackings();
271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mRenderTarget != null) {
272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mRenderTarget.release();
273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mRenderTarget = null;
274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onReleaseFrames() {
278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mFrameManager.destroyBackings();
279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onInit() {
282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mThreadRunner.set(GraphRunner.this);
283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (getContext().isOpenGLSupported()) {
284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mRenderTarget = RenderTarget.newTarget(1, 1);
285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mRenderTarget.focus();
286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onPrepare(FilterGraph graph) {
290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current() == State.STOPPED) {
291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.setState(State.PREPARING);
292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mCaughtException = null;
293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onOpenGraph(graph);
294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onOpenGraph(FilterGraph graph) {
298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            loadFilters(graph);
299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mOpenedGraphs.add(graph);
300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mScheduler.prepare(currentFilters());
301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            pushEvent(BEGIN_EVENT);
302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onBegin() {
305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current() == State.PREPARING) {
306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mState.setState(State.RUNNING);
307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pushEvent(STEP_EVENT);
308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onStarve() {
312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mFilters.pop();
313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mFilters.empty()) {
314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onStop();
315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                SubListener listener = mSubListeners.pop();
317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (listener != null) {
318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    listener.onSubGraphRunEnded(GraphRunner.this);
319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mScheduler.prepare(currentFilters());
321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                pushEvent(STEP_EVENT);
322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onStop() {
326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.check(State.RUNNING)) {
327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                // Close filters if not already halted (and already closed)
328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (!mState.check(State.HALTED)) {
329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    closeAllFilters();
330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                cleanUp();
332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void cleanUp() {
336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mState.setState(State.STOPPED);
337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (flushOnClose()) {
338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                onFlush();
339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mOpenedGraphs.clear();
341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mFilters.clear();
342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            onRunnerStopped(mCaughtException, mClosedSuccessfully);
343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mStopCondition.open();
344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onStep() {
347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mState.current() == State.RUNNING) {
348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Filter bestFilter = null;
349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                long maxPriority = PRIORITY_STOP;
350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mScheduler.beginStep();
351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Filter[] filters = currentFilters();
352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                for (int i = 0; i < filters.length; ++i) {
353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    Filter filter = filters[i];
354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    long priority = mScheduler.priorityForFilter(filter);
355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    if (priority > maxPriority) {
356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        maxPriority = priority;
357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        bestFilter = filter;
358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    }
359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (maxPriority == PRIORITY_SLEEP) {
361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // NOOP: When going into sleep mode, we simply do not schedule another node.
362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // If some other event (such as a resume()) does schedule, then we may schedule
363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // during sleeping. This is an edge case an irrelevant. (On the other hand,
364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // going into a dedicated "sleep state" requires highly complex synchronization
365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // to not "miss" a wake-up event. Thus we choose the more defensive approach
366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    // here).
367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                } else if (maxPriority == PRIORITY_STOP) {
368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    onStarve();
369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                } else {
370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    scheduleFilter(bestFilter);
371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    pushEvent(STEP_EVENT);
372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.w("GraphRunner", "State is not running! (" + mState.current() + ")");
375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onFlush() {
379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks           if (mState.check(State.HALTED) || mState.check(State.STOPPED)) {
380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks               for (FilterGraph graph : mOpenedGraphs) {
381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                   graph.flushFrames();
382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks               }
383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks           }
384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void onTearDown(FilterGraph graph) {
387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (Filter filter : graph.getAllFilters()) {
388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                filter.performTearDown();
389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            graph.wipe();
391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void loadFilters(FilterGraph graph) {
394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter[] filters = graph.getAllFilters();
395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mFilters.push(filters);
396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void closeAllFilters() {
399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (FilterGraph graph : mOpenedGraphs) {
400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                closeFilters(graph);
401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void closeFilters(FilterGraph graph) {
405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // [Non-iterator looping]
406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Log.v("GraphRunner", "CLOSING FILTERS");
407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Filter[] filters = graph.getAllFilters();
408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            boolean isVerbose = isVerbose();
409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (int i = 0; i < filters.length; ++i) {
410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (isVerbose) {
411227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    Log.i("GraphRunner", "Closing Filter " + filters[i] + "!");
412227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
413227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                filters[i].softReset();
414227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
415227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
416227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
417227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private Filter[] currentFilters() {
418227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mFilters.peek();
419227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
420227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
421227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private void scheduleFilter(Filter filter) {
422227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            long scheduleTime = 0;
423227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (isVerbose()) {
424227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                scheduleTime = SystemClock.elapsedRealtime();
425227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.i("GraphRunner", scheduleTime + ": Scheduling " + filter + "!");
426227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
427227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            filter.execute();
428227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (isVerbose()) {
429227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                long nowTime = SystemClock.elapsedRealtime();
430227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.i("GraphRunner",
431227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        "-> Schedule time (" + filter + ") = " + (nowTime - scheduleTime) + " ms.");
432227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
433227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
434227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
435227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
436227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
437227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // GraphRunner.Scheduler classes ///////////////////////////////////////////////////////////////
438227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private interface Scheduler {
439227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void prepare(Filter[] filters);
440227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
441227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getStrategy();
442227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
443227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void beginStep();
444227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
445227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public long priorityForFilter(Filter filter);
446227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
447227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
448227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
449227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private class LruScheduler implements Scheduler {
450227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
451227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private long mNow;
452227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
453227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
454227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void prepare(Filter[] filters) {
455227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
456227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
457227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
458227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getStrategy() {
459227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return STRATEGY_LRU;
460227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
461227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
462227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
463227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void beginStep() {
464227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // TODO(renn): We could probably do this with a simple GraphRunner counter that would
465227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // represent GraphRunner local time. This would allow us to use integers instead of
466227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // longs, and save us calls to the system clock.
467227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mNow = SystemClock.elapsedRealtime();
468227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
469227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
470227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
471227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public long priorityForFilter(Filter filter) {
472227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (filter.isSleeping()) {
473227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return PRIORITY_SLEEP;
474227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (filter.canSchedule()) {
475227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return mNow - filter.getLastScheduleTime();
476227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else {
477227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                return PRIORITY_STOP;
478227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
479227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
480227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
481227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
482227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
483227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private class LfuScheduler implements Scheduler {
484227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
485227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private final int MAX_PRIORITY = Integer.MAX_VALUE;
486227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
487227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
488227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void prepare(Filter[] filters) {
489227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // [Non-iterator looping]
490227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (int i = 0; i < filters.length; ++i) {
491227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                filters[i].resetScheduleCount();
492227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
493227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
494227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
495227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
496227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getStrategy() {
497227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return STRATEGY_LFU;
498227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
499227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
500227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
501227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void beginStep() {
502227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
503227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
504227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
505227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public long priorityForFilter(Filter filter) {
506227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return filter.isSleeping() ? PRIORITY_SLEEP
507227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    : (filter.canSchedule() ? (MAX_PRIORITY - filter.getScheduleCount())
508227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            : PRIORITY_STOP);
509227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
510227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
511227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
512227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
513227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private class OneShotScheduler extends LfuScheduler {
514227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        private int mCurCount = 1;
515227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
516227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
517227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void prepare(Filter[] filters) {
518227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // [Non-iterator looping]
519227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            for (int i = 0; i < filters.length; ++i) {
520227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                filters[i].resetScheduleCount();
521227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
522227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
523227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
524227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
525227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int getStrategy() {
526227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return STRATEGY_ONESHOT;
527227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
528227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
529227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
530227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void beginStep() {
531227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
532227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
533227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        @Override
534227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public long priorityForFilter(Filter filter) {
535227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return filter.getScheduleCount() < mCurCount ? super.priorityForFilter(filter)
536227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    : PRIORITY_STOP;
537227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
538227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
539227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
540227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
541227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // GraphRunner.Listener callback class /////////////////////////////////////////////////////////
542227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public interface Listener {
543227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
544227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Callback method that is called when the runner completes a run. This method is called
545227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * only if the graph completed without an error.
546227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
547227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void onGraphRunnerStopped(GraphRunner runner);
548227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
549227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /**
550227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * Callback method that is called when runner encounters an error.
551227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
552227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *  Any exceptions thrown in the GraphRunner's thread will cause the run to abort. The
553227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * thrown exception is passed to the listener in this method. If no listener is set, the
554227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * exception message is logged to the error stream. You will not receive an
555227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * {@link #onGraphRunnerStopped(GraphRunner)} callback in case of an error.
556227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         *
557227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param exception the exception that was thrown.
558227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         * @param closedSuccessfully true, if the graph was closed successfully after the error.
559227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks         */
560227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void onGraphRunnerError(Exception exception, boolean closedSuccessfully);
561227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
562227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
563227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public interface SubListener {
564227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public void onSubGraphRunEnded(GraphRunner runner);
565227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
566227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
567227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
568227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Config class to setup a GraphRunner with a custom configuration.
569227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
570227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The configuration object is passed to the constructor. Any changes to it will not affect
571227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * the created GraphRunner instance.
572227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
573227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static class Config {
574227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /** The runner's thread priority. */
575227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public int threadPriority = Thread.NORM_PRIORITY;
576227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        /** Whether to allow filters to use OpenGL or not. */
577227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public boolean allowOpenGL = true;
578227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
579227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
580227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Parameters shared between run-thread and GraphRunner frontend. */
581227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private class RunParameters {
582227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public Listener listener = null;
583227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public boolean isVerbose = false;
584227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        public boolean flushOnClose = true;
585227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
586227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
587227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // GraphRunner implementation //////////////////////////////////////////////////////////////////
588227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Schedule strategy: From set of candidates, pick a random one. */
589227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static final int STRATEGY_RANDOM = 1;
590227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Schedule strategy: From set of candidates, pick node executed least recently executed. */
591227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static final int STRATEGY_LRU = 2;
592227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Schedule strategy: From set of candidates, pick node executed least number of times. */
593227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static final int STRATEGY_LFU = 3;
594227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Schedule strategy: Schedules no node more than once. */
595227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static final int STRATEGY_ONESHOT = 4;
596227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
597227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final MffContext mContext;
598227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
599227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private FilterGraph mRunningGraph = null;
600227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Set<FilterGraph> mGraphs = new HashSet<FilterGraph>();
601227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
602227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Scheduler mScheduler;
603227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
604227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private GraphRunLoop mRunLoop;
605227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
606227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Thread mRunThread = null;
607227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
608227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private FrameManager mFrameManager = null;
609227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
610227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static ThreadLocal<GraphRunner> mThreadRunner = new ThreadLocal<GraphRunner>();
611227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
612227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private RunParameters mParams = new RunParameters();
613227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
614227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
615227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Creates a new GraphRunner with the default configuration. You must attach FilterGraph
616227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * instances to this runner before you can execute any of these graphs.
617227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
618227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param context The MffContext instance for this runner.
619227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
620227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public GraphRunner(MffContext context) {
621227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mContext = context;
622227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        init(new Config());
623227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
624227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
625227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
626227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Creates a new GraphRunner with the specified configuration. You must attach FilterGraph
627227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * instances to this runner before you can execute any of these graphs.
628227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
629227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param context The MffContext instance for this runner.
630227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param config A Config instance with the configuration of this runner.
631227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
632227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public GraphRunner(MffContext context, Config config) {
633227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mContext = context;
634227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        init(config);
635227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
636227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
637227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
638227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the currently running graph-runner.
639227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return The currently running graph-runner.
640227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
641227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static GraphRunner current() {
642227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mThreadRunner.get();
643227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
644227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
645227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
646227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the graph that this runner is currently executing. Returns null if no graph is
647227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * currently being executed by this runner.
648227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
649227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the FilterGraph instance that this GraphRunner is executing.
650227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
651227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public synchronized FilterGraph getRunningGraph() {
652227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mRunningGraph;
653227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
654227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
655227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
656227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the context that this runner is bound to.
657227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
658227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the MffContext instance that this runner is bound to.
659227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
660227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public MffContext getContext() {
661227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mContext;
662227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
663227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
664227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
665227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Begins graph execution. The graph filters are scheduled and executed until processing
666227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * finishes or is stopped.
667227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
668227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public synchronized void start(FilterGraph graph) {
669227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (graph.mRunner != this) {
670227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Graph must be attached to runner!");
671227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
672227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunningGraph = graph;
673227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.getStopCondition().close();
674227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(Event.PREPARE, graph);
675227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
676227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
677227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
678227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Begin executing a sub-graph. This only succeeds if the current runner is already
679227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * executing.
680227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
681227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void enterSubGraph(FilterGraph graph, SubListener listener) {
682227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (Thread.currentThread() != mRunThread) {
683227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException("enterSubGraph must be called from the runner's thread!");
684227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
685227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.enterSubGraph(graph, listener);
686227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
687227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
688227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
689227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Waits until graph execution has finished or stopped with an error.
690227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Care must be taken when using this method to not block the UI thread. This is typically
691227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * used when a graph is run in one-shot mode to compute a result.
692227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
693227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void waitUntilStop() {
694227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.getStopCondition().block();
695227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
696227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
697227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
698227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Pauses graph execution.
699227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
700227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void pause() {
701227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(PAUSE_EVENT);
702227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
703227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
704227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
705227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Resumes graph execution after pausing.
706227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
707227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void resume() {
708227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(RESUME_EVENT);
709227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
710227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
711227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
712227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Stops graph execution.
713227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
714227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void stop() {
715227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(STOP_EVENT);
716227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
717227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
718227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
719227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the graph is currently being executed. A graph is considered to be running,
720227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * even if it is paused or in the process of being stopped.
721227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
722227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the graph is currently being executed.
723227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
724227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isRunning() {
725227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return !mRunLoop.checkState(State.STOPPED);
726227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
727227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
728227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
729227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the graph is currently paused.
730227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
731227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the graph is currently paused.
732227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
733227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isPaused() {
734227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mRunLoop.checkState(State.PAUSED);
735227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
736227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
737227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
738227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the graph is currently stopped.
739227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
740227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the graph is currently stopped.
741227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
742227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isStopped() {
743227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mRunLoop.checkState(State.STOPPED);
744227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
745227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
746227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
747227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Sets the filter scheduling strategy. This method can not be called when the GraphRunner is
748227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * running.
749227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
750227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param strategy a constant specifying which scheduler strategy to use.
751227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws RuntimeException if the GraphRunner is running.
752227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalArgumentException if invalid strategy is specified.
753227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #getSchedulerStrategy()
754227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
755227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setSchedulerStrategy(int strategy) {
756227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (isRunning()) {
757227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new RuntimeException(
758227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    "Attempting to change scheduling strategy on running " + "GraphRunner!");
759227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
760227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        createScheduler(strategy);
761227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
762227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
763227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
764227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the current scheduling strategy.
765227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
766227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the scheduling strategy used by this GraphRunner.
767227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setSchedulerStrategy(int)
768227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
769227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public int getSchedulerStrategy() {
770227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mScheduler.getStrategy();
771227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
772227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
773227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
774227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Set whether or not the runner is verbose. When set to true, the runner will output individual
775227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * scheduling steps that may help identify and debug problems in the graph structure. The
776227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * default is false.
777227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
778227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param isVerbose true, if the GraphRunner should log scheduling details.
779227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #isVerbose()
780227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
781227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setIsVerbose(boolean isVerbose) {
782227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
783227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mParams.isVerbose = isVerbose;
784227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
785227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
786227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
787227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
788227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the GraphRunner is verbose.
789227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
790227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the GraphRunner logs scheduling details.
791227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setIsVerbose(boolean)
792227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
793227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isVerbose() {
794227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
795227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mParams.isVerbose;
796227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
797227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
798227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
799227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
800227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether Filters of this GraphRunner can use OpenGL.
801227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
802227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Filters may use OpenGL if the MffContext supports OpenGL and the GraphRunner allows it.
803227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
804227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if Filters are allowed to use OpenGL.
805227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
806227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean isOpenGLSupported() {
807227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mRunLoop.isOpenGLAllowed() && mContext.isOpenGLSupported();
808227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
809227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
810227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
811227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Enable flushing all frames from the graph when running completes.
812227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
813227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * If this is set to false, then frames may remain in the pipeline even after running completes.
814227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The default value is true.
815227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
816227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param flush true, if the GraphRunner should flush the graph when running completes.
817227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #flushOnClose()
818227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
819227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setFlushOnClose(boolean flush) {
820227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
821227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mParams.flushOnClose = flush;
822227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
823227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
824227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
825227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
826227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns whether the GraphRunner flushes frames when running completes.
827227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
828227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return true, if the GraphRunner flushes frames when running completes.
829227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setFlushOnClose(boolean)
830227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
831227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public boolean flushOnClose() {
832227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
833227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mParams.flushOnClose;
834227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
835227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
836227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
837227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
838227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Sets the listener for receiving runtime events. A GraphRunner.Listener instance can be used
839227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * to determine when certain events occur during graph execution (and react on them). See the
840227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@link GraphRunner.Listener} class for details.
841227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
842227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param listener the GraphRunner.Listener instance to set.
843227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #getListener()
844227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
845227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setListener(Listener listener) {
846227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
847227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mParams.listener = listener;
848227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
849227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
850227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
851227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
852227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the currently assigned GraphRunner.Listener.
853227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
854227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the currently assigned GraphRunner.Listener instance.
855227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @see #setListener(Listener)
856227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
857227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Listener getListener() {
858227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
859227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            return mParams.listener;
860227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
861227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
862227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
863227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
864227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the FrameManager that manages the runner's frames.
865227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
866227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the FrameManager instance that manages the runner's frames.
867227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
868227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public FrameManager getFrameManager() {
869227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mFrameManager;
870227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
871227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
872227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
873227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Tear down a GraphRunner and all its resources.
874227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * <p>
875227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * You must make sure that before calling this, no more graphs are attached to this runner.
876227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Typically, graphs are removed from runners when they are torn down.
877227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
878227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalStateException if there are still graphs attached to this runner.
879227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
880227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void tearDown() {
881227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mGraphs) {
882227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (!mGraphs.isEmpty()) {
883227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalStateException("Attempting to tear down runner with "
884227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        + mGraphs.size() + " graphs still attached!");
885227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
886227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
887227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(KILL_EVENT);
888227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Wait for thread to complete, so that everything is torn down by the time we return.
889227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        try {
890227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mRunThread.join();
891227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } catch (InterruptedException e) {
892227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            Log.e("GraphRunner", "Error waiting for runner thread to finish!");
893227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
894227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
895227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
896227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
897227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Release all frames managed by this runner.
898227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * <p>
899227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Note, that you must make sure no graphs are attached to this runner before calling this
900227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * method, as otherwise Filters in the graph may reference frames that are now released.
901227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
902227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * TODO: Eventually, this method should be removed. Instead we should have better analysis
903227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * that catches leaking frames from filters.
904227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
905227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @throws IllegalStateException if there are still graphs attached to this runner.
906227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
907227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void releaseFrames() {
908227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mGraphs) {
909227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (!mGraphs.isEmpty()) {
910227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalStateException("Attempting to release frames with "
911227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        + mGraphs.size() + " graphs still attached!");
912227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
913227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
914227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(RELEASE_FRAMES_EVENT);
915227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
916227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
917227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Core internal methods ///////////////////////////////////////////////////////////////////////
918227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void attachGraph(FilterGraph graph) {
919227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mGraphs) {
920227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mGraphs.add(graph);
921227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
922227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
923227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
924227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void signalWakeUp() {
925227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushWakeEvent(STEP_EVENT);
926227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
927227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
928227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void begin() {
929227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(BEGIN_EVENT);
930227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
931227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
932227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Like pause(), but closes all filters. Can be resumed using restart(). */
933227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void halt() {
934227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(HALT_EVENT);
935227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
936227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
937227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /** Resumes a previously halted runner, and restores it to its non-halted state. */
938227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void restart() {
939227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(RESTART_EVENT);
940227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
941227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
942227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
943227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Tears down the specified graph.
944227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
945227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The graph must be attached to this runner.
946227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
947227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void tearDownGraph(FilterGraph graph) {
948227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (graph.getRunner() != this) {
949227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Attempting to tear down graph with foreign "
950227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "GraphRunner!");
951227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
952227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(Event.TEARDOWN, graph);
953227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mGraphs) {
954227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mGraphs.remove(graph);
955227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
956227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
957227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
958227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
959227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Remove all frames that are waiting to be processed.
960227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
961227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Removes and releases frames that are waiting in the graph connections of the currently
962227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * halted graphs, i.e. frames that are waiting to be processed. This does not include frames
963227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * that may be held or cached by filters themselves.
964227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
965227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * TODO: With the new sub-graph architecture, this can now be simplified and made public.
966227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * It can then no longer rely on opened graphs, and instead flush a graph and all its
967227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * sub-graphs.
968227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
969227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    void flushFrames() {
970227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop.pushEvent(FLUSH_EVENT);
971227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
972227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
973227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Private methods /////////////////////////////////////////////////////////////////////////////
974227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void init(Config config) {
975227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mFrameManager = new FrameManager(this, FrameManager.FRAME_CACHE_LRU);
976227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        createScheduler(STRATEGY_LRU);
977227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunLoop = new GraphRunLoop(config.allowOpenGL);
978227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunThread = new Thread(mRunLoop);
979227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunThread.setPriority(config.threadPriority);
980227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunThread.start();
981227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mContext.addRunner(this);
982227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
983227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
984227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void createScheduler(int strategy) {
985227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        switch (strategy) {
986227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case STRATEGY_LRU:
987227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mScheduler = new LruScheduler();
988227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
989227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case STRATEGY_LFU:
990227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mScheduler = new LfuScheduler();
991227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
992227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case STRATEGY_ONESHOT:
993227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                mScheduler = new OneShotScheduler();
994227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
995227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            default:
996227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException(
997227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        "Unknown schedule-strategy constant " + strategy + "!");
998227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
999227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
1000227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
1001227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    // Called within the runner's thread
1002227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void onRunnerStopped(final Exception exception, final boolean closed) {
1003227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mRunningGraph = null;
1004227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        synchronized (mParams) {
1005227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (mParams.listener != null) {
1006227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                getContext().postRunnable(new Runnable() {
1007227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    @Override
1008227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    public void run() {
1009227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        if (exception == null) {
1010227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            mParams.listener.onGraphRunnerStopped(GraphRunner.this);
1011227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        } else {
1012227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                            mParams.listener.onGraphRunnerError(exception, closed);
1013227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        }
1014227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    }
1015227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                });
1016227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            } else if (exception != null) {
1017227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                Log.e("GraphRunner",
1018227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        "Uncaught exception during graph execution! Stack Trace: ");
1019227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                exception.printStackTrace();
1020227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
1021227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
1022227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
1023227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
1024