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