1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.media.filterfw;
18 
19 /**
20  * Output ports are the data emitting ports of filters.
21  * <p>
22  * Filters push data frames onto output-ports, which in turn push them onto their connected input
23  * ports. Output ports must be connected to an input port before data can be pushed onto them.
24  * Input and output ports share their Frame slot, meaning that when a frame is waiting on an output
25  * port, it is also waiting on the connected input port.
26  * </p><p>
27  * Only one frame can be pushed onto an output port at a time. In other words, a Frame must first
28  * be consumed by the target filter before a new frame can be pushed on the output port. If the
29  * output port is set to wait until it becomes free (see {@link #setWaitsUntilAvailable(boolean)}),
30  * it is guaranteed to be available when {@code onProcess()} is called. This is the default setting.
31  * </p>
32  */
33 public final class OutputPort {
34 
35     private Filter mFilter;
36     private String mName;
37     private Signature.PortInfo mInfo;
38     private FrameQueue.Builder mQueueBuilder = null;
39     private FrameQueue mQueue = null;
40     private boolean mWaitsUntilAvailable = true;
41     private InputPort mTarget = null;
42 
43     /**
44      * Returns true, if this port is connected to a target port.
45      * @return true, if this port is connected to a target port.
46      */
isConnected()47     public boolean isConnected() {
48         return mTarget != null;
49     }
50 
51     /**
52      * Returns true, if there is no frame waiting on this port.
53      * @return true, if no Frame instance is waiting on this port.
54      */
isAvailable()55     public boolean isAvailable() {
56         return mQueue == null || mQueue.canPush();
57     }
58 
59     /**
60      * Returns a frame for writing.
61      *
62      * Call this method to fetch a new frame to write into. When you have finished writing the
63      * frame data, you can push it into the output queue using {@link #pushFrame(Frame)}. Note,
64      * that the Frame returned is owned by the queue. If you wish to hold on to the frame, you
65      * must detach it.
66      *
67      * @param dimensions the size of the Frame you wish to obtain.
68      * @return a writable Frame instance.
69      */
fetchAvailableFrame(int[] dimensions)70     public Frame fetchAvailableFrame(int[] dimensions) {
71         Frame frame = getQueue().fetchAvailableFrame(dimensions);
72         if (frame != null) {
73             //Log.i("OutputPort", "Adding frame " + frame + " to auto-release pool");
74             mFilter.addAutoReleaseFrame(frame);
75         }
76         return frame;
77     }
78 
79     /**
80      * Pushes a frame onto this output port.
81      *
82      * This is typically a Frame instance you obtained by previously calling
83      * {@link #fetchAvailableFrame(int[])}, but may come from other sources such as an input port
84      * that is attached to this output port.
85      *
86      * Once you have pushed a frame to an output, you may no longer modify it as it may be shared
87      * among other filters.
88      *
89      * @param frame the frame to push to the output queue.
90      */
pushFrame(Frame frame)91     public void pushFrame(Frame frame) {
92         // Some queues allow pushing without fetching, so we need to make sure queue is open
93         // before pushing!
94         long timestamp = frame.getTimestamp();
95         if (timestamp == Frame.TIMESTAMP_NOT_SET)
96             frame.setTimestamp(mFilter.getCurrentTimestamp());
97         getQueue().pushFrame(frame);
98     }
99 
100     /**
101      * Sets whether to wait until this port becomes available before processing.
102      * When set to true, the Filter will not be scheduled for processing unless there is no Frame
103      * waiting on this port. The default value is true.
104      *
105      * @param wait true, if filter should wait for the port to become available before processing.
106      * @see #waitsUntilAvailable()
107      */
setWaitsUntilAvailable(boolean wait)108     public void setWaitsUntilAvailable(boolean wait) {
109         mWaitsUntilAvailable = wait;
110     }
111 
112     /**
113      * Returns whether the filter waits until this port is available before processing.
114      * @return true, if the filter waits until this port is available before processing.
115      * @see #setWaitsUntilAvailable(boolean)
116      */
waitsUntilAvailable()117     public boolean waitsUntilAvailable() {
118         return mWaitsUntilAvailable;
119     }
120 
121     /**
122      * Returns the output port's name.
123      * This is the name that was specified when the output port was connected.
124      *
125      * @return the output port's name.
126      */
getName()127     public String getName() {
128         return mName;
129     }
130 
131     /**
132      * Return the filter object that this port belongs to.
133      *
134      * @return the output port's filter.
135      */
getFilter()136     public Filter getFilter() {
137         return mFilter;
138     }
139 
140     @Override
toString()141     public String toString() {
142         return mFilter.getName() + ":" + mName;
143     }
144 
OutputPort(Filter filter, String name, Signature.PortInfo info)145     OutputPort(Filter filter, String name, Signature.PortInfo info) {
146         mFilter = filter;
147         mName = name;
148         mInfo = info;
149     }
150 
setTarget(InputPort target)151     void setTarget(InputPort target) {
152         mTarget = target;
153     }
154 
155     /**
156      * Return the (input) port that this output port is connected to.
157      *
158      * @return the connected port, null if not connected.
159      */
getTarget()160     public InputPort getTarget() {
161         return mTarget;
162     }
163 
getQueue()164     FrameQueue getQueue() {
165         return mQueue;
166     }
167 
setQueue(FrameQueue queue)168     void setQueue(FrameQueue queue) {
169         mQueue = queue;
170         mQueueBuilder = null;
171     }
172 
onOpen(FrameQueue.Builder builder)173     void onOpen(FrameQueue.Builder builder) {
174         mQueueBuilder = builder;
175         mQueueBuilder.setWriteType(mInfo.type);
176         mFilter.onOutputPortOpen(this);
177     }
178 
isOpen()179     boolean isOpen() {
180         return mQueue != null;
181     }
182 
conditionsMet()183     final boolean conditionsMet() {
184         return !mWaitsUntilAvailable || isAvailable();
185     }
186 
clear()187     void clear() {
188         if (mQueue != null) {
189             mQueue.clear();
190         }
191     }
192 }
193 
194