130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni/* 230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Copyright (C) 2011 The Android Open Source Project 330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * 430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Licensed under the Apache License, Version 2.0 (the "License"); 530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * you may not use this file except in compliance with the License. 630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * You may obtain a copy of the License at 730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * 830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * http://www.apache.org/licenses/LICENSE-2.0 930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * 1030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Unless required by applicable law or agreed to in writing, software 1130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * distributed under the License is distributed on an "AS IS" BASIS, 1230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * See the License for the specific language governing permissions and 1430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * limitations under the License. 1530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni */ 1630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 1730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 1830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipackage android.filterpacks.imageproc; 1930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 2030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Filter; 21692c3bf7a1c7e2d5b1066cf7a1b057e993742c87Marius Rennimport android.filterfw.core.FilterContext; 2230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Frame; 2330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.FrameFormat; 2421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.core.GenerateFieldPort; 2530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.KeyValueMap; 2630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.MutableFrameFormat; 2730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.NativeProgram; 2830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.NativeFrame; 2930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.Program; 3030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.core.ShaderProgram; 3130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.geometry.Point; 3230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.filterfw.geometry.Quad; 33c0017fd82acec5d0427306ea5f536c3d78854f95Marius Rennimport android.filterfw.format.ImageFormat; 3421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Rennimport android.filterfw.format.ObjectFormat; 3530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 3630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniimport android.util.Log; 3730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 38a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala/** 39a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala * @hide 40a3bfbe5389c6146abe318a7add3fa688d69bc01bEino-Ville Talvala */ 4130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronipublic class CropFilter extends Filter { 4230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 4321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn private Program mProgram; 44262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua private FrameFormat mLastFormat = null; 45c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn 4621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "owidth") 47c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn private int mOutputWidth = -1; 48c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn 4921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn @GenerateFieldPort(name = "oheight") 50c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn private int mOutputHeight = -1; 5130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 521cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng @GenerateFieldPort(name = "fillblack") 531cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng private boolean mFillBlack = false; 541cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng 5530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni public CropFilter(String name) { 5630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni super(name); 5730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 5830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 591cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng private final String mFragShader = 601cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng "precision mediump float;\n" + 611cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng "uniform sampler2D tex_sampler_0;\n" + 621cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng "varying vec2 v_texcoord;\n" + 631cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng "void main() {\n" + 641cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " const vec2 lo = vec2(0.0, 0.0);\n" + 651cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " const vec2 hi = vec2(1.0, 1.0);\n" + 661cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " const vec4 black = vec4(0.0, 0.0, 0.0, 1.0);\n" + 671cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " bool out_of_bounds =\n" + 681cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " any(lessThan(v_texcoord, lo)) ||\n" + 691cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " any(greaterThan(v_texcoord, hi));\n" + 701cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " if (out_of_bounds) {\n" + 711cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " gl_FragColor = black;\n" + 721cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " } else {\n" + 731cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 741cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng " }\n" + 751cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng "}\n"; 761cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng 7733d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 7821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void setupPorts() { 7921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); 80bf4aaebc555cfb1e49ee411e3477203749fe6a11Marius Renn addMaskedInputPort("box", ObjectFormat.fromClass(Quad.class, FrameFormat.TARGET_SIMPLE)); 8121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn addOutputBasedOnInput("image", "image"); 8230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 8330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 8433d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 8521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { 8621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn // Make sure output size is set to unspecified, as we do not know what we will be resizing 8721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn // to. 8821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn MutableFrameFormat outputFormat = inputFormat.mutableCopy(); 8921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn outputFormat.setDimensions(FrameFormat.SIZE_UNSPECIFIED, FrameFormat.SIZE_UNSPECIFIED); 9021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn return outputFormat; 9130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 9230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 93262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua protected void createProgram(FilterContext context, FrameFormat format) { 9421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn // TODO: Add CPU version 95262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua if (mLastFormat != null && mLastFormat.getTarget() == format.getTarget()) return; 96262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua mLastFormat = format; 97262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua mProgram = null; 98262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua switch (format.getTarget()) { 9921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn case FrameFormat.TARGET_GPU: 1001cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng if(mFillBlack) 1011cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng mProgram = new ShaderProgram(context, mFragShader); 1021cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng else 103511360e61650864ea22a171159efe073c80d0cdbMarius Renn mProgram = ShaderProgram.createIdentity(context); 1041cfe527ff61b629f3a1bf0d5882243ac6780297aYifan Peng 10521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn break; 10621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn } 10721d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn if (mProgram == null) { 10821d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn throw new RuntimeException("Could not create a program for crop filter " + this + "!"); 10921d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn } 11030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 11130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 11233d107bf315c9cc01a02a7a4a2c10a01f62e8c85Wei Hua @Override 11321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn public void process(FilterContext env) { 11430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Get input frame 11521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn Frame imageFrame = pullInput("image"); 11621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn Frame boxFrame = pullInput("box"); 11730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 118262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua createProgram(env, imageFrame.getFormat()); 119262a009cbd3e4eab125246cf70f110ad3cd6c75eWei Hua 12030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Get the box 12130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni Quad box = (Quad)boxFrame.getObjectValue(); 12230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 123c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn // Create output format 124c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn MutableFrameFormat outputFormat = imageFrame.getFormat().mutableCopy(); 125c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn outputFormat.setDimensions(mOutputWidth == -1 ? outputFormat.getWidth() : mOutputWidth, 126c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn mOutputHeight == -1 ? outputFormat.getHeight() : mOutputHeight); 127c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn 12830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Create output frame 129c0017fd82acec5d0427306ea5f536c3d78854f95Marius Renn Frame output = env.getFrameManager().newFrame(outputFormat); 13030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 13121d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn // Set the program parameters 13221d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn if (mProgram instanceof ShaderProgram) { 13321d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn ShaderProgram shaderProgram = (ShaderProgram)mProgram; 13421d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn shaderProgram.setSourceRegion(box); 13521d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn } 13621d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn 13730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni mProgram.process(imageFrame, output); 13830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 13930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Push output 14021d0ac7403b836e32e2bdbdc8dc98f42b2dfa4e5Marius Renn pushOutput("image", output); 14130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 14230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Release pushed frame 14330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni output.release(); 14430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 14530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 14630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 14730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 148