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 17 18package android.filterpacks.imageproc; 19 20import android.filterfw.core.Filter; 21import android.filterfw.core.FilterContext; 22import android.filterfw.core.Frame; 23import android.filterfw.core.FrameFormat; 24import android.filterfw.core.GenerateFieldPort; 25import android.filterfw.core.MutableFrameFormat; 26import android.filterfw.core.Program; 27import android.filterfw.core.ShaderProgram; 28import android.filterfw.format.ImageFormat; 29 30import java.lang.Math; 31/** 32 * @hide 33 */ 34public class ToPackedGrayFilter extends Filter { 35 36 @GenerateFieldPort(name = "owidth", hasDefault = true) 37 private int mOWidth = FrameFormat.SIZE_UNSPECIFIED; 38 @GenerateFieldPort(name = "oheight", hasDefault = true) 39 private int mOHeight = FrameFormat.SIZE_UNSPECIFIED; 40 @GenerateFieldPort(name = "keepAspectRatio", hasDefault = true) 41 private boolean mKeepAspectRatio = false; 42 43 private Program mProgram; 44 45 private final String mColorToPackedGrayShader = 46 "precision mediump float;\n" + 47 "const vec4 coeff_y = vec4(0.299, 0.587, 0.114, 0);\n" + 48 "uniform sampler2D tex_sampler_0;\n" + 49 "uniform float pix_stride;\n" + 50 "varying vec2 v_texcoord;\n" + 51 "void main() {\n" + 52 " for (int i = 0; i < 4; ++i) {\n" + 53 " vec4 p = texture2D(tex_sampler_0,\n" + 54 " v_texcoord + vec2(pix_stride * float(i), 0.0));\n" + 55 " gl_FragColor[i] = dot(p, coeff_y);\n" + 56 " }\n" + 57 "}\n"; 58 59 public ToPackedGrayFilter(String name) { 60 super(name); 61 } 62 63 @Override 64 public void setupPorts() { 65 addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 66 FrameFormat.TARGET_GPU)); 67 addOutputBasedOnInput("image", "image"); 68 } 69 70 @Override 71 public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { 72 return convertInputFormat(inputFormat); 73 } 74 75 private void checkOutputDimensions(int outputWidth, int outputHeight) { 76 if (outputWidth <= 0 || outputHeight <= 0) { 77 throw new RuntimeException("Invalid output dimensions: " + 78 outputWidth + " " + outputHeight); 79 } 80 } 81 82 private FrameFormat convertInputFormat(FrameFormat inputFormat) { 83 int ow = mOWidth; 84 int oh = mOHeight; 85 int w = inputFormat.getWidth(); 86 int h = inputFormat.getHeight(); 87 if (mOWidth == FrameFormat.SIZE_UNSPECIFIED) { 88 ow = w; 89 } 90 if (mOHeight == FrameFormat.SIZE_UNSPECIFIED) { 91 oh = h; 92 } 93 if (mKeepAspectRatio) { 94 // if keep aspect ratio, use the bigger dimension to determine the 95 // final output size 96 if (w > h) { 97 ow = Math.max(ow, oh); 98 oh = ow * h / w; 99 } else { 100 oh = Math.max(ow, oh); 101 ow = oh * w / h; 102 } 103 } 104 ow = (ow > 0 && ow < 4) ? 4 : (ow / 4) * 4; // ensure width is multiple of 4 105 return ImageFormat.create(ow, oh, 106 ImageFormat.COLORSPACE_GRAY, 107 FrameFormat.TARGET_NATIVE); 108 } 109 110 @Override 111 public void prepare(FilterContext context) { 112 mProgram = new ShaderProgram(context, mColorToPackedGrayShader); 113 } 114 115 @Override 116 public void process(FilterContext context) { 117 Frame input = pullInput("image"); 118 FrameFormat inputFormat = input.getFormat(); 119 FrameFormat outputFormat = convertInputFormat(inputFormat); 120 int ow = outputFormat.getWidth(); 121 int oh = outputFormat.getHeight(); 122 checkOutputDimensions(ow, oh); 123 mProgram.setHostValue("pix_stride", 1.0f / ow); 124 125 // Do the RGBA to luminance conversion. 126 MutableFrameFormat tempFrameFormat = inputFormat.mutableCopy(); 127 tempFrameFormat.setDimensions(ow / 4, oh); 128 Frame temp = context.getFrameManager().newFrame(tempFrameFormat); 129 mProgram.process(input, temp); 130 131 // Read frame from GPU to CPU. 132 Frame output = context.getFrameManager().newFrame(outputFormat); 133 output.setDataFromFrame(temp); 134 temp.release(); 135 136 // Push output and yield ownership. 137 pushOutput("image", output); 138 output.release(); 139 } 140 141} 142