EffectFactory.java revision 65953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9
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.media.effect; 19 20import java.lang.reflect.Constructor; 21import java.util.HashMap; 22 23/** 24 * <p>The EffectFactory class defines the list of available Effects, and provides functionality to 25 * inspect and instantiate them. Some effects may not be available on all platforms, so before 26 * creating a certain effect, the application should confirm that the effect is supported on this 27 * platform by calling {@link #isEffectSupported(String)}.</p> 28 */ 29public class EffectFactory { 30 31 private EffectContext mEffectContext; 32 33 private final static String[] EFFECT_PACKAGES = { 34 "android.media.effect.effects.", // Default effect package 35 "" // Allows specifying full class path 36 }; 37 38 /** List of Effects */ 39 /** 40 * <p>Copies the input texture to the output.</p> 41 * <p>Available parameters: None</p> 42 * @hide 43 */ 44 public final static String EFFECT_IDENTITY = "IdentityEffect"; 45 46 /** 47 * <p>Adjusts the brightness of the image.</p> 48 * <p>Available parameters:</p> 49 * <table> 50 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 51 * <tr><td><code>brightness</code></td> 52 * <td>The brightness multiplier.</td> 53 * <td>Positive float. 1.0 means no change; 54 larger values will increase brightness.</td> 55 * </tr> 56 * </table> 57 */ 58 public final static String EFFECT_BRIGHTNESS = 59 "android.media.effect.effects.BrightnessEffect"; 60 61 /** 62 * <p>Adjusts the contrast of the image.</p> 63 * <p>Available parameters:</p> 64 * <table> 65 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 66 * <tr><td><code>contrast</code></td> 67 * <td>The contrast multiplier.</td> 68 * <td>Float. 1.0 means no change; 69 larger values will increase contrast.</td> 70 * </tr> 71 * </table> 72 */ 73 public final static String EFFECT_CONTRAST = 74 "android.media.effect.effects.ContrastEffect"; 75 76 /** 77 * <p>Applies a fisheye lens distortion to the image.</p> 78 * <p>Available parameters:</p> 79 * <table> 80 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 81 * <tr><td><code>scale</code></td> 82 * <td>The scale of the distortion.</td> 83 * <td>Float, between 0 and 1. Zero means no distortion.</td> 84 * </tr> 85 * </table> 86 */ 87 public final static String EFFECT_FISHEYE = 88 "android.media.effect.effects.FisheyeEffect"; 89 90 /** 91 * <p>Replaces the background of the input frames with frames from a 92 * selected video. Requires an initial learning period with only the 93 * background visible before the effect becomes active. The effect will wait 94 * until it does not see any motion in the scene before learning the 95 * background and starting the effect.</p> 96 * 97 * <p>Available parameters:</p> 98 * <table> 99 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 100 * <tr><td><code>source</code></td> 101 * <td>A URI for the background video to use. This parameter must be 102 * supplied before calling apply() for the first time.</td> 103 * <td>String, such as from 104 * {@link android.net.Uri#toString Uri.toString()}</td> 105 * </tr> 106 * </table> 107 * 108 * <p>If the update listener is set for this effect using 109 * {@link Effect#setUpdateListener}, it will be called when the effect has 110 * finished learning the background, with a null value for the info 111 * parameter.</p> 112 */ 113 public final static String EFFECT_BACKDROPPER = 114 "android.media.effect.effects.BackDropperEffect"; 115 116 /** 117 * <p>Attempts to auto-fix the image based on histogram equalization.</p> 118 * <p>Available parameters:</p> 119 * <table> 120 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 121 * <tr><td><code>scale</code></td> 122 * <td>The scale of the adjustment.</td> 123 * <td>Float, between 0 and 1. Zero means no adjustment, while 1 indicates the maximum 124 * amount of adjustment.</td> 125 * </tr> 126 * </table> 127 */ 128 public final static String EFFECT_AUTOFIX = 129 "android.media.effect.effects.AutoFixEffect"; 130 131 /** 132 * <p>Adjusts the range of minimal and maximal color pixel intensities.</p> 133 * <p>Available parameters:</p> 134 * <table> 135 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 136 * <tr><td><code>black</code></td> 137 * <td>The value of the minimal pixel.</td> 138 * <td>Float, between 0 and 1.</td> 139 * </tr> 140 * <tr><td><code>white</code></td> 141 * <td>The value of the maximal pixel.</td> 142 * <td>Float, between 0 and 1.</td> 143 * </tr> 144 * </table> 145 */ 146 public final static String EFFECT_BLACKWHITE = 147 "android.media.effect.effects.BlackWhiteEffect"; 148 149 /** 150 * <p>Crops an upright rectangular area from the image. If the crop region falls outside of 151 * the image bounds, the results are undefined.</p> 152 * <p>Available parameters:</p> 153 * <table> 154 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 155 * <tr><td><code>xorigin</code></td> 156 * <td>The origin's x-value.</td> 157 * <td>Integer, between 0 and width of the image.</td> 158 * </tr> 159 * <tr><td><code>yorigin</code></td> 160 * <td>The origin's y-value.</td> 161 * <td>Integer, between 0 and height of the image.</td> 162 * </tr> 163 * <tr><td><code>width</code></td> 164 * <td>The width of the cropped image.</td> 165 * <td>Integer, between 1 and the width of the image minus xorigin.</td> 166 * </tr> 167 * <tr><td><code>height</code></td> 168 * <td>The height of the cropped image.</td> 169 * <td>Integer, between 1 and the height of the image minus yorigin.</td> 170 * </tr> 171 * </table> 172 */ 173 public final static String EFFECT_CROP = 174 "android.media.effect.effects.CropEffect"; 175 176 /** 177 * <p>Applies a cross process effect on image, in which the red and green channels are 178 * enhanced while the blue channel is restricted.</p> 179 * <p>Available parameters: None</p> 180 */ 181 public final static String EFFECT_CROSSPROCESS = 182 "android.media.effect.effects.CrossProcessEffect"; 183 184 /** 185 * <p>Applies black and white documentary style effect on image..</p> 186 * <p>Available parameters: None</p> 187 */ 188 public final static String EFFECT_DOCUMENTARY = 189 "android.media.effect.effects.DocumentaryEffect"; 190 191 192 /** 193 * <p>Overlays a bitmap (with premultiplied alpha channel) onto the input image. The bitmap 194 * is stretched to fit the input image.</p> 195 * <p>Available parameters:</p> 196 * <table> 197 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 198 * <tr><td><code>bitmap</code></td> 199 * <td>The overlay bitmap.</td> 200 * <td>A non-null Bitmap instance.</td> 201 * </tr> 202 * </table> 203 */ 204 public final static String EFFECT_BITMAPOVERLAY = 205 "android.media.effect.effects.BitmapOverlayEffect"; 206 207 /** 208 * <p>Representation of photo using only two color tones.</p> 209 * <p>Available parameters:</p> 210 * <table> 211 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 212 * <tr><td><code>first_color</code></td> 213 * <td>The first color tone.</td> 214 * <td>Integer, representing an ARGB color with 8 bits per channel. May be created using 215 * {@link android.graphics.Color Color} class.</td> 216 * </tr> 217 * <tr><td><code>second_color</code></td> 218 * <td>The second color tone.</td> 219 * <td>Integer, representing an ARGB color with 8 bits per channel. May be created using 220 * {@link android.graphics.Color Color} class.</td> 221 * </tr> 222 * </table> 223 */ 224 public final static String EFFECT_DUOTONE = 225 "android.media.effect.effects.DuotoneEffect"; 226 227 /** 228 * <p>Applies back-light filling to the image.</p> 229 * <p>Available parameters:</p> 230 * <table> 231 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 232 * <tr><td><code>strength</code></td> 233 * <td>The strength of the backlight.</td> 234 * <td>Float, between 0 and 1. Zero means no change.</td> 235 * </tr> 236 * </table> 237 */ 238 public final static String EFFECT_FILLLIGHT = 239 "android.media.effect.effects.FillLightEffect"; 240 241 /** 242 * <p>Flips image vertically and/or horizontally.</p> 243 * <p>Available parameters:</p> 244 * <table> 245 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 246 * <tr><td><code>vertical</code></td> 247 * <td>Whether to flip image vertically.</td> 248 * <td>Boolean</td> 249 * </tr> 250 * <tr><td><code>horizontal</code></td> 251 * <td>Whether to flip image horizontally.</td> 252 * <td>Boolean</td> 253 * </tr> 254 * </table> 255 */ 256 public final static String EFFECT_FLIP = 257 "android.media.effect.effects.FlipEffect"; 258 259 /** 260 * <p>Applies film grain effect to image.</p> 261 * <p>Available parameters:</p> 262 * <table> 263 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 264 * <tr><td><code>strength</code></td> 265 * <td>The strength of the grain effect.</td> 266 * <td>Float, between 0 and 1. Zero means no change.</td> 267 * </tr> 268 * </table> 269 */ 270 public final static String EFFECT_GRAIN = 271 "android.media.effect.effects.GrainEffect"; 272 273 /** 274 * <p>Converts image to grayscale.</p> 275 * <p>Available parameters: None</p> 276 */ 277 public final static String EFFECT_GRAYSCALE = 278 "android.media.effect.effects.GrayscaleEffect"; 279 280 /** 281 * <p>Applies lomo-camera style effect to image.</p> 282 * <p>Available parameters: None</p> 283 */ 284 public final static String EFFECT_LOMOISH = 285 "android.media.effect.effects.LomoishEffect"; 286 287 /** 288 * <p>Inverts the image colors.</p> 289 * <p>Available parameters: None</p> 290 */ 291 public final static String EFFECT_NEGATIVE = 292 "android.media.effect.effects.NegativeEffect"; 293 294 /** 295 * <p>Applies posterization effect to image.</p> 296 * <p>Available parameters: None</p> 297 */ 298 public final static String EFFECT_POSTERIZE = 299 "android.media.effect.effects.PosterizeEffect"; 300 301 /** 302 * <p>Removes red eyes on specified region.</p> 303 * <p>Available parameters:</p> 304 * <table> 305 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 306 * <tr><td><code>centers</code></td> 307 * <td>Multiple center points (x, y) of the red eye regions.</td> 308 * <td>An array of floats, where (f[2*i], f[2*i+1]) specifies the center of the i'th eye. 309 * Coordinate values are expected to be normalized between 0 and 1.</td> 310 * </tr> 311 * </table> 312 */ 313 public final static String EFFECT_REDEYE = 314 "android.media.effect.effects.RedEyeEffect"; 315 316 /** 317 * <p>Rotates the image. The output frame size must be able to fit the rotated version of 318 * the input image. Note that the rotation snaps to a the closest multiple of 90 degrees.</p> 319 * <p>Available parameters:</p> 320 * <table> 321 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 322 * <tr><td><code>angle</code></td> 323 * <td>The angle of rotation in degrees.</td> 324 * <td>Integer value. This will be rounded to the nearest multiple of 90.</td> 325 * </tr> 326 * </table> 327 */ 328 public final static String EFFECT_ROTATE = 329 "android.media.effect.effects.RotateEffect"; 330 331 /** 332 * <p>Adjusts color saturation of image.</p> 333 * <p>Available parameters:</p> 334 * <table> 335 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 336 * <tr><td><code>scale</code></td> 337 * <td>The scale of color saturation.</td> 338 * <td>Float, between -1 and 1. 0 means no change, while -1 indicates full desaturation, 339 * i.e. grayscale.</td> 340 * </tr> 341 * </table> 342 */ 343 public final static String EFFECT_SATURATE = 344 "android.media.effect.effects.SaturateEffect"; 345 346 /** 347 * <p>Converts image to sepia tone.</p> 348 * <p>Available parameters: None</p> 349 */ 350 public final static String EFFECT_SEPIA = 351 "android.media.effect.effects.SepiaEffect"; 352 353 /** 354 * <p>Sharpens the image.</p> 355 * <p>Available parameters:</p> 356 * <table> 357 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 358 * <tr><td><code>scale</code></td> 359 * <td>The degree of sharpening.</td> 360 * <td>Float, between 0 and 1. 0 means no change.</td> 361 * </tr> 362 * </table> 363 */ 364 public final static String EFFECT_SHARPEN = 365 "android.media.effect.effects.SharpenEffect"; 366 367 /** 368 * <p>Rotates the image according to the specified angle, and crops the image so that no 369 * non-image portions are visible.</p> 370 * <p>Available parameters:</p> 371 * <table> 372 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 373 * <tr><td><code>angle</code></td> 374 * <td>The angle of rotation.</td> 375 * <td>Float, between -45 and +45.</td> 376 * </tr> 377 * </table> 378 */ 379 public final static String EFFECT_STRAIGHTEN = 380 "android.media.effect.effects.StraightenEffect"; 381 382 /** 383 * <p>Adjusts color temperature of the image.</p> 384 * <p>Available parameters:</p> 385 * <table> 386 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 387 * <tr><td><code>scale</code></td> 388 * <td>The value of color temperature.</td> 389 * <td>Float, between 0 and 1, with 0 indicating cool, and 1 indicating warm. A value of 390 * of 0.5 indicates no change.</td> 391 * </tr> 392 * </table> 393 */ 394 public final static String EFFECT_TEMPERATURE = 395 "android.media.effect.effects.ColorTemperatureEffect"; 396 397 /** 398 * <p>Tints the photo with specified color.</p> 399 * <p>Available parameters:</p> 400 * <table> 401 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 402 * <tr><td><code>tint</code></td> 403 * <td>The color of the tint.</td> 404 * <td>Integer, representing an ARGB color with 8 bits per channel. May be created using 405 * {@link android.graphics.Color Color} class.</td> 406 * </tr> 407 * </table> 408 */ 409 public final static String EFFECT_TINT = 410 "android.media.effect.effects.TintEffect"; 411 412 /** 413 * <p>Adds a vignette effect to image, i.e. fades away the outer image edges.</p> 414 * <p>Available parameters:</p> 415 * <table> 416 * <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr> 417 * <tr><td><code>scale</code></td> 418 * <td>The scale of vignetting.</td> 419 * <td>Float, between 0 and 1. 0 means no change.</td> 420 * </tr> 421 * </table> 422 */ 423 public final static String EFFECT_VIGNETTE = 424 "android.media.effect.effects.VignetteEffect"; 425 426 EffectFactory(EffectContext effectContext) { 427 mEffectContext = effectContext; 428 } 429 430 /** 431 * Instantiate a new effect with the given effect name. 432 * 433 * <p>The effect's parameters will be set to their default values.</p> 434 * 435 * <p>Note that the EGL context associated with the current EffectContext need not be made 436 * current when creating an effect. This allows the host application to instantiate effects 437 * before any EGL context has become current.</p> 438 * 439 * @param effectName The name of the effect to create. 440 * @return A new Effect instance. 441 * @throws IllegalArgumentException if the effect with the specified name is not supported or 442 * not known. 443 */ 444 public Effect createEffect(String effectName) { 445 Class effectClass = getEffectClassByName(effectName); 446 if (effectClass == null) { 447 throw new IllegalArgumentException("Cannot instantiate unknown effect '" + 448 effectName + "'!"); 449 } 450 return instantiateEffect(effectClass, effectName); 451 } 452 453 /** 454 * Check if an effect is supported on this platform. 455 * 456 * <p>Some effects may only be available on certain platforms. Use this method before 457 * instantiating an effect to make sure it is supported.</p> 458 * 459 * @param effectName The name of the effect. 460 * @return true, if the effect is supported on this platform. 461 * @throws IllegalArgumentException if the effect name is not known. 462 */ 463 public static boolean isEffectSupported(String effectName) { 464 return getEffectClassByName(effectName) != null; 465 } 466 467 private static Class getEffectClassByName(String className) { 468 Class effectClass = null; 469 470 // Get context's classloader; otherwise cannot load non-framework effects 471 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 472 473 // Look for the class in the imported packages 474 for (String packageName : EFFECT_PACKAGES) { 475 try { 476 effectClass = contextClassLoader.loadClass(packageName + className); 477 } catch (ClassNotFoundException e) { 478 continue; 479 } 480 // Exit loop if class was found. 481 if (effectClass != null) { 482 break; 483 } 484 } 485 return effectClass; 486 } 487 488 private Effect instantiateEffect(Class effectClass, String name) { 489 // Make sure this is an Effect subclass 490 try { 491 effectClass.asSubclass(Effect.class); 492 } catch (ClassCastException e) { 493 throw new IllegalArgumentException("Attempting to allocate effect '" + effectClass 494 + "' which is not a subclass of Effect!", e); 495 } 496 497 // Look for the correct constructor 498 Constructor effectConstructor = null; 499 try { 500 effectConstructor = effectClass.getConstructor(EffectContext.class, String.class); 501 } catch (NoSuchMethodException e) { 502 throw new RuntimeException("The effect class '" + effectClass + "' does not have " 503 + "the required constructor.", e); 504 } 505 506 // Construct the effect 507 Effect effect = null; 508 try { 509 effect = (Effect)effectConstructor.newInstance(mEffectContext, name); 510 } catch (Throwable t) { 511 throw new RuntimeException("There was an error constructing the effect '" + effectClass 512 + "'!", t); 513 } 514 515 return effect; 516 } 517} 518