1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright 2013 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.filterpacks.image;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Filter;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Frame;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameBuffer2D;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameImage2D;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameType;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.ImageShader;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.MffContext;
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.OutputPort;
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.RenderTarget;
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Signature;
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.geometry.Quad;
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer;
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class ToGrayValuesFilter extends Filter {
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final static String mGrayPackFragment =
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "precision mediump float;\n" +
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "const vec4 coeff_y = vec4(0.299, 0.587, 0.114, 0);\n" +
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "uniform sampler2D tex_sampler_0;\n" +
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "uniform float pix_stride;\n" +
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "varying vec2 v_texcoord;\n" +
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "void main() {\n" +
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "  for (int i = 0; i < 4; i++) {\n" +
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Here is an example showing how this works:
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Assuming the input texture is 1x4 while the output texture is 1x1
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // the coordinates of the 4 input pixels will be:
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // { (0.125, 0.5), (0.375, 0.5), (0.625, 0.5), (0.875, 0.5) }
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // and the coordinates of the 1 output pixels will be:
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // { (0.5, 0.5) }
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // the equation below locates the 4 input pixels from the coordinate of the output pixel
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "    vec4 p = texture2D(tex_sampler_0,\n" +
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "                       v_texcoord + vec2(pix_stride * (float(i) - 1.5), 0.0));\n" +
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "    gl_FragColor[i] = dot(p, coeff_y);\n" +
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "  }\n" +
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        "}\n";
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private ImageShader mShader;
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private FrameType mImageInType;
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public ToGrayValuesFilter(MffContext context, String name) {
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        super(context, name);
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Signature getSignature() {
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mImageInType = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_GPU);
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameType imageOut = FrameType.buffer2D(FrameType.ELEMENT_INT8);
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Signature()
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            .addInputPort("image", Signature.PORT_REQUIRED, mImageInType)
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            .addOutputPort("image", Signature.PORT_REQUIRED, imageOut)
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            .disallowOtherPorts();
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onPrepare() {
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (isOpenGLSupported()) {
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShader = new ImageShader(mGrayPackFragment);
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    protected void onProcess() {
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        OutputPort outPort = getConnectedOutputPort("image");
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameImage2D inputImage = getConnectedInputPort("image").pullFrame().asFrameImage2D();
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        int[] dim = inputImage.getDimensions();
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameBuffer2D outputFrame;
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ByteBuffer grayBuffer;
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (isOpenGLSupported()) {
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            // crop out the portion of inputImage that will be used to generate outputFrame.
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int modular = dim[0] % 4;
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] outDim = new int[] {dim[0] - modular, dim[1]};
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outputFrame = outPort.fetchAvailableFrame(outDim).asFrameBuffer2D();
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            grayBuffer = outputFrame.lockBytes(Frame.MODE_WRITE);
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            int[] targetDims = new int[] { outDim[0] / 4, outDim[1] };
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            FrameImage2D targetFrame = Frame.create(mImageInType, targetDims).asFrameImage2D();
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShader.setSourceQuad(Quad.fromRect(0f, 0f, ((float)outDim[0])/dim[0], 1f));
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShader.setUniformValue("pix_stride", 1f / outDim[0]);
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            mShader.process(inputImage, targetFrame);
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            RenderTarget grayTarget = targetFrame.lockRenderTarget();
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            grayTarget.readPixelData(grayBuffer, targetDims[0], targetDims[1]);
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            targetFrame.unlock();
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            targetFrame.release();
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            outputFrame = outPort.fetchAvailableFrame(dim).asFrameBuffer2D();
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            grayBuffer = outputFrame.lockBytes(Frame.MODE_WRITE);
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            ByteBuffer inputBuffer  = inputImage.lockBytes(Frame.MODE_READ);
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            if (!toGrayValues(inputBuffer, grayBuffer)) {
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new RuntimeException(
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        "Native implementation encountered an error during processing!");
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            }
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            inputImage.unlock();
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outputFrame.unlock();
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        outPort.pushFrame(outputFrame);
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static native boolean toGrayValues(ByteBuffer imageBuffer, ByteBuffer grayBuffer);
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    static {
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        System.loadLibrary("smartcamera_jni");
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
125