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 android.graphics.Rect;
     20 import android.graphics.RectF;
     21 import android.view.View;
     22 
     23 /**
     24  * TODO: Move this to filterpacks/base?
     25  */
     26 public abstract class ViewFilter extends Filter {
     27 
     28     public static final int SCALE_STRETCH = 1;
     29     public static final int SCALE_FIT = 2;
     30     public static final int SCALE_FILL = 3;
     31 
     32     protected int mScaleMode = SCALE_FIT;
     33     protected float[] mClearColor = new float[] { 0f, 0f, 0f, 1f };
     34     protected boolean mFlipVertically = true;
     35 
     36     private String mRequestedScaleMode = null;
     37 
     38     protected ViewFilter(MffContext context, String name) {
     39         super(context, name);
     40     }
     41 
     42     /**
     43      * Binds the filter to a view.
     44      * View filters support visualizing data to a view. Check the specific filter documentation
     45      * for details. The view may be bound only if the filter's graph is not running.
     46      *
     47      * @param view the view to bind to.
     48      * @throws IllegalStateException if the method is called while the graph is running.
     49      */
     50     public void bindToView(View view) {
     51         if (isRunning()) {
     52             throw new IllegalStateException("Attempting to bind filter to view while it is "
     53                 + "running!");
     54         }
     55         onBindToView(view);
     56     }
     57 
     58     public void setScaleMode(int scaleMode) {
     59         if (isRunning()) {
     60             throw new IllegalStateException("Attempting to change scale mode while filter is "
     61                 + "running!");
     62         }
     63         mScaleMode = scaleMode;
     64     }
     65 
     66     @Override
     67     public Signature getSignature() {
     68         return new Signature()
     69             .addInputPort("scaleMode", Signature.PORT_OPTIONAL, FrameType.single(String.class))
     70             .addInputPort("flip", Signature.PORT_OPTIONAL, FrameType.single(boolean.class));
     71     }
     72 
     73     /**
     74      * Subclasses must override this method to bind their filter to the specified view.
     75      *
     76      * When this method is called, Filter implementations may assume that the graph is not
     77      * currently running.
     78      */
     79     protected abstract void onBindToView(View view);
     80 
     81     /**
     82      * TODO: Document.
     83      */
     84     protected RectF getTargetRect(Rect frameRect, Rect bufferRect) {
     85         RectF result = new RectF();
     86         if (bufferRect.width() > 0 && bufferRect.height() > 0) {
     87             float frameAR = (float)frameRect.width() / frameRect.height();
     88             float bufferAR = (float)bufferRect.width() / bufferRect.height();
     89             float relativeAR = bufferAR / frameAR;
     90             switch (mScaleMode) {
     91                 case SCALE_STRETCH:
     92                     result.set(0f, 0f, 1f, 1f);
     93                     break;
     94                 case SCALE_FIT:
     95                     if (relativeAR > 1.0f) {
     96                         float x = 0.5f - 0.5f / relativeAR;
     97                         float y = 0.0f;
     98                         result.set(x, y, x + 1.0f / relativeAR, y + 1.0f);
     99                     } else {
    100                         float x = 0.0f;
    101                         float y = 0.5f - 0.5f * relativeAR;
    102                         result.set(x, y, x + 1.0f, y + relativeAR);
    103                     }
    104                     break;
    105                 case SCALE_FILL:
    106                     if (relativeAR > 1.0f) {
    107                         float x = 0.0f;
    108                         float y = 0.5f - 0.5f * relativeAR;
    109                         result.set(x, y, x + 1.0f, y + relativeAR);
    110                     } else {
    111                         float x = 0.5f - 0.5f / relativeAR;
    112                         float y = 0.0f;
    113                         result.set(x, y, x + 1.0f / relativeAR, y + 1.0f);
    114                     }
    115                     break;
    116             }
    117         }
    118         return result;
    119     }
    120 
    121     protected void connectViewInputs(InputPort port) {
    122         if (port.getName().equals("scaleMode")) {
    123             port.bindToListener(mScaleModeListener);
    124             port.setAutoPullEnabled(true);
    125         } else if (port.getName().equals("flip")) {
    126             port.bindToFieldNamed("mFlipVertically");
    127             port.setAutoPullEnabled(true);
    128         }
    129     }
    130 
    131     protected void setupShader(ImageShader shader, Rect frameRect, Rect outputRect) {
    132         shader.setTargetRect(getTargetRect(frameRect, outputRect));
    133         shader.setClearsOutput(true);
    134         shader.setClearColor(mClearColor);
    135         if (mFlipVertically) {
    136             shader.setSourceRect(0f, 1f, 1f, -1f);
    137         }
    138     }
    139 
    140     private InputPort.FrameListener mScaleModeListener = new InputPort.FrameListener() {
    141         @Override
    142         public void onFrameReceived(InputPort port, Frame frame) {
    143             String scaleMode = (String)frame.asFrameValue().getValue();
    144             if (!scaleMode.equals(mRequestedScaleMode)) {
    145                 mRequestedScaleMode = scaleMode;
    146                 if (scaleMode.equals("stretch")) {
    147                     mScaleMode = SCALE_STRETCH;
    148                 } else if (scaleMode.equals("fit")) {
    149                     mScaleMode = SCALE_FIT;
    150                 } else if (scaleMode.equals("fill")) {
    151                     mScaleMode = SCALE_FILL;
    152                 } else {
    153                     throw new RuntimeException("Unknown scale-mode '" + scaleMode + "'!");
    154                 }
    155             }
    156         }
    157     };
    158 }
    159 
    160