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
17package android.filterpacks.imageproc;
18
19import android.filterfw.core.Filter;
20import android.filterfw.core.FilterContext;
21import android.filterfw.core.Frame;
22import android.filterfw.core.FrameFormat;
23import android.filterfw.core.GenerateFieldPort;
24import android.filterfw.core.KeyValueMap;
25import android.filterfw.core.NativeProgram;
26import android.filterfw.core.NativeFrame;
27import android.filterfw.core.Program;
28import android.filterfw.core.ShaderProgram;
29import android.filterfw.format.ImageFormat;
30import android.filterpacks.imageproc.ImageCombineFilter;
31import android.graphics.Bitmap;
32
33import android.util.Log;
34
35/**
36 * @hide
37 */
38public class BitmapOverlayFilter extends Filter {
39
40    @GenerateFieldPort(name = "bitmap")
41    private Bitmap mBitmap;
42
43    @GenerateFieldPort(name = "tile_size", hasDefault = true)
44    private int mTileSize = 640;
45
46    private Program mProgram;
47    private Frame mFrame;
48
49    private int mWidth = 0;
50    private int mHeight = 0;
51    private int mTarget = FrameFormat.TARGET_UNSPECIFIED;
52
53    private final String mOverlayShader =
54            "precision mediump float;\n" +
55            "uniform sampler2D tex_sampler_0;\n" +
56            "uniform sampler2D tex_sampler_1;\n" +
57            "varying vec2 v_texcoord;\n" +
58            "void main() {\n" +
59            "  vec4 original = texture2D(tex_sampler_0, v_texcoord);\n" +
60            "  vec4 mask = texture2D(tex_sampler_1, v_texcoord);\n" +
61            "  gl_FragColor = vec4(original.rgb * (1.0 - mask.a) + mask.rgb, 1.0);\n" +
62            "}\n";
63
64    public BitmapOverlayFilter(String name) {
65        super(name);
66    }
67
68    @Override
69    public void setupPorts() {
70        addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
71        addOutputBasedOnInput("image", "image");
72    }
73
74    @Override
75    public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
76        return inputFormat;
77    }
78
79    public void initProgram(FilterContext context, int target) {
80        switch (target) {
81            case FrameFormat.TARGET_GPU:
82                ShaderProgram shaderProgram = new ShaderProgram(context, mOverlayShader);
83                shaderProgram.setMaximumTileSize(mTileSize);
84                mProgram = shaderProgram;
85                break;
86
87            default:
88                throw new RuntimeException("Filter FisheyeFilter does not support frames of " +
89                    "target " + target + "!");
90        }
91        mTarget = target;
92    }
93
94    @Override
95    public void tearDown(FilterContext context) {
96        if (mFrame != null) {
97            mFrame.release();
98            mFrame = null;
99        }
100    }
101
102    @Override
103    public void process(FilterContext context) {
104        // Get input frame
105        Frame input = pullInput("image");
106        FrameFormat inputFormat = input.getFormat();
107
108        // Create output frame
109        Frame output = context.getFrameManager().newFrame(inputFormat);
110
111        // Create program if not created already
112        if (mProgram == null || inputFormat.getTarget() != mTarget) {
113            initProgram(context, inputFormat.getTarget());
114        }
115
116        // Check if the frame size has changed
117        if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) {
118            mWidth = inputFormat.getWidth();
119            mHeight = inputFormat.getHeight();
120
121            createBitmapFrame(context);
122        }
123
124        // Process
125        Frame[] inputs = {input, mFrame};
126        mProgram.process(inputs, output);
127
128        // Push output
129        pushOutput("image", output);
130
131        // Release pushed frame
132        output.release();
133    }
134
135    private void createBitmapFrame(FilterContext context) {
136        if (mBitmap != null) {
137            FrameFormat format = ImageFormat.create(mBitmap.getWidth(),
138                                                    mBitmap.getHeight(),
139                                                    ImageFormat.COLORSPACE_RGBA,
140                                                    FrameFormat.TARGET_GPU);
141
142            if (mFrame != null) {
143                mFrame.release();
144            }
145
146            mFrame = context.getFrameManager().newFrame(format);
147            mFrame.setBitmap(mBitmap);
148
149            mBitmap.recycle();
150            mBitmap = null;
151        }
152    }
153}
154