1 /* 2 * Copyright 2013 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 17 package androidx.media.filterpacks.image; 18 19 import androidx.media.filterfw.Filter; 20 import androidx.media.filterfw.Frame; 21 import androidx.media.filterfw.FrameBuffer2D; 22 import androidx.media.filterfw.FrameImage2D; 23 import androidx.media.filterfw.FrameType; 24 import androidx.media.filterfw.ImageShader; 25 import androidx.media.filterfw.MffContext; 26 import androidx.media.filterfw.OutputPort; 27 import androidx.media.filterfw.RenderTarget; 28 import androidx.media.filterfw.Signature; 29 import androidx.media.filterfw.geometry.Quad; 30 31 import java.nio.ByteBuffer; 32 33 public class ToGrayValuesFilter extends Filter { 34 35 private final static String mGrayPackFragment = 36 "precision mediump float;\n" + 37 "const vec4 coeff_y = vec4(0.299, 0.587, 0.114, 0);\n" + 38 "uniform sampler2D tex_sampler_0;\n" + 39 "uniform float pix_stride;\n" + 40 "varying vec2 v_texcoord;\n" + 41 "void main() {\n" + 42 " for (int i = 0; i < 4; i++) {\n" + 43 // Here is an example showing how this works: 44 // Assuming the input texture is 1x4 while the output texture is 1x1 45 // the coordinates of the 4 input pixels will be: 46 // { (0.125, 0.5), (0.375, 0.5), (0.625, 0.5), (0.875, 0.5) } 47 // and the coordinates of the 1 output pixels will be: 48 // { (0.5, 0.5) } 49 // the equation below locates the 4 input pixels from the coordinate of the output pixel 50 " vec4 p = texture2D(tex_sampler_0,\n" + 51 " v_texcoord + vec2(pix_stride * (float(i) - 1.5), 0.0));\n" + 52 " gl_FragColor[i] = dot(p, coeff_y);\n" + 53 " }\n" + 54 "}\n"; 55 56 private ImageShader mShader; 57 58 private FrameType mImageInType; 59 60 public ToGrayValuesFilter(MffContext context, String name) { 61 super(context, name); 62 } 63 64 @Override 65 public Signature getSignature() { 66 mImageInType = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_GPU); 67 FrameType imageOut = FrameType.buffer2D(FrameType.ELEMENT_INT8); 68 return new Signature() 69 .addInputPort("image", Signature.PORT_REQUIRED, mImageInType) 70 .addOutputPort("image", Signature.PORT_REQUIRED, imageOut) 71 .disallowOtherPorts(); 72 } 73 74 @Override 75 protected void onPrepare() { 76 if (isOpenGLSupported()) { 77 mShader = new ImageShader(mGrayPackFragment); 78 } 79 } 80 81 @Override 82 protected void onProcess() { 83 OutputPort outPort = getConnectedOutputPort("image"); 84 FrameImage2D inputImage = getConnectedInputPort("image").pullFrame().asFrameImage2D(); 85 int[] dim = inputImage.getDimensions(); 86 FrameBuffer2D outputFrame; 87 ByteBuffer grayBuffer; 88 89 if (isOpenGLSupported()) { 90 // crop out the portion of inputImage that will be used to generate outputFrame. 91 int modular = dim[0] % 4; 92 int[] outDim = new int[] {dim[0] - modular, dim[1]}; 93 outputFrame = outPort.fetchAvailableFrame(outDim).asFrameBuffer2D(); 94 grayBuffer = outputFrame.lockBytes(Frame.MODE_WRITE); 95 96 int[] targetDims = new int[] { outDim[0] / 4, outDim[1] }; 97 FrameImage2D targetFrame = Frame.create(mImageInType, targetDims).asFrameImage2D(); 98 mShader.setSourceQuad(Quad.fromRect(0f, 0f, ((float)outDim[0])/dim[0], 1f)); 99 mShader.setUniformValue("pix_stride", 1f / outDim[0]); 100 mShader.process(inputImage, targetFrame); 101 RenderTarget grayTarget = targetFrame.lockRenderTarget(); 102 grayTarget.readPixelData(grayBuffer, targetDims[0], targetDims[1]); 103 targetFrame.unlock(); 104 targetFrame.release(); 105 } else { 106 outputFrame = outPort.fetchAvailableFrame(dim).asFrameBuffer2D(); 107 grayBuffer = outputFrame.lockBytes(Frame.MODE_WRITE); 108 ByteBuffer inputBuffer = inputImage.lockBytes(Frame.MODE_READ); 109 if (!toGrayValues(inputBuffer, grayBuffer)) { 110 throw new RuntimeException( 111 "Native implementation encountered an error during processing!"); 112 } 113 inputImage.unlock(); 114 } 115 outputFrame.unlock(); 116 outPort.pushFrame(outputFrame); 117 } 118 119 private static native boolean toGrayValues(ByteBuffer imageBuffer, ByteBuffer grayBuffer); 120 121 static { 122 System.loadLibrary("smartcamera_jni"); 123 } 124 } 125