130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni/*
230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Copyright (C) 2011 The Android Open Source Project
330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Licensed under the Apache License, Version 2.0 (the "License");
530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * you may not use this file except in compliance with the License.
630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * You may obtain a copy of the License at
730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *            http://www.apache.org/licenses/LICENSE-2.0
930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
1030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Unless required by applicable law or agreed to in writing, software
1130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * distributed under the License is distributed on an "AS IS" BASIS,
1230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * See the License for the specific language governing permissions and
1430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * limitations under the License.
1530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni */
1630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
1730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
1830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipackage android.filterfw.core;
1930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
20692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Rennimport android.filterfw.core.FilterContext;
2130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FilterPort;
2230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.KeyValueMap;
23c0017fd82acec5d0427306ea5f536c3d78854f95Marius Rennimport android.filterfw.io.TextGraphReader;
24c0017fd82acec5d0427306ea5f536c3d78854f95Marius Rennimport android.filterfw.io.GraphIOException;
2521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.format.ObjectFormat;
2621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.util.Log;
2730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
287eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Rennimport java.io.Serializable;
29c0017fd82acec5d0427306ea5f536c3d78854f95Marius Rennimport java.lang.annotation.Annotation;
30c0017fd82acec5d0427306ea5f536c3d78854f95Marius Rennimport java.lang.reflect.Field;
31f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvalaimport java.lang.Thread;
3221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport java.util.Collection;
3330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport java.util.HashMap;
3430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport java.util.HashSet;
35c0017fd82acec5d0427306ea5f536c3d78854f95Marius Rennimport java.util.Map.Entry;
3630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport java.util.LinkedList;
3730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport java.util.Set;
3830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
39a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/**
40a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide
41a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */
4230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipublic abstract class Filter {
4330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
4421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    static final int STATUS_PREINIT               = 0;
4521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    static final int STATUS_UNPREPARED            = 1;
468541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn    static final int STATUS_PREPARED              = 2;
4721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    static final int STATUS_PROCESSING            = 3;
4821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    static final int STATUS_SLEEPING              = 4;
4921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    static final int STATUS_FINISHED              = 5;
5021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    static final int STATUS_ERROR                 = 6;
51c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua    static final int STATUS_RELEASED              = 7;
5230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
5330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private String mName;
5430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
5530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private int mInputCount = -1;
5630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private int mOutputCount = -1;
5730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
58f24dc0f733da39b32f15177871a79810d52e6212Marius Renn    private HashMap<String, InputPort> mInputPorts;
59f24dc0f733da39b32f15177871a79810d52e6212Marius Renn    private HashMap<String, OutputPort> mOutputPorts;
6030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
6121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private HashSet<Frame> mFramesToRelease;
6221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private HashMap<String, Frame> mFramesToSet;
6330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
6430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private int mStatus = 0;
6530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private boolean mIsOpen = false;
6621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private int mSleepDelay;
6730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
685b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala    private long mCurrentTimestamp;
695b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala
7057774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala    private boolean mLogVerbose;
710c60e0ab6013df46586bcb6c26f48a850f4c7115Eino-Ville Talvala    private static final String TAG = "Filter";
7257774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala
7330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public Filter(String name) {
7430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mName = name;
7521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mFramesToRelease = new HashSet<Frame>();
7621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mFramesToSet = new HashMap<String, Frame>();
7721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mStatus = STATUS_PREINIT;
7857774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala
7957774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
8030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
8130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
82f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala    /** Tests to see if a given filter is installed on the system. Requires
83f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala     * full filter package name, including filterpack.
84f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala     */
85f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala    public static final boolean isAvailable(String filterName) {
86f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
87f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        Class filterClass;
88f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        // First see if a class of that name exists
89f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        try {
90f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala            filterClass = contextClassLoader.loadClass(filterName);
91f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        } catch (ClassNotFoundException e) {
92f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala            return false;
93f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        }
94f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        // Then make sure it's a subclass of Filter.
95f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        try {
96f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala            filterClass.asSubclass(Filter.class);
97f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        } catch (ClassCastException e) {
98f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala            return false;
99f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        }
100f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala        return true;
101f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala    }
102f9ffc783f43d3092223a1827fec1b95490e3d743Eino-Ville Talvala
10321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final void initWithValueMap(KeyValueMap valueMap) {
10421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Initialization
10521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        initFinalPorts(valueMap);
10621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
10721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Setup remaining ports
10821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        initRemainingPorts(valueMap);
10921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
11021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // This indicates that final ports can no longer be set
11121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mStatus = STATUS_UNPREPARED;
11230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
11330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
11421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final void initWithAssignmentString(String assignments) {
115c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn        try {
11621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            KeyValueMap valueMap = new TextGraphReader().readKeyValueAssignments(assignments);
11721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            initWithValueMap(valueMap);
118c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn        } catch (GraphIOException e) {
119c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn            throw new IllegalArgumentException(e.getMessage());
120c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn        }
12130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
12230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
12321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final void initWithAssignmentList(Object... keyValues) {
12421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        KeyValueMap valueMap = new KeyValueMap();
12521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        valueMap.setKeyValues(keyValues);
12621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        initWithValueMap(valueMap);
12730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
12830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
12930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public final void init() throws ProtocolException {
13021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        KeyValueMap valueMap = new KeyValueMap();
13121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        initWithValueMap(valueMap);
13230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
13330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
13430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public String getFilterClassName() {
13530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return getClass().getSimpleName();
13630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
13730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
13830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public final String getName() {
13930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return mName;
14030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
14130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
14230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public boolean isOpen() {
14330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return mIsOpen;
14430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
14530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
146f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    public void setInputFrame(String inputName, Frame frame) {
14721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        FilterPort port = getInputPort(inputName);
14821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (!port.isOpen()) {
14921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            port.open();
150c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn        }
15121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        port.setFrame(frame);
15230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
15330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
15421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final void setInputValue(String inputName, Object value) {
155f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        setInputFrame(inputName, wrapInputValue(inputName, value));
15630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
15730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
158692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    protected void prepare(FilterContext context) {
15930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
16030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
16130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    protected void parametersUpdated(Set<String> updated) {
16230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
16330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
16421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void delayNextProcess(int millisecs) {
16521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mSleepDelay = millisecs;
16621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mStatus = STATUS_SLEEPING;
16721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
16830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
16921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public abstract void setupPorts();
17030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
17121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
17221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return null;
173b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn    }
174b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn
17521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final FrameFormat getInputFormat(String portName) {
176f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        InputPort inputPort = getInputPort(portName);
17721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return inputPort.getSourceFormat();
17821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
179692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn
18021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void open(FilterContext context) {
18130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
18230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
18321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public abstract void process(FilterContext context);
18430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
18521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final int getSleepDelay() {
18630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return 250;
18730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
18830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
189692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public void close(FilterContext context) {
19030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
19130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
192692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public void tearDown(FilterContext context) {
19330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
19430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
19521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final int getNumberOfConnectedInputs() {
19621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        int c = 0;
197f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
19821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (inputPort.isConnected()) {
19921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                ++c;
20021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            }
20130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
20221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return c;
20330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
20430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
20521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final int getNumberOfConnectedOutputs() {
20621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        int c = 0;
207f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
20821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (outputPort.isConnected()) {
20921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                ++c;
21021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            }
21130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
21221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return c;
21330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
21430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
21521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final int getNumberOfInputs() {
21621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return mOutputPorts == null ? 0 : mInputPorts.size();
21721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
21821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
21921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public final int getNumberOfOutputs() {
22021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return mInputPorts == null ? 0 : mOutputPorts.size();
22121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
22221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
223f24dc0f733da39b32f15177871a79810d52e6212Marius Renn    public final InputPort getInputPort(String portName) {
224cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn        if (mInputPorts == null) {
225cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn            throw new NullPointerException("Attempting to access input port '" + portName
226cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn                + "' of " + this + " before Filter has been initialized!");
227cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn        }
228f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        InputPort result = mInputPorts.get(portName);
229b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn        if (result == null) {
230b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn            throw new IllegalArgumentException("Unknown input port '" + portName + "' on filter "
231b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn                + this + "!");
232b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn        }
233b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn        return result;
23430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
23530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
236f24dc0f733da39b32f15177871a79810d52e6212Marius Renn    public final OutputPort getOutputPort(String portName) {
237cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn        if (mInputPorts == null) {
238cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn            throw new NullPointerException("Attempting to access output port '" + portName
239cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn                + "' of " + this + " before Filter has been initialized!");
240cfda0a38d6f394724e0cbd831ec9bc71d951fc74Marius Renn        }
241f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        OutputPort result = mOutputPorts.get(portName);
242b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn        if (result == null) {
243b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn            throw new IllegalArgumentException("Unknown output port '" + portName + "' on filter "
244b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn                + this + "!");
245b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn        }
246b64fe6f6bbad306e4b10fafefcbdd981ec82a5baMarius Renn        return result;
24730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
24830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
24921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected final void pushOutput(String name, Frame frame) {
2505b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala        if (frame.getTimestamp() == Frame.TIMESTAMP_NOT_SET) {
2515b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Default-setting output Frame timestamp on port " + name + " to " + mCurrentTimestamp);
2525b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala            frame.setTimestamp(mCurrentTimestamp);
2535b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala        }
25421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        getOutputPort(name).pushFrame(frame);
25530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
25630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
25721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected final Frame pullInput(String name) {
25821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        Frame result = getInputPort(name).pullFrame();
2595b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala        if (mCurrentTimestamp == Frame.TIMESTAMP_UNKNOWN) {
2605b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala            mCurrentTimestamp = result.getTimestamp();
261d0d514c296daba245f4c70871f1a1db39535f87cEino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Default-setting current timestamp from input port " + name + " to " + mCurrentTimestamp);
2625b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala        }
26321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // As result is retained, we add it to the release pool here
26421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mFramesToRelease.add(result);
26530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
26630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return result;
26730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
26830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
26921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    public void fieldPortValueUpdated(String name, FilterContext context) {
27021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
27121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
27221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    /**
27316c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn     * Transfers any frame from an input port to its destination. This is useful to force a
27416c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn     * transfer from a FieldPort or ProgramPort to its connected target (field or program variable).
27516c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn     */
27616c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn    protected void transferInputPortFrame(String name, FilterContext context) {
27716c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn        getInputPort(name).transfer(context);
27816c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn    }
27916c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn
28016c2d40d344a19b7d85777b5c71c1102db48769eMarius Renn    /**
2813f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn     * Assigns all program variables to the ports they are connected to. Call this after
2823f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn     * constructing a Program instance with attached ProgramPorts.
2833f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn     */
2843f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn    protected void initProgramInputs(Program program, FilterContext context) {
2853f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn        if (program != null) {
2863f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn            for (InputPort inputPort : mInputPorts.values()) {
2873f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn                if (inputPort.getTarget() == program) {
2883f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn                    inputPort.transfer(context);
2893f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn                }
2903f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn            }
2913f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn        }
2923f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn    }
2933f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn
2943f7ca5db73a94285e404e09d377dd5fd6afc7aafMarius Renn    /**
29521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * Adds an input port to the filter. You should call this from within setupPorts, if your
29621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * filter has input ports. No type-checking is performed on the input. If you would like to
29721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * check against a type mask, use
29821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * {@link #addMaskedInputPort(String, FrameFormat) addMaskedInputPort} instead.
29921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     *
30021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param name the name of the input port
30121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     */
30221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void addInputPort(String name) {
30321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addMaskedInputPort(name, null);
30421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
30521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
30621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    /**
30721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * Adds an input port to the filter. You should call this from within setupPorts, if your
30821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * filter has input ports. When type-checking is performed, the input format is
30921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * checked against the provided format mask. An exception is thrown in case of a conflict.
31021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     *
31121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param name the name of the input port
31221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param formatMask a format mask, which filters the allowable input types
31321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     */
31421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void addMaskedInputPort(String name, FrameFormat formatMask) {
315f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        InputPort port = new StreamPort(this, name);
31657774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
31721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mInputPorts.put(name, port);
31821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        port.setPortFormat(formatMask);
31921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
32021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
32121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    /**
32221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * Adds an output port to the filter with a fixed output format. You should call this from
32321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * within setupPorts, if your filter has output ports. You cannot use this method, if your
32421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * output format depends on the input format (e.g. in a pass-through filter). In this case, use
32521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * {@link #addOutputBasedOnInput(String, String) addOutputBasedOnInput} instead.
32621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     *
32721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param name the name of the output port
32821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param format the fixed output format of this port
32921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     */
33021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void addOutputPort(String name, FrameFormat format) {
33121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        OutputPort port = new OutputPort(this, name);
33257774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
33321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        port.setPortFormat(format);
33421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mOutputPorts.put(name, port);
33521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
33621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
33721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    /**
33821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * Adds an output port to the filter. You should call this from within setupPorts, if your
33921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * filter has output ports. Using this method indicates that the output format for this
34021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * particular port, depends on the format of an input port. You MUST also override
34121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * {@link #getOutputFormat(String, FrameFormat) getOutputFormat} to specify what format your
34221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * filter will output for a given input. If the output format of your filter port does not
34321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * depend on the input, use {@link #addOutputPort(String, FrameFormat) addOutputPort} instead.
34421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     *
34521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param outputName the name of the output port
34621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     * @param inputName the name of the input port, that this output depends on
34721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn     */
34821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void addOutputBasedOnInput(String outputName, String inputName) {
34921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        OutputPort port = new OutputPort(this, outputName);
35057774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
35121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        port.setBasePort(getInputPort(inputName));
35221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mOutputPorts.put(outputName, port);
35321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
35421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
35521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void addFieldPort(String name,
35621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                Field field,
35721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                boolean hasDefault,
35821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                boolean isFinal) {
35921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Make sure field is accessible
36021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        field.setAccessible(true);
36121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
36221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Create port for this input
363f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        InputPort fieldPort = isFinal
36421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            ? new FinalPort(this, name, field, hasDefault)
36521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            : new FieldPort(this, name, field, hasDefault);
36621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
36721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Create format for this input
36857774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + fieldPort);
36921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        MutableFrameFormat format = ObjectFormat.fromClass(field.getType(),
370bf4aaebc555cfb1e49ee411e3477203749fe6a11Marius Renn                                                           FrameFormat.TARGET_SIMPLE);
37121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        fieldPort.setPortFormat(format);
37221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
37321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Add port
37421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mInputPorts.put(name, fieldPort);
37521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
37621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
37721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void addProgramPort(String name,
37821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                  String varName,
37921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                  Field field,
38021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                  Class varType,
38121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                  boolean hasDefault) {
38221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Make sure field is accessible
38321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        field.setAccessible(true);
38421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
38521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Create port for this input
386f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        InputPort programPort = new ProgramPort(this, name, varName, field, hasDefault);
38721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
38821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Create format for this input
38957774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + programPort);
39021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        MutableFrameFormat format = ObjectFormat.fromClass(varType,
391bf4aaebc555cfb1e49ee411e3477203749fe6a11Marius Renn                                                           FrameFormat.TARGET_SIMPLE);
39221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        programPort.setPortFormat(format);
39321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
39421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        // Add port
39521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mInputPorts.put(name, programPort);
39621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
39721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
39821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    protected void closeOutputPort(String name) {
39921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        getOutputPort(name).close();
40021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
40121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
40248189dec808108f392000edbdc90bbd6b1818671Marius Renn    /**
40348189dec808108f392000edbdc90bbd6b1818671Marius Renn     * Specifies whether the filter should not be scheduled until a frame is available on that
40448189dec808108f392000edbdc90bbd6b1818671Marius Renn     * input port. Note, that setting this to false, does not block a new frame from coming in
40548189dec808108f392000edbdc90bbd6b1818671Marius Renn     * (though there is no necessity to pull that frame for processing).
40648189dec808108f392000edbdc90bbd6b1818671Marius Renn     * @param portName the name of the input port.
40748189dec808108f392000edbdc90bbd6b1818671Marius Renn     * @param waits true, if the filter should wait for a frame on this port.
40848189dec808108f392000edbdc90bbd6b1818671Marius Renn     */
40948189dec808108f392000edbdc90bbd6b1818671Marius Renn    protected void setWaitsOnInputPort(String portName, boolean waits) {
41048189dec808108f392000edbdc90bbd6b1818671Marius Renn        getInputPort(portName).setBlocking(waits);
411c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn    }
412c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn
41348189dec808108f392000edbdc90bbd6b1818671Marius Renn    /**
41448189dec808108f392000edbdc90bbd6b1818671Marius Renn     * Specifies whether the filter should not be scheduled until the output port is free, i.e.
41548189dec808108f392000edbdc90bbd6b1818671Marius Renn     * there is no frame waiting on that output.
41648189dec808108f392000edbdc90bbd6b1818671Marius Renn     * @param portName the name of the output port.
41748189dec808108f392000edbdc90bbd6b1818671Marius Renn     * @param waits true, if the filter should wait for the port to become free.
41848189dec808108f392000edbdc90bbd6b1818671Marius Renn     */
41948189dec808108f392000edbdc90bbd6b1818671Marius Renn    protected void setWaitsOnOutputPort(String portName, boolean waits) {
42048189dec808108f392000edbdc90bbd6b1818671Marius Renn        getOutputPort(portName).setBlocking(waits);
421c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn    }
422c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn
42330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public String toString() {
42430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return "'" + getName() + "' (" + getFilterClassName() + ")";
42530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
42630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
42730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    // Core internal methods ///////////////////////////////////////////////////////////////////////
428f24dc0f733da39b32f15177871a79810d52e6212Marius Renn    final Collection<InputPort> getInputPorts() {
42921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return mInputPorts.values();
43021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
43121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn
432f24dc0f733da39b32f15177871a79810d52e6212Marius Renn    final Collection<OutputPort> getOutputPorts() {
43321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return mOutputPorts.values();
43430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
43530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
43621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    final synchronized int getStatus() {
43721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return mStatus;
43830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
43930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
44030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    final synchronized void unsetStatus(int flag) {
44130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mStatus &= ~flag;
44230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
44330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
44421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    final synchronized void performOpen(FilterContext context) {
44521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (!mIsOpen) {
44621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (mStatus == STATUS_UNPREPARED) {
44757774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Preparing " + this);
44821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                prepare(context);
4498541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn                mStatus = STATUS_PREPARED;
45021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            }
4518541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn            if (mStatus == STATUS_PREPARED) {
45257774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Opening " + this);
45321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                open(context);
45421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                mStatus = STATUS_PROCESSING;
45521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            }
45621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (mStatus != STATUS_PROCESSING) {
45721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                throw new RuntimeException("Filter " + this + " was brought into invalid state during "
45821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    + "opening (state: " + mStatus + ")!");
45921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            }
46021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            mIsOpen = true;
46130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
46230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
46330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
46421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    final synchronized void performProcess(FilterContext context) {
465c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua        if (mStatus == STATUS_RELEASED) {
466c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua            throw new RuntimeException("Filter " + this + " is already torn down!");
467c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua        }
46821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        transferInputFrames(context);
46921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (mStatus < STATUS_PROCESSING) {
47021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            performOpen(context);
47121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
47257774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Processing " + this);
4735b9eb6d686c439545dafcc8e25e9e3747281c3deEino-Ville Talvala        mCurrentTimestamp = Frame.TIMESTAMP_UNKNOWN;
47421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        process(context);
47521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        releasePulledFrames(context);
47621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (filterMustClose()) {
47721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            performClose(context);
47830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
47930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
48030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
48121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    final synchronized void performClose(FilterContext context) {
48221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (mIsOpen) {
48357774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala            if (mLogVerbose) Log.v(TAG, "Closing " + this);
48430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mIsOpen = false;
4858541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn            mStatus = STATUS_PREPARED;
486692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn            close(context);
48721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            closePorts();
48830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
48930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
49030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
491c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua    final synchronized void performTearDown(FilterContext context) {
492c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua        performClose(context);
493c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua        if (mStatus != STATUS_RELEASED) {
494c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua            tearDown(context);
495c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua            mStatus = STATUS_RELEASED;
496c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua        }
497c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua    }
498c64256d3d005329f36ea0d618ec5b5a6c8bab7d1Wei Hua
49930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    synchronized final boolean canProcess() {
500489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn        if (mLogVerbose) Log.v(TAG, "Checking if can process: " + this + " (" + mStatus + ").");
50121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        if (mStatus <= STATUS_PROCESSING) {
50221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            return inputConditionsMet() && outputConditionsMet();
50321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        } else {
50430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            return false;
50530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
50621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
50730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
5088541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn    final void openOutputs() {
50957774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Opening all output ports on " + this + "!");
510f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
5118541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn            if (!outputPort.isOpen()) {
5128541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn                outputPort.open();
5138541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn            }
51430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
51521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
51630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
51748189dec808108f392000edbdc90bbd6b1818671Marius Renn    final void clearInputs() {
51848189dec808108f392000edbdc90bbd6b1818671Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
51948189dec808108f392000edbdc90bbd6b1818671Marius Renn            inputPort.clear();
52048189dec808108f392000edbdc90bbd6b1818671Marius Renn        }
52148189dec808108f392000edbdc90bbd6b1818671Marius Renn    }
52248189dec808108f392000edbdc90bbd6b1818671Marius Renn
523489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn    final void clearOutputs() {
524489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
525489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn            outputPort.clear();
526489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn        }
527489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn    }
528489c240d3ae33e83dc62ea6f3cc864e47c0e2e3bMarius Renn
52976f9fef4322f86842fda773a3753172878e311f7Marius Renn    final void notifyFieldPortValueUpdated(String name, FilterContext context) {
5308541cea20c74fdfe35a6c63c09459dd969292b7eMarius Renn        if (mStatus == STATUS_PROCESSING || mStatus == STATUS_PREPARED) {
53176f9fef4322f86842fda773a3753172878e311f7Marius Renn            fieldPortValueUpdated(name, context);
53276f9fef4322f86842fda773a3753172878e311f7Marius Renn        }
53376f9fef4322f86842fda773a3753172878e311f7Marius Renn    }
53476f9fef4322f86842fda773a3753172878e311f7Marius Renn
535f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    final synchronized void pushInputFrame(String inputName, Frame frame) {
536f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        FilterPort port = getInputPort(inputName);
537f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        if (!port.isOpen()) {
538f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn            port.open();
539f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        }
540f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        port.pushFrame(frame);
541f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    }
542f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn
543f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    final synchronized void pushInputValue(String inputName, Object value) {
544f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        pushInputFrame(inputName, wrapInputValue(inputName, value));
545f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    }
546f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn
54721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    // Filter internal methods /////////////////////////////////////////////////////////////////////
54821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void initFinalPorts(KeyValueMap values) {
549f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        mInputPorts = new HashMap<String, InputPort>();
550f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        mOutputPorts = new HashMap<String, OutputPort>();
55121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addAndSetFinalPorts(values);
55221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
55330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
55421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void initRemainingPorts(KeyValueMap values) {
55521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addAnnotatedPorts();
55621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        setupPorts();   // TODO: rename to addFilterPorts() ?
55721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        setInitialInputValues(values);
55830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
55930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
56021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void addAndSetFinalPorts(KeyValueMap values) {
56121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        Class filterClass = getClass();
56221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        Annotation annotation;
56321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        for (Field field : filterClass.getDeclaredFields()) {
56421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if ((annotation = field.getAnnotation(GenerateFinalPort.class)) != null) {
56521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                GenerateFinalPort generator = (GenerateFinalPort)annotation;
56621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                String name = generator.name().isEmpty() ? field.getName() : generator.name();
56721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                boolean hasDefault = generator.hasDefault();
56821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                addFieldPort(name, field, hasDefault, true);
56921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                if (values.containsKey(name)) {
57021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    setImmediateInputValue(name, values.get(name));
57121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    values.remove(name);
57221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                } else if (!generator.hasDefault()) {
57321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    throw new RuntimeException("No value specified for final input port '"
57421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                        + name + "' of filter " + this + "!");
57521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                }
57630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
57730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
57830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
57930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
58021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void addAnnotatedPorts() {
58121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        Class filterClass = getClass();
58221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        Annotation annotation;
58321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        for (Field field : filterClass.getDeclaredFields()) {
58421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if ((annotation = field.getAnnotation(GenerateFieldPort.class)) != null) {
58521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                GenerateFieldPort generator = (GenerateFieldPort)annotation;
58621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                addFieldGenerator(generator, field);
58721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            } else if ((annotation = field.getAnnotation(GenerateProgramPort.class)) != null) {
58821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                GenerateProgramPort generator = (GenerateProgramPort)annotation;
58921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                addProgramGenerator(generator, field);
59021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            } else if ((annotation = field.getAnnotation(GenerateProgramPorts.class)) != null) {
59121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                GenerateProgramPorts generators = (GenerateProgramPorts)annotation;
59221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                for (GenerateProgramPort generator : generators.value()) {
59321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                    addProgramGenerator(generator, field);
59421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                }
59530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
59630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
59730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
59830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
59921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void addFieldGenerator(GenerateFieldPort generator, Field field) {
60021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        String name = generator.name().isEmpty() ? field.getName() : generator.name();
60121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        boolean hasDefault = generator.hasDefault();
60221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addFieldPort(name, field, hasDefault, false);
60330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
60430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
60521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void addProgramGenerator(GenerateProgramPort generator, Field field) {
60621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        String name = generator.name();
60721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        String varName = generator.variableName().isEmpty() ? name
60821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                                                            : generator.variableName();
60921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        Class varType = generator.type();
61021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        boolean hasDefault = generator.hasDefault();
61121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        addProgramPort(name, varName, field, varType, hasDefault);
61221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
61330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
61421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void setInitialInputValues(KeyValueMap values) {
61521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        for (Entry<String, Object> entry : values.entrySet()) {
61621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            setInputValue(entry.getKey(), entry.getValue());
61730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
61821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
61930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
62021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void setImmediateInputValue(String name, Object value) {
62157774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Setting immediate value " + value + " for port " + name + "!");
62221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        FilterPort port = getInputPort(name);
62321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        port.open();
624bf4aaebc555cfb1e49ee411e3477203749fe6a11Marius Renn        port.setFrame(SimpleFrame.wrapObject(value, null));
62530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
62630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
62721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void transferInputFrames(FilterContext context) {
628f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
62921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            inputPort.transfer(context);
63021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
63121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    }
63230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
633f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    private final Frame wrapInputValue(String inputName, Object value) {
634bf4aaebc555cfb1e49ee411e3477203749fe6a11Marius Renn        MutableFrameFormat inputFormat = ObjectFormat.fromObject(value, FrameFormat.TARGET_SIMPLE);
635f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        if (value == null) {
636f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn            // If the value is null, the format cannot guess the class, so we adjust it to the
637f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn            // class of the input port here
638f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn            FrameFormat portFormat = getInputPort(inputName).getPortFormat();
639f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn            Class portClass = (portFormat == null) ? null : portFormat.getObjectClass();
640f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn            inputFormat.setObjectClass(portClass);
641f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        }
6427eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn
6437eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn        // Serialize if serializable, and type is not an immutable primitive.
6447eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn        boolean shouldSerialize = !(value instanceof Number)
6457eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn            && !(value instanceof Boolean)
6467eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn            && !(value instanceof String)
6477eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn            && value instanceof Serializable;
6487eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn
6497eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn        // Create frame wrapper
6507eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn        Frame frame = shouldSerialize
6517eacc1981bcbd53a79721b23a2a9da6fd0c0a1abMarius Renn            ? new SerializedFrame(inputFormat, null)
652bf4aaebc555cfb1e49ee411e3477203749fe6a11Marius Renn            : new SimpleFrame(inputFormat, null);
653f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        frame.setObjectValue(value);
654f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        return frame;
655f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    }
656f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn
65721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void releasePulledFrames(FilterContext context) {
65821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        for (Frame frame : mFramesToRelease) {
65921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            context.getFrameManager().releaseFrame(frame);
66021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
66121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        mFramesToRelease.clear();
66230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
66330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
66421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final boolean inputConditionsMet() {
66521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        for (FilterPort port : mInputPorts.values()) {
66621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (!port.isReady()) {
66757774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Input condition not met: " + port + "!");
66821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                return false;
66930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
67030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
67121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return true;
67230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
67330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
67421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final boolean outputConditionsMet() {
67521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        for (FilterPort port : mOutputPorts.values()) {
67621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (!port.isReady()) {
67757774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Output condition not met: " + port + "!");
67821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                return false;
67930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
68030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
68121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return true;
68230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
68330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
68421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final void closePorts() {
68557774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala        if (mLogVerbose) Log.v(TAG, "Closing all ports on " + this + "!");
686f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
68721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            inputPort.close();
68821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
689f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
69021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            outputPort.close();
69130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
69230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
69330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
69421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn    private final boolean filterMustClose() {
695f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (InputPort inputPort : mInputPorts.values()) {
69621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (inputPort.filterMustClose()) {
69757774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + inputPort);
69821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                return true;
69930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
70030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
701f24dc0f733da39b32f15177871a79810d52e6212Marius Renn        for (OutputPort outputPort : mOutputPorts.values()) {
70221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            if (outputPort.filterMustClose()) {
70357774b9e8ea96fa5088e68bac7a21465fa429b15Eino-Ville Talvala                if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + outputPort);
70421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn                return true;
70521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn            }
70621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        }
70721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn        return false;
70830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
70930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
710