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.Program; 26import android.filterfw.core.ShaderProgram; 27import android.filterfw.format.ImageFormat; 28import android.filterfw.geometry.Quad; 29import android.filterfw.geometry.Point; 30 31/** 32 * @hide 33 */ 34public class RotateFilter extends Filter { 35 36 @GenerateFieldPort(name = "angle") 37 private int mAngle; 38 39 @GenerateFieldPort(name = "tile_size", hasDefault = true) 40 private int mTileSize = 640; 41 42 private Program mProgram; 43 44 private int mWidth = 0; 45 private int mHeight = 0; 46 private int mTarget = FrameFormat.TARGET_UNSPECIFIED; 47 48 private int mOutputWidth; 49 private int mOutputHeight; 50 51 public RotateFilter(String name) { 52 super(name); 53 } 54 55 @Override 56 public void setupPorts() { 57 addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); 58 addOutputBasedOnInput("image", "image"); 59 } 60 61 public void initProgram(FilterContext context, int target) { 62 switch (target) { 63 case FrameFormat.TARGET_GPU: 64 ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); 65 shaderProgram.setMaximumTileSize(mTileSize); 66 shaderProgram.setClearsOutput(true); 67 mProgram = shaderProgram; 68 break; 69 70 default: 71 throw new RuntimeException("Filter Sharpen does not support frames of " + 72 "target " + target + "!"); 73 } 74 mTarget = target; 75 } 76 77 @Override 78 public void fieldPortValueUpdated(String name, FilterContext context) { 79 if (mProgram != null) { 80 updateParameters(); 81 } 82 } 83 84 @Override 85 public void process(FilterContext context) { 86 // Get input frame 87 Frame input = pullInput("image"); 88 FrameFormat inputFormat = input.getFormat(); 89 90 // Create program if not created already 91 if (mProgram == null || inputFormat.getTarget() != mTarget) { 92 initProgram(context, inputFormat.getTarget()); 93 } 94 95 if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { 96 mWidth = inputFormat.getWidth(); 97 mHeight = inputFormat.getHeight(); 98 mOutputWidth = mWidth; 99 mOutputHeight = mHeight; 100 101 updateParameters(); 102 } 103 104 // Create output frame 105 FrameFormat outputFormat = ImageFormat.create(mOutputWidth, mOutputHeight, 106 ImageFormat.COLORSPACE_RGBA, 107 FrameFormat.TARGET_GPU); 108 109 Frame output = context.getFrameManager().newFrame(outputFormat); 110 111 // Process 112 mProgram.process(input, output); 113 114 // Push output 115 pushOutput("image", output); 116 117 // Release pushed frame 118 output.release(); 119 } 120 121 private void updateParameters() { 122 float sinTheta; 123 float cosTheta; 124 125 if (mAngle % 90 == 0) { 126 if (mAngle % 180 == 0) { 127 sinTheta = 0f; 128 cosTheta = (mAngle % 360 == 0) ? 1f:-1f; 129 } else { 130 cosTheta = 0f; 131 sinTheta = ((mAngle + 90) % 360 == 0) ? -1f:1f; 132 133 mOutputWidth = mHeight; 134 mOutputHeight = mWidth; 135 } 136 } else { 137 throw new RuntimeException("degree has to be multiply of 90."); 138 } 139 140 Point x0 = new Point(0.5f * (-cosTheta + sinTheta + 1f), 141 0.5f * (-sinTheta - cosTheta + 1f)); 142 Point x1 = new Point(0.5f * (cosTheta + sinTheta + 1f), 143 0.5f * (sinTheta - cosTheta + 1f)); 144 Point x2 = new Point(0.5f * (-cosTheta - sinTheta + 1f), 145 0.5f * (-sinTheta + cosTheta + 1f)); 146 Point x3 = new Point(0.5f * (cosTheta - sinTheta + 1f), 147 0.5f * (sinTheta + cosTheta + 1f)); 148 Quad quad = new Quad(x0, x1, x2, x3); 149 ((ShaderProgram) mProgram).setTargetRegion(quad); 150 } 151} 152