Home | History | Annotate | Download | only in filterfw
      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 import java.util.Arrays;
     20 
     21 /**
     22  * Frames are the data containers that are transported between Filters.
     23  *
     24  * Frames may be used only within a Filter during filter graph execution. Accessing Frames outside
     25  * of graph execution may cause unexpected results.
     26  *
     27  * There are two ways to obtain new Frame instances. You can call
     28  * {@link OutputPort#fetchAvailableFrame(int[])} on an OutputPort to obtain a Frame to pass to an
     29  * output. You can also call {@link #create(FrameType, int[])} to obtain
     30  * a detached Frame instance that you may hold onto in your filter. If you need to hold on to a
     31  * Frame that is owned by an input or output queue, you must call
     32  * {@link #retain()} on it.
     33  *
     34  * When you are done using a detached Frame, you must release it yourself.
     35  *
     36  * To access frame data, call any of the {@code lock}-methods. This will give you access to the
     37  * frame data in the desired format. You must pass in a {@code mode} indicating whether you wish
     38  * to read or write to the data. Writing to a read-locked Frame may produce unexpected results and
     39  * interfere with other filters. When you are done reading or writing to the data, you must call
     40  * {@link #unlock()}. Note, that a Frame must be unlocked before you push it into an output queue.
     41  *
     42  * Generally, any type of access format to a Frame's data will be granted. However, it is strongly
     43  * recommended to specify the access format that you intend to use in your filter's signature or
     44  * in the access flags passed to {@code newFrame()}. This will allow the Frame to allocate
     45  * the most efficient backings for the intended type of access.
     46  *
     47  * A frame can be be pushed to an OutputPort by calling the {@link OutputPort#pushFrame(Frame)}
     48  * method. Frames that have been pushed become read-only, and can no longer be modified.
     49  *
     50  * On the other end, a Filter can pull in an input Frame by calling {@link InputPort#pullFrame()}
     51  * on the desired InputPort. Such frames are always read-only.
     52  */
     53 public class Frame {
     54 
     55     /** Special timestamp value indicating that no time-stamp was set. */
     56     public static final long TIMESTAMP_NOT_SET = -1;
     57 
     58     /** Frame data access mode: Read */
     59     public static final int MODE_READ = 1;
     60     /** Frame data access mode: Write */
     61     public static final int MODE_WRITE = 2;
     62 
     63     BackingStore mBackingStore;
     64     boolean mReadOnly = false;
     65 
     66     // Public API //////////////////////////////////////////////////////////////////////////////////
     67     /**
     68      * Returns the frame's type.
     69      * @return A FrameType instance describing the frame data-type.
     70      */
     71     public final FrameType getType() {
     72         return mBackingStore.getFrameType();
     73     }
     74 
     75     public final int getElementCount() {
     76         return mBackingStore.getElementCount();
     77     }
     78 
     79     /**
     80      * Set the frame's timestamp in nanoseconds.
     81      *
     82      * @param timestamp the timestamp of this frame in nanoseconds.
     83      */
     84     public final void setTimestamp(long timestamp) {
     85         mBackingStore.setTimestamp(timestamp);
     86     }
     87 
     88     /**
     89      * @return the frame's timestamp in nanoseconds.
     90      */
     91     public final long getTimestamp() {
     92         return mBackingStore.getTimestamp();
     93     }
     94 
     95     /**
     96      * @return the frame's timestamp in milliseconds.
     97      */
     98     public final long getTimestampMillis() {
     99         return mBackingStore.getTimestamp() / 1000000L;
    100     }
    101 
    102     public final boolean isReadOnly() {
    103         return mReadOnly;
    104     }
    105 
    106     public final FrameValue asFrameValue() {
    107         return FrameValue.create(mBackingStore);
    108     }
    109 
    110     public final FrameValues asFrameValues() {
    111         return FrameValues.create(mBackingStore);
    112     }
    113 
    114     public final FrameBuffer1D asFrameBuffer1D() {
    115         return FrameBuffer1D.create(mBackingStore);
    116     }
    117 
    118     public final FrameBuffer2D asFrameBuffer2D() {
    119         return FrameBuffer2D.create(mBackingStore);
    120     }
    121 
    122     public final FrameImage2D asFrameImage2D() {
    123         return FrameImage2D.create(mBackingStore);
    124     }
    125 
    126     @Override
    127     public String toString() {
    128         return "Frame[" + getType().toString() + "]: " + mBackingStore;
    129     }
    130 
    131     @Override
    132     public boolean equals(Object object) {
    133         return object instanceof Frame && ((Frame)object).mBackingStore == mBackingStore;
    134     }
    135 
    136     public static Frame create(FrameType type, int[] dimensions) {
    137         FrameManager manager = FrameManager.current();
    138         if (manager == null) {
    139             throw new IllegalStateException("Attempting to create new Frame outside of "
    140                 + "FrameManager context!");
    141         }
    142         return new Frame(type, dimensions, manager);
    143     }
    144 
    145     public final Frame release() {
    146         mBackingStore = mBackingStore.release();
    147         return mBackingStore != null ? this : null;
    148     }
    149 
    150     public final Frame retain() {
    151         mBackingStore = mBackingStore.retain();
    152         return this;
    153     }
    154 
    155     public void unlock() {
    156         if (!mBackingStore.unlock()) {
    157             throw new RuntimeException("Attempting to unlock frame that is not locked!");
    158         }
    159     }
    160 
    161     public int[] getDimensions() {
    162         int[] dim = mBackingStore.getDimensions();
    163         return dim != null ? Arrays.copyOf(dim, dim.length) : null;
    164     }
    165 
    166     Frame(FrameType type, int[] dimensions, FrameManager manager) {
    167         mBackingStore = new BackingStore(type, dimensions, manager);
    168     }
    169 
    170     Frame(BackingStore backingStore) {
    171         mBackingStore = backingStore;
    172     }
    173 
    174     final void assertAccessible(int mode) {
    175         // Make sure frame is in write-mode
    176         if (mReadOnly && mode == MODE_WRITE) {
    177             throw new RuntimeException("Attempting to write to read-only frame " + this + "!");
    178         }
    179     }
    180 
    181     final void setReadOnly(boolean readOnly) {
    182         mReadOnly = readOnly;
    183     }
    184 
    185     void resize(int[] newDims) {
    186         int[] oldDims = mBackingStore.getDimensions();
    187         int oldCount = oldDims == null ? 0 : oldDims.length;
    188         int newCount = newDims == null ? 0 : newDims.length;
    189         if (oldCount != newCount) {
    190             throw new IllegalArgumentException("Cannot resize " + oldCount + "-dimensional "
    191                 + "Frame to " + newCount + "-dimensional Frame!");
    192         } else if (newDims != null && !Arrays.equals(oldDims, newDims)) {
    193             mBackingStore.resize(newDims);
    194         }
    195     }
    196 
    197     Frame makeCpuCopy(FrameManager frameManager) {
    198         Frame frame = new Frame(getType(), getDimensions(), frameManager);
    199         frame.mBackingStore.importStore(mBackingStore);
    200         return frame;
    201     }
    202 }
    203 
    204