1a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni/* 2a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * Copyright (C) 2011 The Android Open Source Project 3a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * 4a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * Licensed under the Apache License, Version 2.0 (the "License"); 5a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * you may not use this file except in compliance with the License. 6a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * You may obtain a copy of the License at 7a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * 8a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * http://www.apache.org/licenses/LICENSE-2.0 9a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * 10a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * Unless required by applicable law or agreed to in writing, software 11a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * distributed under the License is distributed on an "AS IS" BASIS, 12a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * See the License for the specific language governing permissions and 14a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni * limitations under the License. 15a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni */ 16a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 17a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 18a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceronipackage android.filterpacks.imageproc; 19a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 20a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.Filter; 21a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.FilterContext; 22a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.Frame; 23a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.FrameFormat; 2421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GenerateFieldPort; 25a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.MutableFrameFormat; 26a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.Program; 27a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.core.ShaderProgram; 28a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.filterfw.format.ImageFormat; 29a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 30a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroniimport android.util.Log; 31a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 32979b9d227671081fcc90eb74b6de1b340c7ef781Wei Huaimport java.lang.Math; 33a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/** 34a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide 35a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */ 36a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceronipublic class ToPackedGrayFilter extends Filter { 37a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 3821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "owidth", hasDefault = true) 39a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni private int mOWidth = FrameFormat.SIZE_UNSPECIFIED; 4021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "oheight", hasDefault = true) 41a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni private int mOHeight = FrameFormat.SIZE_UNSPECIFIED; 4247a6896582866f0ed834c87b95e9a40ed164baacWei Hua @GenerateFieldPort(name = "keepAspectRatio", hasDefault = true) 4347a6896582866f0ed834c87b95e9a40ed164baacWei Hua private boolean mKeepAspectRatio = false; 44a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 45a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni private Program mProgram; 46a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 47a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni private final String mColorToPackedGrayShader = 48a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "precision mediump float;\n" + 49a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "const vec4 coeff_y = vec4(0.299, 0.587, 0.114, 0);\n" + 50a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "uniform sampler2D tex_sampler_0;\n" + 51a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "uniform float pix_stride;\n" + 52a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "varying vec2 v_texcoord;\n" + 53a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "void main() {\n" + 54a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni " for (int i = 0; i < 4; ++i) {\n" + 55a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni " vec4 p = texture2D(tex_sampler_0,\n" + 56a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni " v_texcoord + vec2(pix_stride * float(i), 0.0));\n" + 57a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni " gl_FragColor[i] = dot(p, coeff_y);\n" + 58a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni " }\n" + 59a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni "}\n"; 60a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 61a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni public ToPackedGrayFilter(String name) { 62a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni super(name); 63a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 64a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 6533d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 6621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void setupPorts() { 6721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 6821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn FrameFormat.TARGET_GPU)); 6921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn addOutputBasedOnInput("image", "image"); 70a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 71a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 7233d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 7321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { 7421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn return convertInputFormat(inputFormat); 75a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 76a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 77979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua private void checkOutputDimensions(int outputWidth, int outputHeight) { 78979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua if (outputWidth <= 0 || outputHeight <= 0) { 79979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua throw new RuntimeException("Invalid output dimensions: " + 80979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua outputWidth + " " + outputHeight); 81a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 82a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 83a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 8421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn private FrameFormat convertInputFormat(FrameFormat inputFormat) { 85979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua int ow = mOWidth; 86979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua int oh = mOHeight; 87979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua int w = inputFormat.getWidth(); 88979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua int h = inputFormat.getHeight(); 8921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn if (mOWidth == FrameFormat.SIZE_UNSPECIFIED) { 90979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua ow = w; 9121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn } 9221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn if (mOHeight == FrameFormat.SIZE_UNSPECIFIED) { 93979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua oh = h; 9421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn } 9547a6896582866f0ed834c87b95e9a40ed164baacWei Hua if (mKeepAspectRatio) { 96979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua // if keep aspect ratio, use the bigger dimension to determine the 97979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua // final output size 98979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua if (w > h) { 99979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua ow = Math.max(ow, oh); 100979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua oh = ow * h / w; 101979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua } else { 102979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua oh = Math.max(ow, oh); 103979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua ow = oh * w / h; 104979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua } 10547a6896582866f0ed834c87b95e9a40ed164baacWei Hua } 106979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua ow = (ow / 4) * 4; // ensure width is multiply of 4 107979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua return ImageFormat.create(ow, oh, 10821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn ImageFormat.COLORSPACE_GRAY, 10921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn FrameFormat.TARGET_NATIVE); 11021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn } 11121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn 11233d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 11321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void prepare(FilterContext context) { 114511360e61650864ea22a171159efe073c80d0cdbMarius Renn mProgram = new ShaderProgram(context, mColorToPackedGrayShader); 115a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 116a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 11733d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 11821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void process(FilterContext context) { 11921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn Frame input = pullInput("image"); 12021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn FrameFormat inputFormat = input.getFormat(); 12121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn FrameFormat outputFormat = convertInputFormat(inputFormat); 122979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua int ow = outputFormat.getWidth(); 123979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua int oh = outputFormat.getHeight(); 124979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua checkOutputDimensions(ow, oh); 125979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua mProgram.setHostValue("pix_stride", 1.0f / ow); 126a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 127a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni // Do the RGBA to luminance conversion. 128a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni MutableFrameFormat tempFrameFormat = inputFormat.mutableCopy(); 129979b9d227671081fcc90eb74b6de1b340c7ef781Wei Hua tempFrameFormat.setDimensions(ow / 4, oh); 13021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn Frame temp = context.getFrameManager().newFrame(tempFrameFormat); 131a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni mProgram.process(input, temp); 132a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 133a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni // Read frame from GPU to CPU. 13421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn Frame output = context.getFrameManager().newFrame(outputFormat); 135a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni output.setDataFromFrame(temp); 136a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni temp.release(); 137a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 138a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni // Push output and yield ownership. 13921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn pushOutput("image", output); 140a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni output.release(); 141a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni } 142a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni 143a4e8683367b9d4cfc4f8a6cbf3875fe2e35009f0Rodrigo Carceroni} 144