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