165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/*
265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project
365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License");
565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License.
665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at
765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *            http://www.apache.org/licenses/LICENSE-2.0
965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn *
1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software
1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS,
1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and
1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License.
1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */
1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpackage android.filterfw.core;
1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterContext;
2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterPort;
2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.KeyValueMap;
2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.io.TextGraphReader;
2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.io.GraphIOException;
2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.format.ObjectFormat;
2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.util.Log;
2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.io.Serializable;
2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.annotation.Annotation;
3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.reflect.Field;
3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.Thread;
3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Collection;
3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.HashMap;
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.HashSet;
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Map.Entry;
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.LinkedList;
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Set;
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/**
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic abstract class Filter {
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_PREINIT               = 0;
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_UNPREPARED            = 1;
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_PREPARED              = 2;
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_PROCESSING            = 3;
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_SLEEPING              = 4;
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_FINISHED              = 5;
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_ERROR                 = 6;
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    static final int STATUS_RELEASED              = 7;
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private String mName;
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private int mInputCount = -1;
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private int mOutputCount = -1;
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private HashMap<String, InputPort> mInputPorts;
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private HashMap<String, OutputPort> mOutputPorts;
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private HashSet<Frame> mFramesToRelease;
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private HashMap<String, Frame> mFramesToSet;
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private int mStatus = 0;
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private boolean mIsOpen = false;
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private int mSleepDelay;
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private long mCurrentTimestamp;
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private boolean mLogVerbose;
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private static final String TAG = "Filter";
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public Filter(String name) {
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mName = name;
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mFramesToRelease = new HashSet<Frame>();
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mFramesToSet = new HashMap<String, Frame>();
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mStatus = STATUS_PREINIT;
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /** Tests to see if a given filter is installed on the system. Requires
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * full filter package name, including filterpack.
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public static final boolean isAvailable(String filterName) {
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Class filterClass;
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // First see if a class of that name exists
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        try {
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            filterClass = contextClassLoader.loadClass(filterName);
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } catch (ClassNotFoundException e) {
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return false;
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Then make sure it's a subclass of Filter.
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        try {
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            filterClass.asSubclass(Filter.class);
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } catch (ClassCastException e) {
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return false;
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return true;
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final void initWithValueMap(KeyValueMap valueMap) {
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Initialization
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        initFinalPorts(valueMap);
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Setup remaining ports
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        initRemainingPorts(valueMap);
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // This indicates that final ports can no longer be set
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mStatus = STATUS_UNPREPARED;
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final void initWithAssignmentString(String assignments) {
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        try {
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            KeyValueMap valueMap = new TextGraphReader().readKeyValueAssignments(assignments);
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            initWithValueMap(valueMap);
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } catch (GraphIOException e) {
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new IllegalArgumentException(e.getMessage());
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final void initWithAssignmentList(Object... keyValues) {
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        KeyValueMap valueMap = new KeyValueMap();
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        valueMap.setKeyValues(keyValues);
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        initWithValueMap(valueMap);
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final void init() throws ProtocolException {
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        KeyValueMap valueMap = new KeyValueMap();
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        initWithValueMap(valueMap);
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public String getFilterClassName() {
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return getClass().getSimpleName();
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final String getName() {
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mName;
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public boolean isOpen() {
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mIsOpen;
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void setInputFrame(String inputName, Frame frame) {
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        FilterPort port = getInputPort(inputName);
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (!port.isOpen()) {
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            port.open();
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.setFrame(frame);
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final void setInputValue(String inputName, Object value) {
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        setInputFrame(inputName, wrapInputValue(inputName, value));
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void prepare(FilterContext context) {
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void parametersUpdated(Set<String> updated) {
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void delayNextProcess(int millisecs) {
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mSleepDelay = millisecs;
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mStatus = STATUS_SLEEPING;
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public abstract void setupPorts();
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return null;
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final FrameFormat getInputFormat(String portName) {
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        InputPort inputPort = getInputPort(portName);
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return inputPort.getSourceFormat();
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void open(FilterContext context) {
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public abstract void process(FilterContext context);
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final int getSleepDelay() {
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return 250;
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void close(FilterContext context) {
19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void tearDown(FilterContext context) {
19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final int getNumberOfConnectedInputs() {
19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        int c = 0;
19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (inputPort.isConnected()) {
19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                ++c;
20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return c;
20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final int getNumberOfConnectedOutputs() {
20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        int c = 0;
20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (outputPort.isConnected()) {
20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                ++c;
21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return c;
21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final int getNumberOfInputs() {
21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mOutputPorts == null ? 0 : mInputPorts.size();
21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final int getNumberOfOutputs() {
22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mInputPorts == null ? 0 : mOutputPorts.size();
22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final InputPort getInputPort(String portName) {
22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mInputPorts == null) {
22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new NullPointerException("Attempting to access input port '" + portName
22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                + "' of " + this + " before Filter has been initialized!");
22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        InputPort result = mInputPorts.get(portName);
22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (result == null) {
23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new IllegalArgumentException("Unknown input port '" + portName + "' on filter "
23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                + this + "!");
23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return result;
23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public final OutputPort getOutputPort(String portName) {
23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mInputPorts == null) {
23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new NullPointerException("Attempting to access output port '" + portName
23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                + "' of " + this + " before Filter has been initialized!");
24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        OutputPort result = mOutputPorts.get(portName);
24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (result == null) {
24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new IllegalArgumentException("Unknown output port '" + portName + "' on filter "
24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                + this + "!");
24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return result;
24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected final void pushOutput(String name, Frame frame) {
25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (frame.getTimestamp() == Frame.TIMESTAMP_NOT_SET) {
25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mLogVerbose) Log.v(TAG, "Default-setting output Frame timestamp on port " + name + " to " + mCurrentTimestamp);
25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            frame.setTimestamp(mCurrentTimestamp);
25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getOutputPort(name).pushFrame(frame);
25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected final Frame pullInput(String name) {
25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Frame result = getInputPort(name).pullFrame();
25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mCurrentTimestamp == Frame.TIMESTAMP_UNKNOWN) {
26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mCurrentTimestamp = result.getTimestamp();
26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mLogVerbose) Log.v(TAG, "Default-setting current timestamp from input port " + name + " to " + mCurrentTimestamp);
26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // As result is retained, we add it to the release pool here
26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mFramesToRelease.add(result);
26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return result;
26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public void fieldPortValueUpdated(String name, FilterContext context) {
27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Transfers any frame from an input port to its destination. This is useful to force a
27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * transfer from a FieldPort or ProgramPort to its connected target (field or program variable).
27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void transferInputPortFrame(String name, FilterContext context) {
27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getInputPort(name).transfer(context);
27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Assigns all program variables to the ports they are connected to. Call this after
28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * constructing a Program instance with attached ProgramPorts.
28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void initProgramInputs(Program program, FilterContext context) {
28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (program != null) {
28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            for (InputPort inputPort : mInputPorts.values()) {
28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (inputPort.getTarget() == program) {
28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    inputPort.transfer(context);
28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                }
29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Adds an input port to the filter. You should call this from within setupPorts, if your
29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * filter has input ports. No type-checking is performed on the input. If you would like to
29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * check against a type mask, use
29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * {@link #addMaskedInputPort(String, FrameFormat) addMaskedInputPort} instead.
29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param name the name of the input port
30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void addInputPort(String name) {
30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        addMaskedInputPort(name, null);
30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Adds an input port to the filter. You should call this from within setupPorts, if your
30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * filter has input ports. When type-checking is performed, the input format is
30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * checked against the provided format mask. An exception is thrown in case of a conflict.
31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param name the name of the input port
31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param formatMask a format mask, which filters the allowable input types
31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void addMaskedInputPort(String name, FrameFormat formatMask) {
31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        InputPort port = new StreamPort(this, name);
31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mInputPorts.put(name, port);
31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.setPortFormat(formatMask);
31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Adds an output port to the filter with a fixed output format. You should call this from
32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * within setupPorts, if your filter has output ports. You cannot use this method, if your
32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * output format depends on the input format (e.g. in a pass-through filter). In this case, use
32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * {@link #addOutputBasedOnInput(String, String) addOutputBasedOnInput} instead.
32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param name the name of the output port
32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param format the fixed output format of this port
32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void addOutputPort(String name, FrameFormat format) {
33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        OutputPort port = new OutputPort(this, name);
33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.setPortFormat(format);
33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mOutputPorts.put(name, port);
33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Adds an output port to the filter. You should call this from within setupPorts, if your
33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * filter has output ports. Using this method indicates that the output format for this
34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * particular port, depends on the format of an input port. You MUST also override
34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * {@link #getOutputFormat(String, FrameFormat) getOutputFormat} to specify what format your
34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * filter will output for a given input. If the output format of your filter port does not
34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * depend on the input, use {@link #addOutputPort(String, FrameFormat) addOutputPort} instead.
34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     *
34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param outputName the name of the output port
34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param inputName the name of the input port, that this output depends on
34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void addOutputBasedOnInput(String outputName, String inputName) {
34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        OutputPort port = new OutputPort(this, outputName);
35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.setBasePort(getInputPort(inputName));
35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mOutputPorts.put(outputName, port);
35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void addFieldPort(String name,
35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                Field field,
35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                boolean hasDefault,
35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                boolean isFinal) {
35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Make sure field is accessible
36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        field.setAccessible(true);
36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Create port for this input
36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        InputPort fieldPort = isFinal
36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            ? new FinalPort(this, name, field, hasDefault)
36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            : new FieldPort(this, name, field, hasDefault);
36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Create format for this input
36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + fieldPort);
36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        MutableFrameFormat format = ObjectFormat.fromClass(field.getType(),
37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                           FrameFormat.TARGET_SIMPLE);
37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        fieldPort.setPortFormat(format);
37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Add port
37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mInputPorts.put(name, fieldPort);
37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void addProgramPort(String name,
37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                  String varName,
37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                  Field field,
38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                  Class varType,
38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                  boolean hasDefault) {
38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Make sure field is accessible
38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        field.setAccessible(true);
38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Create port for this input
38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        InputPort programPort = new ProgramPort(this, name, varName, field, hasDefault);
38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Create format for this input
38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + programPort);
39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        MutableFrameFormat format = ObjectFormat.fromClass(varType,
39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                           FrameFormat.TARGET_SIMPLE);
39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        programPort.setPortFormat(format);
39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Add port
39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mInputPorts.put(name, programPort);
39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void closeOutputPort(String name) {
39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getOutputPort(name).close();
40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Specifies whether the filter should not be scheduled until a frame is available on that
40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * input port. Note, that setting this to false, does not block a new frame from coming in
40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * (though there is no necessity to pull that frame for processing).
40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param portName the name of the input port.
40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param waits true, if the filter should wait for a frame on this port.
40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void setWaitsOnInputPort(String portName, boolean waits) {
41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getInputPort(portName).setBlocking(waits);
41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    /**
41465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * Specifies whether the filter should not be scheduled until the output port is free, i.e.
41565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * there is no frame waiting on that output.
41665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param portName the name of the output port.
41765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     * @param waits true, if the filter should wait for the port to become free.
41865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn     */
41965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    protected void setWaitsOnOutputPort(String portName, boolean waits) {
42065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        getOutputPort(portName).setBlocking(waits);
42165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
42265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    public String toString() {
42465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return "'" + getName() + "' (" + getFilterClassName() + ")";
42565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
42665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Core internal methods ///////////////////////////////////////////////////////////////////////
42865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final Collection<InputPort> getInputPorts() {
42965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mInputPorts.values();
43065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
43165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
43265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final Collection<OutputPort> getOutputPorts() {
43365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mOutputPorts.values();
43465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
43565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
43665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized int getStatus() {
43765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return mStatus;
43865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
43965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
44065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void unsetStatus(int flag) {
44165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mStatus &= ~flag;
44265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
44365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
44465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void performOpen(FilterContext context) {
44565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (!mIsOpen) {
44665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mStatus == STATUS_UNPREPARED) {
44765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (mLogVerbose) Log.v(TAG, "Preparing " + this);
44865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                prepare(context);
44965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                mStatus = STATUS_PREPARED;
45065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
45165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mStatus == STATUS_PREPARED) {
45265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (mLogVerbose) Log.v(TAG, "Opening " + this);
45365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                open(context);
45465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                mStatus = STATUS_PROCESSING;
45565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
45665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mStatus != STATUS_PROCESSING) {
45765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                throw new RuntimeException("Filter " + this + " was brought into invalid state during "
45865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    + "opening (state: " + mStatus + ")!");
45965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
46065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mIsOpen = true;
46165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
46265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
46365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
46465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void performProcess(FilterContext context) {
46565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mStatus == STATUS_RELEASED) {
46665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            throw new RuntimeException("Filter " + this + " is already torn down!");
46765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
46865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        transferInputFrames(context);
46965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mStatus < STATUS_PROCESSING) {
47065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            performOpen(context);
47165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
47265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Processing " + this);
47365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mCurrentTimestamp = Frame.TIMESTAMP_UNKNOWN;
47465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        process(context);
47565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        releasePulledFrames(context);
47665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (filterMustClose()) {
47765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            performClose(context);
47865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
47965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
48065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
48165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void performClose(FilterContext context) {
48265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mIsOpen) {
48365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (mLogVerbose) Log.v(TAG, "Closing " + this);
48465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mIsOpen = false;
48565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mStatus = STATUS_PREPARED;
48665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            close(context);
48765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            closePorts();
48865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
48965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
49065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
49165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void performTearDown(FilterContext context) {
49265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        performClose(context);
49365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mStatus != STATUS_RELEASED) {
49465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            tearDown(context);
49565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            mStatus = STATUS_RELEASED;
49665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
49765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
49865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
49965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    synchronized final boolean canProcess() {
50065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Checking if can process: " + this + " (" + mStatus + ").");
50165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mStatus <= STATUS_PROCESSING) {
50265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return inputConditionsMet() && outputConditionsMet();
50365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } else {
50465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            return false;
50565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
50665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
50765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
50865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final void openOutputs() {
50965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Opening all output ports on " + this + "!");
51065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
51165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (!outputPort.isOpen()) {
51265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                outputPort.open();
51365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
51465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
51565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
51665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
51765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final void clearInputs() {
51865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
51965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            inputPort.clear();
52065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
52165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
52265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
52365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final void clearOutputs() {
52465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
52565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            outputPort.clear();
52665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
52765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
52865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
52965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final void notifyFieldPortValueUpdated(String name, FilterContext context) {
53065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mStatus == STATUS_PROCESSING || mStatus == STATUS_PREPARED) {
53165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            fieldPortValueUpdated(name, context);
53265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
53365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
53465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
53565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void pushInputFrame(String inputName, Frame frame) {
53665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        FilterPort port = getInputPort(inputName);
53765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (!port.isOpen()) {
53865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            port.open();
53965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
54065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.pushFrame(frame);
54165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
54265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
54365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    final synchronized void pushInputValue(String inputName, Object value) {
54465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        pushInputFrame(inputName, wrapInputValue(inputName, value));
54565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
54665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
54765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Filter internal methods /////////////////////////////////////////////////////////////////////
54865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void initFinalPorts(KeyValueMap values) {
54965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mInputPorts = new HashMap<String, InputPort>();
55065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mOutputPorts = new HashMap<String, OutputPort>();
55165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        addAndSetFinalPorts(values);
55265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
55365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
55465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void initRemainingPorts(KeyValueMap values) {
55565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        addAnnotatedPorts();
55665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        setupPorts();   // TODO: rename to addFilterPorts() ?
55765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        setInitialInputValues(values);
55865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
55965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
56065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void addAndSetFinalPorts(KeyValueMap values) {
56165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Class filterClass = getClass();
56265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Annotation annotation;
56365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (Field field : filterClass.getDeclaredFields()) {
56465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if ((annotation = field.getAnnotation(GenerateFinalPort.class)) != null) {
56565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                GenerateFinalPort generator = (GenerateFinalPort)annotation;
56665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                String name = generator.name().isEmpty() ? field.getName() : generator.name();
56765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                boolean hasDefault = generator.hasDefault();
56865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                addFieldPort(name, field, hasDefault, true);
56965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (values.containsKey(name)) {
57065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    setImmediateInputValue(name, values.get(name));
57165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    values.remove(name);
57265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                } else if (!generator.hasDefault()) {
57365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    throw new RuntimeException("No value specified for final input port '"
57465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                        + name + "' of filter " + this + "!");
57565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                }
57665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
57765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
57865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
57965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
58065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void addAnnotatedPorts() {
58165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Class filterClass = getClass();
58265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Annotation annotation;
58365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (Field field : filterClass.getDeclaredFields()) {
58465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if ((annotation = field.getAnnotation(GenerateFieldPort.class)) != null) {
58565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                GenerateFieldPort generator = (GenerateFieldPort)annotation;
58665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                addFieldGenerator(generator, field);
58765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } else if ((annotation = field.getAnnotation(GenerateProgramPort.class)) != null) {
58865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                GenerateProgramPort generator = (GenerateProgramPort)annotation;
58965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                addProgramGenerator(generator, field);
59065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            } else if ((annotation = field.getAnnotation(GenerateProgramPorts.class)) != null) {
59165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                GenerateProgramPorts generators = (GenerateProgramPorts)annotation;
59265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                for (GenerateProgramPort generator : generators.value()) {
59365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                    addProgramGenerator(generator, field);
59465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                }
59565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
59665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
59765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
59865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
59965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void addFieldGenerator(GenerateFieldPort generator, Field field) {
60065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        String name = generator.name().isEmpty() ? field.getName() : generator.name();
60165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        boolean hasDefault = generator.hasDefault();
60265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        addFieldPort(name, field, hasDefault, false);
60365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
60465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
60565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void addProgramGenerator(GenerateProgramPort generator, Field field) {
60665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        String name = generator.name();
60765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        String varName = generator.variableName().isEmpty() ? name
60865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                            : generator.variableName();
60965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Class varType = generator.type();
61065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        boolean hasDefault = generator.hasDefault();
61165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        addProgramPort(name, varName, field, varType, hasDefault);
61265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
61365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
61465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void setInitialInputValues(KeyValueMap values) {
61565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (Entry<String, Object> entry : values.entrySet()) {
61665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            setInputValue(entry.getKey(), entry.getValue());
61765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
61865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
61965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
62065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void setImmediateInputValue(String name, Object value) {
62165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Setting immediate value " + value + " for port " + name + "!");
62265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        FilterPort port = getInputPort(name);
62365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.open();
62465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        port.setFrame(SimpleFrame.wrapObject(value, null));
62565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
62665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
62765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void transferInputFrames(FilterContext context) {
62865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
62965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            inputPort.transfer(context);
63065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
63165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
63265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
63365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final Frame wrapInputValue(String inputName, Object value) {
63465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        MutableFrameFormat inputFormat = ObjectFormat.fromObject(value, FrameFormat.TARGET_SIMPLE);
63565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (value == null) {
63665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            // If the value is null, the format cannot guess the class, so we adjust it to the
63765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            // class of the input port here
63865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            FrameFormat portFormat = getInputPort(inputName).getPortFormat();
63965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Class portClass = (portFormat == null) ? null : portFormat.getObjectClass();
64065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            inputFormat.setObjectClass(portClass);
64165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
64265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
64365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Serialize if serializable, and type is not an immutable primitive.
64465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        boolean shouldSerialize = !(value instanceof Number)
64565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            && !(value instanceof Boolean)
64665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            && !(value instanceof String)
64765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            && value instanceof Serializable;
64865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
64965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Create frame wrapper
65065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Frame frame = shouldSerialize
65165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            ? new SerializedFrame(inputFormat, null)
65265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            : new SimpleFrame(inputFormat, null);
65365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        frame.setObjectValue(value);
65465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return frame;
65565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
65665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
65765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void releasePulledFrames(FilterContext context) {
65865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (Frame frame : mFramesToRelease) {
65965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            context.getFrameManager().releaseFrame(frame);
66065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
66165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        mFramesToRelease.clear();
66265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
66365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
66465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final boolean inputConditionsMet() {
66565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (FilterPort port : mInputPorts.values()) {
66665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (!port.isReady()) {
66765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (mLogVerbose) Log.v(TAG, "Input condition not met: " + port + "!");
66865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                return false;
66965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
67065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
67165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return true;
67265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
67365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
67465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final boolean outputConditionsMet() {
67565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (FilterPort port : mOutputPorts.values()) {
67665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (!port.isReady()) {
67765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (mLogVerbose) Log.v(TAG, "Output condition not met: " + port + "!");
67865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                return false;
67965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
68065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
68165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return true;
68265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
68365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
68465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final void closePorts() {
68565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (mLogVerbose) Log.v(TAG, "Closing all ports on " + this + "!");
68665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
68765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            inputPort.close();
68865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
68965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
69065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            outputPort.close();
69165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
69265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
69365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
69465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    private final boolean filterMustClose() {
69565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
69665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (inputPort.filterMustClose()) {
69765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + inputPort);
69865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                return true;
69965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
70065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
70165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
70265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            if (outputPort.filterMustClose()) {
70365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + outputPort);
70465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                return true;
70565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            }
70665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
70765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
70865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
70965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
710