SurfaceRenderFilter.java revision 692c3bf7a1c7e2d5b1066cf7a1b057e993742c87
130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni/*
230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Copyright (C) 2011 The Android Open Source Project
330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Licensed under the Apache License, Version 2.0 (the "License");
530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * you may not use this file except in compliance with the License.
630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * You may obtain a copy of the License at
730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *      http://www.apache.org/licenses/LICENSE-2.0
930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
1030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Unless required by applicable law or agreed to in writing, software
1130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * distributed under the License is distributed on an "AS IS" BASIS,
1230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * See the License for the specific language governing permissions and
1430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * limitations under the License.
1530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni */
1630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
1730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
1830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipackage android.filterpacks.ui;
1930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
2030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Filter;
21692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Rennimport android.filterfw.core.FilterContext;
2230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FilterParameter;
2330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FilterSurfaceView;
2430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FilterSurfaceRenderer;
2530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Frame;
2630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FrameFormat;
2730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.GLEnvironment;
2830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.GLFrame;
2930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.KeyValueMap;
3030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.MutableFrameFormat;
3130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.NativeProgram;
3230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.NativeFrame;
3330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Program;
3430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.ShaderProgram;
3530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
3630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.view.Surface;
3730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.view.SurfaceHolder;
3830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.view.SurfaceView;
3930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
4030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.graphics.Rect;
4130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
4230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.util.Log;
4330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
4430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipublic class SurfaceRenderFilter extends Filter implements FilterSurfaceRenderer {
4530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
4630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private final int RENDERMODE_STRETCH   = 0;
4730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private final int RENDERMODE_FIT       = 1;
4830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private final int RENDERMODE_FILL_CROP = 2;
4930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
5030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    /** Required. Sets the destination filter surface view for this
5130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * node.
5230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     */
5330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @FilterParameter(name = "surfaceView", isOptional = false)
5430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private FilterSurfaceView mSurfaceView;
5530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
5630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    /** Optional. Control how the incoming frames are rendered onto the
5730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * output. Default is FIT.
5830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * RENDERMODE_STRETCH: Just fill the output surfaceView.
5930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * RENDERMODE_FIT: Keep aspect ratio and fit without cropping. May
6030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * have black bars.
6130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * RENDERMODE_FILL_CROP: Keep aspect ratio and fit without black
6230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     * bars. May crop.
6330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni     */
6430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @FilterParameter(name = "renderMode", isOptional = true)
6530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private String mRenderModeString;
6630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
6730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private ShaderProgram mProgram;
6830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private GLFrame mScreen;
6930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private int mRenderMode = RENDERMODE_FIT;
7030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private float mAspectRatio;
7130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
7230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private int mScreenWidth;
7330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private int mScreenHeight;
7430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
7530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private static final boolean LOGV = false;
7630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private static final String TAG = "SurfaceRenderFilter";
7730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
7830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public SurfaceRenderFilter(String name) {
7930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        super(name);
8030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
8130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
8230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    protected void finalize() throws Throwable {
8330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mSurfaceView != null) {
8430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mSurfaceView.unbind();
8530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
8630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
8730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
8830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
8930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public void initFilter() {
9030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // SurfaceView
9130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mSurfaceView == null) {
9230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            throw new RuntimeException("NULL SurfaceView passed to SurfaceRenderFilter");
9330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
9430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
9530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // RenderMode
9630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mRenderModeString != null) {
9730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            if (mRenderModeString == "stretch") {
9830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                mRenderMode = RENDERMODE_STRETCH;
9930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            } else if (mRenderModeString == "fit") {
10030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                mRenderMode = RENDERMODE_FIT;
10130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            } else if (mRenderModeString == "fill_crop") {
10230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                mRenderMode = RENDERMODE_FILL_CROP;
10330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            } else {
10430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                throw new RuntimeException("Unknown render mode '" + mRenderModeString + "'!");
10530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
10630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
10730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
10830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mAspectRatio = 1.f;
10930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
11030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
11130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
11230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public String[] getInputNames() {
11330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return new String[] { "frame" };
11430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
11530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
11630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
11730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public String[] getOutputNames() {
11830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return null;
11930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
12030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
12130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
122692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public boolean acceptsInputFormat(int index, FrameFormat format) {
12330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (format.isBinaryDataType() &&
12430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            format.getBytesPerSample() == 4 &&
12530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            format.getNumberOfDimensions() == 2 &&
12630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            (format.getTarget() == FrameFormat.TARGET_NATIVE ||
12730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni             format.getTarget() == FrameFormat.TARGET_GPU)) {
12830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
12930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            return true;
13030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
13130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return false;
13230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
13330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
13430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
135692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public FrameFormat getOutputFormat(int index) {
13630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return null;
13730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
13830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
13930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
140692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public void prepare(FilterContext environment) {
14130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // Create identity shader to render, and make sure to render upside-down, as textures
14230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // are stored internally bottom-to-top.
14330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mProgram = ShaderProgram.createIdentity();
14430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mProgram.setSourceRect(0, 1, 1, -1);
14530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mProgram.setClearsOutput(true);
14630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mProgram.setClearColor(0.0f, 0.0f, 0.0f);
14730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
14830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        updateTargetRect();
14930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
15030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // Create a frame representing the screen
15130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        MutableFrameFormat screenFormat = new MutableFrameFormat(FrameFormat.TYPE_BYTE,
15230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                                                 FrameFormat.TARGET_GPU);
15330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        screenFormat.setBytesPerSample(4);
15430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        screenFormat.setDimensions(mSurfaceView.getWidth(), mSurfaceView.getHeight());
15530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        mScreen = (GLFrame)environment.getFrameManager().newBoundFrame(screenFormat,
15630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                                                       GLFrame.EXISTING_FBO_BINDING,
15730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                                                       0);
15830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
15930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // Bind surface view to us. This will emit a surfaceChanged call that will update our
16030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // screen width and height.
16130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mSurfaceView != null) {
16230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mSurfaceView.unbind();
16330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mSurfaceView.bindToRenderer(this, environment.getGLEnvironment());
16430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
16530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
16630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
16730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
168692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public int process(FilterContext env) {
16930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mSurfaceView != null) {
17030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            if (LOGV) Log.v(TAG, "Starting frame processing");
17130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
17230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            // Make sure we are processing in the correct GL environment
17330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            GLEnvironment glEnv = mSurfaceView.getGLEnv();
17430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            if (glEnv != env.getGLEnvironment()) {
17530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                throw new RuntimeException("Surface created under different GLEnvironment!");
17630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
17730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
17830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            // Get input frame
17930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            Frame input = pullInput(0);
18030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            boolean createdFrame = false;
18130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
18230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            float currentAspectRatio = (float)input.getFormat().getWidth() / input.getFormat().getHeight();
18330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            if (currentAspectRatio != mAspectRatio) {
18430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                if (LOGV) Log.v(TAG, "New aspect ratio: " + currentAspectRatio +", previously: " + mAspectRatio);
18530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                mAspectRatio = currentAspectRatio;
18630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                updateTargetRect();
18730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
18830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
18930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            // See if we need to copy to GPU
19030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            Frame gpuFrame = null;
19130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            if (input.getFormat().getTarget() == FrameFormat.TARGET_NATIVE) {
19230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                MutableFrameFormat gpuFormat = input.getFormat().mutableCopy();
19330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                gpuFormat.setTarget(FrameFormat.TARGET_GPU);
19430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                gpuFrame = env.getFrameManager().newFrame(gpuFormat);
19530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                gpuFrame.setData(input.getData());
19630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                createdFrame = true;
19730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            } else {
19830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                gpuFrame = input;
19930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
20030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
20130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            // Activate our surface
20230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            glEnv.activateSurfaceWithId(mSurfaceView.getSurfaceId());
20330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
20430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            // Process
20530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mProgram.process(gpuFrame, mScreen);
20630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
20730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            // And swap buffers
20830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            glEnv.swapBuffers();
20930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
21030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            if (createdFrame) {
21130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                gpuFrame.release();
21230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            }
21330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
21430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
21530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // Wait for next input and free output
21630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        return Filter.STATUS_WAIT_FOR_ALL_INPUTS |
21730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                Filter.STATUS_WAIT_FOR_FREE_OUTPUTS;
21830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
21930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
22030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
221692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Renn    public void tearDown(FilterContext env) {
22230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mScreen != null) {
22330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mScreen.release();
22430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
22530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
22630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
22730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    @Override
22830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public synchronized void surfaceChanged(int format, int width, int height) {
22930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // If the screen is null, we do not care about surface changes (yet). Once we have a
23030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // screen object, we need to keep track of these changes.
23130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mScreen != null) {
23230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mScreenWidth = width;
23330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mScreenHeight = height;
23430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            mScreen.setViewport(0, 0, mScreenWidth, mScreenHeight);
23530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            updateTargetRect();
23630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
23730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
23830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
23930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    public synchronized void surfaceDestroyed() {
24030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // We do nothing here but declare this synchronized so that the surface is not destroyed
24130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        // behind our backs.
24230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
24330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
24430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    private void updateTargetRect() {
24530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        if (mScreenWidth > 0 && mScreenHeight > 0 && mProgram != null) {
24630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            float screenAspectRatio = (float)mScreenWidth / mScreenHeight;
24730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            float relativeAspectRatio = screenAspectRatio / mAspectRatio;
24830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
24930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            switch (mRenderMode) {
25030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                case RENDERMODE_STRETCH:
25130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    mProgram.setTargetRect(0, 0, 1, 1);
25230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    break;
25330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                case RENDERMODE_FIT:
25430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    if (relativeAspectRatio > 1.0f) {
25530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        // Screen is wider than the camera, scale down X
25630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        mProgram.setTargetRect(0.5f - 0.5f / relativeAspectRatio, 0.0f,
25730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                               1.0f / relativeAspectRatio, 1.0f);
25830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    } else {
25930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        // Screen is taller than the camera, scale down Y
26030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        mProgram.setTargetRect(0.0f, 0.5f - 0.5f * relativeAspectRatio,
26130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                               1.0f, relativeAspectRatio);
26230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    }
26330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    break;
26430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                case RENDERMODE_FILL_CROP:
26530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    if (relativeAspectRatio > 1) {
26630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        // Screen is wider than the camera, crop in Y
26730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        mProgram.setTargetRect(0.0f, 0.5f - 0.5f * relativeAspectRatio,
26830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                               1.0f, relativeAspectRatio);
26930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    } else {
27030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        // Screen is taller than the camera, crop in X
27130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                        mProgram.setTargetRect(0.5f - 0.5f / relativeAspectRatio, 0.0f,
27230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                                               1.0f / relativeAspectRatio, 1.0f);
27330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    }
27430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                    break;
27530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni            };
27630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni        }
27730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
27830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
279