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