1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/* 2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2011 The Android Open Source Project 3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License"); 5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License. 6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at 7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0 9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software 11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS, 12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and 14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License. 15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw; 18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Rect; 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.RectF; 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.View; 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/** 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * TODO: Move this to filterpacks/base? 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic abstract class ViewFilter extends Filter { 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int SCALE_STRETCH = 1; 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int SCALE_FIT = 2; 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int SCALE_FILL = 3; 31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected int mScaleMode = SCALE_FIT; 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected float[] mClearColor = new float[] { 0f, 0f, 0f, 1f }; 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected boolean mFlipVertically = true; 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private String mRequestedScaleMode = null; 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ViewFilter(MffContext context, String name) { 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super(context, name); 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Binds the filter to a view. 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * View filters support visualizing data to a view. Check the specific filter documentation 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * for details. The view may be bound only if the filter's graph is not running. 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param view the view to bind to. 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @throws IllegalStateException if the method is called while the graph is running. 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void bindToView(View view) { 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (isRunning()) { 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalStateException("Attempting to bind filter to view while it is " 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "running!"); 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onBindToView(view); 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setScaleMode(int scaleMode) { 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (isRunning()) { 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalStateException("Attempting to change scale mode while filter is " 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "running!"); 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mScaleMode = scaleMode; 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Signature getSignature() { 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return new Signature() 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks .addInputPort("scaleMode", Signature.PORT_OPTIONAL, FrameType.single(String.class)) 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks .addInputPort("flip", Signature.PORT_OPTIONAL, FrameType.single(boolean.class)); 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Subclasses must override this method to bind their filter to the specified view. 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * When this method is called, Filter implementations may assume that the graph is not 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * currently running. 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected abstract void onBindToView(View view); 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * TODO: Document. 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected RectF getTargetRect(Rect frameRect, Rect bufferRect) { 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks RectF result = new RectF(); 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (bufferRect.width() > 0 && bufferRect.height() > 0) { 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float frameAR = (float)frameRect.width() / frameRect.height(); 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float bufferAR = (float)bufferRect.width() / bufferRect.height(); 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float relativeAR = bufferAR / frameAR; 90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch (mScaleMode) { 91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case SCALE_STRETCH: 92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks result.set(0f, 0f, 1f, 1f); 93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case SCALE_FIT: 95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (relativeAR > 1.0f) { 96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float x = 0.5f - 0.5f / relativeAR; 97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float y = 0.0f; 98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks result.set(x, y, x + 1.0f / relativeAR, y + 1.0f); 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float x = 0.0f; 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float y = 0.5f - 0.5f * relativeAR; 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks result.set(x, y, x + 1.0f, y + relativeAR); 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case SCALE_FILL: 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (relativeAR > 1.0f) { 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float x = 0.0f; 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float y = 0.5f - 0.5f * relativeAR; 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks result.set(x, y, x + 1.0f, y + relativeAR); 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float x = 0.5f - 0.5f / relativeAR; 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float y = 0.0f; 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks result.set(x, y, x + 1.0f / relativeAR, y + 1.0f); 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return result; 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void connectViewInputs(InputPort port) { 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (port.getName().equals("scaleMode")) { 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks port.bindToListener(mScaleModeListener); 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks port.setAutoPullEnabled(true); 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (port.getName().equals("flip")) { 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks port.bindToFieldNamed("mFlipVertically"); 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks port.setAutoPullEnabled(true); 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void setupShader(ImageShader shader, Rect frameRect, Rect outputRect) { 132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setTargetRect(getTargetRect(frameRect, outputRect)); 133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setClearsOutput(true); 134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setClearColor(mClearColor); 135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mFlipVertically) { 136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setSourceRect(0f, 1f, 1f, -1f); 137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private InputPort.FrameListener mScaleModeListener = new InputPort.FrameListener() { 141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onFrameReceived(InputPort port, Frame frame) { 143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks String scaleMode = (String)frame.asFrameValue().getValue(); 144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (!scaleMode.equals(mRequestedScaleMode)) { 145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedScaleMode = scaleMode; 146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (scaleMode.equals("stretch")) { 147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mScaleMode = SCALE_STRETCH; 148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (scaleMode.equals("fit")) { 149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mScaleMode = SCALE_FIT; 150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (scaleMode.equals("fill")) { 151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mScaleMode = SCALE_FILL; 152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Unknown scale-mode '" + scaleMode + "'!"); 154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks }; 158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 160