Merge "Multi-Project Commit: Move of filterfw out of system/media (2 of 7)"
This commit is contained in:
@@ -324,9 +324,6 @@ fwbase_dirs_to_document := \
|
||||
# include definition of libcore_to_document
|
||||
include $(LOCAL_PATH)/../../libcore/Docs.mk
|
||||
|
||||
# include definition of libfilterfw_to_document
|
||||
include $(LOCAL_PATH)/../../system/media/mca/Docs.mk
|
||||
|
||||
non_base_dirs := \
|
||||
../../external/apache-http/src/org/apache/http
|
||||
|
||||
@@ -349,8 +346,7 @@ html_dirs := \
|
||||
# Common sources for doc check and api check
|
||||
common_src_files := \
|
||||
$(call find-other-html-files, $(html_dirs)) \
|
||||
$(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore)) \
|
||||
$(addprefix ../../system/media/mca/, $(call libfilterfw_to_document, $(LOCAL_PATH)/../../system/media/mca)) \
|
||||
$(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore))
|
||||
|
||||
# These are relative to frameworks/base
|
||||
framework_docs_LOCAL_SRC_FILES := \
|
||||
|
||||
21
media/mca/Android.mk
Normal file
21
media/mca/Android.mk
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2011 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
#
|
||||
# Build all native libraries
|
||||
#
|
||||
include $(call all-subdir-makefiles)
|
||||
|
||||
|
||||
111
media/mca/effect/java/android/media/effect/Effect.java
Normal file
111
media/mca/effect/java/android/media/effect/Effect.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Effects are high-performance transformations that can be applied to image frames. These are
|
||||
* passed in the form of OpenGL ES 2.0 texture names. Typical frames could be images loaded from
|
||||
* disk, or frames from the camera or other video streams.</p>
|
||||
*
|
||||
* <p>To create an Effect you must first create an EffectContext. You can obtain an instance of the
|
||||
* context's EffectFactory by calling
|
||||
* {@link android.media.effect.EffectContext#getFactory() getFactory()}. The EffectFactory allows
|
||||
* you to instantiate specific Effects.</p>
|
||||
*
|
||||
* <p>The application is responsible for creating an EGL context, and making it current before
|
||||
* applying an effect. An effect is bound to a single EffectContext, which in turn is bound to a
|
||||
* single EGL context. If your EGL context is destroyed, the EffectContext becomes invalid and any
|
||||
* effects bound to this context can no longer be used.</p>
|
||||
*
|
||||
*/
|
||||
public abstract class Effect {
|
||||
|
||||
/**
|
||||
* Get the effect name.
|
||||
*
|
||||
* Returns the unique name of the effect, which matches the name used for instantiating this
|
||||
* effect by the EffectFactory.
|
||||
*
|
||||
* @return The name of the effect.
|
||||
*/
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Apply an effect to GL textures.
|
||||
*
|
||||
* <p>Apply the Effect on the specified input GL texture, and write the result into the
|
||||
* output GL texture. The texture names passed must be valid in the current GL context.</p>
|
||||
*
|
||||
* <p>The input texture must be a valid texture name with the given width and height and must be
|
||||
* bound to a GL_TEXTURE_2D texture image (usually done by calling the glTexImage2D() function).
|
||||
* Multiple mipmap levels may be provided.</p>
|
||||
*
|
||||
* <p>If the output texture has not been bound to a texture image, it will be automatically
|
||||
* bound by the effect as a GL_TEXTURE_2D. It will contain one mipmap level (0), which will have
|
||||
* the same size as the input. No other mipmap levels are defined. If the output texture was
|
||||
* bound already, and its size does not match the input texture size, the result may be clipped
|
||||
* or only partially fill the texture.</p>
|
||||
*
|
||||
* <p>Note, that regardless of whether a texture image was originally provided or not, both the
|
||||
* input and output textures are owned by the caller. That is, the caller is responsible for
|
||||
* calling glDeleteTextures() to deallocate the input and output textures.</p>
|
||||
*
|
||||
* @param inputTexId The GL texture name of a valid and bound input texture.
|
||||
* @param width The width of the input texture in pixels.
|
||||
* @param height The height of the input texture in pixels.
|
||||
* @param outputTexId The GL texture name of the output texture.
|
||||
*/
|
||||
public abstract void apply(int inputTexId, int width, int height, int outputTexId);
|
||||
|
||||
/**
|
||||
* Set a filter parameter.
|
||||
*
|
||||
* Consult the effect documentation for a list of supported parameter keys for each effect.
|
||||
*
|
||||
* @param parameterKey The name of the parameter to adjust.
|
||||
* @param value The new value to set the parameter to.
|
||||
* @throws InvalidArgumentException if parameterName is not a recognized name, or the value is
|
||||
* not a valid value for this parameter.
|
||||
*/
|
||||
public abstract void setParameter(String parameterKey, Object value);
|
||||
|
||||
/**
|
||||
* Set an effect listener.
|
||||
*
|
||||
* Some effects may report state changes back to the host, if a listener is set. Consult the
|
||||
* individual effect documentation for more details.
|
||||
*
|
||||
* @param listener The listener to receive update callbacks on.
|
||||
*/
|
||||
public void setUpdateListener(EffectUpdateListener listener) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Release an effect.
|
||||
*
|
||||
* <p>Releases the effect and any resources associated with it. You may call this if you need to
|
||||
* make sure acquired resources are no longer held by the effect. Releasing an effect makes it
|
||||
* invalid for reuse.</p>
|
||||
*
|
||||
* <p>Note that this method must be called with the EffectContext and EGL context current, as
|
||||
* the effect may release internal GL resources.</p>
|
||||
*/
|
||||
public abstract void release();
|
||||
}
|
||||
|
||||
131
media/mca/effect/java/android/media/effect/EffectContext.java
Normal file
131
media/mca/effect/java/android/media/effect/EffectContext.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
import android.filterfw.core.CachedFrameManager;
|
||||
import android.filterfw.core.FilterContext;
|
||||
import android.filterfw.core.FilterFactory;
|
||||
import android.filterfw.core.GLEnvironment;
|
||||
import android.filterfw.core.GLFrame;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.opengl.GLES20;
|
||||
|
||||
/**
|
||||
* <p>An EffectContext keeps all necessary state information to run Effects within a Open GL ES 2.0
|
||||
* context.</p>
|
||||
*
|
||||
* <p>Every EffectContext is bound to one GL context. The application is responsible for creating
|
||||
* this EGL context, and making it current before applying any effect. If your EGL context is
|
||||
* destroyed, the EffectContext becomes invalid and any effects bound to this context can no longer
|
||||
* be used. If you switch to another EGL context, you must create a new EffectContext. Each Effect
|
||||
* is bound to a single EffectContext, and can only be executed in that context.</p>
|
||||
*/
|
||||
public class EffectContext {
|
||||
|
||||
private final int GL_STATE_FBO = 0;
|
||||
private final int GL_STATE_PROGRAM = 1;
|
||||
private final int GL_STATE_ARRAYBUFFER = 2;
|
||||
private final int GL_STATE_COUNT = 3;
|
||||
|
||||
FilterContext mFilterContext;
|
||||
|
||||
private EffectFactory mFactory;
|
||||
|
||||
private int[] mOldState = new int[GL_STATE_COUNT];
|
||||
|
||||
/**
|
||||
* Creates a context within the current GL context.
|
||||
*
|
||||
* <p>Binds the EffectContext to the current OpenGL context. All subsequent calls to the
|
||||
* EffectContext must be made in the GL context that was active during creation.
|
||||
* When you have finished using a context, you must call {@link #release()}. to dispose of all
|
||||
* resources associated with this context.</p>
|
||||
*/
|
||||
public static EffectContext createWithCurrentGlContext() {
|
||||
EffectContext result = new EffectContext();
|
||||
result.initInCurrentGlContext();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the EffectFactory for this context.
|
||||
*
|
||||
* <p>The EffectFactory returned from this method allows instantiating new effects within this
|
||||
* context.</p>
|
||||
*
|
||||
* @return The EffectFactory instance for this context.
|
||||
*/
|
||||
public EffectFactory getFactory() {
|
||||
return mFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the context.
|
||||
*
|
||||
* <p>Releases all the resources and effects associated with the EffectContext. This renders the
|
||||
* context and all the effects bound to this context invalid. You must no longer use the context
|
||||
* or any of its bound effects after calling release().</p>
|
||||
*
|
||||
* <p>Note that this method must be called with the proper EGL context made current, as the
|
||||
* EffectContext and its effects may release internal GL resources.</p>
|
||||
*/
|
||||
public void release() {
|
||||
mFilterContext.tearDown();
|
||||
mFilterContext = null;
|
||||
}
|
||||
|
||||
private EffectContext() {
|
||||
mFilterContext = new FilterContext();
|
||||
mFilterContext.setFrameManager(new CachedFrameManager());
|
||||
mFactory = new EffectFactory(this);
|
||||
}
|
||||
|
||||
private void initInCurrentGlContext() {
|
||||
if (!GLEnvironment.isAnyContextActive()) {
|
||||
throw new RuntimeException("Attempting to initialize EffectContext with no active "
|
||||
+ "GL context!");
|
||||
}
|
||||
GLEnvironment glEnvironment = new GLEnvironment();
|
||||
glEnvironment.initWithCurrentContext();
|
||||
mFilterContext.initGLEnvironment(glEnvironment);
|
||||
}
|
||||
|
||||
final void assertValidGLState() {
|
||||
GLEnvironment glEnv = mFilterContext.getGLEnvironment();
|
||||
if (glEnv == null || !glEnv.isContextActive()) {
|
||||
if (GLEnvironment.isAnyContextActive()) {
|
||||
throw new RuntimeException("Applying effect in wrong GL context!");
|
||||
} else {
|
||||
throw new RuntimeException("Attempting to apply effect without valid GL context!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void saveGLState() {
|
||||
GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, mOldState, GL_STATE_FBO);
|
||||
GLES20.glGetIntegerv(GLES20.GL_CURRENT_PROGRAM, mOldState, GL_STATE_PROGRAM);
|
||||
GLES20.glGetIntegerv(GLES20.GL_ARRAY_BUFFER_BINDING, mOldState, GL_STATE_ARRAYBUFFER);
|
||||
}
|
||||
|
||||
final void restoreGLState() {
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mOldState[GL_STATE_FBO]);
|
||||
GLES20.glUseProgram(mOldState[GL_STATE_PROGRAM]);
|
||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mOldState[GL_STATE_ARRAYBUFFER]);
|
||||
}
|
||||
}
|
||||
|
||||
517
media/mca/effect/java/android/media/effect/EffectFactory.java
Normal file
517
media/mca/effect/java/android/media/effect/EffectFactory.java
Normal file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* <p>The EffectFactory class defines the list of available Effects, and provides functionality to
|
||||
* inspect and instantiate them. Some effects may not be available on all platforms, so before
|
||||
* creating a certain effect, the application should confirm that the effect is supported on this
|
||||
* platform by calling {@link #isEffectSupported(String)}.</p>
|
||||
*/
|
||||
public class EffectFactory {
|
||||
|
||||
private EffectContext mEffectContext;
|
||||
|
||||
private final static String[] EFFECT_PACKAGES = {
|
||||
"android.media.effect.effects.", // Default effect package
|
||||
"" // Allows specifying full class path
|
||||
};
|
||||
|
||||
/** List of Effects */
|
||||
/**
|
||||
* <p>Copies the input texture to the output.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
* @hide
|
||||
*/
|
||||
public final static String EFFECT_IDENTITY = "IdentityEffect";
|
||||
|
||||
/**
|
||||
* <p>Adjusts the brightness of the image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>brightness</code></td>
|
||||
* <td>The brightness multiplier.</td>
|
||||
* <td>Positive float. 1.0 means no change;
|
||||
larger values will increase brightness.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_BRIGHTNESS =
|
||||
"android.media.effect.effects.BrightnessEffect";
|
||||
|
||||
/**
|
||||
* <p>Adjusts the contrast of the image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>contrast</code></td>
|
||||
* <td>The contrast multiplier.</td>
|
||||
* <td>Float. 1.0 means no change;
|
||||
larger values will increase contrast.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_CONTRAST =
|
||||
"android.media.effect.effects.ContrastEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies a fisheye lens distortion to the image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>scale</code></td>
|
||||
* <td>The scale of the distortion.</td>
|
||||
* <td>Float, between 0 and 1. Zero means no distortion.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_FISHEYE =
|
||||
"android.media.effect.effects.FisheyeEffect";
|
||||
|
||||
/**
|
||||
* <p>Replaces the background of the input frames with frames from a
|
||||
* selected video. Requires an initial learning period with only the
|
||||
* background visible before the effect becomes active. The effect will wait
|
||||
* until it does not see any motion in the scene before learning the
|
||||
* background and starting the effect.</p>
|
||||
*
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>source</code></td>
|
||||
* <td>A URI for the background video to use. This parameter must be
|
||||
* supplied before calling apply() for the first time.</td>
|
||||
* <td>String, such as from
|
||||
* {@link android.net.Uri#toString Uri.toString()}</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>If the update listener is set for this effect using
|
||||
* {@link Effect#setUpdateListener}, it will be called when the effect has
|
||||
* finished learning the background, with a null value for the info
|
||||
* parameter.</p>
|
||||
*/
|
||||
public final static String EFFECT_BACKDROPPER =
|
||||
"android.media.effect.effects.BackDropperEffect";
|
||||
|
||||
/**
|
||||
* <p>Attempts to auto-fix the image based on histogram equalization.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>scale</code></td>
|
||||
* <td>The scale of the adjustment.</td>
|
||||
* <td>Float, between 0 and 1. Zero means no adjustment, while 1 indicates the maximum
|
||||
* amount of adjustment.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_AUTOFIX =
|
||||
"android.media.effect.effects.AutoFixEffect";
|
||||
|
||||
/**
|
||||
* <p>Adjusts the range of minimal and maximal color pixel intensities.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>black</code></td>
|
||||
* <td>The value of the minimal pixel.</td>
|
||||
* <td>Float, between 0 and 1.</td>
|
||||
* </tr>
|
||||
* <tr><td><code>white</code></td>
|
||||
* <td>The value of the maximal pixel.</td>
|
||||
* <td>Float, between 0 and 1.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_BLACKWHITE =
|
||||
"android.media.effect.effects.BlackWhiteEffect";
|
||||
|
||||
/**
|
||||
* <p>Crops an upright rectangular area from the image. If the crop region falls outside of
|
||||
* the image bounds, the results are undefined.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>xorigin</code></td>
|
||||
* <td>The origin's x-value.</td>
|
||||
* <td>Integer, between 0 and width of the image.</td>
|
||||
* </tr>
|
||||
* <tr><td><code>yorigin</code></td>
|
||||
* <td>The origin's y-value.</td>
|
||||
* <td>Integer, between 0 and height of the image.</td>
|
||||
* </tr>
|
||||
* <tr><td><code>width</code></td>
|
||||
* <td>The width of the cropped image.</td>
|
||||
* <td>Integer, between 1 and the width of the image minus xorigin.</td>
|
||||
* </tr>
|
||||
* <tr><td><code>height</code></td>
|
||||
* <td>The height of the cropped image.</td>
|
||||
* <td>Integer, between 1 and the height of the image minus yorigin.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_CROP =
|
||||
"android.media.effect.effects.CropEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies a cross process effect on image, in which the red and green channels are
|
||||
* enhanced while the blue channel is restricted.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_CROSSPROCESS =
|
||||
"android.media.effect.effects.CrossProcessEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies black and white documentary style effect on image..</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_DOCUMENTARY =
|
||||
"android.media.effect.effects.DocumentaryEffect";
|
||||
|
||||
|
||||
/**
|
||||
* <p>Overlays a bitmap (with premultiplied alpha channel) onto the input image. The bitmap
|
||||
* is stretched to fit the input image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>bitmap</code></td>
|
||||
* <td>The overlay bitmap.</td>
|
||||
* <td>A non-null Bitmap instance.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_BITMAPOVERLAY =
|
||||
"android.media.effect.effects.BitmapOverlayEffect";
|
||||
|
||||
/**
|
||||
* <p>Representation of photo using only two color tones.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>first_color</code></td>
|
||||
* <td>The first color tone.</td>
|
||||
* <td>Integer, representing an ARGB color with 8 bits per channel. May be created using
|
||||
* {@link android.graphics.Color Color} class.</td>
|
||||
* </tr>
|
||||
* <tr><td><code>second_color</code></td>
|
||||
* <td>The second color tone.</td>
|
||||
* <td>Integer, representing an ARGB color with 8 bits per channel. May be created using
|
||||
* {@link android.graphics.Color Color} class.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_DUOTONE =
|
||||
"android.media.effect.effects.DuotoneEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies back-light filling to the image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>strength</code></td>
|
||||
* <td>The strength of the backlight.</td>
|
||||
* <td>Float, between 0 and 1. Zero means no change.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_FILLLIGHT =
|
||||
"android.media.effect.effects.FillLightEffect";
|
||||
|
||||
/**
|
||||
* <p>Flips image vertically and/or horizontally.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>vertical</code></td>
|
||||
* <td>Whether to flip image vertically.</td>
|
||||
* <td>Boolean</td>
|
||||
* </tr>
|
||||
* <tr><td><code>horizontal</code></td>
|
||||
* <td>Whether to flip image horizontally.</td>
|
||||
* <td>Boolean</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_FLIP =
|
||||
"android.media.effect.effects.FlipEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies film grain effect to image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>strength</code></td>
|
||||
* <td>The strength of the grain effect.</td>
|
||||
* <td>Float, between 0 and 1. Zero means no change.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_GRAIN =
|
||||
"android.media.effect.effects.GrainEffect";
|
||||
|
||||
/**
|
||||
* <p>Converts image to grayscale.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_GRAYSCALE =
|
||||
"android.media.effect.effects.GrayscaleEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies lomo-camera style effect to image.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_LOMOISH =
|
||||
"android.media.effect.effects.LomoishEffect";
|
||||
|
||||
/**
|
||||
* <p>Inverts the image colors.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_NEGATIVE =
|
||||
"android.media.effect.effects.NegativeEffect";
|
||||
|
||||
/**
|
||||
* <p>Applies posterization effect to image.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_POSTERIZE =
|
||||
"android.media.effect.effects.PosterizeEffect";
|
||||
|
||||
/**
|
||||
* <p>Removes red eyes on specified region.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>centers</code></td>
|
||||
* <td>Multiple center points (x, y) of the red eye regions.</td>
|
||||
* <td>An array of floats, where (f[2*i], f[2*i+1]) specifies the center of the i'th eye.
|
||||
* Coordinate values are expected to be normalized between 0 and 1.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_REDEYE =
|
||||
"android.media.effect.effects.RedEyeEffect";
|
||||
|
||||
/**
|
||||
* <p>Rotates the image. The output frame size must be able to fit the rotated version of
|
||||
* the input image. Note that the rotation snaps to a the closest multiple of 90 degrees.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>angle</code></td>
|
||||
* <td>The angle of rotation in degrees.</td>
|
||||
* <td>Integer value. This will be rounded to the nearest multiple of 90.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_ROTATE =
|
||||
"android.media.effect.effects.RotateEffect";
|
||||
|
||||
/**
|
||||
* <p>Adjusts color saturation of image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>scale</code></td>
|
||||
* <td>The scale of color saturation.</td>
|
||||
* <td>Float, between -1 and 1. 0 means no change, while -1 indicates full desaturation,
|
||||
* i.e. grayscale.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_SATURATE =
|
||||
"android.media.effect.effects.SaturateEffect";
|
||||
|
||||
/**
|
||||
* <p>Converts image to sepia tone.</p>
|
||||
* <p>Available parameters: None</p>
|
||||
*/
|
||||
public final static String EFFECT_SEPIA =
|
||||
"android.media.effect.effects.SepiaEffect";
|
||||
|
||||
/**
|
||||
* <p>Sharpens the image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>scale</code></td>
|
||||
* <td>The degree of sharpening.</td>
|
||||
* <td>Float, between 0 and 1. 0 means no change.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_SHARPEN =
|
||||
"android.media.effect.effects.SharpenEffect";
|
||||
|
||||
/**
|
||||
* <p>Rotates the image according to the specified angle, and crops the image so that no
|
||||
* non-image portions are visible.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>angle</code></td>
|
||||
* <td>The angle of rotation.</td>
|
||||
* <td>Float, between -45 and +45.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_STRAIGHTEN =
|
||||
"android.media.effect.effects.StraightenEffect";
|
||||
|
||||
/**
|
||||
* <p>Adjusts color temperature of the image.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>scale</code></td>
|
||||
* <td>The value of color temperature.</td>
|
||||
* <td>Float, between 0 and 1, with 0 indicating cool, and 1 indicating warm. A value of
|
||||
* of 0.5 indicates no change.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_TEMPERATURE =
|
||||
"android.media.effect.effects.ColorTemperatureEffect";
|
||||
|
||||
/**
|
||||
* <p>Tints the photo with specified color.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>tint</code></td>
|
||||
* <td>The color of the tint.</td>
|
||||
* <td>Integer, representing an ARGB color with 8 bits per channel. May be created using
|
||||
* {@link android.graphics.Color Color} class.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_TINT =
|
||||
"android.media.effect.effects.TintEffect";
|
||||
|
||||
/**
|
||||
* <p>Adds a vignette effect to image, i.e. fades away the outer image edges.</p>
|
||||
* <p>Available parameters:</p>
|
||||
* <table>
|
||||
* <tr><td>Parameter name</td><td>Meaning</td><td>Valid values</td></tr>
|
||||
* <tr><td><code>scale</code></td>
|
||||
* <td>The scale of vignetting.</td>
|
||||
* <td>Float, between 0 and 1. 0 means no change.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public final static String EFFECT_VIGNETTE =
|
||||
"android.media.effect.effects.VignetteEffect";
|
||||
|
||||
EffectFactory(EffectContext effectContext) {
|
||||
mEffectContext = effectContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a new effect with the given effect name.
|
||||
*
|
||||
* <p>The effect's parameters will be set to their default values.</p>
|
||||
*
|
||||
* <p>Note that the EGL context associated with the current EffectContext need not be made
|
||||
* current when creating an effect. This allows the host application to instantiate effects
|
||||
* before any EGL context has become current.</p>
|
||||
*
|
||||
* @param effectName The name of the effect to create.
|
||||
* @return A new Effect instance.
|
||||
* @throws IllegalArgumentException if the effect with the specified name is not supported or
|
||||
* not known.
|
||||
*/
|
||||
public Effect createEffect(String effectName) {
|
||||
Class effectClass = getEffectClassByName(effectName);
|
||||
if (effectClass == null) {
|
||||
throw new IllegalArgumentException("Cannot instantiate unknown effect '" +
|
||||
effectName + "'!");
|
||||
}
|
||||
return instantiateEffect(effectClass, effectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an effect is supported on this platform.
|
||||
*
|
||||
* <p>Some effects may only be available on certain platforms. Use this method before
|
||||
* instantiating an effect to make sure it is supported.</p>
|
||||
*
|
||||
* @param effectName The name of the effect.
|
||||
* @return true, if the effect is supported on this platform.
|
||||
* @throws IllegalArgumentException if the effect name is not known.
|
||||
*/
|
||||
public static boolean isEffectSupported(String effectName) {
|
||||
return getEffectClassByName(effectName) != null;
|
||||
}
|
||||
|
||||
private static Class getEffectClassByName(String className) {
|
||||
Class effectClass = null;
|
||||
|
||||
// Get context's classloader; otherwise cannot load non-framework effects
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
// Look for the class in the imported packages
|
||||
for (String packageName : EFFECT_PACKAGES) {
|
||||
try {
|
||||
effectClass = contextClassLoader.loadClass(packageName + className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
continue;
|
||||
}
|
||||
// Exit loop if class was found.
|
||||
if (effectClass != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return effectClass;
|
||||
}
|
||||
|
||||
private Effect instantiateEffect(Class effectClass, String name) {
|
||||
// Make sure this is an Effect subclass
|
||||
try {
|
||||
effectClass.asSubclass(Effect.class);
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalArgumentException("Attempting to allocate effect '" + effectClass
|
||||
+ "' which is not a subclass of Effect!", e);
|
||||
}
|
||||
|
||||
// Look for the correct constructor
|
||||
Constructor effectConstructor = null;
|
||||
try {
|
||||
effectConstructor = effectClass.getConstructor(EffectContext.class, String.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("The effect class '" + effectClass + "' does not have "
|
||||
+ "the required constructor.", e);
|
||||
}
|
||||
|
||||
// Construct the effect
|
||||
Effect effect = null;
|
||||
try {
|
||||
effect = (Effect)effectConstructor.newInstance(mEffectContext, name);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("There was an error constructing the effect '" + effectClass
|
||||
+ "'!", t);
|
||||
}
|
||||
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
/**
|
||||
* Some effects may issue callbacks to inform the host of changes to the effect state. This is the
|
||||
* listener interface for receiving those callbacks.
|
||||
*/
|
||||
public interface EffectUpdateListener {
|
||||
|
||||
/**
|
||||
* Called when the effect state is updated.
|
||||
*
|
||||
* @param effect The effect that has been updated.
|
||||
* @param info A value that gives more information about the update. See the effect's
|
||||
* documentation for more details on what this object is.
|
||||
*/
|
||||
public void onEffectUpdated(Effect effect, Object info);
|
||||
|
||||
}
|
||||
|
||||
101
media/mca/effect/java/android/media/effect/FilterEffect.java
Normal file
101
media/mca/effect/java/android/media/effect/FilterEffect.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
import android.filterfw.core.CachedFrameManager;
|
||||
import android.filterfw.core.FilterContext;
|
||||
import android.filterfw.core.FilterFactory;
|
||||
import android.filterfw.core.GLEnvironment;
|
||||
import android.filterfw.core.GLFrame;
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.format.ImageFormat;
|
||||
|
||||
/**
|
||||
* The FilterEffect class is the base class for all Effects based on Filters from the Mobile
|
||||
* Filter Framework (MFF).
|
||||
* @hide
|
||||
*/
|
||||
public abstract class FilterEffect extends Effect {
|
||||
|
||||
protected EffectContext mEffectContext;
|
||||
private String mName;
|
||||
|
||||
/**
|
||||
* Protected constructor as FilterEffects should be created by Factory.
|
||||
*/
|
||||
protected FilterEffect(EffectContext context, String name) {
|
||||
mEffectContext = context;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effect name.
|
||||
*
|
||||
* Returns the unique name of the effect, which matches the name used for instantiating this
|
||||
* effect by the EffectFactory.
|
||||
*
|
||||
* @return The name of the effect.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
// Helper Methods for subclasses ///////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Call this before manipulating the GL context. Will assert that the GL environment is in a
|
||||
* valid state, and save it.
|
||||
*/
|
||||
protected void beginGLEffect() {
|
||||
mEffectContext.assertValidGLState();
|
||||
mEffectContext.saveGLState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after manipulating the GL context. Restores the previous GL state.
|
||||
*/
|
||||
protected void endGLEffect() {
|
||||
mEffectContext.restoreGLState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active filter context for this effect.
|
||||
*/
|
||||
protected FilterContext getFilterContext() {
|
||||
return mEffectContext.mFilterContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a texture into a Frame.
|
||||
*/
|
||||
protected Frame frameFromTexture(int texId, int width, int height) {
|
||||
FrameManager manager = getFilterContext().getFrameManager();
|
||||
FrameFormat format = ImageFormat.create(width, height,
|
||||
ImageFormat.COLORSPACE_RGBA,
|
||||
FrameFormat.TARGET_GPU);
|
||||
Frame frame = manager.newBoundFrame(format,
|
||||
GLFrame.EXISTING_TEXTURE_BINDING,
|
||||
texId);
|
||||
frame.setTimestamp(Frame.TIMESTAMP_UNKNOWN);
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.FilterGraph;
|
||||
import android.filterfw.core.GraphRunner;
|
||||
import android.filterfw.core.SimpleScheduler;
|
||||
import android.filterfw.core.SyncRunner;
|
||||
import android.media.effect.Effect;
|
||||
import android.media.effect.FilterEffect;
|
||||
import android.media.effect.EffectContext;
|
||||
import android.filterfw.io.GraphIOException;
|
||||
import android.filterfw.io.GraphReader;
|
||||
import android.filterfw.io.TextGraphReader;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Effect subclass for effects based on a single Filter. Subclasses need only invoke the
|
||||
* constructor with the correct arguments to obtain an Effect implementation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class FilterGraphEffect extends FilterEffect {
|
||||
|
||||
private static final String TAG = "FilterGraphEffect";
|
||||
|
||||
protected String mInputName;
|
||||
protected String mOutputName;
|
||||
protected GraphRunner mRunner;
|
||||
protected FilterGraph mGraph;
|
||||
protected Class mSchedulerClass;
|
||||
|
||||
/**
|
||||
* Constructs a new FilterGraphEffect.
|
||||
*
|
||||
* @param name The name of this effect (used to create it in the EffectFactory).
|
||||
* @param graphString The graph string to create the graph.
|
||||
* @param inputName The name of the input GLTextureSource filter.
|
||||
* @param outputName The name of the output GLTextureSource filter.
|
||||
*/
|
||||
public FilterGraphEffect(EffectContext context,
|
||||
String name,
|
||||
String graphString,
|
||||
String inputName,
|
||||
String outputName,
|
||||
Class scheduler) {
|
||||
super(context, name);
|
||||
|
||||
mInputName = inputName;
|
||||
mOutputName = outputName;
|
||||
mSchedulerClass = scheduler;
|
||||
createGraph(graphString);
|
||||
|
||||
}
|
||||
|
||||
private void createGraph(String graphString) {
|
||||
GraphReader reader = new TextGraphReader();
|
||||
try {
|
||||
mGraph = reader.readGraphString(graphString);
|
||||
} catch (GraphIOException e) {
|
||||
throw new RuntimeException("Could not setup effect", e);
|
||||
}
|
||||
|
||||
if (mGraph == null) {
|
||||
throw new RuntimeException("Could not setup effect");
|
||||
}
|
||||
mRunner = new SyncRunner(getFilterContext(), mGraph, mSchedulerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(int inputTexId, int width, int height, int outputTexId) {
|
||||
beginGLEffect();
|
||||
Filter src = mGraph.getFilter(mInputName);
|
||||
if (src != null) {
|
||||
src.setInputValue("texId", inputTexId);
|
||||
src.setInputValue("width", width);
|
||||
src.setInputValue("height", height);
|
||||
} else {
|
||||
throw new RuntimeException("Internal error applying effect");
|
||||
}
|
||||
Filter dest = mGraph.getFilter(mOutputName);
|
||||
if (dest != null) {
|
||||
dest.setInputValue("texId", outputTexId);
|
||||
} else {
|
||||
throw new RuntimeException("Internal error applying effect");
|
||||
}
|
||||
try {
|
||||
mRunner.run();
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Internal error applying effect: ", e);
|
||||
}
|
||||
endGLEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(String parameterKey, Object value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
mGraph.tearDown(getFilterContext());
|
||||
mGraph = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.FilterFactory;
|
||||
import android.filterfw.core.FilterFunction;
|
||||
import android.filterfw.core.Frame;
|
||||
import android.media.effect.Effect;
|
||||
import android.media.effect.EffectContext;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Effect subclass for effects based on a single Filter. Subclasses need only invoke the
|
||||
* constructor with the correct arguments to obtain an Effect implementation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SingleFilterEffect extends FilterEffect {
|
||||
|
||||
protected FilterFunction mFunction;
|
||||
protected String mInputName;
|
||||
protected String mOutputName;
|
||||
|
||||
/**
|
||||
* Constructs a new FilterFunctionEffect.
|
||||
*
|
||||
* @param name The name of this effect (used to create it in the EffectFactory).
|
||||
* @param filterClass The class of the filter to wrap.
|
||||
* @param inputName The name of the input image port.
|
||||
* @param outputName The name of the output image port.
|
||||
* @param finalParameters Key-value pairs of final input port assignments.
|
||||
*/
|
||||
public SingleFilterEffect(EffectContext context,
|
||||
String name,
|
||||
Class filterClass,
|
||||
String inputName,
|
||||
String outputName,
|
||||
Object... finalParameters) {
|
||||
super(context, name);
|
||||
|
||||
mInputName = inputName;
|
||||
mOutputName = outputName;
|
||||
|
||||
String filterName = filterClass.getSimpleName();
|
||||
FilterFactory factory = FilterFactory.sharedFactory();
|
||||
Filter filter = factory.createFilterByClass(filterClass, filterName);
|
||||
filter.initWithAssignmentList(finalParameters);
|
||||
|
||||
mFunction = new FilterFunction(getFilterContext(), filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(int inputTexId, int width, int height, int outputTexId) {
|
||||
beginGLEffect();
|
||||
|
||||
Frame inputFrame = frameFromTexture(inputTexId, width, height);
|
||||
Frame outputFrame = frameFromTexture(outputTexId, width, height);
|
||||
|
||||
Frame resultFrame = mFunction.executeWithArgList(mInputName, inputFrame);
|
||||
|
||||
outputFrame.setDataFromFrame(resultFrame);
|
||||
|
||||
inputFrame.release();
|
||||
outputFrame.release();
|
||||
resultFrame.release();
|
||||
|
||||
endGLEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(String parameterKey, Object value) {
|
||||
mFunction.setInputValue(parameterKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
mFunction.tearDown();
|
||||
mFunction = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.FilterFactory;
|
||||
import android.filterfw.core.FilterFunction;
|
||||
import android.filterfw.core.Frame;
|
||||
import android.media.effect.Effect;
|
||||
import android.media.effect.EffectContext;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Effect subclass for effects based on a single Filter with output size differnet
|
||||
* from input. Subclasses need only invoke the constructor with the correct arguments
|
||||
* to obtain an Effect implementation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SizeChangeEffect extends SingleFilterEffect {
|
||||
|
||||
public SizeChangeEffect(EffectContext context,
|
||||
String name,
|
||||
Class filterClass,
|
||||
String inputName,
|
||||
String outputName,
|
||||
Object... finalParameters) {
|
||||
super(context, name, filterClass, inputName, outputName, finalParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(int inputTexId, int width, int height, int outputTexId) {
|
||||
beginGLEffect();
|
||||
|
||||
Frame inputFrame = frameFromTexture(inputTexId, width, height);
|
||||
Frame resultFrame = mFunction.executeWithArgList(mInputName, inputFrame);
|
||||
|
||||
int outputWidth = resultFrame.getFormat().getWidth();
|
||||
int outputHeight = resultFrame.getFormat().getHeight();
|
||||
|
||||
Frame outputFrame = frameFromTexture(outputTexId, outputWidth, outputHeight);
|
||||
outputFrame.setDataFromFrame(resultFrame);
|
||||
|
||||
inputFrame.release();
|
||||
outputFrame.release();
|
||||
resultFrame.release();
|
||||
|
||||
endGLEffect();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.AutoFixFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class AutoFixEffect extends SingleFilterEffect {
|
||||
public AutoFixEffect(EffectContext context, String name) {
|
||||
super(context, name, AutoFixFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.OneShotScheduler;
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.FilterGraphEffect;
|
||||
import android.media.effect.EffectUpdateListener;
|
||||
|
||||
import android.filterpacks.videoproc.BackDropperFilter;
|
||||
import android.filterpacks.videoproc.BackDropperFilter.LearningDoneListener;
|
||||
|
||||
/**
|
||||
* Background replacement Effect.
|
||||
*
|
||||
* Replaces the background of the input video stream with a selected video
|
||||
* Learns the background when it first starts up;
|
||||
* needs unobstructed view of background when this happens.
|
||||
*
|
||||
* Effect parameters:
|
||||
* source: A URI for the background video
|
||||
* Listener: Called when learning period is complete
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class BackDropperEffect extends FilterGraphEffect {
|
||||
private static final String mGraphDefinition =
|
||||
"@import android.filterpacks.base;\n" +
|
||||
"@import android.filterpacks.videoproc;\n" +
|
||||
"@import android.filterpacks.videosrc;\n" +
|
||||
"\n" +
|
||||
"@filter GLTextureSource foreground {\n" +
|
||||
" texId = 0;\n" + // Will be set by base class
|
||||
" width = 0;\n" +
|
||||
" height = 0;\n" +
|
||||
" repeatFrame = true;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"@filter MediaSource background {\n" +
|
||||
" sourceUrl = \"no_file_specified\";\n" +
|
||||
" waitForNewFrame = false;\n" +
|
||||
" sourceIsUrl = true;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"@filter BackDropperFilter replacer {\n" +
|
||||
" autowbToggle = 1;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"@filter GLTextureTarget output {\n" +
|
||||
" texId = 0;\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"@connect foreground[frame] => replacer[video];\n" +
|
||||
"@connect background[video] => replacer[background];\n" +
|
||||
"@connect replacer[video] => output[frame];\n";
|
||||
|
||||
private EffectUpdateListener mEffectListener = null;
|
||||
|
||||
private LearningDoneListener mLearningListener = new LearningDoneListener() {
|
||||
public void onLearningDone(BackDropperFilter filter) {
|
||||
if (mEffectListener != null) {
|
||||
mEffectListener.onEffectUpdated(BackDropperEffect.this, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public BackDropperEffect(EffectContext context, String name) {
|
||||
super(context, name, mGraphDefinition, "foreground", "output", OneShotScheduler.class);
|
||||
|
||||
Filter replacer = mGraph.getFilter("replacer");
|
||||
replacer.setInputValue("learningDoneListener", mLearningListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(String parameterKey, Object value) {
|
||||
if (parameterKey.equals("source")) {
|
||||
Filter background = mGraph.getFilter("background");
|
||||
background.setInputValue("sourceUrl", value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpdateListener(EffectUpdateListener listener) {
|
||||
mEffectListener = listener;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.BitmapOverlayFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class BitmapOverlayEffect extends SingleFilterEffect {
|
||||
public BitmapOverlayEffect(EffectContext context, String name) {
|
||||
super(context, name, BitmapOverlayFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.BlackWhiteFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class BlackWhiteEffect extends SingleFilterEffect {
|
||||
public BlackWhiteEffect(EffectContext context, String name) {
|
||||
super(context, name, BlackWhiteFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.BrightnessFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class BrightnessEffect extends SingleFilterEffect {
|
||||
public BrightnessEffect(EffectContext context, String name) {
|
||||
super(context, name, BrightnessFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.ColorTemperatureFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ColorTemperatureEffect extends SingleFilterEffect {
|
||||
public ColorTemperatureEffect(EffectContext context, String name) {
|
||||
super(context, name, ColorTemperatureFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.ContrastFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ContrastEffect extends SingleFilterEffect {
|
||||
public ContrastEffect(EffectContext context, String name) {
|
||||
super(context, name, ContrastFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SizeChangeEffect;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.CropRectFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
//public class CropEffect extends SingleFilterEffect {
|
||||
public class CropEffect extends SizeChangeEffect {
|
||||
public CropEffect(EffectContext context, String name) {
|
||||
super(context, name, CropRectFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.CrossProcessFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class CrossProcessEffect extends SingleFilterEffect {
|
||||
public CrossProcessEffect(EffectContext context, String name) {
|
||||
super(context, name, CrossProcessFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.DocumentaryFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class DocumentaryEffect extends SingleFilterEffect {
|
||||
public DocumentaryEffect(EffectContext context, String name) {
|
||||
super(context, name, DocumentaryFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.DuotoneFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class DuotoneEffect extends SingleFilterEffect {
|
||||
public DuotoneEffect(EffectContext context, String name) {
|
||||
super(context, name, DuotoneFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.FillLightFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FillLightEffect extends SingleFilterEffect {
|
||||
public FillLightEffect(EffectContext context, String name) {
|
||||
super(context, name, FillLightFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.FisheyeFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FisheyeEffect extends SingleFilterEffect {
|
||||
public FisheyeEffect(EffectContext context, String name) {
|
||||
super(context, name, FisheyeFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.FlipFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FlipEffect extends SingleFilterEffect {
|
||||
public FlipEffect(EffectContext context, String name) {
|
||||
super(context, name, FlipFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.GrainFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class GrainEffect extends SingleFilterEffect {
|
||||
public GrainEffect(EffectContext context, String name) {
|
||||
super(context, name, GrainFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.ToGrayFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class GrayscaleEffect extends SingleFilterEffect {
|
||||
public GrayscaleEffect(EffectContext context, String name) {
|
||||
super(context, name, ToGrayFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.FilterEffect;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class IdentityEffect extends FilterEffect {
|
||||
|
||||
public IdentityEffect(EffectContext context, String name) {
|
||||
super(context, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(int inputTexId, int width, int height, int outputTexId) {
|
||||
beginGLEffect();
|
||||
|
||||
Frame inputFrame = frameFromTexture(inputTexId, width, height);
|
||||
Frame outputFrame = frameFromTexture(outputTexId, width, height);
|
||||
|
||||
outputFrame.setDataFromFrame(inputFrame);
|
||||
|
||||
inputFrame.release();
|
||||
outputFrame.release();
|
||||
|
||||
endGLEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameter(String parameterKey, Object value) {
|
||||
throw new IllegalArgumentException("Unknown parameter " + parameterKey
|
||||
+ " for IdentityEffect!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.LomoishFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class LomoishEffect extends SingleFilterEffect {
|
||||
public LomoishEffect(EffectContext context, String name) {
|
||||
super(context, name, LomoishFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.NegativeFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class NegativeEffect extends SingleFilterEffect {
|
||||
public NegativeEffect(EffectContext context, String name) {
|
||||
super(context, name, NegativeFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.PosterizeFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class PosterizeEffect extends SingleFilterEffect {
|
||||
public PosterizeEffect(EffectContext context, String name) {
|
||||
super(context, name, PosterizeFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.RedEyeFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class RedEyeEffect extends SingleFilterEffect {
|
||||
public RedEyeEffect(EffectContext context, String name) {
|
||||
super(context, name, RedEyeFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SizeChangeEffect;
|
||||
import android.filterpacks.imageproc.RotateFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class RotateEffect extends SizeChangeEffect {
|
||||
public RotateEffect(EffectContext context, String name) {
|
||||
super(context, name, RotateFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.SaturateFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SaturateEffect extends SingleFilterEffect {
|
||||
public SaturateEffect(EffectContext context, String name) {
|
||||
super(context, name, SaturateFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.SepiaFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SepiaEffect extends SingleFilterEffect {
|
||||
public SepiaEffect(EffectContext context, String name) {
|
||||
super(context, name, SepiaFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.SharpenFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SharpenEffect extends SingleFilterEffect {
|
||||
public SharpenEffect(EffectContext context, String name) {
|
||||
super(context, name, SharpenFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.StraightenFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class StraightenEffect extends SingleFilterEffect {
|
||||
public StraightenEffect(EffectContext context, String name) {
|
||||
super(context, name, StraightenFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.TintFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class TintEffect extends SingleFilterEffect {
|
||||
public TintEffect(EffectContext context, String name) {
|
||||
super(context, name, TintFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect.effects;
|
||||
|
||||
import android.media.effect.EffectContext;
|
||||
import android.media.effect.SingleFilterEffect;
|
||||
import android.filterpacks.imageproc.VignetteFilter;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class VignetteEffect extends SingleFilterEffect {
|
||||
public VignetteEffect(EffectContext context, String name) {
|
||||
super(context, name, VignetteFilter.class, "image", "image");
|
||||
}
|
||||
}
|
||||
28
media/mca/effect/java/android/media/effect/package-info.java
Normal file
28
media/mca/effect/java/android/media/effect/package-info.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media.effect;
|
||||
|
||||
/**
|
||||
* <h1>Effect Framework</h1>
|
||||
*
|
||||
* This package includes a collection of high-performance visual effects that make use of the
|
||||
* mobile filter framework subsystem.
|
||||
*
|
||||
* TODO: More Documentation
|
||||
*
|
||||
*/
|
||||
54
media/mca/effect/java/android/media/effect/package.html
Normal file
54
media/mca/effect/java/android/media/effect/package.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<HTML>
|
||||
<BODY>
|
||||
<p>Provides classes that allow you to apply a variety of visual effects to images and
|
||||
videos. For example, you can easily fix red-eye, convert an image to grayscale,
|
||||
adjust brightness, adjust saturation, rotate an image, apply a fisheye effect, and much more. The
|
||||
system performs all effects processing on the GPU to obtain maximum performance.</p>
|
||||
|
||||
<p>For maximum performance, effects are applied directly to OpenGL textures, so your application
|
||||
must have a valid OpenGL context before it can use the effects APIs. The textures to which you apply
|
||||
effects may be from bitmaps, videos or even the camera. However, there are certain restrictions that
|
||||
textures must meet:</p>
|
||||
<ol>
|
||||
<li>They must be bound to a {@link android.opengl.GLES20#GL_TEXTURE_2D} texture image</li>
|
||||
<li>They must contain at least one mipmap level</li>
|
||||
</ol>
|
||||
|
||||
<p>An {@link android.media.effect.Effect} object defines a single media effect that you can apply to
|
||||
an image frame. The basic workflow to create an {@link android.media.effect.Effect} is:</p>
|
||||
|
||||
<ol>
|
||||
<li>Call {@link android.media.effect.EffectContext#createWithCurrentGlContext
|
||||
EffectContext.createWithCurrentGlContext()} from your OpenGL ES 2.0 context.</li>
|
||||
<li>Use the returned {@link android.media.effect.EffectContext} to call {@link
|
||||
android.media.effect.EffectContext#getFactory EffectContext.getFactory()}, which returns an instance
|
||||
of {@link android.media.effect.EffectFactory}.</li>
|
||||
<li>Call {@link android.media.effect.EffectFactory#createEffect createEffect()}, passing it an
|
||||
effect name from @link android.media.effect.EffectFactory}, such as {@link
|
||||
android.media.effect.EffectFactory#EFFECT_FISHEYE} or {@link
|
||||
android.media.effect.EffectFactory#EFFECT_VIGNETTE}.</li>
|
||||
</ol>
|
||||
|
||||
<p>You can adjust an effect’s parameters by calling {@link android.media.effect.Effect#setParameter
|
||||
setParameter()} and passing a parameter name and parameter value. Each type of effect accepts
|
||||
different parameters, which are documented with the effect name. For example, {@link
|
||||
android.media.effect.EffectFactory#EFFECT_FISHEYE} has one parameter for the {@code scale} of the
|
||||
distortion.</p>
|
||||
|
||||
<p>To apply an effect on a texture, call {@link android.media.effect.Effect#apply apply()} on the
|
||||
{@link
|
||||
android.media.effect.Effect} and pass in the input texture, its width and height, and the output
|
||||
texture. The input texture must be bound to a {@link android.opengl.GLES20#GL_TEXTURE_2D} texture
|
||||
image (usually done by calling the {@link android.opengl.GLES20#glTexImage2D glTexImage2D()}
|
||||
function). You may provide multiple mipmap levels. If the output texture has not been bound to a
|
||||
texture image, it will be automatically bound by the effect as a {@link
|
||||
android.opengl.GLES20#GL_TEXTURE_2D} and with one mipmap level (0), which will have the same
|
||||
size as the input.</p>
|
||||
|
||||
<p class="note"><strong>Note:</strong> All effects listed in {@link
|
||||
android.media.effect.EffectFactory} are guaranteed to be supported. However, some additional effects
|
||||
available from external libraries are not supported by all devices, so you must first check if the
|
||||
desired effect from the external library is supported by calling {@link
|
||||
android.media.effect.EffectFactory#isEffectSupported isEffectSupported()}.</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
53
media/mca/filterfw/Android.mk
Normal file
53
media/mca/filterfw/Android.mk
Normal file
@@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2011 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
#####################
|
||||
# Build native sublibraries
|
||||
|
||||
include $(all-subdir-makefiles)
|
||||
|
||||
#####################
|
||||
# Build main libfilterfw
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libfilterfw
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libfilterfw_jni \
|
||||
libfilterfw_native
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libstlport \
|
||||
libGLESv2 \
|
||||
libEGL \
|
||||
libgui \
|
||||
libdl \
|
||||
libcutils \
|
||||
libutils \
|
||||
libandroid \
|
||||
libjnigraphics \
|
||||
libmedia \
|
||||
libmedia_native
|
||||
|
||||
# Don't prelink this library. For more efficient code, you may want
|
||||
# to add this library to the prelink map and set this to true. However,
|
||||
# it's difficult to do this for applications that are not supplied as
|
||||
# part of a system image.
|
||||
LOCAL_PRELINK_MODULE := false
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.FilterFactory;
|
||||
import android.filterfw.core.FilterFunction;
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameManager;
|
||||
|
||||
/**
|
||||
* A FilterFunctionEnvironment provides a simple functional front-end to manually executing
|
||||
* filters. Use this environment if a graph-based approach is not convenient for your case.
|
||||
* Typically, a FilterFunctionEnvironment is used as follows:
|
||||
* 1. Instantiate a new FilterFunctionEnvironment instance.
|
||||
* 2. Perform any configuration, such as setting a GL environment.
|
||||
* 3. Wrap Filters into FilterFunctions by calling createFunction().
|
||||
* 4. Execute FilterFunctions individually and use the results for further processing.
|
||||
* Additionally, there is a convenience method to execute a number of filters in sequence.
|
||||
* @hide
|
||||
*/
|
||||
public class FilterFunctionEnvironment extends MffEnvironment {
|
||||
|
||||
/**
|
||||
* Create a new FilterFunctionEnvironment with the default components.
|
||||
*/
|
||||
public FilterFunctionEnvironment() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FilterFunctionEnvironment with a custom FrameManager. Pass null to auto-create
|
||||
* a FrameManager.
|
||||
*
|
||||
* @param frameManager The FrameManager to use, or null to auto-create one.
|
||||
*/
|
||||
public FilterFunctionEnvironment(FrameManager frameManager) {
|
||||
super(frameManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new FilterFunction from a specific filter class. The function is initialized with
|
||||
* the given key-value list of parameters. Note, that this function uses the default shared
|
||||
* FilterFactory to create the filter instance.
|
||||
*
|
||||
* @param filterClass The class of the filter to wrap. This must be a Filter subclass.
|
||||
* @param parameters An argument list of alternating key-value filter parameters.
|
||||
* @return A new FilterFunction instance.
|
||||
*/
|
||||
public FilterFunction createFunction(Class filterClass, Object... parameters) {
|
||||
String filterName = "FilterFunction(" + filterClass.getSimpleName() + ")";
|
||||
Filter filter = FilterFactory.sharedFactory().createFilterByClass(filterClass, filterName);
|
||||
filter.initWithAssignmentList(parameters);
|
||||
return new FilterFunction(getContext(), filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to execute a sequence of filter functions. Note that every function in
|
||||
* the list MUST have one input and one output port, except the first filter (which must not
|
||||
* have any input ports) and the last filter (which may not have any output ports).
|
||||
*
|
||||
* @param functions A list of filter functions. The first filter must be a source filter.
|
||||
* @return The result of the last filter executed, or null if the last filter did not
|
||||
produce any output.
|
||||
*
|
||||
public Frame executeSequence(FilterFunction[] functions) {
|
||||
Frame oldFrame = null;
|
||||
Frame newFrame = null;
|
||||
for (FilterFunction filterFunction : functions) {
|
||||
if (oldFrame == null) {
|
||||
newFrame = filterFunction.executeWithArgList();
|
||||
} else {
|
||||
newFrame = filterFunction.executeWithArgList(oldFrame);
|
||||
oldFrame.release();
|
||||
}
|
||||
oldFrame = newFrame;
|
||||
}
|
||||
if (oldFrame != null) {
|
||||
oldFrame.release();
|
||||
}
|
||||
return newFrame;
|
||||
}*/
|
||||
|
||||
}
|
||||
197
media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
Normal file
197
media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw;
|
||||
|
||||
import android.content.Context;
|
||||
import android.filterfw.core.AsyncRunner;
|
||||
import android.filterfw.core.FilterGraph;
|
||||
import android.filterfw.core.FilterContext;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.GraphRunner;
|
||||
import android.filterfw.core.RoundRobinScheduler;
|
||||
import android.filterfw.core.SyncRunner;
|
||||
import android.filterfw.io.GraphIOException;
|
||||
import android.filterfw.io.GraphReader;
|
||||
import android.filterfw.io.TextGraphReader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A GraphEnvironment provides a simple front-end to filter graph setup and execution using the
|
||||
* mobile filter framework. Typically, you use a GraphEnvironment in the following fashion:
|
||||
* 1. Instantiate a new GraphEnvironment instance.
|
||||
* 2. Perform any configuration, such as adding graph references and setting a GL environment.
|
||||
* 3. Load a graph file using loadGraph() or add a graph using addGraph().
|
||||
* 4. Obtain a GraphRunner instance using getRunner().
|
||||
* 5. Execute the obtained runner.
|
||||
* Note that it is possible to add multiple graphs and runners to a single GraphEnvironment.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class GraphEnvironment extends MffEnvironment {
|
||||
|
||||
public static final int MODE_ASYNCHRONOUS = 1;
|
||||
public static final int MODE_SYNCHRONOUS = 2;
|
||||
|
||||
private GraphReader mGraphReader;
|
||||
private ArrayList<GraphHandle> mGraphs = new ArrayList<GraphHandle>();
|
||||
|
||||
private class GraphHandle {
|
||||
private FilterGraph mGraph;
|
||||
private AsyncRunner mAsyncRunner;
|
||||
private SyncRunner mSyncRunner;
|
||||
|
||||
public GraphHandle(FilterGraph graph) {
|
||||
mGraph = graph;
|
||||
}
|
||||
|
||||
public FilterGraph getGraph() {
|
||||
return mGraph;
|
||||
}
|
||||
|
||||
public AsyncRunner getAsyncRunner(FilterContext environment) {
|
||||
if (mAsyncRunner == null) {
|
||||
mAsyncRunner = new AsyncRunner(environment, RoundRobinScheduler.class);
|
||||
mAsyncRunner.setGraph(mGraph);
|
||||
}
|
||||
return mAsyncRunner;
|
||||
}
|
||||
|
||||
public GraphRunner getSyncRunner(FilterContext environment) {
|
||||
if (mSyncRunner == null) {
|
||||
mSyncRunner = new SyncRunner(environment, mGraph, RoundRobinScheduler.class);
|
||||
}
|
||||
return mSyncRunner;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GraphEnvironment with default components.
|
||||
*/
|
||||
public GraphEnvironment() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GraphEnvironment with a custom FrameManager and GraphReader. Specifying null
|
||||
* for either of these, will auto-create a default instance.
|
||||
*
|
||||
* @param frameManager The FrameManager to use, or null to auto-create one.
|
||||
* @param reader The GraphReader to use for graph loading, or null to auto-create one.
|
||||
* Note, that the reader will not be created until it is required. Pass
|
||||
* null if you will not load any graph files.
|
||||
*/
|
||||
public GraphEnvironment(FrameManager frameManager, GraphReader reader) {
|
||||
super(frameManager);
|
||||
mGraphReader = reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the used graph reader. This will create one, if a reader has not been set already.
|
||||
*/
|
||||
public GraphReader getGraphReader() {
|
||||
if (mGraphReader == null) {
|
||||
mGraphReader = new TextGraphReader();
|
||||
}
|
||||
return mGraphReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add graph references to resolve during graph reading. The references added here are shared
|
||||
* among all graphs.
|
||||
*
|
||||
* @param references An alternating argument list of keys (Strings) and values.
|
||||
*/
|
||||
public void addReferences(Object... references) {
|
||||
getGraphReader().addReferencesByKeysAndValues(references);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a graph file from the specified resource and adds it to this environment.
|
||||
*
|
||||
* @param context The context in which to read the resource.
|
||||
* @param resourceId The ID of the graph resource to load.
|
||||
* @return A unique ID for the graph.
|
||||
*/
|
||||
public int loadGraph(Context context, int resourceId) {
|
||||
// Read the file into a graph
|
||||
FilterGraph graph = null;
|
||||
try {
|
||||
graph = getGraphReader().readGraphResource(context, resourceId);
|
||||
} catch (GraphIOException e) {
|
||||
throw new RuntimeException("Could not read graph: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Add graph to our list of graphs
|
||||
return addGraph(graph);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a graph to the environment. Consider using loadGraph() if you are loading a graph from
|
||||
* a graph file.
|
||||
*
|
||||
* @param graph The graph to add to the environment.
|
||||
* @return A unique ID for the added graph.
|
||||
*/
|
||||
public int addGraph(FilterGraph graph) {
|
||||
GraphHandle graphHandle = new GraphHandle(graph);
|
||||
mGraphs.add(graphHandle);
|
||||
return mGraphs.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access a specific graph of this environment given a graph ID (previously returned from
|
||||
* loadGraph() or addGraph()). Throws an InvalidArgumentException if no graph with the
|
||||
* specified ID could be found.
|
||||
*
|
||||
* @param graphId The ID of the graph to get.
|
||||
* @return The graph with the specified ID.
|
||||
*/
|
||||
public FilterGraph getGraph(int graphId) {
|
||||
if (graphId < 0 || graphId >= mGraphs.size()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid graph ID " + graphId + " specified in runGraph()!");
|
||||
}
|
||||
return mGraphs.get(graphId).getGraph();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a GraphRunner instance for the graph with the specified ID. The GraphRunner instance can
|
||||
* be used to execute the graph. Throws an InvalidArgumentException if no graph with the
|
||||
* specified ID could be found.
|
||||
*
|
||||
* @param graphId The ID of the graph to get.
|
||||
* @param executionMode The mode of graph execution. Currently this can be either
|
||||
MODE_SYNCHRONOUS or MODE_ASYNCHRONOUS.
|
||||
* @return A GraphRunner instance for this graph.
|
||||
*/
|
||||
public GraphRunner getRunner(int graphId, int executionMode) {
|
||||
switch (executionMode) {
|
||||
case MODE_ASYNCHRONOUS:
|
||||
return mGraphs.get(graphId).getAsyncRunner(getContext());
|
||||
|
||||
case MODE_SYNCHRONOUS:
|
||||
return mGraphs.get(graphId).getSyncRunner(getContext());
|
||||
|
||||
default:
|
||||
throw new RuntimeException(
|
||||
"Invalid execution mode " + executionMode + " specified in getRunner()!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
106
media/mca/filterfw/java/android/filterfw/MffEnvironment.java
Normal file
106
media/mca/filterfw/java/android/filterfw/MffEnvironment.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw;
|
||||
|
||||
import android.filterfw.core.CachedFrameManager;
|
||||
import android.filterfw.core.FilterContext;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.GLEnvironment;
|
||||
|
||||
/**
|
||||
* Base class for mobile filter framework (MFF) frontend environments. These convenience classes
|
||||
* allow using the filter framework without the requirement of performing manual setup of its
|
||||
* required components.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class MffEnvironment {
|
||||
|
||||
private FilterContext mContext;
|
||||
|
||||
/**
|
||||
* Protected constructor to initialize the environment's essential components. These are the
|
||||
* frame-manager and the filter-context. Passing in null for the frame-manager causes this
|
||||
* to be auto-created.
|
||||
*
|
||||
* @param frameManager The FrameManager to use or null to auto-create one.
|
||||
*/
|
||||
protected MffEnvironment(FrameManager frameManager) {
|
||||
// Get or create the frame manager
|
||||
if (frameManager == null) {
|
||||
frameManager = new CachedFrameManager();
|
||||
}
|
||||
|
||||
// Setup the environment
|
||||
mContext = new FilterContext();
|
||||
mContext.setFrameManager(frameManager);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment's filter-context.
|
||||
*/
|
||||
public FilterContext getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the environment's GL environment to the specified environment. This does not activate
|
||||
* the environment.
|
||||
*/
|
||||
public void setGLEnvironment(GLEnvironment glEnvironment) {
|
||||
mContext.initGLEnvironment(glEnvironment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and activate a new GL environment for use in this filter context.
|
||||
*/
|
||||
public void createGLEnvironment() {
|
||||
GLEnvironment glEnvironment = new GLEnvironment();
|
||||
glEnvironment.initWithNewContext();
|
||||
setGLEnvironment(glEnvironment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the GL environment for use in the current thread. A GL environment must have been
|
||||
* previously set or created using setGLEnvironment() or createGLEnvironment()! Call this after
|
||||
* having switched to a new thread for GL filter execution.
|
||||
*/
|
||||
public void activateGLEnvironment() {
|
||||
GLEnvironment glEnv = mContext.getGLEnvironment();
|
||||
if (glEnv != null) {
|
||||
mContext.getGLEnvironment().activate();
|
||||
} else {
|
||||
throw new NullPointerException("No GLEnvironment in place to activate!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate the GL environment from use in the current thread. A GL environment must have been
|
||||
* previously set or created using setGLEnvironment() or createGLEnvironment()! Call this before
|
||||
* running GL filters in another thread.
|
||||
*/
|
||||
public void deactivateGLEnvironment() {
|
||||
GLEnvironment glEnv = mContext.getGLEnvironment();
|
||||
if (glEnv != null) {
|
||||
mContext.getGLEnvironment().deactivate();
|
||||
} else {
|
||||
throw new NullPointerException("No GLEnvironment in place to deactivate!");
|
||||
}
|
||||
}
|
||||
}
|
||||
247
media/mca/filterfw/java/android/filterfw/core/AsyncRunner.java
Normal file
247
media/mca/filterfw/java/android/filterfw/core/AsyncRunner.java
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.InterruptedException;
|
||||
import java.lang.Runnable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class AsyncRunner extends GraphRunner{
|
||||
|
||||
private Class mSchedulerClass;
|
||||
private SyncRunner mRunner;
|
||||
private AsyncRunnerTask mRunTask;
|
||||
|
||||
private OnRunnerDoneListener mDoneListener;
|
||||
private boolean isProcessing;
|
||||
|
||||
private Exception mException;
|
||||
|
||||
private class RunnerResult {
|
||||
public int status = RESULT_UNKNOWN;
|
||||
public Exception exception;
|
||||
}
|
||||
|
||||
private class AsyncRunnerTask extends AsyncTask<SyncRunner, Void, RunnerResult> {
|
||||
|
||||
private static final String TAG = "AsyncRunnerTask";
|
||||
|
||||
@Override
|
||||
protected RunnerResult doInBackground(SyncRunner... runner) {
|
||||
RunnerResult result = new RunnerResult();
|
||||
try {
|
||||
if (runner.length > 1) {
|
||||
throw new RuntimeException("More than one runner received!");
|
||||
}
|
||||
|
||||
runner[0].assertReadyToStep();
|
||||
|
||||
// Preparation
|
||||
if (mLogVerbose) Log.v(TAG, "Starting background graph processing.");
|
||||
activateGlContext();
|
||||
|
||||
if (mLogVerbose) Log.v(TAG, "Preparing filter graph for processing.");
|
||||
runner[0].beginProcessing();
|
||||
|
||||
if (mLogVerbose) Log.v(TAG, "Running graph.");
|
||||
|
||||
// Run loop
|
||||
result.status = RESULT_RUNNING;
|
||||
while (!isCancelled() && result.status == RESULT_RUNNING) {
|
||||
if (!runner[0].performStep()) {
|
||||
result.status = runner[0].determinePostRunState();
|
||||
if (result.status == GraphRunner.RESULT_SLEEPING) {
|
||||
runner[0].waitUntilWake();
|
||||
result.status = RESULT_RUNNING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if (isCancelled()) {
|
||||
result.status = RESULT_STOPPED;
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
result.exception = exception;
|
||||
result.status = RESULT_ERROR;
|
||||
}
|
||||
|
||||
// Deactivate context.
|
||||
try {
|
||||
deactivateGlContext();
|
||||
} catch (Exception exception) {
|
||||
result.exception = exception;
|
||||
result.status = RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (mLogVerbose) Log.v(TAG, "Done with background graph processing.");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled(RunnerResult result) {
|
||||
onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(RunnerResult result) {
|
||||
if (mLogVerbose) Log.v(TAG, "Starting post-execute.");
|
||||
setRunning(false);
|
||||
if (result == null) {
|
||||
// Cancelled before got to doInBackground
|
||||
result = new RunnerResult();
|
||||
result.status = RESULT_STOPPED;
|
||||
}
|
||||
setException(result.exception);
|
||||
if (result.status == RESULT_STOPPED || result.status == RESULT_ERROR) {
|
||||
if (mLogVerbose) Log.v(TAG, "Closing filters.");
|
||||
try {
|
||||
mRunner.close();
|
||||
} catch (Exception exception) {
|
||||
result.status = RESULT_ERROR;
|
||||
setException(exception);
|
||||
}
|
||||
}
|
||||
if (mDoneListener != null) {
|
||||
if (mLogVerbose) Log.v(TAG, "Calling graph done callback.");
|
||||
mDoneListener.onRunnerDone(result.status);
|
||||
}
|
||||
if (mLogVerbose) Log.v(TAG, "Completed post-execute.");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mLogVerbose;
|
||||
private static final String TAG = "AsyncRunner";
|
||||
|
||||
/** Create a new asynchronous graph runner with the given filter
|
||||
* context, and the given scheduler class.
|
||||
*
|
||||
* Must be created on the UI thread.
|
||||
*/
|
||||
public AsyncRunner(FilterContext context, Class schedulerClass) {
|
||||
super(context);
|
||||
|
||||
mSchedulerClass = schedulerClass;
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
/** Create a new asynchronous graph runner with the given filter
|
||||
* context. Uses a default scheduler.
|
||||
*
|
||||
* Must be created on the UI thread.
|
||||
*/
|
||||
public AsyncRunner(FilterContext context) {
|
||||
super(context);
|
||||
|
||||
mSchedulerClass = SimpleScheduler.class;
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
/** Set a callback to be called in the UI thread once the AsyncRunner
|
||||
* completes running a graph, whether the completion is due to a stop() call
|
||||
* or the filters running out of data to process.
|
||||
*/
|
||||
@Override
|
||||
public void setDoneCallback(OnRunnerDoneListener listener) {
|
||||
mDoneListener = listener;
|
||||
}
|
||||
|
||||
/** Sets the graph to be run. Will call prepare() on graph. Cannot be called
|
||||
* when a graph is already running.
|
||||
*/
|
||||
synchronized public void setGraph(FilterGraph graph) {
|
||||
if (isRunning()) {
|
||||
throw new RuntimeException("Graph is already running!");
|
||||
}
|
||||
mRunner = new SyncRunner(mFilterContext, graph, mSchedulerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterGraph getGraph() {
|
||||
return mRunner != null ? mRunner.getGraph() : null;
|
||||
}
|
||||
|
||||
/** Execute the graph in a background thread. */
|
||||
@Override
|
||||
synchronized public void run() {
|
||||
if (mLogVerbose) Log.v(TAG, "Running graph.");
|
||||
setException(null);
|
||||
|
||||
if (isRunning()) {
|
||||
throw new RuntimeException("Graph is already running!");
|
||||
}
|
||||
if (mRunner == null) {
|
||||
throw new RuntimeException("Cannot run before a graph is set!");
|
||||
}
|
||||
mRunTask = this.new AsyncRunnerTask();
|
||||
|
||||
setRunning(true);
|
||||
mRunTask.execute(mRunner);
|
||||
}
|
||||
|
||||
/** Stop graph execution. This is an asynchronous call; register a callback
|
||||
* with setDoneCallback to be notified of when the background processing has
|
||||
* been completed. Calling stop will close the filter graph. */
|
||||
@Override
|
||||
synchronized public void stop() {
|
||||
if (mRunTask != null && !mRunTask.isCancelled() ) {
|
||||
if (mLogVerbose) Log.v(TAG, "Stopping graph.");
|
||||
mRunTask.cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized public void close() {
|
||||
if (isRunning()) {
|
||||
throw new RuntimeException("Cannot close graph while it is running!");
|
||||
}
|
||||
if (mLogVerbose) Log.v(TAG, "Closing filters.");
|
||||
mRunner.close();
|
||||
}
|
||||
|
||||
/** Check if background processing is happening */
|
||||
@Override
|
||||
synchronized public boolean isRunning() {
|
||||
return isProcessing;
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized public Exception getError() {
|
||||
return mException;
|
||||
}
|
||||
|
||||
synchronized private void setRunning(boolean running) {
|
||||
isProcessing = running;
|
||||
}
|
||||
|
||||
synchronized private void setException(Exception exception) {
|
||||
mException = exception;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.SimpleFrameManager;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class CachedFrameManager extends SimpleFrameManager {
|
||||
|
||||
private SortedMap<Integer, Frame> mAvailableFrames;
|
||||
private int mStorageCapacity = 24 * 1024 * 1024; // Cap default storage to 24MB
|
||||
private int mStorageSize = 0;
|
||||
private int mTimeStamp = 0;
|
||||
|
||||
public CachedFrameManager() {
|
||||
super();
|
||||
mAvailableFrames = new TreeMap<Integer, Frame>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame newFrame(FrameFormat format) {
|
||||
Frame result = findAvailableFrame(format, Frame.NO_BINDING, 0);
|
||||
if (result == null) {
|
||||
result = super.newFrame(format);
|
||||
}
|
||||
result.setTimestamp(Frame.TIMESTAMP_NOT_SET);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame newBoundFrame(FrameFormat format, int bindingType, long bindingId) {
|
||||
Frame result = findAvailableFrame(format, bindingType, bindingId);
|
||||
if (result == null) {
|
||||
result = super.newBoundFrame(format, bindingType, bindingId);
|
||||
}
|
||||
result.setTimestamp(Frame.TIMESTAMP_NOT_SET);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame retainFrame(Frame frame) {
|
||||
return super.retainFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame releaseFrame(Frame frame) {
|
||||
if (frame.isReusable()) {
|
||||
int refCount = frame.decRefCount();
|
||||
if (refCount == 0 && frame.hasNativeAllocation()) {
|
||||
if (!storeFrame(frame)) {
|
||||
frame.releaseNativeAllocation();
|
||||
}
|
||||
return null;
|
||||
} else if (refCount < 0) {
|
||||
throw new RuntimeException("Frame reference count dropped below 0!");
|
||||
}
|
||||
} else {
|
||||
super.releaseFrame(frame);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
for (Frame frame : mAvailableFrames.values()) {
|
||||
frame.releaseNativeAllocation();
|
||||
}
|
||||
mAvailableFrames.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() {
|
||||
clearCache();
|
||||
}
|
||||
|
||||
private boolean storeFrame(Frame frame) {
|
||||
synchronized(mAvailableFrames) {
|
||||
// Make sure this frame alone does not exceed capacity
|
||||
int frameSize = frame.getFormat().getSize();
|
||||
if (frameSize > mStorageCapacity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Drop frames if adding this frame would exceed capacity
|
||||
int newStorageSize = mStorageSize + frameSize;
|
||||
while (newStorageSize > mStorageCapacity) {
|
||||
dropOldestFrame();
|
||||
newStorageSize = mStorageSize + frameSize;
|
||||
}
|
||||
|
||||
// Store new frame
|
||||
frame.onFrameStore();
|
||||
mStorageSize = newStorageSize;
|
||||
mAvailableFrames.put(mTimeStamp, frame);
|
||||
++mTimeStamp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void dropOldestFrame() {
|
||||
int oldest = mAvailableFrames.firstKey();
|
||||
Frame frame = mAvailableFrames.get(oldest);
|
||||
mStorageSize -= frame.getFormat().getSize();
|
||||
frame.releaseNativeAllocation();
|
||||
mAvailableFrames.remove(oldest);
|
||||
}
|
||||
|
||||
private Frame findAvailableFrame(FrameFormat format, int bindingType, long bindingId) {
|
||||
// Look for a frame that is compatible with the requested format
|
||||
synchronized(mAvailableFrames) {
|
||||
for (Map.Entry<Integer, Frame> entry : mAvailableFrames.entrySet()) {
|
||||
Frame frame = entry.getValue();
|
||||
// Check that format is compatible
|
||||
if (frame.getFormat().isReplaceableBy(format)) {
|
||||
// Check that binding is compatible (if frame is bound)
|
||||
if ((bindingType == frame.getBindingType())
|
||||
&& (bindingType == Frame.NO_BINDING || bindingId == frame.getBindingId())) {
|
||||
// We found one! Take it out of the set of available frames and attach the
|
||||
// requested format to it.
|
||||
super.retainFrame(frame);
|
||||
mAvailableFrames.remove(entry.getKey());
|
||||
frame.onFrameFetch();
|
||||
frame.reset(format);
|
||||
mStorageSize -= format.getSize();
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
111
media/mca/filterfw/java/android/filterfw/core/FieldPort.java
Normal file
111
media/mca/filterfw/java/android/filterfw/core/FieldPort.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FieldPort extends InputPort {
|
||||
|
||||
protected Field mField;
|
||||
protected boolean mHasFrame;
|
||||
protected boolean mValueWaiting = false;
|
||||
protected Object mValue;
|
||||
|
||||
public FieldPort(Filter filter, String name, Field field, boolean hasDefault) {
|
||||
super(filter, name);
|
||||
mField = field;
|
||||
mHasFrame = hasDefault;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushFrame(Frame frame) {
|
||||
setFieldFrame(frame, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrame(Frame frame) {
|
||||
setFieldFrame(frame, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
try {
|
||||
return mField.get(mFilter);
|
||||
} catch (IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void transfer(FilterContext context) {
|
||||
if (mValueWaiting) {
|
||||
try {
|
||||
mField.set(mFilter, mValue);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(
|
||||
"Access to field '" + mField.getName() + "' was denied!");
|
||||
}
|
||||
mValueWaiting = false;
|
||||
if (context != null) {
|
||||
mFilter.notifyFieldPortValueUpdated(mName, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Frame pullFrame() {
|
||||
throw new RuntimeException("Cannot pull frame on " + this + "!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasFrame() {
|
||||
return mHasFrame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean acceptsFrame() {
|
||||
return !mValueWaiting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "field " + super.toString();
|
||||
}
|
||||
|
||||
protected synchronized void setFieldFrame(Frame frame, boolean isAssignment) {
|
||||
assertPortIsOpen();
|
||||
checkFrameType(frame, isAssignment);
|
||||
|
||||
// Store the object value
|
||||
Object value = frame.getObjectValue();
|
||||
if ((value == null && mValue != null) || !value.equals(mValue)) {
|
||||
mValue = value;
|
||||
mValueWaiting = true;
|
||||
}
|
||||
|
||||
// Since a frame was set, mark this port as having a frame to pull
|
||||
mHasFrame = true;
|
||||
}
|
||||
}
|
||||
709
media/mca/filterfw/java/android/filterfw/core/Filter.java
Normal file
709
media/mca/filterfw/java/android/filterfw/core/Filter.java
Normal file
@@ -0,0 +1,709 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.FilterContext;
|
||||
import android.filterfw.core.FilterPort;
|
||||
import android.filterfw.core.KeyValueMap;
|
||||
import android.filterfw.io.TextGraphReader;
|
||||
import android.filterfw.io.GraphIOException;
|
||||
import android.filterfw.format.ObjectFormat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.Thread;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class Filter {
|
||||
|
||||
static final int STATUS_PREINIT = 0;
|
||||
static final int STATUS_UNPREPARED = 1;
|
||||
static final int STATUS_PREPARED = 2;
|
||||
static final int STATUS_PROCESSING = 3;
|
||||
static final int STATUS_SLEEPING = 4;
|
||||
static final int STATUS_FINISHED = 5;
|
||||
static final int STATUS_ERROR = 6;
|
||||
static final int STATUS_RELEASED = 7;
|
||||
|
||||
private String mName;
|
||||
|
||||
private int mInputCount = -1;
|
||||
private int mOutputCount = -1;
|
||||
|
||||
private HashMap<String, InputPort> mInputPorts;
|
||||
private HashMap<String, OutputPort> mOutputPorts;
|
||||
|
||||
private HashSet<Frame> mFramesToRelease;
|
||||
private HashMap<String, Frame> mFramesToSet;
|
||||
|
||||
private int mStatus = 0;
|
||||
private boolean mIsOpen = false;
|
||||
private int mSleepDelay;
|
||||
|
||||
private long mCurrentTimestamp;
|
||||
|
||||
private boolean mLogVerbose;
|
||||
private static final String TAG = "Filter";
|
||||
|
||||
public Filter(String name) {
|
||||
mName = name;
|
||||
mFramesToRelease = new HashSet<Frame>();
|
||||
mFramesToSet = new HashMap<String, Frame>();
|
||||
mStatus = STATUS_PREINIT;
|
||||
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
/** Tests to see if a given filter is installed on the system. Requires
|
||||
* full filter package name, including filterpack.
|
||||
*/
|
||||
public static final boolean isAvailable(String filterName) {
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
Class filterClass;
|
||||
// First see if a class of that name exists
|
||||
try {
|
||||
filterClass = contextClassLoader.loadClass(filterName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
// Then make sure it's a subclass of Filter.
|
||||
try {
|
||||
filterClass.asSubclass(Filter.class);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void initWithValueMap(KeyValueMap valueMap) {
|
||||
// Initialization
|
||||
initFinalPorts(valueMap);
|
||||
|
||||
// Setup remaining ports
|
||||
initRemainingPorts(valueMap);
|
||||
|
||||
// This indicates that final ports can no longer be set
|
||||
mStatus = STATUS_UNPREPARED;
|
||||
}
|
||||
|
||||
public final void initWithAssignmentString(String assignments) {
|
||||
try {
|
||||
KeyValueMap valueMap = new TextGraphReader().readKeyValueAssignments(assignments);
|
||||
initWithValueMap(valueMap);
|
||||
} catch (GraphIOException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public final void initWithAssignmentList(Object... keyValues) {
|
||||
KeyValueMap valueMap = new KeyValueMap();
|
||||
valueMap.setKeyValues(keyValues);
|
||||
initWithValueMap(valueMap);
|
||||
}
|
||||
|
||||
public final void init() throws ProtocolException {
|
||||
KeyValueMap valueMap = new KeyValueMap();
|
||||
initWithValueMap(valueMap);
|
||||
}
|
||||
|
||||
public String getFilterClassName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
public void setInputFrame(String inputName, Frame frame) {
|
||||
FilterPort port = getInputPort(inputName);
|
||||
if (!port.isOpen()) {
|
||||
port.open();
|
||||
}
|
||||
port.setFrame(frame);
|
||||
}
|
||||
|
||||
public final void setInputValue(String inputName, Object value) {
|
||||
setInputFrame(inputName, wrapInputValue(inputName, value));
|
||||
}
|
||||
|
||||
protected void prepare(FilterContext context) {
|
||||
}
|
||||
|
||||
protected void parametersUpdated(Set<String> updated) {
|
||||
}
|
||||
|
||||
protected void delayNextProcess(int millisecs) {
|
||||
mSleepDelay = millisecs;
|
||||
mStatus = STATUS_SLEEPING;
|
||||
}
|
||||
|
||||
public abstract void setupPorts();
|
||||
|
||||
public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public final FrameFormat getInputFormat(String portName) {
|
||||
InputPort inputPort = getInputPort(portName);
|
||||
return inputPort.getSourceFormat();
|
||||
}
|
||||
|
||||
public void open(FilterContext context) {
|
||||
}
|
||||
|
||||
public abstract void process(FilterContext context);
|
||||
|
||||
public final int getSleepDelay() {
|
||||
return 250;
|
||||
}
|
||||
|
||||
public void close(FilterContext context) {
|
||||
}
|
||||
|
||||
public void tearDown(FilterContext context) {
|
||||
}
|
||||
|
||||
public final int getNumberOfConnectedInputs() {
|
||||
int c = 0;
|
||||
for (InputPort inputPort : mInputPorts.values()) {
|
||||
if (inputPort.isConnected()) {
|
||||
++c;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public final int getNumberOfConnectedOutputs() {
|
||||
int c = 0;
|
||||
for (OutputPort outputPort : mOutputPorts.values()) {
|
||||
if (outputPort.isConnected()) {
|
||||
++c;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public final int getNumberOfInputs() {
|
||||
return mOutputPorts == null ? 0 : mInputPorts.size();
|
||||
}
|
||||
|
||||
public final int getNumberOfOutputs() {
|
||||
return mInputPorts == null ? 0 : mOutputPorts.size();
|
||||
}
|
||||
|
||||
public final InputPort getInputPort(String portName) {
|
||||
if (mInputPorts == null) {
|
||||
throw new NullPointerException("Attempting to access input port '" + portName
|
||||
+ "' of " + this + " before Filter has been initialized!");
|
||||
}
|
||||
InputPort result = mInputPorts.get(portName);
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("Unknown input port '" + portName + "' on filter "
|
||||
+ this + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final OutputPort getOutputPort(String portName) {
|
||||
if (mInputPorts == null) {
|
||||
throw new NullPointerException("Attempting to access output port '" + portName
|
||||
+ "' of " + this + " before Filter has been initialized!");
|
||||
}
|
||||
OutputPort result = mOutputPorts.get(portName);
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("Unknown output port '" + portName + "' on filter "
|
||||
+ this + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected final void pushOutput(String name, Frame frame) {
|
||||
if (frame.getTimestamp() == Frame.TIMESTAMP_NOT_SET) {
|
||||
if (mLogVerbose) Log.v(TAG, "Default-setting output Frame timestamp on port " + name + " to " + mCurrentTimestamp);
|
||||
frame.setTimestamp(mCurrentTimestamp);
|
||||
}
|
||||
getOutputPort(name).pushFrame(frame);
|
||||
}
|
||||
|
||||
protected final Frame pullInput(String name) {
|
||||
Frame result = getInputPort(name).pullFrame();
|
||||
if (mCurrentTimestamp == Frame.TIMESTAMP_UNKNOWN) {
|
||||
mCurrentTimestamp = result.getTimestamp();
|
||||
if (mLogVerbose) Log.v(TAG, "Default-setting current timestamp from input port " + name + " to " + mCurrentTimestamp);
|
||||
}
|
||||
// As result is retained, we add it to the release pool here
|
||||
mFramesToRelease.add(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void fieldPortValueUpdated(String name, FilterContext context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers any frame from an input port to its destination. This is useful to force a
|
||||
* transfer from a FieldPort or ProgramPort to its connected target (field or program variable).
|
||||
*/
|
||||
protected void transferInputPortFrame(String name, FilterContext context) {
|
||||
getInputPort(name).transfer(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns all program variables to the ports they are connected to. Call this after
|
||||
* constructing a Program instance with attached ProgramPorts.
|
||||
*/
|
||||
protected void initProgramInputs(Program program, FilterContext context) {
|
||||
if (program != null) {
|
||||
for (InputPort inputPort : mInputPorts.values()) {
|
||||
if (inputPort.getTarget() == program) {
|
||||
inputPort.transfer(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an input port to the filter. You should call this from within setupPorts, if your
|
||||
* filter has input ports. No type-checking is performed on the input. If you would like to
|
||||
* check against a type mask, use
|
||||
* {@link #addMaskedInputPort(String, FrameFormat) addMaskedInputPort} instead.
|
||||
*
|
||||
* @param name the name of the input port
|
||||
*/
|
||||
protected void addInputPort(String name) {
|
||||
addMaskedInputPort(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an input port to the filter. You should call this from within setupPorts, if your
|
||||
* filter has input ports. When type-checking is performed, the input format is
|
||||
* checked against the provided format mask. An exception is thrown in case of a conflict.
|
||||
*
|
||||
* @param name the name of the input port
|
||||
* @param formatMask a format mask, which filters the allowable input types
|
||||
*/
|
||||
protected void addMaskedInputPort(String name, FrameFormat formatMask) {
|
||||
InputPort port = new StreamPort(this, name);
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
|
||||
mInputPorts.put(name, port);
|
||||
port.setPortFormat(formatMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an output port to the filter with a fixed output format. You should call this from
|
||||
* within setupPorts, if your filter has output ports. You cannot use this method, if your
|
||||
* output format depends on the input format (e.g. in a pass-through filter). In this case, use
|
||||
* {@link #addOutputBasedOnInput(String, String) addOutputBasedOnInput} instead.
|
||||
*
|
||||
* @param name the name of the output port
|
||||
* @param format the fixed output format of this port
|
||||
*/
|
||||
protected void addOutputPort(String name, FrameFormat format) {
|
||||
OutputPort port = new OutputPort(this, name);
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
|
||||
port.setPortFormat(format);
|
||||
mOutputPorts.put(name, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an output port to the filter. You should call this from within setupPorts, if your
|
||||
* filter has output ports. Using this method indicates that the output format for this
|
||||
* particular port, depends on the format of an input port. You MUST also override
|
||||
* {@link #getOutputFormat(String, FrameFormat) getOutputFormat} to specify what format your
|
||||
* filter will output for a given input. If the output format of your filter port does not
|
||||
* depend on the input, use {@link #addOutputPort(String, FrameFormat) addOutputPort} instead.
|
||||
*
|
||||
* @param outputName the name of the output port
|
||||
* @param inputName the name of the input port, that this output depends on
|
||||
*/
|
||||
protected void addOutputBasedOnInput(String outputName, String inputName) {
|
||||
OutputPort port = new OutputPort(this, outputName);
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port);
|
||||
port.setBasePort(getInputPort(inputName));
|
||||
mOutputPorts.put(outputName, port);
|
||||
}
|
||||
|
||||
protected void addFieldPort(String name,
|
||||
Field field,
|
||||
boolean hasDefault,
|
||||
boolean isFinal) {
|
||||
// Make sure field is accessible
|
||||
field.setAccessible(true);
|
||||
|
||||
// Create port for this input
|
||||
InputPort fieldPort = isFinal
|
||||
? new FinalPort(this, name, field, hasDefault)
|
||||
: new FieldPort(this, name, field, hasDefault);
|
||||
|
||||
// Create format for this input
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + fieldPort);
|
||||
MutableFrameFormat format = ObjectFormat.fromClass(field.getType(),
|
||||
FrameFormat.TARGET_SIMPLE);
|
||||
fieldPort.setPortFormat(format);
|
||||
|
||||
// Add port
|
||||
mInputPorts.put(name, fieldPort);
|
||||
}
|
||||
|
||||
protected void addProgramPort(String name,
|
||||
String varName,
|
||||
Field field,
|
||||
Class varType,
|
||||
boolean hasDefault) {
|
||||
// Make sure field is accessible
|
||||
field.setAccessible(true);
|
||||
|
||||
// Create port for this input
|
||||
InputPort programPort = new ProgramPort(this, name, varName, field, hasDefault);
|
||||
|
||||
// Create format for this input
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + programPort);
|
||||
MutableFrameFormat format = ObjectFormat.fromClass(varType,
|
||||
FrameFormat.TARGET_SIMPLE);
|
||||
programPort.setPortFormat(format);
|
||||
|
||||
// Add port
|
||||
mInputPorts.put(name, programPort);
|
||||
}
|
||||
|
||||
protected void closeOutputPort(String name) {
|
||||
getOutputPort(name).close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether the filter should not be scheduled until a frame is available on that
|
||||
* input port. Note, that setting this to false, does not block a new frame from coming in
|
||||
* (though there is no necessity to pull that frame for processing).
|
||||
* @param portName the name of the input port.
|
||||
* @param waits true, if the filter should wait for a frame on this port.
|
||||
*/
|
||||
protected void setWaitsOnInputPort(String portName, boolean waits) {
|
||||
getInputPort(portName).setBlocking(waits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether the filter should not be scheduled until the output port is free, i.e.
|
||||
* there is no frame waiting on that output.
|
||||
* @param portName the name of the output port.
|
||||
* @param waits true, if the filter should wait for the port to become free.
|
||||
*/
|
||||
protected void setWaitsOnOutputPort(String portName, boolean waits) {
|
||||
getOutputPort(portName).setBlocking(waits);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "'" + getName() + "' (" + getFilterClassName() + ")";
|
||||
}
|
||||
|
||||
// Core internal methods ///////////////////////////////////////////////////////////////////////
|
||||
final Collection<InputPort> getInputPorts() {
|
||||
return mInputPorts.values();
|
||||
}
|
||||
|
||||
final Collection<OutputPort> getOutputPorts() {
|
||||
return mOutputPorts.values();
|
||||
}
|
||||
|
||||
final synchronized int getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
final synchronized void unsetStatus(int flag) {
|
||||
mStatus &= ~flag;
|
||||
}
|
||||
|
||||
final synchronized void performOpen(FilterContext context) {
|
||||
if (!mIsOpen) {
|
||||
if (mStatus == STATUS_UNPREPARED) {
|
||||
if (mLogVerbose) Log.v(TAG, "Preparing " + this);
|
||||
prepare(context);
|
||||
mStatus = STATUS_PREPARED;
|
||||
}
|
||||
if (mStatus == STATUS_PREPARED) {
|
||||
if (mLogVerbose) Log.v(TAG, "Opening " + this);
|
||||
open(context);
|
||||
mStatus = STATUS_PROCESSING;
|
||||
}
|
||||
if (mStatus != STATUS_PROCESSING) {
|
||||
throw new RuntimeException("Filter " + this + " was brought into invalid state during "
|
||||
+ "opening (state: " + mStatus + ")!");
|
||||
}
|
||||
mIsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
final synchronized void performProcess(FilterContext context) {
|
||||
if (mStatus == STATUS_RELEASED) {
|
||||
throw new RuntimeException("Filter " + this + " is already torn down!");
|
||||
}
|
||||
transferInputFrames(context);
|
||||
if (mStatus < STATUS_PROCESSING) {
|
||||
performOpen(context);
|
||||
}
|
||||
if (mLogVerbose) Log.v(TAG, "Processing " + this);
|
||||
mCurrentTimestamp = Frame.TIMESTAMP_UNKNOWN;
|
||||
process(context);
|
||||
releasePulledFrames(context);
|
||||
if (filterMustClose()) {
|
||||
performClose(context);
|
||||
}
|
||||
}
|
||||
|
||||
final synchronized void performClose(FilterContext context) {
|
||||
if (mIsOpen) {
|
||||
if (mLogVerbose) Log.v(TAG, "Closing " + this);
|
||||
mIsOpen = false;
|
||||
mStatus = STATUS_PREPARED;
|
||||
close(context);
|
||||
closePorts();
|
||||
}
|
||||
}
|
||||
|
||||
final synchronized void performTearDown(FilterContext context) {
|
||||
performClose(context);
|
||||
if (mStatus != STATUS_RELEASED) {
|
||||
tearDown(context);
|
||||
mStatus = STATUS_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized final boolean canProcess() {
|
||||
if (mLogVerbose) Log.v(TAG, "Checking if can process: " + this + " (" + mStatus + ").");
|
||||
if (mStatus <= STATUS_PROCESSING) {
|
||||
return inputConditionsMet() && outputConditionsMet();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final void openOutputs() {
|
||||
if (mLogVerbose) Log.v(TAG, "Opening all output ports on " + this + "!");
|
||||
for (OutputPort outputPort : mOutputPorts.values()) {
|
||||
if (!outputPort.isOpen()) {
|
||||
outputPort.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void clearInputs() {
|
||||
for (InputPort inputPort : mInputPorts.values()) {
|
||||
inputPort.clear();
|
||||
}
|
||||
}
|
||||
|
||||
final void clearOutputs() {
|
||||
for (OutputPort outputPort : mOutputPorts.values()) {
|
||||
outputPort.clear();
|
||||
}
|
||||
}
|
||||
|
||||
final void notifyFieldPortValueUpdated(String name, FilterContext context) {
|
||||
if (mStatus == STATUS_PROCESSING || mStatus == STATUS_PREPARED) {
|
||||
fieldPortValueUpdated(name, context);
|
||||
}
|
||||
}
|
||||
|
||||
final synchronized void pushInputFrame(String inputName, Frame frame) {
|
||||
FilterPort port = getInputPort(inputName);
|
||||
if (!port.isOpen()) {
|
||||
port.open();
|
||||
}
|
||||
port.pushFrame(frame);
|
||||
}
|
||||
|
||||
final synchronized void pushInputValue(String inputName, Object value) {
|
||||
pushInputFrame(inputName, wrapInputValue(inputName, value));
|
||||
}
|
||||
|
||||
// Filter internal methods /////////////////////////////////////////////////////////////////////
|
||||
private final void initFinalPorts(KeyValueMap values) {
|
||||
mInputPorts = new HashMap<String, InputPort>();
|
||||
mOutputPorts = new HashMap<String, OutputPort>();
|
||||
addAndSetFinalPorts(values);
|
||||
}
|
||||
|
||||
private final void initRemainingPorts(KeyValueMap values) {
|
||||
addAnnotatedPorts();
|
||||
setupPorts(); // TODO: rename to addFilterPorts() ?
|
||||
setInitialInputValues(values);
|
||||
}
|
||||
|
||||
private final void addAndSetFinalPorts(KeyValueMap values) {
|
||||
Class filterClass = getClass();
|
||||
Annotation annotation;
|
||||
for (Field field : filterClass.getDeclaredFields()) {
|
||||
if ((annotation = field.getAnnotation(GenerateFinalPort.class)) != null) {
|
||||
GenerateFinalPort generator = (GenerateFinalPort)annotation;
|
||||
String name = generator.name().isEmpty() ? field.getName() : generator.name();
|
||||
boolean hasDefault = generator.hasDefault();
|
||||
addFieldPort(name, field, hasDefault, true);
|
||||
if (values.containsKey(name)) {
|
||||
setImmediateInputValue(name, values.get(name));
|
||||
values.remove(name);
|
||||
} else if (!generator.hasDefault()) {
|
||||
throw new RuntimeException("No value specified for final input port '"
|
||||
+ name + "' of filter " + this + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void addAnnotatedPorts() {
|
||||
Class filterClass = getClass();
|
||||
Annotation annotation;
|
||||
for (Field field : filterClass.getDeclaredFields()) {
|
||||
if ((annotation = field.getAnnotation(GenerateFieldPort.class)) != null) {
|
||||
GenerateFieldPort generator = (GenerateFieldPort)annotation;
|
||||
addFieldGenerator(generator, field);
|
||||
} else if ((annotation = field.getAnnotation(GenerateProgramPort.class)) != null) {
|
||||
GenerateProgramPort generator = (GenerateProgramPort)annotation;
|
||||
addProgramGenerator(generator, field);
|
||||
} else if ((annotation = field.getAnnotation(GenerateProgramPorts.class)) != null) {
|
||||
GenerateProgramPorts generators = (GenerateProgramPorts)annotation;
|
||||
for (GenerateProgramPort generator : generators.value()) {
|
||||
addProgramGenerator(generator, field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void addFieldGenerator(GenerateFieldPort generator, Field field) {
|
||||
String name = generator.name().isEmpty() ? field.getName() : generator.name();
|
||||
boolean hasDefault = generator.hasDefault();
|
||||
addFieldPort(name, field, hasDefault, false);
|
||||
}
|
||||
|
||||
private final void addProgramGenerator(GenerateProgramPort generator, Field field) {
|
||||
String name = generator.name();
|
||||
String varName = generator.variableName().isEmpty() ? name
|
||||
: generator.variableName();
|
||||
Class varType = generator.type();
|
||||
boolean hasDefault = generator.hasDefault();
|
||||
addProgramPort(name, varName, field, varType, hasDefault);
|
||||
}
|
||||
|
||||
private final void setInitialInputValues(KeyValueMap values) {
|
||||
for (Entry<String, Object> entry : values.entrySet()) {
|
||||
setInputValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private final void setImmediateInputValue(String name, Object value) {
|
||||
if (mLogVerbose) Log.v(TAG, "Setting immediate value " + value + " for port " + name + "!");
|
||||
FilterPort port = getInputPort(name);
|
||||
port.open();
|
||||
port.setFrame(SimpleFrame.wrapObject(value, null));
|
||||
}
|
||||
|
||||
private final void transferInputFrames(FilterContext context) {
|
||||
for (InputPort inputPort : mInputPorts.values()) {
|
||||
inputPort.transfer(context);
|
||||
}
|
||||
}
|
||||
|
||||
private final Frame wrapInputValue(String inputName, Object value) {
|
||||
MutableFrameFormat inputFormat = ObjectFormat.fromObject(value, FrameFormat.TARGET_SIMPLE);
|
||||
if (value == null) {
|
||||
// If the value is null, the format cannot guess the class, so we adjust it to the
|
||||
// class of the input port here
|
||||
FrameFormat portFormat = getInputPort(inputName).getPortFormat();
|
||||
Class portClass = (portFormat == null) ? null : portFormat.getObjectClass();
|
||||
inputFormat.setObjectClass(portClass);
|
||||
}
|
||||
|
||||
// Serialize if serializable, and type is not an immutable primitive.
|
||||
boolean shouldSerialize = !(value instanceof Number)
|
||||
&& !(value instanceof Boolean)
|
||||
&& !(value instanceof String)
|
||||
&& value instanceof Serializable;
|
||||
|
||||
// Create frame wrapper
|
||||
Frame frame = shouldSerialize
|
||||
? new SerializedFrame(inputFormat, null)
|
||||
: new SimpleFrame(inputFormat, null);
|
||||
frame.setObjectValue(value);
|
||||
return frame;
|
||||
}
|
||||
|
||||
private final void releasePulledFrames(FilterContext context) {
|
||||
for (Frame frame : mFramesToRelease) {
|
||||
context.getFrameManager().releaseFrame(frame);
|
||||
}
|
||||
mFramesToRelease.clear();
|
||||
}
|
||||
|
||||
private final boolean inputConditionsMet() {
|
||||
for (FilterPort port : mInputPorts.values()) {
|
||||
if (!port.isReady()) {
|
||||
if (mLogVerbose) Log.v(TAG, "Input condition not met: " + port + "!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private final boolean outputConditionsMet() {
|
||||
for (FilterPort port : mOutputPorts.values()) {
|
||||
if (!port.isReady()) {
|
||||
if (mLogVerbose) Log.v(TAG, "Output condition not met: " + port + "!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private final void closePorts() {
|
||||
if (mLogVerbose) Log.v(TAG, "Closing all ports on " + this + "!");
|
||||
for (InputPort inputPort : mInputPorts.values()) {
|
||||
inputPort.close();
|
||||
}
|
||||
for (OutputPort outputPort : mOutputPorts.values()) {
|
||||
outputPort.close();
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean filterMustClose() {
|
||||
for (InputPort inputPort : mInputPorts.values()) {
|
||||
if (inputPort.filterMustClose()) {
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + inputPort);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (OutputPort outputPort : mOutputPorts.values()) {
|
||||
if (outputPort.filterMustClose()) {
|
||||
if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + outputPort);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
126
media/mca/filterfw/java/android/filterfw/core/FilterContext.java
Normal file
126
media/mca/filterfw/java/android/filterfw/core/FilterContext.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.GLEnvironment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FilterContext {
|
||||
|
||||
private FrameManager mFrameManager;
|
||||
private GLEnvironment mGLEnvironment;
|
||||
private HashMap<String, Frame> mStoredFrames = new HashMap<String, Frame>();
|
||||
private Set<FilterGraph> mGraphs = new HashSet<FilterGraph>();
|
||||
|
||||
public FrameManager getFrameManager() {
|
||||
return mFrameManager;
|
||||
}
|
||||
|
||||
public void setFrameManager(FrameManager manager) {
|
||||
if (manager == null) {
|
||||
throw new NullPointerException("Attempting to set null FrameManager!");
|
||||
} else if (manager.getContext() != null) {
|
||||
throw new IllegalArgumentException("Attempting to set FrameManager which is already "
|
||||
+ "bound to another FilterContext!");
|
||||
} else {
|
||||
mFrameManager = manager;
|
||||
mFrameManager.setContext(this);
|
||||
}
|
||||
}
|
||||
|
||||
public GLEnvironment getGLEnvironment() {
|
||||
return mGLEnvironment;
|
||||
}
|
||||
|
||||
public void initGLEnvironment(GLEnvironment environment) {
|
||||
if (mGLEnvironment == null) {
|
||||
mGLEnvironment = environment;
|
||||
} else {
|
||||
throw new RuntimeException("Attempting to re-initialize GL Environment for " +
|
||||
"FilterContext!");
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnFrameReceivedListener {
|
||||
public void onFrameReceived(Filter filter, Frame frame, Object userData);
|
||||
}
|
||||
|
||||
public synchronized void storeFrame(String key, Frame frame) {
|
||||
Frame storedFrame = fetchFrame(key);
|
||||
if (storedFrame != null) {
|
||||
storedFrame.release();
|
||||
}
|
||||
frame.onFrameStore();
|
||||
mStoredFrames.put(key, frame.retain());
|
||||
}
|
||||
|
||||
public synchronized Frame fetchFrame(String key) {
|
||||
Frame frame = mStoredFrames.get(key);
|
||||
if (frame != null) {
|
||||
frame.onFrameFetch();
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
public synchronized void removeFrame(String key) {
|
||||
Frame frame = mStoredFrames.get(key);
|
||||
if (frame != null) {
|
||||
mStoredFrames.remove(key);
|
||||
frame.release();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void tearDown() {
|
||||
// Release stored frames
|
||||
for (Frame frame : mStoredFrames.values()) {
|
||||
frame.release();
|
||||
}
|
||||
mStoredFrames.clear();
|
||||
|
||||
// Release graphs
|
||||
for (FilterGraph graph : mGraphs) {
|
||||
graph.tearDown(this);
|
||||
}
|
||||
mGraphs.clear();
|
||||
|
||||
// Release frame manager
|
||||
if (mFrameManager != null) {
|
||||
mFrameManager.tearDown();
|
||||
mFrameManager = null;
|
||||
}
|
||||
|
||||
// Release GL context
|
||||
if (mGLEnvironment != null) {
|
||||
mGLEnvironment.tearDown();
|
||||
mGLEnvironment = null;
|
||||
}
|
||||
}
|
||||
|
||||
final void addGraph(FilterGraph graph) {
|
||||
mGraphs.add(graph);
|
||||
}
|
||||
}
|
||||
145
media/mca/filterfw/java/android/filterfw/core/FilterFactory.java
Normal file
145
media/mca/filterfw/java/android/filterfw/core/FilterFactory.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.util.Log;
|
||||
|
||||
import dalvik.system.PathClassLoader;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.ClassLoader;
|
||||
import java.lang.Thread;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FilterFactory {
|
||||
|
||||
private static FilterFactory mSharedFactory;
|
||||
private HashSet<String> mPackages = new HashSet<String>();
|
||||
|
||||
private static ClassLoader mCurrentClassLoader;
|
||||
private static HashSet<String> mLibraries;
|
||||
private static Object mClassLoaderGuard;
|
||||
|
||||
static {
|
||||
mCurrentClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
mLibraries = new HashSet<String>();
|
||||
mClassLoaderGuard = new Object();
|
||||
}
|
||||
|
||||
private static final String TAG = "FilterFactory";
|
||||
private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
public static FilterFactory sharedFactory() {
|
||||
if (mSharedFactory == null) {
|
||||
mSharedFactory = new FilterFactory();
|
||||
}
|
||||
return mSharedFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new Java library to the list to be scanned for filters.
|
||||
* libraryPath must be an absolute path of the jar file. This needs to be
|
||||
* static because only one classloader per process can open a shared native
|
||||
* library, which a filter may well have.
|
||||
*/
|
||||
public static void addFilterLibrary(String libraryPath) {
|
||||
if (mLogVerbose) Log.v(TAG, "Adding filter library " + libraryPath);
|
||||
synchronized(mClassLoaderGuard) {
|
||||
if (mLibraries.contains(libraryPath)) {
|
||||
if (mLogVerbose) Log.v(TAG, "Library already added");
|
||||
return;
|
||||
}
|
||||
mLibraries.add(libraryPath);
|
||||
// Chain another path loader to the current chain
|
||||
mCurrentClassLoader = new PathClassLoader(libraryPath, mCurrentClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPackage(String packageName) {
|
||||
if (mLogVerbose) Log.v(TAG, "Adding package " + packageName);
|
||||
/* TODO: This should use a getPackage call in the caller's context, but no such method exists.
|
||||
Package pkg = Package.getPackage(packageName);
|
||||
if (pkg == null) {
|
||||
throw new IllegalArgumentException("Unknown filter package '" + packageName + "'!");
|
||||
}
|
||||
*/
|
||||
mPackages.add(packageName);
|
||||
}
|
||||
|
||||
public Filter createFilterByClassName(String className, String filterName) {
|
||||
if (mLogVerbose) Log.v(TAG, "Looking up class " + className);
|
||||
Class filterClass = null;
|
||||
|
||||
// Look for the class in the imported packages
|
||||
for (String packageName : mPackages) {
|
||||
try {
|
||||
if (mLogVerbose) Log.v(TAG, "Trying "+packageName + "." + className);
|
||||
synchronized(mClassLoaderGuard) {
|
||||
filterClass = mCurrentClassLoader.loadClass(packageName + "." + className);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
continue;
|
||||
}
|
||||
// Exit loop if class was found.
|
||||
if (filterClass != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filterClass == null) {
|
||||
throw new IllegalArgumentException("Unknown filter class '" + className + "'!");
|
||||
}
|
||||
return createFilterByClass(filterClass, filterName);
|
||||
}
|
||||
|
||||
public Filter createFilterByClass(Class filterClass, String filterName) {
|
||||
// Make sure this is a Filter subclass
|
||||
try {
|
||||
filterClass.asSubclass(Filter.class);
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalArgumentException("Attempting to allocate class '" + filterClass
|
||||
+ "' which is not a subclass of Filter!");
|
||||
}
|
||||
|
||||
// Look for the correct constructor
|
||||
Constructor filterConstructor = null;
|
||||
try {
|
||||
filterConstructor = filterClass.getConstructor(String.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException("The filter class '" + filterClass
|
||||
+ "' does not have a constructor of the form <init>(String name)!");
|
||||
}
|
||||
|
||||
// Construct the filter
|
||||
Filter filter = null;
|
||||
try {
|
||||
filter = (Filter)filterConstructor.newInstance(filterName);
|
||||
} catch (Throwable t) {
|
||||
// Condition checked below
|
||||
}
|
||||
|
||||
if (filter == null) {
|
||||
throw new IllegalArgumentException("Could not construct the filter '"
|
||||
+ filterName + "'!");
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FilterFunction {
|
||||
|
||||
private Filter mFilter;
|
||||
private FilterContext mFilterContext;
|
||||
private boolean mFilterIsSetup = false;
|
||||
private FrameHolderPort[] mResultHolders;
|
||||
|
||||
private class FrameHolderPort extends StreamPort {
|
||||
public FrameHolderPort() {
|
||||
super(null, "holder");
|
||||
}
|
||||
}
|
||||
|
||||
public FilterFunction(FilterContext context, Filter filter) {
|
||||
mFilterContext = context;
|
||||
mFilter = filter;
|
||||
}
|
||||
|
||||
public Frame execute(KeyValueMap inputMap) {
|
||||
int filterOutCount = mFilter.getNumberOfOutputs();
|
||||
|
||||
// Sanity checks
|
||||
if (filterOutCount > 1) {
|
||||
throw new RuntimeException("Calling execute on filter " + mFilter + " with multiple "
|
||||
+ "outputs! Use executeMulti() instead!");
|
||||
}
|
||||
|
||||
// Setup filter
|
||||
if (!mFilterIsSetup) {
|
||||
connectFilterOutputs();
|
||||
mFilterIsSetup = true;
|
||||
}
|
||||
|
||||
// Make sure GL environment is active
|
||||
boolean didActivateGLEnv = false;
|
||||
GLEnvironment glEnv = mFilterContext.getGLEnvironment();
|
||||
if (glEnv != null && !glEnv.isActive()) {
|
||||
glEnv.activate();
|
||||
didActivateGLEnv = true;
|
||||
}
|
||||
|
||||
// Setup the inputs
|
||||
for (Entry<String, Object> entry : inputMap.entrySet()) {
|
||||
if (entry.getValue() instanceof Frame) {
|
||||
mFilter.pushInputFrame(entry.getKey(), (Frame)entry.getValue());
|
||||
} else {
|
||||
mFilter.pushInputValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Process the filter
|
||||
if (mFilter.getStatus() != Filter.STATUS_PROCESSING) {
|
||||
mFilter.openOutputs();
|
||||
}
|
||||
|
||||
mFilter.performProcess(mFilterContext);
|
||||
|
||||
// Create result handle
|
||||
Frame result = null;
|
||||
if (filterOutCount == 1 && mResultHolders[0].hasFrame()) {
|
||||
result = mResultHolders[0].pullFrame();
|
||||
}
|
||||
|
||||
// Deactivate GL environment if activated
|
||||
if (didActivateGLEnv) {
|
||||
glEnv.deactivate();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Frame executeWithArgList(Object... inputs) {
|
||||
return execute(KeyValueMap.fromKeyValues(inputs));
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mFilter.performClose(mFilterContext);
|
||||
}
|
||||
|
||||
public FilterContext getContext() {
|
||||
return mFilterContext;
|
||||
}
|
||||
|
||||
public Filter getFilter() {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
public void setInputFrame(String input, Frame frame) {
|
||||
mFilter.setInputFrame(input, frame);
|
||||
}
|
||||
|
||||
public void setInputValue(String input, Object value) {
|
||||
mFilter.setInputValue(input, value);
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
mFilter.performTearDown(mFilterContext);
|
||||
mFilter = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mFilter.getName();
|
||||
}
|
||||
|
||||
private void connectFilterOutputs() {
|
||||
int i = 0;
|
||||
mResultHolders = new FrameHolderPort[mFilter.getNumberOfOutputs()];
|
||||
for (OutputPort outputPort : mFilter.getOutputPorts()) {
|
||||
mResultHolders[i] = new FrameHolderPort();
|
||||
outputPort.connectTo(mResultHolders[i]);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
363
media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
Normal file
363
media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import android.filterfw.core.FilterContext;
|
||||
import android.filterfw.core.KeyValueMap;
|
||||
import android.filterpacks.base.FrameBranch;
|
||||
import android.filterpacks.base.NullFilter;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FilterGraph {
|
||||
|
||||
private HashSet<Filter> mFilters = new HashSet<Filter>();
|
||||
private HashMap<String, Filter> mNameMap = new HashMap<String, Filter>();
|
||||
private HashMap<OutputPort, LinkedList<InputPort>> mPreconnections = new
|
||||
HashMap<OutputPort, LinkedList<InputPort>>();
|
||||
|
||||
public static final int AUTOBRANCH_OFF = 0;
|
||||
public static final int AUTOBRANCH_SYNCED = 1;
|
||||
public static final int AUTOBRANCH_UNSYNCED = 2;
|
||||
|
||||
public static final int TYPECHECK_OFF = 0;
|
||||
public static final int TYPECHECK_DYNAMIC = 1;
|
||||
public static final int TYPECHECK_STRICT = 2;
|
||||
|
||||
private boolean mIsReady = false;
|
||||
private int mAutoBranchMode = AUTOBRANCH_OFF;
|
||||
private int mTypeCheckMode = TYPECHECK_STRICT;
|
||||
private boolean mDiscardUnconnectedOutputs = false;
|
||||
|
||||
private boolean mLogVerbose;
|
||||
private String TAG = "FilterGraph";
|
||||
|
||||
public FilterGraph() {
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
public boolean addFilter(Filter filter) {
|
||||
if (!containsFilter(filter)) {
|
||||
mFilters.add(filter);
|
||||
mNameMap.put(filter.getName(), filter);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsFilter(Filter filter) {
|
||||
return mFilters.contains(filter);
|
||||
}
|
||||
|
||||
public Filter getFilter(String name) {
|
||||
return mNameMap.get(name);
|
||||
}
|
||||
|
||||
public void connect(Filter source,
|
||||
String outputName,
|
||||
Filter target,
|
||||
String inputName) {
|
||||
if (source == null || target == null) {
|
||||
throw new IllegalArgumentException("Passing null Filter in connect()!");
|
||||
} else if (!containsFilter(source) || !containsFilter(target)) {
|
||||
throw new RuntimeException("Attempting to connect filter not in graph!");
|
||||
}
|
||||
|
||||
OutputPort outPort = source.getOutputPort(outputName);
|
||||
InputPort inPort = target.getInputPort(inputName);
|
||||
if (outPort == null) {
|
||||
throw new RuntimeException("Unknown output port '" + outputName + "' on Filter " +
|
||||
source + "!");
|
||||
} else if (inPort == null) {
|
||||
throw new RuntimeException("Unknown input port '" + inputName + "' on Filter " +
|
||||
target + "!");
|
||||
}
|
||||
|
||||
preconnect(outPort, inPort);
|
||||
}
|
||||
|
||||
public void connect(String sourceName,
|
||||
String outputName,
|
||||
String targetName,
|
||||
String inputName) {
|
||||
Filter source = getFilter(sourceName);
|
||||
Filter target = getFilter(targetName);
|
||||
if (source == null) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to connect unknown source filter '" + sourceName + "'!");
|
||||
} else if (target == null) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to connect unknown target filter '" + targetName + "'!");
|
||||
}
|
||||
connect(source, outputName, target, inputName);
|
||||
}
|
||||
|
||||
public Set<Filter> getFilters() {
|
||||
return mFilters;
|
||||
}
|
||||
|
||||
public void beginProcessing() {
|
||||
if (mLogVerbose) Log.v(TAG, "Opening all filter connections...");
|
||||
for (Filter filter : mFilters) {
|
||||
filter.openOutputs();
|
||||
}
|
||||
mIsReady = true;
|
||||
}
|
||||
|
||||
public void flushFrames() {
|
||||
for (Filter filter : mFilters) {
|
||||
filter.clearOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeFilters(FilterContext context) {
|
||||
if (mLogVerbose) Log.v(TAG, "Closing all filters...");
|
||||
for (Filter filter : mFilters) {
|
||||
filter.performClose(context);
|
||||
}
|
||||
mIsReady = false;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return mIsReady;
|
||||
}
|
||||
|
||||
public void setAutoBranchMode(int autoBranchMode) {
|
||||
mAutoBranchMode = autoBranchMode;
|
||||
}
|
||||
|
||||
public void setDiscardUnconnectedOutputs(boolean discard) {
|
||||
mDiscardUnconnectedOutputs = discard;
|
||||
}
|
||||
|
||||
public void setTypeCheckMode(int typeCheckMode) {
|
||||
mTypeCheckMode = typeCheckMode;
|
||||
}
|
||||
|
||||
public void tearDown(FilterContext context) {
|
||||
if (!mFilters.isEmpty()) {
|
||||
flushFrames();
|
||||
for (Filter filter : mFilters) {
|
||||
filter.performTearDown(context);
|
||||
}
|
||||
mFilters.clear();
|
||||
mNameMap.clear();
|
||||
mIsReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readyForProcessing(Filter filter, Set<Filter> processed) {
|
||||
// Check if this has been already processed
|
||||
if (processed.contains(filter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if all dependencies have been processed
|
||||
for (InputPort port : filter.getInputPorts()) {
|
||||
Filter dependency = port.getSourceFilter();
|
||||
if (dependency != null && !processed.contains(dependency)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void runTypeCheck() {
|
||||
Stack<Filter> filterStack = new Stack<Filter>();
|
||||
Set<Filter> processedFilters = new HashSet<Filter>();
|
||||
filterStack.addAll(getSourceFilters());
|
||||
|
||||
while (!filterStack.empty()) {
|
||||
// Get current filter and mark as processed
|
||||
Filter filter = filterStack.pop();
|
||||
processedFilters.add(filter);
|
||||
|
||||
// Anchor output formats
|
||||
updateOutputs(filter);
|
||||
|
||||
// Perform type check
|
||||
if (mLogVerbose) Log.v(TAG, "Running type check on " + filter + "...");
|
||||
runTypeCheckOn(filter);
|
||||
|
||||
// Push connected filters onto stack
|
||||
for (OutputPort port : filter.getOutputPorts()) {
|
||||
Filter target = port.getTargetFilter();
|
||||
if (target != null && readyForProcessing(target, processedFilters)) {
|
||||
filterStack.push(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all ports were setup
|
||||
if (processedFilters.size() != getFilters().size()) {
|
||||
throw new RuntimeException("Could not schedule all filters! Is your graph malformed?");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOutputs(Filter filter) {
|
||||
for (OutputPort outputPort : filter.getOutputPorts()) {
|
||||
InputPort inputPort = outputPort.getBasePort();
|
||||
if (inputPort != null) {
|
||||
FrameFormat inputFormat = inputPort.getSourceFormat();
|
||||
FrameFormat outputFormat = filter.getOutputFormat(outputPort.getName(),
|
||||
inputFormat);
|
||||
if (outputFormat == null) {
|
||||
throw new RuntimeException("Filter did not return an output format for "
|
||||
+ outputPort + "!");
|
||||
}
|
||||
outputPort.setPortFormat(outputFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runTypeCheckOn(Filter filter) {
|
||||
for (InputPort inputPort : filter.getInputPorts()) {
|
||||
if (mLogVerbose) Log.v(TAG, "Type checking port " + inputPort);
|
||||
FrameFormat sourceFormat = inputPort.getSourceFormat();
|
||||
FrameFormat targetFormat = inputPort.getPortFormat();
|
||||
if (sourceFormat != null && targetFormat != null) {
|
||||
if (mLogVerbose) Log.v(TAG, "Checking " + sourceFormat + " against " + targetFormat + ".");
|
||||
|
||||
boolean compatible = true;
|
||||
switch (mTypeCheckMode) {
|
||||
case TYPECHECK_OFF:
|
||||
inputPort.setChecksType(false);
|
||||
break;
|
||||
case TYPECHECK_DYNAMIC:
|
||||
compatible = sourceFormat.mayBeCompatibleWith(targetFormat);
|
||||
inputPort.setChecksType(true);
|
||||
break;
|
||||
case TYPECHECK_STRICT:
|
||||
compatible = sourceFormat.isCompatibleWith(targetFormat);
|
||||
inputPort.setChecksType(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!compatible) {
|
||||
throw new RuntimeException("Type mismatch: Filter " + filter + " expects a "
|
||||
+ "format of type " + targetFormat + " but got a format of type "
|
||||
+ sourceFormat + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkConnections() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void discardUnconnectedOutputs() {
|
||||
// Connect unconnected ports to Null filters
|
||||
LinkedList<Filter> addedFilters = new LinkedList<Filter>();
|
||||
for (Filter filter : mFilters) {
|
||||
int id = 0;
|
||||
for (OutputPort port : filter.getOutputPorts()) {
|
||||
if (!port.isConnected()) {
|
||||
if (mLogVerbose) Log.v(TAG, "Autoconnecting unconnected " + port + " to Null filter.");
|
||||
NullFilter nullFilter = new NullFilter(filter.getName() + "ToNull" + id);
|
||||
nullFilter.init();
|
||||
addedFilters.add(nullFilter);
|
||||
port.connectTo(nullFilter.getInputPort("frame"));
|
||||
++id;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add all added filters to this graph
|
||||
for (Filter filter : addedFilters) {
|
||||
addFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeFilter(Filter filter) {
|
||||
mFilters.remove(filter);
|
||||
mNameMap.remove(filter.getName());
|
||||
}
|
||||
|
||||
private void preconnect(OutputPort outPort, InputPort inPort) {
|
||||
LinkedList<InputPort> targets;
|
||||
targets = mPreconnections.get(outPort);
|
||||
if (targets == null) {
|
||||
targets = new LinkedList<InputPort>();
|
||||
mPreconnections.put(outPort, targets);
|
||||
}
|
||||
targets.add(inPort);
|
||||
}
|
||||
|
||||
private void connectPorts() {
|
||||
int branchId = 1;
|
||||
for (Entry<OutputPort, LinkedList<InputPort>> connection : mPreconnections.entrySet()) {
|
||||
OutputPort outputPort = connection.getKey();
|
||||
LinkedList<InputPort> inputPorts = connection.getValue();
|
||||
if (inputPorts.size() == 1) {
|
||||
outputPort.connectTo(inputPorts.get(0));
|
||||
} else if (mAutoBranchMode == AUTOBRANCH_OFF) {
|
||||
throw new RuntimeException("Attempting to connect " + outputPort + " to multiple "
|
||||
+ "filter ports! Enable auto-branching to allow this.");
|
||||
} else {
|
||||
if (mLogVerbose) Log.v(TAG, "Creating branch for " + outputPort + "!");
|
||||
FrameBranch branch = null;
|
||||
if (mAutoBranchMode == AUTOBRANCH_SYNCED) {
|
||||
branch = new FrameBranch("branch" + branchId++);
|
||||
} else {
|
||||
throw new RuntimeException("TODO: Unsynced branches not implemented yet!");
|
||||
}
|
||||
KeyValueMap branchParams = new KeyValueMap();
|
||||
branch.initWithAssignmentList("outputs", inputPorts.size());
|
||||
addFilter(branch);
|
||||
outputPort.connectTo(branch.getInputPort("in"));
|
||||
Iterator<InputPort> inputPortIter = inputPorts.iterator();
|
||||
for (OutputPort branchOutPort : ((Filter)branch).getOutputPorts()) {
|
||||
branchOutPort.connectTo(inputPortIter.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
mPreconnections.clear();
|
||||
}
|
||||
|
||||
private HashSet<Filter> getSourceFilters() {
|
||||
HashSet<Filter> sourceFilters = new HashSet<Filter>();
|
||||
for (Filter filter : getFilters()) {
|
||||
if (filter.getNumberOfConnectedInputs() == 0) {
|
||||
if (mLogVerbose) Log.v(TAG, "Found source filter: " + filter);
|
||||
sourceFilters.add(filter);
|
||||
}
|
||||
}
|
||||
return sourceFilters;
|
||||
}
|
||||
|
||||
// Core internal methods /////////////////////////////////////////////////////////////////////////
|
||||
void setupFilters() {
|
||||
if (mDiscardUnconnectedOutputs) {
|
||||
discardUnconnectedOutputs();
|
||||
}
|
||||
connectPorts();
|
||||
checkConnections();
|
||||
runTypeCheck();
|
||||
}
|
||||
}
|
||||
134
media/mca/filterfw/java/android/filterfw/core/FilterPort.java
Normal file
134
media/mca/filterfw/java/android/filterfw/core/FilterPort.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class FilterPort {
|
||||
|
||||
protected Filter mFilter;
|
||||
protected String mName;
|
||||
protected FrameFormat mPortFormat;
|
||||
protected boolean mIsBlocking = true;
|
||||
protected boolean mIsOpen = false;
|
||||
protected boolean mChecksType = false;
|
||||
private boolean mLogVerbose;
|
||||
private static final String TAG = "FilterPort";
|
||||
|
||||
public FilterPort(Filter filter, String name) {
|
||||
mName = name;
|
||||
mFilter = filter;
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
public boolean isAttached() {
|
||||
return mFilter != null;
|
||||
}
|
||||
|
||||
public FrameFormat getPortFormat() {
|
||||
return mPortFormat;
|
||||
}
|
||||
|
||||
public void setPortFormat(FrameFormat format) {
|
||||
mPortFormat = format;
|
||||
}
|
||||
|
||||
public Filter getFilter() {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setBlocking(boolean blocking) {
|
||||
mIsBlocking = blocking;
|
||||
}
|
||||
|
||||
public void setChecksType(boolean checksType) {
|
||||
mChecksType = checksType;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
if (!mIsOpen) {
|
||||
if (mLogVerbose) Log.v(TAG, "Opening " + this);
|
||||
}
|
||||
mIsOpen = true;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (mIsOpen) {
|
||||
if (mLogVerbose) Log.v(TAG, "Closing " + this);
|
||||
}
|
||||
mIsOpen = false;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
public boolean isBlocking() {
|
||||
return mIsBlocking;
|
||||
}
|
||||
|
||||
public abstract boolean filterMustClose();
|
||||
|
||||
public abstract boolean isReady();
|
||||
|
||||
public abstract void pushFrame(Frame frame);
|
||||
|
||||
public abstract void setFrame(Frame frame);
|
||||
|
||||
public abstract Frame pullFrame();
|
||||
|
||||
public abstract boolean hasFrame();
|
||||
|
||||
public abstract void clear();
|
||||
|
||||
public String toString() {
|
||||
return "port '" + mName + "' of " + mFilter;
|
||||
}
|
||||
|
||||
protected void assertPortIsOpen() {
|
||||
if (!isOpen()) {
|
||||
throw new RuntimeException("Illegal operation on closed " + this + "!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkFrameType(Frame frame, boolean forceCheck) {
|
||||
if ((mChecksType || forceCheck)
|
||||
&& mPortFormat != null
|
||||
&& !frame.getFormat().isCompatibleWith(mPortFormat)) {
|
||||
throw new RuntimeException("Frame passed to " + this + " is of incorrect type! "
|
||||
+ "Expected " + mPortFormat + " but got " + frame.getFormat());
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkFrameManager(Frame frame, FilterContext context) {
|
||||
if (frame.getFrameManager() != null
|
||||
&& frame.getFrameManager() != context.getFrameManager()) {
|
||||
throw new RuntimeException("Frame " + frame + " is managed by foreign FrameManager! ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FilterSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
|
||||
private static int STATE_ALLOCATED = 0;
|
||||
private static int STATE_CREATED = 1;
|
||||
private static int STATE_INITIALIZED = 2;
|
||||
|
||||
private int mState = STATE_ALLOCATED;
|
||||
private SurfaceHolder.Callback mListener;
|
||||
private GLEnvironment mGLEnv;
|
||||
private int mFormat;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private int mSurfaceId = -1;
|
||||
|
||||
public FilterSurfaceView(Context context) {
|
||||
super(context);
|
||||
getHolder().addCallback(this);
|
||||
}
|
||||
|
||||
public FilterSurfaceView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
getHolder().addCallback(this);
|
||||
}
|
||||
|
||||
public synchronized void bindToListener(SurfaceHolder.Callback listener, GLEnvironment glEnv) {
|
||||
// Make sure we are not bound already
|
||||
if (listener == null) {
|
||||
throw new NullPointerException("Attempting to bind null filter to SurfaceView!");
|
||||
} else if (mListener != null && mListener != listener) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to bind filter " + listener + " to SurfaceView with another open "
|
||||
+ "filter " + mListener + " attached already!");
|
||||
}
|
||||
|
||||
// Set listener
|
||||
mListener = listener;
|
||||
|
||||
// Set GLEnv
|
||||
if (mGLEnv != null && mGLEnv != glEnv) {
|
||||
mGLEnv.unregisterSurfaceId(mSurfaceId);
|
||||
}
|
||||
mGLEnv = glEnv;
|
||||
|
||||
// Check if surface has been created already
|
||||
if (mState >= STATE_CREATED) {
|
||||
// Register with env (double registration will be ignored by GLEnv, so we can simply
|
||||
// try to do it here).
|
||||
registerSurface();
|
||||
|
||||
// Forward surface created to listener
|
||||
mListener.surfaceCreated(getHolder());
|
||||
|
||||
// Forward surface changed to listener
|
||||
if (mState == STATE_INITIALIZED) {
|
||||
mListener.surfaceChanged(getHolder(), mFormat, mWidth, mHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void unbind() {
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
public synchronized int getSurfaceId() {
|
||||
return mSurfaceId;
|
||||
}
|
||||
|
||||
public synchronized GLEnvironment getGLEnv() {
|
||||
return mGLEnv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void surfaceCreated(SurfaceHolder holder) {
|
||||
mState = STATE_CREATED;
|
||||
|
||||
// Register with GLEnvironment if we have it already
|
||||
if (mGLEnv != null) {
|
||||
registerSurface();
|
||||
}
|
||||
|
||||
// Forward callback to listener
|
||||
if (mListener != null) {
|
||||
mListener.surfaceCreated(holder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void surfaceChanged(SurfaceHolder holder,
|
||||
int format,
|
||||
int width,
|
||||
int height) {
|
||||
// Remember these values
|
||||
mFormat = format;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mState = STATE_INITIALIZED;
|
||||
|
||||
// Forward to renderer
|
||||
if (mListener != null) {
|
||||
mListener.surfaceChanged(holder, format, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mState = STATE_ALLOCATED;
|
||||
|
||||
// Forward to renderer
|
||||
if (mListener != null) {
|
||||
mListener.surfaceDestroyed(holder);
|
||||
}
|
||||
|
||||
// Get rid of internal objects associated with this surface
|
||||
unregisterSurface();
|
||||
}
|
||||
|
||||
private void registerSurface() {
|
||||
mSurfaceId = mGLEnv.registerSurface(getHolder().getSurface());
|
||||
if (mSurfaceId < 0) {
|
||||
throw new RuntimeException("Could not register Surface: " + getHolder().getSurface() +
|
||||
" in FilterSurfaceView!");
|
||||
}
|
||||
}
|
||||
private void unregisterSurface() {
|
||||
if (mGLEnv != null && mSurfaceId > 0) {
|
||||
mGLEnv.unregisterSurfaceId(mSurfaceId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
48
media/mca/filterfw/java/android/filterfw/core/FinalPort.java
Normal file
48
media/mca/filterfw/java/android/filterfw/core/FinalPort.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FinalPort extends FieldPort {
|
||||
|
||||
public FinalPort(Filter filter, String name, Field field, boolean hasDefault) {
|
||||
super(filter, name, field, hasDefault);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void setFieldFrame(Frame frame, boolean isAssignment) {
|
||||
assertPortIsOpen();
|
||||
checkFrameType(frame, isAssignment);
|
||||
if (mFilter.getStatus() != Filter.STATUS_PREINIT) {
|
||||
throw new RuntimeException("Attempting to modify " + this + "!");
|
||||
} else {
|
||||
super.setFieldFrame(frame, isAssignment);
|
||||
super.transfer(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "final " + super.toString();
|
||||
}
|
||||
|
||||
}
|
||||
236
media/mca/filterfw/java/android/filterfw/core/Frame.java
Normal file
236
media/mca/filterfw/java/android/filterfw/core/Frame.java
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class Frame {
|
||||
|
||||
public final static int NO_BINDING = 0;
|
||||
|
||||
public final static long TIMESTAMP_NOT_SET = -2;
|
||||
public final static long TIMESTAMP_UNKNOWN = -1;
|
||||
|
||||
private FrameFormat mFormat;
|
||||
private FrameManager mFrameManager;
|
||||
private boolean mReadOnly = false;
|
||||
private boolean mReusable = false;
|
||||
private int mRefCount = 1;
|
||||
private int mBindingType = NO_BINDING;
|
||||
private long mBindingId = 0;
|
||||
private long mTimestamp = TIMESTAMP_NOT_SET;
|
||||
|
||||
Frame(FrameFormat format, FrameManager frameManager) {
|
||||
mFormat = format.mutableCopy();
|
||||
mFrameManager = frameManager;
|
||||
}
|
||||
|
||||
Frame(FrameFormat format, FrameManager frameManager, int bindingType, long bindingId) {
|
||||
mFormat = format.mutableCopy();
|
||||
mFrameManager = frameManager;
|
||||
mBindingType = bindingType;
|
||||
mBindingId = bindingId;
|
||||
}
|
||||
|
||||
public FrameFormat getFormat() {
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
public int getCapacity() {
|
||||
return getFormat().getSize();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return mReadOnly;
|
||||
}
|
||||
|
||||
public int getBindingType() {
|
||||
return mBindingType;
|
||||
}
|
||||
|
||||
public long getBindingId() {
|
||||
return mBindingId;
|
||||
}
|
||||
|
||||
public void setObjectValue(Object object) {
|
||||
assertFrameMutable();
|
||||
|
||||
// Attempt to set the value using a specific setter (which may be more optimized), and
|
||||
// fall back to the setGenericObjectValue(...) in case of no match.
|
||||
if (object instanceof int[]) {
|
||||
setInts((int[])object);
|
||||
} else if (object instanceof float[]) {
|
||||
setFloats((float[])object);
|
||||
} else if (object instanceof ByteBuffer) {
|
||||
setData((ByteBuffer)object);
|
||||
} else if (object instanceof Bitmap) {
|
||||
setBitmap((Bitmap)object);
|
||||
} else {
|
||||
setGenericObjectValue(object);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Object getObjectValue();
|
||||
|
||||
public abstract void setInts(int[] ints);
|
||||
|
||||
public abstract int[] getInts();
|
||||
|
||||
public abstract void setFloats(float[] floats);
|
||||
|
||||
public abstract float[] getFloats();
|
||||
|
||||
public abstract void setData(ByteBuffer buffer, int offset, int length);
|
||||
|
||||
public void setData(ByteBuffer buffer) {
|
||||
setData(buffer, 0, buffer.limit());
|
||||
}
|
||||
|
||||
public void setData(byte[] bytes, int offset, int length) {
|
||||
setData(ByteBuffer.wrap(bytes, offset, length));
|
||||
}
|
||||
|
||||
public abstract ByteBuffer getData();
|
||||
|
||||
public abstract void setBitmap(Bitmap bitmap);
|
||||
|
||||
public abstract Bitmap getBitmap();
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
public void setDataFromFrame(Frame frame) {
|
||||
setData(frame.getData());
|
||||
}
|
||||
|
||||
protected boolean requestResize(int[] newDimensions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getRefCount() {
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
public Frame release() {
|
||||
if (mFrameManager != null) {
|
||||
return mFrameManager.releaseFrame(this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Frame retain() {
|
||||
if (mFrameManager != null) {
|
||||
return mFrameManager.retainFrame(this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public FrameManager getFrameManager() {
|
||||
return mFrameManager;
|
||||
}
|
||||
|
||||
protected void assertFrameMutable() {
|
||||
if (isReadOnly()) {
|
||||
throw new RuntimeException("Attempting to modify read-only frame!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setReusable(boolean reusable) {
|
||||
mReusable = reusable;
|
||||
}
|
||||
|
||||
protected void setFormat(FrameFormat format) {
|
||||
mFormat = format.mutableCopy();
|
||||
}
|
||||
|
||||
protected void setGenericObjectValue(Object value) {
|
||||
throw new RuntimeException(
|
||||
"Cannot set object value of unsupported type: " + value.getClass());
|
||||
}
|
||||
|
||||
protected static Bitmap convertBitmapToRGBA(Bitmap bitmap) {
|
||||
if (bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
|
||||
return bitmap;
|
||||
} else {
|
||||
Bitmap result = bitmap.copy(Bitmap.Config.ARGB_8888, false);
|
||||
if (result == null) {
|
||||
throw new RuntimeException("Error converting bitmap to RGBA!");
|
||||
} else if (result.getRowBytes() != result.getWidth() * 4) {
|
||||
throw new RuntimeException("Unsupported row byte count in bitmap!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
protected void reset(FrameFormat newFormat) {
|
||||
mFormat = newFormat.mutableCopy();
|
||||
mReadOnly = false;
|
||||
mRefCount = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called just before a frame is stored, such as when storing to a cache or context.
|
||||
*/
|
||||
protected void onFrameStore() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a frame is fetched from an internal store such as a cache.
|
||||
*/
|
||||
protected void onFrameFetch() {
|
||||
}
|
||||
|
||||
// Core internal methods ///////////////////////////////////////////////////////////////////////
|
||||
protected abstract boolean hasNativeAllocation();
|
||||
|
||||
protected abstract void releaseNativeAllocation();
|
||||
|
||||
final int incRefCount() {
|
||||
++mRefCount;
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
final int decRefCount() {
|
||||
--mRefCount;
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
final boolean isReusable() {
|
||||
return mReusable;
|
||||
}
|
||||
|
||||
final void markReadOnly() {
|
||||
mReadOnly = true;
|
||||
}
|
||||
|
||||
}
|
||||
439
media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
Normal file
439
media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.KeyValueMap;
|
||||
import android.filterfw.core.MutableFrameFormat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class FrameFormat {
|
||||
|
||||
public static final int TYPE_UNSPECIFIED = 0;
|
||||
public static final int TYPE_BIT = 1;
|
||||
public static final int TYPE_BYTE = 2;
|
||||
public static final int TYPE_INT16 = 3;
|
||||
public static final int TYPE_INT32 = 4;
|
||||
public static final int TYPE_FLOAT = 5;
|
||||
public static final int TYPE_DOUBLE = 6;
|
||||
public static final int TYPE_POINTER = 7;
|
||||
public static final int TYPE_OBJECT = 8;
|
||||
|
||||
public static final int TARGET_UNSPECIFIED = 0;
|
||||
public static final int TARGET_SIMPLE = 1;
|
||||
public static final int TARGET_NATIVE = 2;
|
||||
public static final int TARGET_GPU = 3;
|
||||
public static final int TARGET_VERTEXBUFFER = 4;
|
||||
public static final int TARGET_RS = 5;
|
||||
|
||||
public static final int SIZE_UNSPECIFIED = 0;
|
||||
|
||||
// TODO: When convenience formats are used, consider changing this to 0 and have the convenience
|
||||
// intializers use a proper BPS.
|
||||
public static final int BYTES_PER_SAMPLE_UNSPECIFIED = 1;
|
||||
|
||||
protected static final int SIZE_UNKNOWN = -1;
|
||||
|
||||
protected int mBaseType = TYPE_UNSPECIFIED;
|
||||
protected int mBytesPerSample = 1;
|
||||
protected int mSize = SIZE_UNKNOWN;
|
||||
protected int mTarget = TARGET_UNSPECIFIED;
|
||||
protected int[] mDimensions;
|
||||
protected KeyValueMap mMetaData;
|
||||
protected Class mObjectClass;
|
||||
|
||||
protected FrameFormat() {
|
||||
}
|
||||
|
||||
public FrameFormat(int baseType, int target) {
|
||||
mBaseType = baseType;
|
||||
mTarget = target;
|
||||
initDefaults();
|
||||
}
|
||||
|
||||
public static FrameFormat unspecified() {
|
||||
return new FrameFormat(TYPE_UNSPECIFIED, TARGET_UNSPECIFIED);
|
||||
}
|
||||
|
||||
public int getBaseType() {
|
||||
return mBaseType;
|
||||
}
|
||||
|
||||
public boolean isBinaryDataType() {
|
||||
return mBaseType >= TYPE_BIT && mBaseType <= TYPE_DOUBLE;
|
||||
}
|
||||
|
||||
public int getBytesPerSample() {
|
||||
return mBytesPerSample;
|
||||
}
|
||||
|
||||
public int getValuesPerSample() {
|
||||
return mBytesPerSample / bytesPerSampleOf(mBaseType);
|
||||
}
|
||||
|
||||
public int getTarget() {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
public int[] getDimensions() {
|
||||
return mDimensions;
|
||||
}
|
||||
|
||||
public int getDimension(int i) {
|
||||
return mDimensions[i];
|
||||
}
|
||||
|
||||
public int getDimensionCount() {
|
||||
return mDimensions == null ? 0 : mDimensions.length;
|
||||
}
|
||||
|
||||
public boolean hasMetaKey(String key) {
|
||||
return mMetaData != null ? mMetaData.containsKey(key) : false;
|
||||
}
|
||||
|
||||
public boolean hasMetaKey(String key, Class expectedClass) {
|
||||
if (mMetaData != null && mMetaData.containsKey(key)) {
|
||||
if (!expectedClass.isAssignableFrom(mMetaData.get(key).getClass())) {
|
||||
throw new RuntimeException(
|
||||
"FrameFormat meta-key '" + key + "' is of type " +
|
||||
mMetaData.get(key).getClass() + " but expected to be of type " +
|
||||
expectedClass + "!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object getMetaValue(String key) {
|
||||
return mMetaData != null ? mMetaData.get(key) : null;
|
||||
}
|
||||
|
||||
public int getNumberOfDimensions() {
|
||||
return mDimensions != null ? mDimensions.length : 0;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return (mDimensions != null && mDimensions.length >= 1) ? mDimensions[0] : -1;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return getLength();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return (mDimensions != null && mDimensions.length >= 2) ? mDimensions[1] : -1;
|
||||
}
|
||||
|
||||
public int getDepth() {
|
||||
return (mDimensions != null && mDimensions.length >= 3) ? mDimensions[2] : -1;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
if (mSize == SIZE_UNKNOWN) mSize = calcSize(mDimensions);
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public Class getObjectClass() {
|
||||
return mObjectClass;
|
||||
}
|
||||
|
||||
public MutableFrameFormat mutableCopy() {
|
||||
MutableFrameFormat result = new MutableFrameFormat();
|
||||
result.setBaseType(getBaseType());
|
||||
result.setTarget(getTarget());
|
||||
result.setBytesPerSample(getBytesPerSample());
|
||||
result.setDimensions(getDimensions());
|
||||
result.setObjectClass(getObjectClass());
|
||||
result.mMetaData = mMetaData == null ? null : (KeyValueMap)mMetaData.clone();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(object instanceof FrameFormat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FrameFormat format = (FrameFormat)object;
|
||||
return format.mBaseType == mBaseType &&
|
||||
format.mTarget == mTarget &&
|
||||
format.mBytesPerSample == mBytesPerSample &&
|
||||
Arrays.equals(format.mDimensions, mDimensions) &&
|
||||
format.mMetaData.equals(mMetaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 4211 ^ mBaseType ^ mBytesPerSample ^ getSize();
|
||||
}
|
||||
|
||||
public boolean isCompatibleWith(FrameFormat specification) {
|
||||
// Check base type
|
||||
if (specification.getBaseType() != TYPE_UNSPECIFIED
|
||||
&& getBaseType() != specification.getBaseType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check target
|
||||
if (specification.getTarget() != TARGET_UNSPECIFIED
|
||||
&& getTarget() != specification.getTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check bytes per sample
|
||||
if (specification.getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED
|
||||
&& getBytesPerSample() != specification.getBytesPerSample()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check number of dimensions
|
||||
if (specification.getDimensionCount() > 0
|
||||
&& getDimensionCount() != specification.getDimensionCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check dimensions
|
||||
for (int i = 0; i < specification.getDimensionCount(); ++i) {
|
||||
int specDim = specification.getDimension(i);
|
||||
if (specDim != SIZE_UNSPECIFIED && getDimension(i) != specDim) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check class
|
||||
if (specification.getObjectClass() != null) {
|
||||
if (getObjectClass() == null
|
||||
|| !specification.getObjectClass().isAssignableFrom(getObjectClass())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check meta-data
|
||||
if (specification.mMetaData != null) {
|
||||
for (String specKey : specification.mMetaData.keySet()) {
|
||||
if (mMetaData == null
|
||||
|| !mMetaData.containsKey(specKey)
|
||||
|| !mMetaData.get(specKey).equals(specification.mMetaData.get(specKey))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Passed all the tests
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean mayBeCompatibleWith(FrameFormat specification) {
|
||||
// Check base type
|
||||
if (specification.getBaseType() != TYPE_UNSPECIFIED
|
||||
&& getBaseType() != TYPE_UNSPECIFIED
|
||||
&& getBaseType() != specification.getBaseType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check target
|
||||
if (specification.getTarget() != TARGET_UNSPECIFIED
|
||||
&& getTarget() != TARGET_UNSPECIFIED
|
||||
&& getTarget() != specification.getTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check bytes per sample
|
||||
if (specification.getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED
|
||||
&& getBytesPerSample() != BYTES_PER_SAMPLE_UNSPECIFIED
|
||||
&& getBytesPerSample() != specification.getBytesPerSample()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check number of dimensions
|
||||
if (specification.getDimensionCount() > 0
|
||||
&& getDimensionCount() > 0
|
||||
&& getDimensionCount() != specification.getDimensionCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check dimensions
|
||||
for (int i = 0; i < specification.getDimensionCount(); ++i) {
|
||||
int specDim = specification.getDimension(i);
|
||||
if (specDim != SIZE_UNSPECIFIED
|
||||
&& getDimension(i) != SIZE_UNSPECIFIED
|
||||
&& getDimension(i) != specDim) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check class
|
||||
if (specification.getObjectClass() != null && getObjectClass() != null) {
|
||||
if (!specification.getObjectClass().isAssignableFrom(getObjectClass())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check meta-data
|
||||
if (specification.mMetaData != null && mMetaData != null) {
|
||||
for (String specKey : specification.mMetaData.keySet()) {
|
||||
if (mMetaData.containsKey(specKey)
|
||||
&& !mMetaData.get(specKey).equals(specification.mMetaData.get(specKey))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Passed all the tests
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int bytesPerSampleOf(int baseType) {
|
||||
// Defaults based on base-type
|
||||
switch (baseType) {
|
||||
case TYPE_BIT:
|
||||
case TYPE_BYTE:
|
||||
return 1;
|
||||
case TYPE_INT16:
|
||||
return 2;
|
||||
case TYPE_INT32:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_POINTER:
|
||||
return 4;
|
||||
case TYPE_DOUBLE:
|
||||
return 8;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static String dimensionsToString(int[] dimensions) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if (dimensions != null) {
|
||||
int n = dimensions.length;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (dimensions[i] == SIZE_UNSPECIFIED) {
|
||||
buffer.append("[]");
|
||||
} else {
|
||||
buffer.append("[" + String.valueOf(dimensions[i]) + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public static String baseTypeToString(int baseType) {
|
||||
switch (baseType) {
|
||||
case TYPE_UNSPECIFIED: return "unspecified";
|
||||
case TYPE_BIT: return "bit";
|
||||
case TYPE_BYTE: return "byte";
|
||||
case TYPE_INT16: return "int";
|
||||
case TYPE_INT32: return "int";
|
||||
case TYPE_FLOAT: return "float";
|
||||
case TYPE_DOUBLE: return "double";
|
||||
case TYPE_POINTER: return "pointer";
|
||||
case TYPE_OBJECT: return "object";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public static String targetToString(int target) {
|
||||
switch (target) {
|
||||
case TARGET_UNSPECIFIED: return "unspecified";
|
||||
case TARGET_SIMPLE: return "simple";
|
||||
case TARGET_NATIVE: return "native";
|
||||
case TARGET_GPU: return "gpu";
|
||||
case TARGET_VERTEXBUFFER: return "vbo";
|
||||
case TARGET_RS: return "renderscript";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public static String metaDataToString(KeyValueMap metaData) {
|
||||
if (metaData == null) {
|
||||
return "";
|
||||
} else {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("{ ");
|
||||
for (Entry<String, Object> entry : metaData.entrySet()) {
|
||||
buffer.append(entry.getKey() + ": " + entry.getValue() + " ");
|
||||
}
|
||||
buffer.append("}");
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static int readTargetString(String targetString) {
|
||||
if (targetString.equalsIgnoreCase("CPU") || targetString.equalsIgnoreCase("NATIVE")) {
|
||||
return FrameFormat.TARGET_NATIVE;
|
||||
} else if (targetString.equalsIgnoreCase("GPU")) {
|
||||
return FrameFormat.TARGET_GPU;
|
||||
} else if (targetString.equalsIgnoreCase("SIMPLE")) {
|
||||
return FrameFormat.TARGET_SIMPLE;
|
||||
} else if (targetString.equalsIgnoreCase("VERTEXBUFFER")) {
|
||||
return FrameFormat.TARGET_VERTEXBUFFER;
|
||||
} else if (targetString.equalsIgnoreCase("UNSPECIFIED")) {
|
||||
return FrameFormat.TARGET_UNSPECIFIED;
|
||||
} else {
|
||||
throw new RuntimeException("Unknown target type '" + targetString + "'!");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: FromString
|
||||
|
||||
public String toString() {
|
||||
int valuesPerSample = getValuesPerSample();
|
||||
String sampleCountString = valuesPerSample == 1 ? "" : String.valueOf(valuesPerSample);
|
||||
String targetString = mTarget == TARGET_UNSPECIFIED ? "" : (targetToString(mTarget) + " ");
|
||||
String classString = mObjectClass == null
|
||||
? ""
|
||||
: (" class(" + mObjectClass.getSimpleName() + ") ");
|
||||
|
||||
return targetString
|
||||
+ baseTypeToString(mBaseType)
|
||||
+ sampleCountString
|
||||
+ dimensionsToString(mDimensions)
|
||||
+ classString
|
||||
+ metaDataToString(mMetaData);
|
||||
}
|
||||
|
||||
private void initDefaults() {
|
||||
mBytesPerSample = bytesPerSampleOf(mBaseType);
|
||||
}
|
||||
|
||||
// Core internal methods ///////////////////////////////////////////////////////////////////////
|
||||
int calcSize(int[] dimensions) {
|
||||
if (dimensions != null && dimensions.length > 0) {
|
||||
int size = getBytesPerSample();
|
||||
for (int dim : dimensions) {
|
||||
size *= dim;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean isReplaceableBy(FrameFormat format) {
|
||||
return mTarget == format.mTarget
|
||||
&& getSize() == format.getSize()
|
||||
&& Arrays.equals(format.mDimensions, mDimensions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.MutableFrameFormat;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class FrameManager {
|
||||
|
||||
private FilterContext mContext;
|
||||
|
||||
public abstract Frame newFrame(FrameFormat format);
|
||||
|
||||
public abstract Frame newBoundFrame(FrameFormat format, int bindingType, long bindingId);
|
||||
|
||||
public Frame duplicateFrame(Frame frame) {
|
||||
Frame result = newFrame(frame.getFormat());
|
||||
result.setDataFromFrame(frame);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Frame duplicateFrameToTarget(Frame frame, int newTarget) {
|
||||
MutableFrameFormat newFormat = frame.getFormat().mutableCopy();
|
||||
newFormat.setTarget(newTarget);
|
||||
Frame result = newFrame(newFormat);
|
||||
result.setDataFromFrame(frame);
|
||||
return result;
|
||||
}
|
||||
|
||||
public abstract Frame retainFrame(Frame frame);
|
||||
|
||||
public abstract Frame releaseFrame(Frame frame);
|
||||
|
||||
public FilterContext getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public GLEnvironment getGLEnvironment() {
|
||||
return mContext != null ? mContext.getGLEnvironment() : null;
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
void setContext(FilterContext context) {
|
||||
mContext = context;
|
||||
}
|
||||
}
|
||||
180
media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
Normal file
180
media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.NativeAllocatorTag;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.media.MediaRecorder;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class GLEnvironment {
|
||||
|
||||
private int glEnvId;
|
||||
|
||||
public GLEnvironment() {
|
||||
nativeAllocate();
|
||||
}
|
||||
|
||||
private GLEnvironment(NativeAllocatorTag tag) {
|
||||
}
|
||||
|
||||
public synchronized void tearDown() {
|
||||
if (glEnvId != -1) {
|
||||
nativeDeallocate();
|
||||
glEnvId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
tearDown();
|
||||
}
|
||||
|
||||
public void initWithNewContext() {
|
||||
if (!nativeInitWithNewContext()) {
|
||||
throw new RuntimeException("Could not initialize GLEnvironment with new context!");
|
||||
}
|
||||
}
|
||||
|
||||
public void initWithCurrentContext() {
|
||||
if (!nativeInitWithCurrentContext()) {
|
||||
throw new RuntimeException("Could not initialize GLEnvironment with current context!");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return nativeIsActive();
|
||||
}
|
||||
|
||||
public boolean isContextActive() {
|
||||
return nativeIsContextActive();
|
||||
}
|
||||
|
||||
public static boolean isAnyContextActive() {
|
||||
return nativeIsAnyContextActive();
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
if (Looper.myLooper() != null && Looper.myLooper().equals(Looper.getMainLooper())) {
|
||||
Log.e("FilterFramework", "Activating GL context in UI thread!");
|
||||
}
|
||||
if (!nativeActivate()) {
|
||||
throw new RuntimeException("Could not activate GLEnvironment!");
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
if (!nativeDeactivate()) {
|
||||
throw new RuntimeException("Could not deactivate GLEnvironment!");
|
||||
}
|
||||
}
|
||||
|
||||
public void swapBuffers() {
|
||||
if (!nativeSwapBuffers()) {
|
||||
throw new RuntimeException("Error swapping EGL buffers!");
|
||||
}
|
||||
}
|
||||
|
||||
public int registerSurface(Surface surface) {
|
||||
int result = nativeAddSurface(surface);
|
||||
if (result < 0) {
|
||||
throw new RuntimeException("Error registering surface " + surface + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int registerSurfaceTexture(SurfaceTexture surfaceTexture, int width, int height) {
|
||||
Surface surface = new Surface(surfaceTexture);
|
||||
int result = nativeAddSurfaceWidthHeight(surface, width, height);
|
||||
surface.release();
|
||||
if (result < 0) {
|
||||
throw new RuntimeException("Error registering surfaceTexture " + surfaceTexture + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int registerSurfaceFromMediaRecorder(MediaRecorder mediaRecorder) {
|
||||
int result = nativeAddSurfaceFromMediaRecorder(mediaRecorder);
|
||||
if (result < 0) {
|
||||
throw new RuntimeException("Error registering surface from "
|
||||
+ "MediaRecorder" + mediaRecorder + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void activateSurfaceWithId(int surfaceId) {
|
||||
if (!nativeActivateSurfaceId(surfaceId)) {
|
||||
throw new RuntimeException("Could not activate surface " + surfaceId + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterSurfaceId(int surfaceId) {
|
||||
if (!nativeRemoveSurfaceId(surfaceId)) {
|
||||
throw new RuntimeException("Could not unregister surface " + surfaceId + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setSurfaceTimestamp(long timestamp) {
|
||||
if (!nativeSetSurfaceTimestamp(timestamp)) {
|
||||
throw new RuntimeException("Could not set timestamp for current surface!");
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
private native boolean nativeInitWithNewContext();
|
||||
|
||||
private native boolean nativeInitWithCurrentContext();
|
||||
|
||||
private native boolean nativeIsActive();
|
||||
|
||||
private native boolean nativeIsContextActive();
|
||||
|
||||
private static native boolean nativeIsAnyContextActive();
|
||||
|
||||
private native boolean nativeActivate();
|
||||
|
||||
private native boolean nativeDeactivate();
|
||||
|
||||
private native boolean nativeSwapBuffers();
|
||||
|
||||
private native boolean nativeAllocate();
|
||||
|
||||
private native boolean nativeDeallocate();
|
||||
|
||||
private native int nativeAddSurface(Surface surface);
|
||||
|
||||
private native int nativeAddSurfaceWidthHeight(Surface surface, int width, int height);
|
||||
|
||||
private native int nativeAddSurfaceFromMediaRecorder(MediaRecorder mediaRecorder);
|
||||
|
||||
private native boolean nativeDisconnectSurfaceMediaSource(MediaRecorder mediaRecorder);
|
||||
|
||||
private native boolean nativeActivateSurfaceId(int surfaceId);
|
||||
|
||||
private native boolean nativeRemoveSurfaceId(int surfaceId);
|
||||
|
||||
private native boolean nativeSetSurfaceTimestamp(long timestamp);
|
||||
}
|
||||
417
media/mca/filterfw/java/android/filterfw/core/GLFrame.java
Normal file
417
media/mca/filterfw/java/android/filterfw/core/GLFrame.java
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.NativeFrame;
|
||||
import android.filterfw.core.StopWatchMap;
|
||||
import android.graphics.Bitmap;
|
||||
import android.opengl.GLES20;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
class GLFrameTimer {
|
||||
|
||||
private static StopWatchMap mTimer = null;
|
||||
|
||||
public static StopWatchMap get() {
|
||||
if (mTimer == null) {
|
||||
mTimer = new StopWatchMap();
|
||||
}
|
||||
return mTimer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class GLFrame extends Frame {
|
||||
|
||||
// GL-related binding types
|
||||
public final static int EXISTING_TEXTURE_BINDING = 100;
|
||||
public final static int EXISTING_FBO_BINDING = 101;
|
||||
public final static int NEW_TEXTURE_BINDING = 102; // TODO: REMOVE THIS
|
||||
public final static int NEW_FBO_BINDING = 103; // TODO: REMOVE THIS
|
||||
public final static int EXTERNAL_TEXTURE = 104;
|
||||
|
||||
private int glFrameId = -1;
|
||||
|
||||
/**
|
||||
* Flag whether we own the texture or not. If we do not, we must be careful when caching or
|
||||
* storing the frame, as the user may delete, and regenerate it.
|
||||
*/
|
||||
private boolean mOwnsTexture = true;
|
||||
|
||||
/**
|
||||
* Keep a reference to the GL environment, so that it does not get deallocated while there
|
||||
* are still frames living in it.
|
||||
*/
|
||||
private GLEnvironment mGLEnvironment;
|
||||
|
||||
GLFrame(FrameFormat format, FrameManager frameManager) {
|
||||
super(format, frameManager);
|
||||
}
|
||||
|
||||
GLFrame(FrameFormat format, FrameManager frameManager, int bindingType, long bindingId) {
|
||||
super(format, frameManager, bindingType, bindingId);
|
||||
}
|
||||
|
||||
void init(GLEnvironment glEnv) {
|
||||
FrameFormat format = getFormat();
|
||||
mGLEnvironment = glEnv;
|
||||
|
||||
// Check that we have a valid format
|
||||
if (format.getBytesPerSample() != 4) {
|
||||
throw new IllegalArgumentException("GL frames must have 4 bytes per sample!");
|
||||
} else if (format.getDimensionCount() != 2) {
|
||||
throw new IllegalArgumentException("GL frames must be 2-dimensional!");
|
||||
} else if (getFormat().getSize() < 0) {
|
||||
throw new IllegalArgumentException("Initializing GL frame with zero size!");
|
||||
}
|
||||
|
||||
// Create correct frame
|
||||
int bindingType = getBindingType();
|
||||
boolean reusable = true;
|
||||
if (bindingType == Frame.NO_BINDING) {
|
||||
initNew(false);
|
||||
} else if (bindingType == EXTERNAL_TEXTURE) {
|
||||
initNew(true);
|
||||
reusable = false;
|
||||
} else if (bindingType == EXISTING_TEXTURE_BINDING) {
|
||||
initWithTexture((int)getBindingId());
|
||||
} else if (bindingType == EXISTING_FBO_BINDING) {
|
||||
initWithFbo((int)getBindingId());
|
||||
} else if (bindingType == NEW_TEXTURE_BINDING) {
|
||||
initWithTexture((int)getBindingId());
|
||||
} else if (bindingType == NEW_FBO_BINDING) {
|
||||
initWithFbo((int)getBindingId());
|
||||
} else {
|
||||
throw new RuntimeException("Attempting to create GL frame with unknown binding type "
|
||||
+ bindingType + "!");
|
||||
}
|
||||
setReusable(reusable);
|
||||
}
|
||||
|
||||
private void initNew(boolean isExternal) {
|
||||
if (isExternal) {
|
||||
if (!nativeAllocateExternal(mGLEnvironment)) {
|
||||
throw new RuntimeException("Could not allocate external GL frame!");
|
||||
}
|
||||
} else {
|
||||
if (!nativeAllocate(mGLEnvironment, getFormat().getWidth(), getFormat().getHeight())) {
|
||||
throw new RuntimeException("Could not allocate GL frame!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initWithTexture(int texId) {
|
||||
int width = getFormat().getWidth();
|
||||
int height = getFormat().getHeight();
|
||||
if (!nativeAllocateWithTexture(mGLEnvironment, texId, width, height)) {
|
||||
throw new RuntimeException("Could not allocate texture backed GL frame!");
|
||||
}
|
||||
mOwnsTexture = false;
|
||||
markReadOnly();
|
||||
}
|
||||
|
||||
private void initWithFbo(int fboId) {
|
||||
int width = getFormat().getWidth();
|
||||
int height = getFormat().getHeight();
|
||||
if (!nativeAllocateWithFbo(mGLEnvironment, fboId, width, height)) {
|
||||
throw new RuntimeException("Could not allocate FBO backed GL frame!");
|
||||
}
|
||||
}
|
||||
|
||||
void flushGPU(String message) {
|
||||
StopWatchMap timer = GLFrameTimer.get();
|
||||
if (timer.LOG_MFF_RUNNING_TIMES) {
|
||||
timer.start("glFinish " + message);
|
||||
GLES20.glFinish();
|
||||
timer.stop("glFinish " + message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized boolean hasNativeAllocation() {
|
||||
return glFrameId != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void releaseNativeAllocation() {
|
||||
nativeDeallocate();
|
||||
glFrameId = -1;
|
||||
}
|
||||
|
||||
public GLEnvironment getGLEnvironment() {
|
||||
return mGLEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectValue() {
|
||||
assertGLEnvValid();
|
||||
return ByteBuffer.wrap(getNativeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInts(int[] ints) {
|
||||
assertFrameMutable();
|
||||
assertGLEnvValid();
|
||||
if (!setNativeInts(ints)) {
|
||||
throw new RuntimeException("Could not set int values for GL frame!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getInts() {
|
||||
assertGLEnvValid();
|
||||
flushGPU("getInts");
|
||||
return getNativeInts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloats(float[] floats) {
|
||||
assertFrameMutable();
|
||||
assertGLEnvValid();
|
||||
if (!setNativeFloats(floats)) {
|
||||
throw new RuntimeException("Could not set int values for GL frame!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] getFloats() {
|
||||
assertGLEnvValid();
|
||||
flushGPU("getFloats");
|
||||
return getNativeFloats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(ByteBuffer buffer, int offset, int length) {
|
||||
assertFrameMutable();
|
||||
assertGLEnvValid();
|
||||
byte[] bytes = buffer.array();
|
||||
if (getFormat().getSize() != bytes.length) {
|
||||
throw new RuntimeException("Data size in setData does not match GL frame size!");
|
||||
} else if (!setNativeData(bytes, offset, length)) {
|
||||
throw new RuntimeException("Could not set GL frame data!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getData() {
|
||||
assertGLEnvValid();
|
||||
flushGPU("getData");
|
||||
return ByteBuffer.wrap(getNativeData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
assertFrameMutable();
|
||||
assertGLEnvValid();
|
||||
if (getFormat().getWidth() != bitmap.getWidth() ||
|
||||
getFormat().getHeight() != bitmap.getHeight()) {
|
||||
throw new RuntimeException("Bitmap dimensions do not match GL frame dimensions!");
|
||||
} else {
|
||||
Bitmap rgbaBitmap = convertBitmapToRGBA(bitmap);
|
||||
if (!setNativeBitmap(rgbaBitmap, rgbaBitmap.getByteCount())) {
|
||||
throw new RuntimeException("Could not set GL frame bitmap data!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
assertGLEnvValid();
|
||||
flushGPU("getBitmap");
|
||||
Bitmap result = Bitmap.createBitmap(getFormat().getWidth(),
|
||||
getFormat().getHeight(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
if (!getNativeBitmap(result)) {
|
||||
throw new RuntimeException("Could not get bitmap data from GL frame!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataFromFrame(Frame frame) {
|
||||
assertGLEnvValid();
|
||||
|
||||
// Make sure frame fits
|
||||
if (getFormat().getSize() < frame.getFormat().getSize()) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to assign frame of size " + frame.getFormat().getSize() + " to " +
|
||||
"smaller GL frame of size " + getFormat().getSize() + "!");
|
||||
}
|
||||
|
||||
// Invoke optimized implementations if possible
|
||||
if (frame instanceof NativeFrame) {
|
||||
nativeCopyFromNative((NativeFrame)frame);
|
||||
} else if (frame instanceof GLFrame) {
|
||||
nativeCopyFromGL((GLFrame)frame);
|
||||
} else if (frame instanceof SimpleFrame) {
|
||||
setObjectValue(frame.getObjectValue());
|
||||
} else {
|
||||
super.setDataFromFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewport(int x, int y, int width, int height) {
|
||||
assertFrameMutable();
|
||||
setNativeViewport(x, y, width, height);
|
||||
}
|
||||
|
||||
public void setViewport(Rect rect) {
|
||||
assertFrameMutable();
|
||||
setNativeViewport(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
public void generateMipMap() {
|
||||
assertFrameMutable();
|
||||
assertGLEnvValid();
|
||||
if (!generateNativeMipMap()) {
|
||||
throw new RuntimeException("Could not generate mip-map for GL frame!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setTextureParameter(int param, int value) {
|
||||
assertFrameMutable();
|
||||
assertGLEnvValid();
|
||||
if (!setNativeTextureParam(param, value)) {
|
||||
throw new RuntimeException("Could not set texture value " + param + " = " + value + " " +
|
||||
"for GLFrame!");
|
||||
}
|
||||
}
|
||||
|
||||
public int getTextureId() {
|
||||
return getNativeTextureId();
|
||||
}
|
||||
|
||||
public int getFboId() {
|
||||
return getNativeFboId();
|
||||
}
|
||||
|
||||
public void focus() {
|
||||
if (!nativeFocus()) {
|
||||
throw new RuntimeException("Could not focus on GLFrame for drawing!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GLFrame id: " + glFrameId + " (" + getFormat() + ") with texture ID "
|
||||
+ getTextureId() + ", FBO ID " + getFboId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reset(FrameFormat newFormat) {
|
||||
if (!nativeResetParams()) {
|
||||
throw new RuntimeException("Could not reset GLFrame texture parameters!");
|
||||
}
|
||||
super.reset(newFormat);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameStore() {
|
||||
if (!mOwnsTexture) {
|
||||
// Detach texture from FBO in case user manipulates it.
|
||||
nativeDetachTexFromFbo();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameFetch() {
|
||||
if (!mOwnsTexture) {
|
||||
// Reattach texture to FBO when using frame again. This may reallocate the texture
|
||||
// in case it has become invalid.
|
||||
nativeReattachTexToFbo();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertGLEnvValid() {
|
||||
if (!mGLEnvironment.isContextActive()) {
|
||||
if (GLEnvironment.isAnyContextActive()) {
|
||||
throw new RuntimeException("Attempting to access " + this + " with foreign GL " +
|
||||
"context active!");
|
||||
} else {
|
||||
throw new RuntimeException("Attempting to access " + this + " with no GL context " +
|
||||
" active!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
private native boolean nativeAllocate(GLEnvironment env, int width, int height);
|
||||
|
||||
private native boolean nativeAllocateWithTexture(GLEnvironment env,
|
||||
int textureId,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
private native boolean nativeAllocateWithFbo(GLEnvironment env,
|
||||
int fboId,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
private native boolean nativeAllocateExternal(GLEnvironment env);
|
||||
|
||||
private native boolean nativeDeallocate();
|
||||
|
||||
private native boolean setNativeData(byte[] data, int offset, int length);
|
||||
|
||||
private native byte[] getNativeData();
|
||||
|
||||
private native boolean setNativeInts(int[] ints);
|
||||
|
||||
private native boolean setNativeFloats(float[] floats);
|
||||
|
||||
private native int[] getNativeInts();
|
||||
|
||||
private native float[] getNativeFloats();
|
||||
|
||||
private native boolean setNativeBitmap(Bitmap bitmap, int size);
|
||||
|
||||
private native boolean getNativeBitmap(Bitmap bitmap);
|
||||
|
||||
private native boolean setNativeViewport(int x, int y, int width, int height);
|
||||
|
||||
private native int getNativeTextureId();
|
||||
|
||||
private native int getNativeFboId();
|
||||
|
||||
private native boolean generateNativeMipMap();
|
||||
|
||||
private native boolean setNativeTextureParam(int param, int value);
|
||||
|
||||
private native boolean nativeResetParams();
|
||||
|
||||
private native boolean nativeCopyFromNative(NativeFrame frame);
|
||||
|
||||
private native boolean nativeCopyFromGL(GLFrame frame);
|
||||
|
||||
private native boolean nativeFocus();
|
||||
|
||||
private native boolean nativeReattachTexToFbo();
|
||||
|
||||
private native boolean nativeDetachTexFromFbo();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface GenerateFieldPort {
|
||||
String name() default "";
|
||||
boolean hasDefault() default false;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface GenerateFinalPort {
|
||||
String name() default "";
|
||||
boolean hasDefault() default false;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface GenerateProgramPort {
|
||||
String name();
|
||||
Class type();
|
||||
String variableName() default "";
|
||||
boolean hasDefault() default false;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface GenerateProgramPorts {
|
||||
GenerateProgramPort[] value();
|
||||
}
|
||||
100
media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
Normal file
100
media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class GraphRunner {
|
||||
|
||||
protected FilterContext mFilterContext = null;
|
||||
|
||||
/** Interface for listeners waiting for the runner to complete. */
|
||||
public interface OnRunnerDoneListener {
|
||||
/** Callback method to be called when the runner completes a
|
||||
* {@link #run()} call.
|
||||
*
|
||||
* @param result will be RESULT_FINISHED if the graph finished running
|
||||
* on its own, RESULT_STOPPED if the runner was stopped by a call
|
||||
* to stop(), RESULT_BLOCKED if no filters could run due to lack
|
||||
* of inputs or outputs or due to scheduling policies, and
|
||||
* RESULT_SLEEPING if a filter node requested sleep.
|
||||
*/
|
||||
public void onRunnerDone(int result);
|
||||
}
|
||||
|
||||
public static final int RESULT_UNKNOWN = 0;
|
||||
public static final int RESULT_RUNNING = 1;
|
||||
public static final int RESULT_FINISHED = 2;
|
||||
public static final int RESULT_SLEEPING = 3;
|
||||
public static final int RESULT_BLOCKED = 4;
|
||||
public static final int RESULT_STOPPED = 5;
|
||||
public static final int RESULT_ERROR = 6;
|
||||
|
||||
public GraphRunner(FilterContext context) {
|
||||
mFilterContext = context;
|
||||
}
|
||||
|
||||
public abstract FilterGraph getGraph();
|
||||
|
||||
public FilterContext getContext() {
|
||||
return mFilterContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for subclasses to activate the GL environment before running.
|
||||
* @return true, if the GL environment was activated. Returns false, if the GL environment
|
||||
* was already active.
|
||||
*/
|
||||
protected boolean activateGlContext() {
|
||||
GLEnvironment glEnv = mFilterContext.getGLEnvironment();
|
||||
if (glEnv != null && !glEnv.isActive()) {
|
||||
glEnv.activate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for subclasses to deactivate the GL environment after running.
|
||||
*/
|
||||
protected void deactivateGlContext() {
|
||||
GLEnvironment glEnv = mFilterContext.getGLEnvironment();
|
||||
if (glEnv != null) {
|
||||
glEnv.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
/** Starts running the graph. Will open the filters in the graph if they are not already open. */
|
||||
public abstract void run();
|
||||
|
||||
public abstract void setDoneCallback(OnRunnerDoneListener listener);
|
||||
public abstract boolean isRunning();
|
||||
|
||||
/** Stops graph execution. As part of stopping, also closes the graph nodes. */
|
||||
public abstract void stop();
|
||||
|
||||
/** Closes the filters in a graph. Can only be called if the graph is not running. */
|
||||
public abstract void close();
|
||||
|
||||
/**
|
||||
* Returns the last exception that happened during an asynchronous run. Returns null if
|
||||
* there is nothing to report.
|
||||
*/
|
||||
public abstract Exception getError();
|
||||
}
|
||||
85
media/mca/filterfw/java/android/filterfw/core/InputPort.java
Normal file
85
media/mca/filterfw/java/android/filterfw/core/InputPort.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class InputPort extends FilterPort {
|
||||
|
||||
protected OutputPort mSourcePort;
|
||||
|
||||
public InputPort(Filter filter, String name) {
|
||||
super(filter, name);
|
||||
}
|
||||
|
||||
public void setSourcePort(OutputPort source) {
|
||||
if (mSourcePort != null) {
|
||||
throw new RuntimeException(this + " already connected to " + mSourcePort + "!");
|
||||
}
|
||||
mSourcePort = source;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return mSourcePort != null;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
super.open();
|
||||
if (mSourcePort != null && !mSourcePort.isOpen()) {
|
||||
mSourcePort.open();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (mSourcePort != null && mSourcePort.isOpen()) {
|
||||
mSourcePort.close();
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
public OutputPort getSourcePort() {
|
||||
return mSourcePort;
|
||||
}
|
||||
|
||||
public Filter getSourceFilter() {
|
||||
return mSourcePort == null ? null : mSourcePort.getFilter();
|
||||
}
|
||||
|
||||
public FrameFormat getSourceFormat() {
|
||||
return mSourcePort != null ? mSourcePort.getPortFormat() : getPortFormat();
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean filterMustClose() {
|
||||
return !isOpen() && isBlocking() && !hasFrame();
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return hasFrame() || !isBlocking();
|
||||
}
|
||||
|
||||
public boolean acceptsFrame() {
|
||||
return !hasFrame();
|
||||
}
|
||||
|
||||
public abstract void transfer(FilterContext context);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class KeyValueMap extends HashMap<String, Object> {
|
||||
|
||||
public void setKeyValues(Object... keyValues) {
|
||||
if (keyValues.length % 2 != 0) {
|
||||
throw new RuntimeException("Key-Value arguments passed into setKeyValues must be "
|
||||
+ "an alternating list of keys and values!");
|
||||
}
|
||||
for (int i = 0; i < keyValues.length; i += 2) {
|
||||
if (!(keyValues[i] instanceof String)) {
|
||||
throw new RuntimeException("Key-value argument " + i + " must be a key of type "
|
||||
+ "String, but found an object of type " + keyValues[i].getClass() + "!");
|
||||
}
|
||||
String key = (String)keyValues[i];
|
||||
Object value = keyValues[i+1];
|
||||
put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyValueMap fromKeyValues(Object... keyValues) {
|
||||
KeyValueMap result = new KeyValueMap();
|
||||
result.setKeyValues(keyValues);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
Object result = get(key);
|
||||
return result != null ? (String)result : null;
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
Object result = get(key);
|
||||
return result != null ? (Integer)result : null;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
Object result = get(key);
|
||||
return result != null ? (Float)result : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringWriter writer = new StringWriter();
|
||||
for (Map.Entry<String, Object> entry : entrySet()) {
|
||||
String valueString;
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof String) {
|
||||
valueString = "\"" + value + "\"";
|
||||
} else {
|
||||
valueString = value.toString();
|
||||
}
|
||||
writer.write(entry.getKey() + " = " + valueString + ";\n");
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.KeyValueMap;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class MutableFrameFormat extends FrameFormat {
|
||||
|
||||
public MutableFrameFormat() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MutableFrameFormat(int baseType, int target) {
|
||||
super(baseType, target);
|
||||
}
|
||||
|
||||
public void setBaseType(int baseType) {
|
||||
mBaseType = baseType;
|
||||
mBytesPerSample = bytesPerSampleOf(baseType);
|
||||
}
|
||||
|
||||
public void setTarget(int target) {
|
||||
mTarget = target;
|
||||
}
|
||||
|
||||
public void setBytesPerSample(int bytesPerSample) {
|
||||
mBytesPerSample = bytesPerSample;
|
||||
mSize = SIZE_UNKNOWN;
|
||||
}
|
||||
|
||||
public void setDimensions(int[] dimensions) {
|
||||
mDimensions = (dimensions == null) ? null : Arrays.copyOf(dimensions, dimensions.length);
|
||||
mSize = SIZE_UNKNOWN;
|
||||
}
|
||||
|
||||
public void setDimensions(int size) {
|
||||
int[] dimensions = new int[1];
|
||||
dimensions[0] = size;
|
||||
mDimensions = dimensions;
|
||||
mSize = SIZE_UNKNOWN;
|
||||
}
|
||||
|
||||
public void setDimensions(int width, int height) {
|
||||
int[] dimensions = new int[2];
|
||||
dimensions[0] = width;
|
||||
dimensions[1] = height;
|
||||
mDimensions = dimensions;
|
||||
mSize = SIZE_UNKNOWN;
|
||||
}
|
||||
|
||||
public void setDimensions(int width, int height, int depth) {
|
||||
int[] dimensions = new int[3];
|
||||
dimensions[0] = width;
|
||||
dimensions[1] = height;
|
||||
dimensions[2] = depth;
|
||||
mDimensions = dimensions;
|
||||
mSize = SIZE_UNKNOWN;
|
||||
}
|
||||
|
||||
public void setDimensionCount(int count) {
|
||||
mDimensions = new int[count];
|
||||
}
|
||||
|
||||
public void setObjectClass(Class objectClass) {
|
||||
mObjectClass = objectClass;
|
||||
}
|
||||
|
||||
public void setMetaValue(String key, Object value) {
|
||||
if (mMetaData == null) {
|
||||
mMetaData = new KeyValueMap();
|
||||
}
|
||||
mMetaData.put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* This class is simply a place-holder type used to identify calls coming
|
||||
* from the native layer. This way method signatures can be selected
|
||||
* that are to be accessed from the native layer only.
|
||||
*
|
||||
* @hide
|
||||
**/
|
||||
public class NativeAllocatorTag {
|
||||
}
|
||||
129
media/mca/filterfw/java/android/filterfw/core/NativeBuffer.java
Normal file
129
media/mca/filterfw/java/android/filterfw/core/NativeBuffer.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class NativeBuffer {
|
||||
|
||||
// These are set by the native layer
|
||||
private long mDataPointer = 0;
|
||||
private int mSize = 0;
|
||||
|
||||
private Frame mAttachedFrame;
|
||||
|
||||
private boolean mOwnsData = false;
|
||||
private int mRefCount = 1;
|
||||
|
||||
public NativeBuffer() {
|
||||
}
|
||||
|
||||
public NativeBuffer(int count) {
|
||||
allocate(count * getElementSize());
|
||||
mOwnsData = true;
|
||||
}
|
||||
|
||||
public NativeBuffer mutableCopy() {
|
||||
NativeBuffer result = null;
|
||||
try {
|
||||
Class myClass = getClass();
|
||||
result = (NativeBuffer)myClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to allocate a copy of " + getClass() + "! Make " +
|
||||
"sure the class has a default constructor!");
|
||||
}
|
||||
if (mSize > 0 && !nativeCopyTo(result)) {
|
||||
throw new RuntimeException("Failed to copy NativeBuffer to mutable instance!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return (mDataPointer != 0) ? mSize / getElementSize() : 0;
|
||||
}
|
||||
|
||||
public int getElementSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public NativeBuffer retain() {
|
||||
if (mAttachedFrame != null) {
|
||||
mAttachedFrame.retain();
|
||||
} else if (mOwnsData) {
|
||||
++mRefCount;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeBuffer release() {
|
||||
// Decrement refcount
|
||||
boolean doDealloc = false;
|
||||
if (mAttachedFrame != null) {
|
||||
doDealloc = (mAttachedFrame.release() == null);
|
||||
} else if (mOwnsData) {
|
||||
--mRefCount;
|
||||
doDealloc = (mRefCount == 0);
|
||||
}
|
||||
|
||||
// Deallocate if necessary
|
||||
if (doDealloc) {
|
||||
deallocate(mOwnsData);
|
||||
return null;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return (mAttachedFrame != null) ? mAttachedFrame.isReadOnly() : false;
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
void attachToFrame(Frame frame) {
|
||||
// We do not auto-retain. We expect the user to call retain() if they want to hold on to
|
||||
// the frame.
|
||||
mAttachedFrame = frame;
|
||||
}
|
||||
|
||||
protected void assertReadable() {
|
||||
if (mDataPointer == 0 || mSize == 0
|
||||
|| (mAttachedFrame != null && !mAttachedFrame.hasNativeAllocation())) {
|
||||
throw new NullPointerException("Attempting to read from null data frame!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertWritable() {
|
||||
if (isReadOnly()) {
|
||||
throw new RuntimeException("Attempting to modify read-only native (structured) data!");
|
||||
}
|
||||
}
|
||||
|
||||
private native boolean allocate(int size);
|
||||
private native boolean deallocate(boolean ownsData);
|
||||
private native boolean nativeCopyTo(NativeBuffer buffer);
|
||||
}
|
||||
265
media/mca/filterfw/java/android/filterfw/core/NativeFrame.java
Normal file
265
media/mca/filterfw/java/android/filterfw/core/NativeFrame.java
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.GLFrame;
|
||||
import android.filterfw.core.NativeBuffer;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class NativeFrame extends Frame {
|
||||
|
||||
private int nativeFrameId = -1;
|
||||
|
||||
NativeFrame(FrameFormat format, FrameManager frameManager) {
|
||||
super(format, frameManager);
|
||||
int capacity = format.getSize();
|
||||
nativeAllocate(capacity);
|
||||
setReusable(capacity != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void releaseNativeAllocation() {
|
||||
nativeDeallocate();
|
||||
nativeFrameId = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized boolean hasNativeAllocation() {
|
||||
return nativeFrameId != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCapacity() {
|
||||
return getNativeCapacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native frame's Object value.
|
||||
*
|
||||
* If the frame's base-type is not TYPE_OBJECT, this returns a data buffer containing the native
|
||||
* data (this is equivalent to calling getData().
|
||||
* If the frame is based on an object type, this type is expected to be a subclass of
|
||||
* NativeBuffer. The NativeBuffer returned is only valid for as long as the frame is alive. If
|
||||
* you need to hold on to the returned value, you must retain it.
|
||||
*/
|
||||
@Override
|
||||
public Object getObjectValue() {
|
||||
// If this is not a structured frame, return our data
|
||||
if (getFormat().getBaseType() != FrameFormat.TYPE_OBJECT) {
|
||||
return getData();
|
||||
}
|
||||
|
||||
// Get the structure class
|
||||
Class structClass = getFormat().getObjectClass();
|
||||
if (structClass == null) {
|
||||
throw new RuntimeException("Attempting to get object data from frame that does " +
|
||||
"not specify a structure object class!");
|
||||
}
|
||||
|
||||
// Make sure it is a NativeBuffer subclass
|
||||
if (!NativeBuffer.class.isAssignableFrom(structClass)) {
|
||||
throw new RuntimeException("NativeFrame object class must be a subclass of " +
|
||||
"NativeBuffer!");
|
||||
}
|
||||
|
||||
// Instantiate a new empty instance of this class
|
||||
NativeBuffer structData = null;
|
||||
try {
|
||||
structData = (NativeBuffer)structClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not instantiate new structure instance of type '" +
|
||||
structClass + "'!");
|
||||
}
|
||||
|
||||
// Wrap it around our data
|
||||
if (!getNativeBuffer(structData)) {
|
||||
throw new RuntimeException("Could not get the native structured data for frame!");
|
||||
}
|
||||
|
||||
// Attach this frame to it
|
||||
structData.attachToFrame(this);
|
||||
|
||||
return structData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInts(int[] ints) {
|
||||
assertFrameMutable();
|
||||
if (ints.length * nativeIntSize() > getFormat().getSize()) {
|
||||
throw new RuntimeException(
|
||||
"NativeFrame cannot hold " + ints.length + " integers. (Can only hold " +
|
||||
(getFormat().getSize() / nativeIntSize()) + " integers).");
|
||||
} else if (!setNativeInts(ints)) {
|
||||
throw new RuntimeException("Could not set int values for native frame!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getInts() {
|
||||
return getNativeInts(getFormat().getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloats(float[] floats) {
|
||||
assertFrameMutable();
|
||||
if (floats.length * nativeFloatSize() > getFormat().getSize()) {
|
||||
throw new RuntimeException(
|
||||
"NativeFrame cannot hold " + floats.length + " floats. (Can only hold " +
|
||||
(getFormat().getSize() / nativeFloatSize()) + " floats).");
|
||||
} else if (!setNativeFloats(floats)) {
|
||||
throw new RuntimeException("Could not set int values for native frame!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] getFloats() {
|
||||
return getNativeFloats(getFormat().getSize());
|
||||
}
|
||||
|
||||
// TODO: This function may be a bit confusing: Is the offset the target or source offset? Maybe
|
||||
// we should allow specifying both? (May be difficult for other frame types).
|
||||
@Override
|
||||
public void setData(ByteBuffer buffer, int offset, int length) {
|
||||
assertFrameMutable();
|
||||
byte[] bytes = buffer.array();
|
||||
if ((length + offset) > buffer.limit()) {
|
||||
throw new RuntimeException("Offset and length exceed buffer size in native setData: " +
|
||||
(length + offset) + " bytes given, but only " + buffer.limit() +
|
||||
" bytes available!");
|
||||
} else if (getFormat().getSize() != length) {
|
||||
throw new RuntimeException("Data size in setData does not match native frame size: " +
|
||||
"Frame size is " + getFormat().getSize() + " bytes, but " +
|
||||
length + " bytes given!");
|
||||
} else if (!setNativeData(bytes, offset, length)) {
|
||||
throw new RuntimeException("Could not set native frame data!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getData() {
|
||||
byte[] data = getNativeData(getFormat().getSize());
|
||||
return data == null ? null : ByteBuffer.wrap(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
assertFrameMutable();
|
||||
if (getFormat().getNumberOfDimensions() != 2) {
|
||||
throw new RuntimeException("Attempting to set Bitmap for non 2-dimensional native frame!");
|
||||
} else if (getFormat().getWidth() != bitmap.getWidth() ||
|
||||
getFormat().getHeight() != bitmap.getHeight()) {
|
||||
throw new RuntimeException("Bitmap dimensions do not match native frame dimensions!");
|
||||
} else {
|
||||
Bitmap rgbaBitmap = convertBitmapToRGBA(bitmap);
|
||||
int byteCount = rgbaBitmap.getByteCount();
|
||||
int bps = getFormat().getBytesPerSample();
|
||||
if (!setNativeBitmap(rgbaBitmap, byteCount, bps)) {
|
||||
throw new RuntimeException("Could not set native frame bitmap data!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
if (getFormat().getNumberOfDimensions() != 2) {
|
||||
throw new RuntimeException("Attempting to get Bitmap for non 2-dimensional native frame!");
|
||||
}
|
||||
Bitmap result = Bitmap.createBitmap(getFormat().getWidth(),
|
||||
getFormat().getHeight(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
int byteCount = result.getByteCount();
|
||||
int bps = getFormat().getBytesPerSample();
|
||||
if (!getNativeBitmap(result, byteCount, bps)) {
|
||||
throw new RuntimeException("Could not get bitmap data from native frame!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataFromFrame(Frame frame) {
|
||||
// Make sure frame fits
|
||||
if (getFormat().getSize() < frame.getFormat().getSize()) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to assign frame of size " + frame.getFormat().getSize() + " to " +
|
||||
"smaller native frame of size " + getFormat().getSize() + "!");
|
||||
}
|
||||
|
||||
// Invoke optimized implementations if possible
|
||||
if (frame instanceof NativeFrame) {
|
||||
nativeCopyFromNative((NativeFrame)frame);
|
||||
} else if (frame instanceof GLFrame) {
|
||||
nativeCopyFromGL((GLFrame)frame);
|
||||
} else if (frame instanceof SimpleFrame) {
|
||||
setObjectValue(frame.getObjectValue());
|
||||
} else {
|
||||
super.setDataFromFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NativeFrame id: " + nativeFrameId + " (" + getFormat() + ") of size "
|
||||
+ getCapacity();
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
private native boolean nativeAllocate(int capacity);
|
||||
|
||||
private native boolean nativeDeallocate();
|
||||
|
||||
private native int getNativeCapacity();
|
||||
|
||||
private static native int nativeIntSize();
|
||||
|
||||
private static native int nativeFloatSize();
|
||||
|
||||
private native boolean setNativeData(byte[] data, int offset, int length);
|
||||
|
||||
private native byte[] getNativeData(int byteCount);
|
||||
|
||||
private native boolean getNativeBuffer(NativeBuffer buffer);
|
||||
|
||||
private native boolean setNativeInts(int[] ints);
|
||||
|
||||
private native boolean setNativeFloats(float[] floats);
|
||||
|
||||
private native int[] getNativeInts(int byteCount);
|
||||
|
||||
private native float[] getNativeFloats(int byteCount);
|
||||
|
||||
private native boolean setNativeBitmap(Bitmap bitmap, int size, int bytesPerSample);
|
||||
|
||||
private native boolean getNativeBitmap(Bitmap bitmap, int size, int bytesPerSample);
|
||||
|
||||
private native boolean nativeCopyFromNative(NativeFrame frame);
|
||||
|
||||
private native boolean nativeCopyFromGL(GLFrame frame);
|
||||
}
|
||||
176
media/mca/filterfw/java/android/filterfw/core/NativeProgram.java
Normal file
176
media/mca/filterfw/java/android/filterfw/core/NativeProgram.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.Program;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class NativeProgram extends Program {
|
||||
|
||||
private int nativeProgramId;
|
||||
private boolean mHasInitFunction = false;
|
||||
private boolean mHasTeardownFunction = false;
|
||||
private boolean mHasSetValueFunction = false;
|
||||
private boolean mHasGetValueFunction = false;
|
||||
private boolean mHasResetFunction = false;
|
||||
private boolean mTornDown = false;
|
||||
|
||||
public NativeProgram(String nativeLibName, String nativeFunctionPrefix) {
|
||||
// Allocate the native instance
|
||||
allocate();
|
||||
|
||||
// Open the native library
|
||||
String fullLibName = "lib" + nativeLibName + ".so";
|
||||
if (!openNativeLibrary(fullLibName)) {
|
||||
throw new RuntimeException("Could not find native library named '" + fullLibName + "' " +
|
||||
"required for native program!");
|
||||
}
|
||||
|
||||
// Bind the native functions
|
||||
String processFuncName = nativeFunctionPrefix + "_process";
|
||||
if (!bindProcessFunction(processFuncName)) {
|
||||
throw new RuntimeException("Could not find native program function name " +
|
||||
processFuncName + " in library " + fullLibName + "! " +
|
||||
"This function is required!");
|
||||
}
|
||||
|
||||
String initFuncName = nativeFunctionPrefix + "_init";
|
||||
mHasInitFunction = bindInitFunction(initFuncName);
|
||||
|
||||
String teardownFuncName = nativeFunctionPrefix + "_teardown";
|
||||
mHasTeardownFunction = bindTeardownFunction(teardownFuncName);
|
||||
|
||||
String setValueFuncName = nativeFunctionPrefix + "_setvalue";
|
||||
mHasSetValueFunction = bindSetValueFunction(setValueFuncName);
|
||||
|
||||
String getValueFuncName = nativeFunctionPrefix + "_getvalue";
|
||||
mHasGetValueFunction = bindGetValueFunction(getValueFuncName);
|
||||
|
||||
String resetFuncName = nativeFunctionPrefix + "_reset";
|
||||
mHasResetFunction = bindResetFunction(resetFuncName);
|
||||
|
||||
// Initialize the native code
|
||||
if (mHasInitFunction && !callNativeInit()) {
|
||||
throw new RuntimeException("Could not initialize NativeProgram!");
|
||||
}
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
if (mTornDown) return;
|
||||
if (mHasTeardownFunction && !callNativeTeardown()) {
|
||||
throw new RuntimeException("Could not tear down NativeProgram!");
|
||||
}
|
||||
deallocate();
|
||||
mTornDown = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
if (mHasResetFunction && !callNativeReset()) {
|
||||
throw new RuntimeException("Could not reset NativeProgram!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
tearDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Frame[] inputs, Frame output) {
|
||||
if (mTornDown) {
|
||||
throw new RuntimeException("NativeProgram already torn down!");
|
||||
}
|
||||
NativeFrame[] nativeInputs = new NativeFrame[inputs.length];
|
||||
for (int i = 0; i < inputs.length; ++i) {
|
||||
if (inputs[i] == null || inputs[i] instanceof NativeFrame) {
|
||||
nativeInputs[i] = (NativeFrame)inputs[i];
|
||||
} else {
|
||||
throw new RuntimeException("NativeProgram got non-native frame as input "+ i +"!");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the native output frame
|
||||
NativeFrame nativeOutput = null;
|
||||
if (output == null || output instanceof NativeFrame) {
|
||||
nativeOutput = (NativeFrame)output;
|
||||
} else {
|
||||
throw new RuntimeException("NativeProgram got non-native output frame!");
|
||||
}
|
||||
|
||||
// Process!
|
||||
if (!callNativeProcess(nativeInputs, nativeOutput)) {
|
||||
throw new RuntimeException("Calling native process() caused error!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHostValue(String variableName, Object value) {
|
||||
if (mTornDown) {
|
||||
throw new RuntimeException("NativeProgram already torn down!");
|
||||
}
|
||||
if (!mHasSetValueFunction) {
|
||||
throw new RuntimeException("Attempting to set native variable, but native code does not " +
|
||||
"define native setvalue function!");
|
||||
}
|
||||
if (!callNativeSetValue(variableName, value.toString())) {
|
||||
throw new RuntimeException("Error setting native value for variable '" + variableName + "'!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHostValue(String variableName) {
|
||||
if (mTornDown) {
|
||||
throw new RuntimeException("NativeProgram already torn down!");
|
||||
}
|
||||
if (!mHasGetValueFunction) {
|
||||
throw new RuntimeException("Attempting to get native variable, but native code does not " +
|
||||
"define native getvalue function!");
|
||||
}
|
||||
return callNativeGetValue(variableName);
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
private native boolean allocate();
|
||||
|
||||
private native boolean deallocate();
|
||||
|
||||
private native boolean nativeInit();
|
||||
|
||||
private native boolean openNativeLibrary(String libName);
|
||||
|
||||
private native boolean bindInitFunction(String funcName);
|
||||
private native boolean bindSetValueFunction(String funcName);
|
||||
private native boolean bindGetValueFunction(String funcName);
|
||||
private native boolean bindProcessFunction(String funcName);
|
||||
private native boolean bindResetFunction(String funcName);
|
||||
private native boolean bindTeardownFunction(String funcName);
|
||||
|
||||
private native boolean callNativeInit();
|
||||
private native boolean callNativeSetValue(String key, String value);
|
||||
private native String callNativeGetValue(String key);
|
||||
private native boolean callNativeProcess(NativeFrame[] inputs, NativeFrame output);
|
||||
private native boolean callNativeReset();
|
||||
private native boolean callNativeTeardown();
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.Scheduler;
|
||||
import android.filterfw.core.RoundRobinScheduler;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This OneShotScheduler only schedules source filters at most once. All other
|
||||
* filters will be scheduled, and possibly repeatedly, until there is no filter
|
||||
* that can be scheduled.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class OneShotScheduler extends RoundRobinScheduler {
|
||||
private HashMap <String, Integer> scheduled;
|
||||
|
||||
private final boolean mLogVerbose;
|
||||
private static final String TAG = "OneShotScheduler";
|
||||
|
||||
public OneShotScheduler(FilterGraph graph) {
|
||||
super(graph);
|
||||
scheduled = new HashMap<String, Integer>();
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
scheduled.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter scheduleNextNode() {
|
||||
Filter first = null;
|
||||
// return the first filter that is not scheduled before.
|
||||
while (true) {
|
||||
Filter filter = super.scheduleNextNode();
|
||||
if (filter == null) {
|
||||
if (mLogVerbose) Log.v(TAG, "No filters available to run.");
|
||||
return null;
|
||||
}
|
||||
if (!scheduled.containsKey(filter.getName())) {
|
||||
if (filter.getNumberOfConnectedInputs() == 0)
|
||||
scheduled.put(filter.getName(),1);
|
||||
if (mLogVerbose) Log.v(TAG, "Scheduling filter \"" + filter.getName() + "\" of type " + filter.getFilterClassName());
|
||||
return filter;
|
||||
}
|
||||
// if loop back, nothing available
|
||||
if (first == filter) {
|
||||
break;
|
||||
}
|
||||
// save the first scheduled one
|
||||
if (first == null) first = filter;
|
||||
}
|
||||
if (mLogVerbose) Log.v(TAG, "One pass through graph completed.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
122
media/mca/filterfw/java/android/filterfw/core/OutputPort.java
Normal file
122
media/mca/filterfw/java/android/filterfw/core/OutputPort.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class OutputPort extends FilterPort {
|
||||
|
||||
protected InputPort mTargetPort;
|
||||
protected InputPort mBasePort;
|
||||
|
||||
public OutputPort(Filter filter, String name) {
|
||||
super(filter, name);
|
||||
}
|
||||
|
||||
public void connectTo(InputPort target) {
|
||||
if (mTargetPort != null) {
|
||||
throw new RuntimeException(this + " already connected to " + mTargetPort + "!");
|
||||
}
|
||||
mTargetPort = target;
|
||||
mTargetPort.setSourcePort(this);
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return mTargetPort != null;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
super.open();
|
||||
if (mTargetPort != null && !mTargetPort.isOpen()) {
|
||||
mTargetPort.open();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.close();
|
||||
if (mTargetPort != null && mTargetPort.isOpen()) {
|
||||
mTargetPort.close();
|
||||
}
|
||||
}
|
||||
|
||||
public InputPort getTargetPort() {
|
||||
return mTargetPort;
|
||||
}
|
||||
|
||||
public Filter getTargetFilter() {
|
||||
return mTargetPort == null ? null : mTargetPort.getFilter();
|
||||
}
|
||||
|
||||
public void setBasePort(InputPort basePort) {
|
||||
mBasePort = basePort;
|
||||
}
|
||||
|
||||
public InputPort getBasePort() {
|
||||
return mBasePort;
|
||||
}
|
||||
|
||||
public boolean filterMustClose() {
|
||||
return !isOpen() && isBlocking();
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return (isOpen() && mTargetPort.acceptsFrame()) || !isBlocking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (mTargetPort != null) {
|
||||
mTargetPort.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushFrame(Frame frame) {
|
||||
if (mTargetPort == null) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to push frame on unconnected port: " + this + "!");
|
||||
}
|
||||
mTargetPort.pushFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrame(Frame frame) {
|
||||
assertPortIsOpen();
|
||||
if (mTargetPort == null) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to set frame on unconnected port: " + this + "!");
|
||||
}
|
||||
mTargetPort.setFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame pullFrame() {
|
||||
throw new RuntimeException("Cannot pull frame on " + this + "!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFrame() {
|
||||
return mTargetPort == null ? false : mTargetPort.hasFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "output " + super.toString();
|
||||
}
|
||||
}
|
||||
41
media/mca/filterfw/java/android/filterfw/core/Program.java
Normal file
41
media/mca/filterfw/java/android/filterfw/core/Program.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class Program {
|
||||
|
||||
public abstract void process(Frame[] inputs, Frame output);
|
||||
|
||||
public void process(Frame input, Frame output) {
|
||||
Frame[] inputs = new Frame[1];
|
||||
inputs[0] = input;
|
||||
process(inputs, output);
|
||||
}
|
||||
|
||||
public abstract void setHostValue(String variableName, Object value);
|
||||
|
||||
public abstract Object getHostValue(String variableName);
|
||||
|
||||
public void reset() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ProgramPort extends FieldPort {
|
||||
|
||||
protected String mVarName;
|
||||
|
||||
public ProgramPort(Filter filter,
|
||||
String name,
|
||||
String varName,
|
||||
Field field,
|
||||
boolean hasDefault) {
|
||||
super(filter, name, field, hasDefault);
|
||||
mVarName = varName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Program " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void transfer(FilterContext context) {
|
||||
if (mValueWaiting) {
|
||||
try {
|
||||
Object fieldValue = mField.get(mFilter);
|
||||
if (fieldValue != null) {
|
||||
Program program = (Program)fieldValue;
|
||||
program.setHostValue(mVarName, mValue);
|
||||
mValueWaiting = false;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(
|
||||
"Access to program field '" + mField.getName() + "' was denied!");
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException("Non Program field '" + mField.getName()
|
||||
+ "' annotated with ProgramParameter!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ProgramVariable {
|
||||
|
||||
private Program mProgram;
|
||||
private String mVarName;
|
||||
|
||||
public ProgramVariable(Program program, String varName) {
|
||||
mProgram = program;
|
||||
mVarName = varName;
|
||||
}
|
||||
|
||||
public Program getProgram() {
|
||||
return mProgram;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return mVarName;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (mProgram == null) {
|
||||
throw new RuntimeException("Attempting to set program variable '" + mVarName
|
||||
+ "' but the program is null!");
|
||||
}
|
||||
mProgram.setHostValue(mVarName, value);
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
if (mProgram == null) {
|
||||
throw new RuntimeException("Attempting to get program variable '" + mVarName
|
||||
+ "' but the program is null!");
|
||||
}
|
||||
return mProgram.getHostValue(mVarName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ProtocolException extends RuntimeException {
|
||||
|
||||
public ProtocolException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ProtocolException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.Scheduler;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class RandomScheduler extends Scheduler {
|
||||
|
||||
private Random mRand = new Random();
|
||||
|
||||
public RandomScheduler(FilterGraph graph) {
|
||||
super(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter scheduleNextNode() {
|
||||
Vector<Filter> candidates = new Vector<Filter>();
|
||||
for (Filter filter : getGraph().getFilters()) {
|
||||
if (filter.canProcess())
|
||||
candidates.add(filter);
|
||||
}
|
||||
if (candidates.size() > 0) {
|
||||
int r = mRand.nextInt(candidates.size());
|
||||
return candidates.elementAt(r);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.Scheduler;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class RoundRobinScheduler extends Scheduler {
|
||||
|
||||
private int mLastPos = -1;
|
||||
|
||||
public RoundRobinScheduler(FilterGraph graph) {
|
||||
super(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mLastPos = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter scheduleNextNode() {
|
||||
Set<Filter> all_filters = getGraph().getFilters();
|
||||
if (mLastPos >= all_filters.size()) mLastPos = -1;
|
||||
int pos = 0;
|
||||
Filter first = null;
|
||||
int firstNdx = -1;
|
||||
for (Filter filter : all_filters) {
|
||||
if (filter.canProcess()) {
|
||||
if (pos <= mLastPos) {
|
||||
if (first == null) {
|
||||
// store the first available filter
|
||||
first = filter;
|
||||
firstNdx = pos;
|
||||
}
|
||||
} else {
|
||||
// return the next available filter since last
|
||||
mLastPos = pos;
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
pos ++;
|
||||
}
|
||||
// going around from the beginning
|
||||
if (first != null ) {
|
||||
mLastPos = firstNdx;
|
||||
return first;
|
||||
}
|
||||
// if there is nothing to be scheduled, still keep the previous
|
||||
// position.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
47
media/mca/filterfw/java/android/filterfw/core/Scheduler.java
Normal file
47
media/mca/filterfw/java/android/filterfw/core/Scheduler.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.FilterGraph;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class Scheduler {
|
||||
// All methods are core internal methods as Scheduler internals are only used by the GraphRunner.
|
||||
|
||||
private FilterGraph mGraph;
|
||||
|
||||
Scheduler(FilterGraph graph) {
|
||||
mGraph = graph;
|
||||
}
|
||||
|
||||
FilterGraph getGraph() {
|
||||
return mGraph;
|
||||
}
|
||||
|
||||
abstract void reset();
|
||||
|
||||
abstract Filter scheduleNextNode();
|
||||
|
||||
boolean finished() {
|
||||
// TODO: Check that the state of all nodes is FINISHED.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.NativeBuffer;
|
||||
import android.filterfw.format.ObjectFormat;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OptionalDataException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A frame that serializes any assigned values. Such a frame is used when passing data objects
|
||||
* between threads.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SerializedFrame extends Frame {
|
||||
|
||||
/**
|
||||
* The initial capacity of the serialized data stream.
|
||||
*/
|
||||
private final static int INITIAL_CAPACITY = 64;
|
||||
|
||||
/**
|
||||
* The internal data streams.
|
||||
*/
|
||||
private DirectByteOutputStream mByteOutputStream;
|
||||
private ObjectOutputStream mObjectOut;
|
||||
|
||||
/**
|
||||
* An unsynchronized output stream that writes data to an accessible byte array. Callers are
|
||||
* responsible for synchronization. This is more efficient than a ByteArrayOutputStream, as
|
||||
* there are no array copies or synchronization involved to read back written data.
|
||||
*/
|
||||
private class DirectByteOutputStream extends OutputStream {
|
||||
private byte[] mBuffer = null;
|
||||
private int mOffset = 0;
|
||||
private int mDataOffset = 0;
|
||||
|
||||
public DirectByteOutputStream(int size) {
|
||||
mBuffer = new byte[size];
|
||||
}
|
||||
|
||||
private final void ensureFit(int bytesToWrite) {
|
||||
if (mOffset + bytesToWrite > mBuffer.length) {
|
||||
byte[] oldBuffer = mBuffer;
|
||||
mBuffer = new byte[Math.max(mOffset + bytesToWrite, mBuffer.length * 2)];
|
||||
System.arraycopy(oldBuffer, 0, mBuffer, 0, mOffset);
|
||||
oldBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public final void markHeaderEnd() {
|
||||
mDataOffset = mOffset;
|
||||
}
|
||||
|
||||
public final int getSize() {
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
public byte[] getByteArray() {
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(byte b[]) {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(byte b[], int off, int len) {
|
||||
ensureFit(len);
|
||||
System.arraycopy(b, off, mBuffer, mOffset, len);
|
||||
mOffset += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void write(int b) {
|
||||
ensureFit(1);
|
||||
mBuffer[mOffset++] = (byte)b;
|
||||
}
|
||||
|
||||
public final void reset() {
|
||||
mOffset = mDataOffset;
|
||||
}
|
||||
|
||||
public final DirectByteInputStream getInputStream() {
|
||||
return new DirectByteInputStream(mBuffer, mOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An unsynchronized input stream that reads data directly from a provided byte array. Callers
|
||||
* are responsible for synchronization and ensuring that the byte buffer is valid.
|
||||
*/
|
||||
private class DirectByteInputStream extends InputStream {
|
||||
|
||||
private byte[] mBuffer;
|
||||
private int mPos = 0;
|
||||
private int mSize;
|
||||
|
||||
public DirectByteInputStream(byte[] buffer, int size) {
|
||||
mBuffer = buffer;
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int available() {
|
||||
return mSize - mPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int read() {
|
||||
return (mPos < mSize) ? (mBuffer[mPos++] & 0xFF) : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int read(byte[] b, int off, int len) {
|
||||
if (mPos >= mSize) {
|
||||
return -1;
|
||||
}
|
||||
if ((mPos + len) > mSize) {
|
||||
len = mSize - mPos;
|
||||
}
|
||||
System.arraycopy(mBuffer, mPos, b, off, len);
|
||||
mPos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long skip(long n) {
|
||||
if ((mPos + n) > mSize) {
|
||||
n = mSize - mPos;
|
||||
}
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
mPos += n;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
SerializedFrame(FrameFormat format, FrameManager frameManager) {
|
||||
super(format, frameManager);
|
||||
setReusable(false);
|
||||
|
||||
// Setup streams
|
||||
try {
|
||||
mByteOutputStream = new DirectByteOutputStream(INITIAL_CAPACITY);
|
||||
mObjectOut = new ObjectOutputStream(mByteOutputStream);
|
||||
mByteOutputStream.markHeaderEnd();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not create serialization streams for "
|
||||
+ "SerializedFrame!", e);
|
||||
}
|
||||
}
|
||||
|
||||
static SerializedFrame wrapObject(Object object, FrameManager frameManager) {
|
||||
FrameFormat format = ObjectFormat.fromObject(object, FrameFormat.TARGET_SIMPLE);
|
||||
SerializedFrame result = new SerializedFrame(format, frameManager);
|
||||
result.setObjectValue(object);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasNativeAllocation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseNativeAllocation() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectValue() {
|
||||
return deserializeObjectValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInts(int[] ints) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(ints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getInts() {
|
||||
Object result = deserializeObjectValue();
|
||||
return (result instanceof int[]) ? (int[])result : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloats(float[] floats) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(floats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] getFloats() {
|
||||
Object result = deserializeObjectValue();
|
||||
return (result instanceof float[]) ? (float[])result : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(ByteBuffer buffer, int offset, int length) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(ByteBuffer.wrap(buffer.array(), offset, length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getData() {
|
||||
Object result = deserializeObjectValue();
|
||||
return (result instanceof ByteBuffer) ? (ByteBuffer)result : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
Object result = deserializeObjectValue();
|
||||
return (result instanceof Bitmap) ? (Bitmap)result : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setGenericObjectValue(Object object) {
|
||||
serializeObjectValue(object);
|
||||
}
|
||||
|
||||
private final void serializeObjectValue(Object object) {
|
||||
try {
|
||||
mByteOutputStream.reset();
|
||||
mObjectOut.writeObject(object);
|
||||
mObjectOut.flush();
|
||||
mObjectOut.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not serialize object " + object + " in "
|
||||
+ this + "!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Object deserializeObjectValue() {
|
||||
try {
|
||||
InputStream inputStream = mByteOutputStream.getInputStream();
|
||||
ObjectInputStream objectStream = new ObjectInputStream(inputStream);
|
||||
return objectStream.readObject();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not deserialize object in " + this + "!", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Unable to deserialize object of unknown class in "
|
||||
+ this + "!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SerializedFrame (" + getFormat() + ")";
|
||||
}
|
||||
}
|
||||
301
media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
Normal file
301
media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.NativeAllocatorTag;
|
||||
import android.filterfw.core.Program;
|
||||
import android.filterfw.core.StopWatchMap;
|
||||
import android.filterfw.core.VertexFrame;
|
||||
import android.filterfw.geometry.Quad;
|
||||
import android.opengl.GLES20;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ShaderProgram extends Program {
|
||||
|
||||
private int shaderProgramId;
|
||||
|
||||
private int mMaxTileSize = 0;
|
||||
|
||||
// Keep a reference to the GL environment, so that it does not get deallocated while there
|
||||
// are still programs living in it.
|
||||
private GLEnvironment mGLEnvironment;
|
||||
|
||||
private StopWatchMap mTimer = null;
|
||||
|
||||
private void setTimer() {
|
||||
mTimer = new StopWatchMap();
|
||||
}
|
||||
|
||||
// Used from native layer for creating empty wrapper only!
|
||||
private ShaderProgram() {
|
||||
}
|
||||
|
||||
private ShaderProgram(NativeAllocatorTag tag) {
|
||||
}
|
||||
|
||||
public ShaderProgram(FilterContext context, String fragmentShader) {
|
||||
mGLEnvironment = getGLEnvironment(context);
|
||||
allocate(mGLEnvironment, null, fragmentShader);
|
||||
if (!compileAndLink()) {
|
||||
throw new RuntimeException("Could not compile and link shader!");
|
||||
}
|
||||
this.setTimer();
|
||||
}
|
||||
|
||||
public ShaderProgram(FilterContext context, String vertexShader, String fragmentShader) {
|
||||
mGLEnvironment = getGLEnvironment(context);
|
||||
allocate(mGLEnvironment, vertexShader, fragmentShader);
|
||||
if (!compileAndLink()) {
|
||||
throw new RuntimeException("Could not compile and link shader!");
|
||||
}
|
||||
this.setTimer();
|
||||
}
|
||||
|
||||
public static ShaderProgram createIdentity(FilterContext context) {
|
||||
ShaderProgram program = nativeCreateIdentity(getGLEnvironment(context));
|
||||
program.setTimer();
|
||||
return program;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
deallocate();
|
||||
}
|
||||
|
||||
public GLEnvironment getGLEnvironment() {
|
||||
return mGLEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Frame[] inputs, Frame output) {
|
||||
if (mTimer.LOG_MFF_RUNNING_TIMES) {
|
||||
mTimer.start("glFinish");
|
||||
GLES20.glFinish();
|
||||
mTimer.stop("glFinish");
|
||||
}
|
||||
|
||||
// Get the GL input frames
|
||||
// TODO: We do the same in the NativeProgram... can we find a better way?!
|
||||
GLFrame[] glInputs = new GLFrame[inputs.length];
|
||||
for (int i = 0; i < inputs.length; ++i) {
|
||||
if (inputs[i] instanceof GLFrame) {
|
||||
glInputs[i] = (GLFrame)inputs[i];
|
||||
} else {
|
||||
throw new RuntimeException("ShaderProgram got non-GL frame as input " + i + "!");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the GL output frame
|
||||
GLFrame glOutput = null;
|
||||
if (output instanceof GLFrame) {
|
||||
glOutput = (GLFrame)output;
|
||||
} else {
|
||||
throw new RuntimeException("ShaderProgram got non-GL output frame!");
|
||||
}
|
||||
|
||||
// Adjust tiles to meet maximum tile size requirement
|
||||
if (mMaxTileSize > 0) {
|
||||
int xTiles = (output.getFormat().getWidth() + mMaxTileSize - 1) / mMaxTileSize;
|
||||
int yTiles = (output.getFormat().getHeight() + mMaxTileSize - 1) / mMaxTileSize;
|
||||
setShaderTileCounts(xTiles, yTiles);
|
||||
}
|
||||
|
||||
// Process!
|
||||
if (!shaderProcess(glInputs, glOutput)) {
|
||||
throw new RuntimeException("Error executing ShaderProgram!");
|
||||
}
|
||||
|
||||
if (mTimer.LOG_MFF_RUNNING_TIMES) {
|
||||
GLES20.glFinish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHostValue(String variableName, Object value) {
|
||||
if (!setUniformValue(variableName, value)) {
|
||||
throw new RuntimeException("Error setting uniform value for variable '" +
|
||||
variableName + "'!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHostValue(String variableName) {
|
||||
return getUniformValue(variableName);
|
||||
}
|
||||
|
||||
public void setAttributeValues(String attributeName, float[] data, int componentCount) {
|
||||
if (!setShaderAttributeValues(attributeName, data, componentCount)) {
|
||||
throw new RuntimeException("Error setting attribute value for attribute '" +
|
||||
attributeName + "'!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setAttributeValues(String attributeName,
|
||||
VertexFrame vertexData,
|
||||
int type,
|
||||
int componentCount,
|
||||
int strideInBytes,
|
||||
int offsetInBytes,
|
||||
boolean normalize) {
|
||||
if (!setShaderAttributeVertexFrame(attributeName,
|
||||
vertexData,
|
||||
type,
|
||||
componentCount,
|
||||
strideInBytes,
|
||||
offsetInBytes,
|
||||
normalize)) {
|
||||
throw new RuntimeException("Error setting attribute value for attribute '" +
|
||||
attributeName + "'!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setSourceRegion(Quad region) {
|
||||
setSourceRegion(region.p0.x, region.p0.y,
|
||||
region.p1.x, region.p1.y,
|
||||
region.p2.x, region.p2.y,
|
||||
region.p3.x, region.p3.y);
|
||||
}
|
||||
|
||||
public void setTargetRegion(Quad region) {
|
||||
setTargetRegion(region.p0.x, region.p0.y,
|
||||
region.p1.x, region.p1.y,
|
||||
region.p2.x, region.p2.y,
|
||||
region.p3.x, region.p3.y);
|
||||
}
|
||||
|
||||
public void setSourceRect(float x, float y, float width, float height) {
|
||||
setSourceRegion(x, y, x + width, y, x, y + height, x + width, y + height);
|
||||
}
|
||||
|
||||
public void setTargetRect(float x, float y, float width, float height) {
|
||||
setTargetRegion(x, y, x + width, y, x, y + height, x + width, y + height);
|
||||
}
|
||||
|
||||
public void setClearsOutput(boolean clears) {
|
||||
if (!setShaderClearsOutput(clears)) {
|
||||
throw new RuntimeException("Could not set clears-output flag to " + clears + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setClearColor(float r, float g, float b) {
|
||||
if (!setShaderClearColor(r, g, b)) {
|
||||
throw new RuntimeException("Could not set clear color to " + r + "," + g + "," + b + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlendEnabled(boolean enable) {
|
||||
if (!setShaderBlendEnabled(enable)) {
|
||||
throw new RuntimeException("Could not set Blending " + enable + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlendFunc(int sfactor, int dfactor) {
|
||||
if (!setShaderBlendFunc(sfactor, dfactor)) {
|
||||
throw new RuntimeException("Could not set BlendFunc " + sfactor +","+ dfactor + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setDrawMode(int drawMode) {
|
||||
if (!setShaderDrawMode(drawMode)) {
|
||||
throw new RuntimeException("Could not set GL draw-mode to " + drawMode + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setVertexCount(int count) {
|
||||
if (!setShaderVertexCount(count)) {
|
||||
throw new RuntimeException("Could not set GL vertex count to " + count + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaximumTileSize(int size) {
|
||||
mMaxTileSize = size;
|
||||
}
|
||||
|
||||
public void beginDrawing() {
|
||||
if (!beginShaderDrawing()) {
|
||||
throw new RuntimeException("Could not prepare shader-program for drawing!");
|
||||
}
|
||||
}
|
||||
|
||||
private static GLEnvironment getGLEnvironment(FilterContext context) {
|
||||
GLEnvironment result = context != null ? context.getGLEnvironment() : null;
|
||||
if (result == null) {
|
||||
throw new NullPointerException("Attempting to create ShaderProgram with no GL "
|
||||
+ "environment in place!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
private native boolean allocate(GLEnvironment glEnv,
|
||||
String vertexShader,
|
||||
String fragmentShader);
|
||||
|
||||
private native boolean deallocate();
|
||||
|
||||
private native boolean compileAndLink();
|
||||
|
||||
private native boolean shaderProcess(GLFrame[] inputs, GLFrame output);
|
||||
|
||||
private native boolean setUniformValue(String name, Object value);
|
||||
|
||||
private native Object getUniformValue(String name);
|
||||
|
||||
public native boolean setSourceRegion(float x0, float y0, float x1, float y1,
|
||||
float x2, float y2, float x3, float y3);
|
||||
|
||||
private native boolean setTargetRegion(float x0, float y0, float x1, float y1,
|
||||
float x2, float y2, float x3, float y3);
|
||||
|
||||
private static native ShaderProgram nativeCreateIdentity(GLEnvironment glEnv);
|
||||
|
||||
private native boolean setShaderClearsOutput(boolean clears);
|
||||
|
||||
private native boolean setShaderBlendEnabled(boolean enable);
|
||||
|
||||
private native boolean setShaderBlendFunc(int sfactor, int dfactor);
|
||||
|
||||
private native boolean setShaderClearColor(float r, float g, float b);
|
||||
|
||||
private native boolean setShaderDrawMode(int drawMode);
|
||||
|
||||
private native boolean setShaderTileCounts(int xCount, int yCount);
|
||||
|
||||
private native boolean setShaderVertexCount(int vertexCount);
|
||||
|
||||
private native boolean beginShaderDrawing();
|
||||
|
||||
private native boolean setShaderAttributeValues(String attributeName,
|
||||
float[] data,
|
||||
int componentCount);
|
||||
|
||||
private native boolean setShaderAttributeVertexFrame(String attributeName,
|
||||
VertexFrame vertexData,
|
||||
int type,
|
||||
int componentCount,
|
||||
int strideInBytes,
|
||||
int offsetInBytes,
|
||||
boolean normalize);
|
||||
|
||||
}
|
||||
161
media/mca/filterfw/java/android/filterfw/core/SimpleFrame.java
Normal file
161
media/mca/filterfw/java/android/filterfw/core/SimpleFrame.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.NativeBuffer;
|
||||
import android.filterfw.format.ObjectFormat;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SimpleFrame extends Frame {
|
||||
|
||||
private Object mObject;
|
||||
|
||||
SimpleFrame(FrameFormat format, FrameManager frameManager) {
|
||||
super(format, frameManager);
|
||||
initWithFormat(format);
|
||||
setReusable(false);
|
||||
}
|
||||
|
||||
static SimpleFrame wrapObject(Object object, FrameManager frameManager) {
|
||||
FrameFormat format = ObjectFormat.fromObject(object, FrameFormat.TARGET_SIMPLE);
|
||||
SimpleFrame result = new SimpleFrame(format, frameManager);
|
||||
result.setObjectValue(object);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void initWithFormat(FrameFormat format) {
|
||||
final int count = format.getLength();
|
||||
final int baseType = format.getBaseType();
|
||||
switch (baseType) {
|
||||
case FrameFormat.TYPE_BYTE:
|
||||
mObject = new byte[count];
|
||||
break;
|
||||
case FrameFormat.TYPE_INT16:
|
||||
mObject = new short[count];
|
||||
break;
|
||||
case FrameFormat.TYPE_INT32:
|
||||
mObject = new int[count];
|
||||
break;
|
||||
case FrameFormat.TYPE_FLOAT:
|
||||
mObject = new float[count];
|
||||
break;
|
||||
case FrameFormat.TYPE_DOUBLE:
|
||||
mObject = new double[count];
|
||||
break;
|
||||
default:
|
||||
mObject = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasNativeAllocation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseNativeAllocation() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectValue() {
|
||||
return mObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInts(int[] ints) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(ints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getInts() {
|
||||
return (mObject instanceof int[]) ? (int[])mObject : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloats(float[] floats) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(floats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] getFloats() {
|
||||
return (mObject instanceof float[]) ? (float[])mObject : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(ByteBuffer buffer, int offset, int length) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(ByteBuffer.wrap(buffer.array(), offset, length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getData() {
|
||||
return (mObject instanceof ByteBuffer) ? (ByteBuffer)mObject : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
assertFrameMutable();
|
||||
setGenericObjectValue(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
return (mObject instanceof Bitmap) ? (Bitmap)mObject : null;
|
||||
}
|
||||
|
||||
private void setFormatObjectClass(Class objectClass) {
|
||||
MutableFrameFormat format = getFormat().mutableCopy();
|
||||
format.setObjectClass(objectClass);
|
||||
setFormat(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setGenericObjectValue(Object object) {
|
||||
// Update the FrameFormat class
|
||||
// TODO: Take this out! FrameFormats should not be modified and convenience formats used
|
||||
// instead!
|
||||
FrameFormat format = getFormat();
|
||||
if (format.getObjectClass() == null) {
|
||||
setFormatObjectClass(object.getClass());
|
||||
} else if (!format.getObjectClass().isAssignableFrom(object.getClass())) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to set object value of type '" + object.getClass() + "' on " +
|
||||
"SimpleFrame of type '" + format.getObjectClass() + "'!");
|
||||
}
|
||||
|
||||
// Set the object value
|
||||
mObject = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimpleFrame (" + getFormat() + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.filterfw.core.GLFrame;
|
||||
import android.filterfw.core.NativeFrame;
|
||||
import android.filterfw.core.SimpleFrame;
|
||||
import android.filterfw.core.VertexFrame;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SimpleFrameManager extends FrameManager {
|
||||
|
||||
public SimpleFrameManager() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame newFrame(FrameFormat format) {
|
||||
return createNewFrame(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame newBoundFrame(FrameFormat format, int bindingType, long bindingId) {
|
||||
Frame result = null;
|
||||
switch(format.getTarget()) {
|
||||
case FrameFormat.TARGET_GPU: {
|
||||
GLFrame glFrame = new GLFrame(format, this, bindingType, bindingId);
|
||||
glFrame.init(getGLEnvironment());
|
||||
result = glFrame;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Attached frames are not supported for target type: "
|
||||
+ FrameFormat.targetToString(format.getTarget()) + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Frame createNewFrame(FrameFormat format) {
|
||||
Frame result = null;
|
||||
switch(format.getTarget()) {
|
||||
case FrameFormat.TARGET_SIMPLE:
|
||||
result = new SimpleFrame(format, this);
|
||||
break;
|
||||
|
||||
case FrameFormat.TARGET_NATIVE:
|
||||
result = new NativeFrame(format, this);
|
||||
break;
|
||||
|
||||
case FrameFormat.TARGET_GPU: {
|
||||
GLFrame glFrame = new GLFrame(format, this);
|
||||
glFrame.init(getGLEnvironment());
|
||||
result = glFrame;
|
||||
break;
|
||||
}
|
||||
|
||||
case FrameFormat.TARGET_VERTEXBUFFER: {
|
||||
result = new VertexFrame(format, this);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unsupported frame target type: " +
|
||||
FrameFormat.targetToString(format.getTarget()) + "!");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame retainFrame(Frame frame) {
|
||||
frame.incRefCount();
|
||||
return frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame releaseFrame(Frame frame) {
|
||||
int refCount = frame.decRefCount();
|
||||
if (refCount == 0 && frame.hasNativeAllocation()) {
|
||||
frame.releaseNativeAllocation();
|
||||
return null;
|
||||
} else if (refCount < 0) {
|
||||
throw new RuntimeException("Frame reference count dropped below 0!");
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Filter;
|
||||
import android.filterfw.core.Scheduler;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SimpleScheduler extends Scheduler {
|
||||
|
||||
public SimpleScheduler(FilterGraph graph) {
|
||||
super(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter scheduleNextNode() {
|
||||
for (Filter filter : getGraph().getFilters()) {
|
||||
if (filter.canProcess())
|
||||
return filter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
101
media/mca/filterfw/java/android/filterfw/core/StopWatchMap.java
Normal file
101
media/mca/filterfw/java/android/filterfw/core/StopWatchMap.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
class StopWatch {
|
||||
|
||||
private int STOP_WATCH_LOGGING_PERIOD = 200;
|
||||
private String TAG = "MFF";
|
||||
|
||||
private String mName;
|
||||
private long mStartTime;
|
||||
private long mTotalTime;
|
||||
private int mNumCalls;
|
||||
|
||||
public StopWatch(String name) {
|
||||
mName = name;
|
||||
mStartTime = -1;
|
||||
mTotalTime = 0;
|
||||
mNumCalls = 0;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (mStartTime != -1) {
|
||||
throw new RuntimeException(
|
||||
"Calling start with StopWatch already running");
|
||||
}
|
||||
mStartTime = SystemClock.elapsedRealtime();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (mStartTime == -1) {
|
||||
throw new RuntimeException(
|
||||
"Calling stop with StopWatch already stopped");
|
||||
}
|
||||
long stopTime = SystemClock.elapsedRealtime();
|
||||
mTotalTime += stopTime - mStartTime;
|
||||
++mNumCalls;
|
||||
mStartTime = -1;
|
||||
if (mNumCalls % STOP_WATCH_LOGGING_PERIOD == 0) {
|
||||
Log.i(TAG, "AVG ms/call " + mName + ": " +
|
||||
String.format("%.1f", mTotalTime * 1.0f / mNumCalls));
|
||||
mTotalTime = 0;
|
||||
mNumCalls = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class StopWatchMap {
|
||||
|
||||
public boolean LOG_MFF_RUNNING_TIMES = false;
|
||||
|
||||
private HashMap<String, StopWatch> mStopWatches = null;
|
||||
|
||||
public StopWatchMap() {
|
||||
mStopWatches = new HashMap<String, StopWatch>();
|
||||
}
|
||||
|
||||
public void start(String stopWatchName) {
|
||||
if (!LOG_MFF_RUNNING_TIMES) {
|
||||
return;
|
||||
}
|
||||
if (!mStopWatches.containsKey(stopWatchName)) {
|
||||
mStopWatches.put(stopWatchName, new StopWatch(stopWatchName));
|
||||
}
|
||||
mStopWatches.get(stopWatchName).start();
|
||||
}
|
||||
|
||||
public void stop(String stopWatchName) {
|
||||
if (!LOG_MFF_RUNNING_TIMES) {
|
||||
return;
|
||||
}
|
||||
if (!mStopWatches.containsKey(stopWatchName)) {
|
||||
throw new RuntimeException(
|
||||
"Calling stop with unknown stopWatchName: " + stopWatchName);
|
||||
}
|
||||
mStopWatches.get(stopWatchName).stop();
|
||||
}
|
||||
|
||||
}
|
||||
100
media/mca/filterfw/java/android/filterfw/core/StreamPort.java
Normal file
100
media/mca/filterfw/java/android/filterfw/core/StreamPort.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class StreamPort extends InputPort {
|
||||
|
||||
private Frame mFrame;
|
||||
private boolean mPersistent;
|
||||
|
||||
public StreamPort(Filter filter, String name) {
|
||||
super(filter, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (mFrame != null) {
|
||||
mFrame.release();
|
||||
mFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrame(Frame frame) {
|
||||
assignFrame(frame, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushFrame(Frame frame) {
|
||||
assignFrame(frame, false);
|
||||
}
|
||||
|
||||
protected synchronized void assignFrame(Frame frame, boolean persistent) {
|
||||
assertPortIsOpen();
|
||||
checkFrameType(frame, persistent);
|
||||
|
||||
if (persistent) {
|
||||
if (mFrame != null) {
|
||||
mFrame.release();
|
||||
}
|
||||
} else if (mFrame != null) {
|
||||
throw new RuntimeException(
|
||||
"Attempting to push more than one frame on port: " + this + "!");
|
||||
}
|
||||
mFrame = frame.retain();
|
||||
mFrame.markReadOnly();
|
||||
mPersistent = persistent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Frame pullFrame() {
|
||||
// Make sure we have a frame
|
||||
if (mFrame == null) {
|
||||
throw new RuntimeException("No frame available to pull on port: " + this + "!");
|
||||
}
|
||||
|
||||
// Return a retained result
|
||||
Frame result = mFrame;
|
||||
if (mPersistent) {
|
||||
mFrame.retain();
|
||||
} else {
|
||||
mFrame = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasFrame() {
|
||||
return mFrame != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "input " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void transfer(FilterContext context) {
|
||||
if (mFrame != null) {
|
||||
checkFrameManager(mFrame, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
227
media/mca/filterfw/java/android/filterfw/core/SyncRunner.java
Normal file
227
media/mca/filterfw/java/android/filterfw/core/SyncRunner.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.os.ConditionVariable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class SyncRunner extends GraphRunner {
|
||||
|
||||
private Scheduler mScheduler = null;
|
||||
|
||||
private OnRunnerDoneListener mDoneListener = null;
|
||||
private ScheduledThreadPoolExecutor mWakeExecutor = new ScheduledThreadPoolExecutor(1);
|
||||
private ConditionVariable mWakeCondition = new ConditionVariable();
|
||||
|
||||
private StopWatchMap mTimer = null;
|
||||
|
||||
private final boolean mLogVerbose;
|
||||
private final static String TAG = "SyncRunner";
|
||||
|
||||
// TODO: Provide factory based constructor?
|
||||
public SyncRunner(FilterContext context, FilterGraph graph, Class schedulerClass) {
|
||||
super(context);
|
||||
|
||||
mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
if (mLogVerbose) Log.v(TAG, "Initializing SyncRunner");
|
||||
|
||||
// Create the scheduler
|
||||
if (Scheduler.class.isAssignableFrom(schedulerClass)) {
|
||||
try {
|
||||
Constructor schedulerConstructor = schedulerClass.getConstructor(FilterGraph.class);
|
||||
mScheduler = (Scheduler)schedulerConstructor.newInstance(graph);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Scheduler does not have constructor <init>(FilterGraph)!", e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException("Could not instantiate the Scheduler instance!", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Cannot access Scheduler constructor!", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("Scheduler constructor threw an exception", e);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not instantiate Scheduler", e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Class provided is not a Scheduler subclass!");
|
||||
}
|
||||
|
||||
// Associate this runner and the graph with the context
|
||||
mFilterContext = context;
|
||||
mFilterContext.addGraph(graph);
|
||||
|
||||
mTimer = new StopWatchMap();
|
||||
|
||||
if (mLogVerbose) Log.v(TAG, "Setting up filters");
|
||||
|
||||
// Setup graph filters
|
||||
graph.setupFilters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterGraph getGraph() {
|
||||
return mScheduler != null ? mScheduler.getGraph() : null;
|
||||
}
|
||||
|
||||
public int step() {
|
||||
assertReadyToStep();
|
||||
if (!getGraph().isReady() ) {
|
||||
throw new RuntimeException("Trying to process graph that is not open!");
|
||||
}
|
||||
return performStep() ? RESULT_RUNNING : determinePostRunState();
|
||||
}
|
||||
|
||||
public void beginProcessing() {
|
||||
mScheduler.reset();
|
||||
getGraph().beginProcessing();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// Close filters
|
||||
if (mLogVerbose) Log.v(TAG, "Closing graph.");
|
||||
getGraph().closeFilters(mFilterContext);
|
||||
mScheduler.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mLogVerbose) Log.v(TAG, "Beginning run.");
|
||||
|
||||
assertReadyToStep();
|
||||
|
||||
// Preparation
|
||||
beginProcessing();
|
||||
boolean glActivated = activateGlContext();
|
||||
|
||||
// Run
|
||||
boolean keepRunning = true;
|
||||
while (keepRunning) {
|
||||
keepRunning = performStep();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
if (glActivated) {
|
||||
deactivateGlContext();
|
||||
}
|
||||
|
||||
// Call completion callback if set
|
||||
if (mDoneListener != null) {
|
||||
if (mLogVerbose) Log.v(TAG, "Calling completion listener.");
|
||||
mDoneListener.onRunnerDone(determinePostRunState());
|
||||
}
|
||||
if (mLogVerbose) Log.v(TAG, "Run complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDoneCallback(OnRunnerDoneListener listener) {
|
||||
mDoneListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
throw new RuntimeException("SyncRunner does not support stopping a graph!");
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized public Exception getError() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void waitUntilWake() {
|
||||
mWakeCondition.block();
|
||||
}
|
||||
|
||||
protected void processFilterNode(Filter filter) {
|
||||
if (mLogVerbose) Log.v(TAG, "Processing filter node");
|
||||
filter.performProcess(mFilterContext);
|
||||
if (filter.getStatus() == Filter.STATUS_ERROR) {
|
||||
throw new RuntimeException("There was an error executing " + filter + "!");
|
||||
} else if (filter.getStatus() == Filter.STATUS_SLEEPING) {
|
||||
if (mLogVerbose) Log.v(TAG, "Scheduling filter wakeup");
|
||||
scheduleFilterWake(filter, filter.getSleepDelay());
|
||||
}
|
||||
}
|
||||
|
||||
protected void scheduleFilterWake(Filter filter, int delay) {
|
||||
// Close the wake condition
|
||||
mWakeCondition.close();
|
||||
|
||||
// Schedule the wake-up
|
||||
final Filter filterToSchedule = filter;
|
||||
final ConditionVariable conditionToWake = mWakeCondition;
|
||||
|
||||
mWakeExecutor.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
filterToSchedule.unsetStatus(Filter.STATUS_SLEEPING);
|
||||
conditionToWake.open();
|
||||
}
|
||||
}, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
protected int determinePostRunState() {
|
||||
boolean isBlocked = false;
|
||||
for (Filter filter : mScheduler.getGraph().getFilters()) {
|
||||
if (filter.isOpen()) {
|
||||
if (filter.getStatus() == Filter.STATUS_SLEEPING) {
|
||||
// If ANY node is sleeping, we return our state as sleeping
|
||||
return RESULT_SLEEPING;
|
||||
} else {
|
||||
// If a node is still open, it is blocked (by input or output)
|
||||
return RESULT_BLOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RESULT_FINISHED;
|
||||
}
|
||||
|
||||
// Core internal methods ///////////////////////////////////////////////////////////////////////
|
||||
boolean performStep() {
|
||||
if (mLogVerbose) Log.v(TAG, "Performing one step.");
|
||||
Filter filter = mScheduler.scheduleNextNode();
|
||||
if (filter != null) {
|
||||
mTimer.start(filter.getName());
|
||||
processFilterNode(filter);
|
||||
mTimer.stop(filter.getName());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void assertReadyToStep() {
|
||||
if (mScheduler == null) {
|
||||
throw new RuntimeException("Attempting to run schedule with no scheduler in place!");
|
||||
} else if (getGraph() == null) {
|
||||
throw new RuntimeException("Calling step on scheduler with no graph in place!");
|
||||
}
|
||||
}
|
||||
}
|
||||
143
media/mca/filterfw/java/android/filterfw/core/VertexFrame.java
Normal file
143
media/mca/filterfw/java/android/filterfw/core/VertexFrame.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.core;
|
||||
|
||||
import android.filterfw.core.Frame;
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.FrameManager;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class VertexFrame extends Frame {
|
||||
|
||||
private int vertexFrameId = -1;
|
||||
|
||||
VertexFrame(FrameFormat format, FrameManager frameManager) {
|
||||
super(format, frameManager);
|
||||
if (getFormat().getSize() <= 0) {
|
||||
throw new IllegalArgumentException("Initializing vertex frame with zero size!");
|
||||
} else {
|
||||
if (!nativeAllocate(getFormat().getSize())) {
|
||||
throw new RuntimeException("Could not allocate vertex frame!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized boolean hasNativeAllocation() {
|
||||
return vertexFrameId != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void releaseNativeAllocation() {
|
||||
nativeDeallocate();
|
||||
vertexFrameId = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectValue() {
|
||||
throw new RuntimeException("Vertex frames do not support reading data!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInts(int[] ints) {
|
||||
assertFrameMutable();
|
||||
if (!setNativeInts(ints)) {
|
||||
throw new RuntimeException("Could not set int values for vertex frame!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getInts() {
|
||||
throw new RuntimeException("Vertex frames do not support reading data!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloats(float[] floats) {
|
||||
assertFrameMutable();
|
||||
if (!setNativeFloats(floats)) {
|
||||
throw new RuntimeException("Could not set int values for vertex frame!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] getFloats() {
|
||||
throw new RuntimeException("Vertex frames do not support reading data!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(ByteBuffer buffer, int offset, int length) {
|
||||
assertFrameMutable();
|
||||
byte[] bytes = buffer.array();
|
||||
if (getFormat().getSize() != bytes.length) {
|
||||
throw new RuntimeException("Data size in setData does not match vertex frame size!");
|
||||
} else if (!setNativeData(bytes, offset, length)) {
|
||||
throw new RuntimeException("Could not set vertex frame data!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getData() {
|
||||
throw new RuntimeException("Vertex frames do not support reading data!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
throw new RuntimeException("Unsupported: Cannot set vertex frame bitmap value!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getBitmap() {
|
||||
throw new RuntimeException("Vertex frames do not support reading data!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataFromFrame(Frame frame) {
|
||||
// TODO: Optimize
|
||||
super.setDataFromFrame(frame);
|
||||
}
|
||||
|
||||
public int getVboId() {
|
||||
return getNativeVboId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VertexFrame (" + getFormat() + ") with VBO ID " + getVboId();
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("filterfw");
|
||||
}
|
||||
|
||||
private native boolean nativeAllocate(int size);
|
||||
|
||||
private native boolean nativeDeallocate();
|
||||
|
||||
private native boolean setNativeData(byte[] data, int offset, int length);
|
||||
|
||||
private native boolean setNativeInts(int[] ints);
|
||||
|
||||
private native boolean setNativeFloats(float[] floats);
|
||||
|
||||
private native int getNativeVboId();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
package android.filterfw.core;
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.format;
|
||||
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.MutableFrameFormat;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ImageFormat {
|
||||
|
||||
public static final String COLORSPACE_KEY = "colorspace";
|
||||
|
||||
public static final int COLORSPACE_GRAY = 1;
|
||||
public static final int COLORSPACE_RGB = 2;
|
||||
public static final int COLORSPACE_RGBA = 3;
|
||||
public static final int COLORSPACE_YUV = 4;
|
||||
|
||||
public static MutableFrameFormat create(int width,
|
||||
int height,
|
||||
int colorspace,
|
||||
int bytesPerSample,
|
||||
int target) {
|
||||
MutableFrameFormat result = new MutableFrameFormat(FrameFormat.TYPE_BYTE, target);
|
||||
result.setDimensions(width, height);
|
||||
result.setBytesPerSample(bytesPerSample);
|
||||
result.setMetaValue(COLORSPACE_KEY, colorspace);
|
||||
if (target == FrameFormat.TARGET_SIMPLE) {
|
||||
result.setObjectClass(Bitmap.class);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static MutableFrameFormat create(int width,
|
||||
int height,
|
||||
int colorspace,
|
||||
int target) {
|
||||
return create(width,
|
||||
height,
|
||||
colorspace,
|
||||
bytesPerSampleForColorspace(colorspace),
|
||||
target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat create(int colorspace, int target) {
|
||||
return create(FrameFormat.SIZE_UNSPECIFIED,
|
||||
FrameFormat.SIZE_UNSPECIFIED,
|
||||
colorspace,
|
||||
bytesPerSampleForColorspace(colorspace),
|
||||
target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat create(int colorspace) {
|
||||
return create(FrameFormat.SIZE_UNSPECIFIED,
|
||||
FrameFormat.SIZE_UNSPECIFIED,
|
||||
colorspace,
|
||||
bytesPerSampleForColorspace(colorspace),
|
||||
FrameFormat.TARGET_UNSPECIFIED);
|
||||
}
|
||||
|
||||
public static int bytesPerSampleForColorspace(int colorspace) {
|
||||
switch (colorspace) {
|
||||
case COLORSPACE_GRAY:
|
||||
return 1;
|
||||
case COLORSPACE_RGB:
|
||||
return 3;
|
||||
case COLORSPACE_RGBA:
|
||||
return 4;
|
||||
case COLORSPACE_YUV:
|
||||
return 3;
|
||||
default:
|
||||
throw new RuntimeException("Unknown colorspace id " + colorspace + "!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.format;
|
||||
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.MutableFrameFormat;
|
||||
import android.filterfw.core.NativeBuffer;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ObjectFormat {
|
||||
|
||||
public static MutableFrameFormat fromClass(Class clazz, int count, int target) {
|
||||
// Create frame format
|
||||
MutableFrameFormat result = new MutableFrameFormat(FrameFormat.TYPE_OBJECT, target);
|
||||
result.setObjectClass(getBoxedClass(clazz));
|
||||
if (count != FrameFormat.SIZE_UNSPECIFIED) {
|
||||
result.setDimensions(count);
|
||||
}
|
||||
result.setBytesPerSample(bytesPerSampleForClass(clazz, target));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static MutableFrameFormat fromClass(Class clazz, int target) {
|
||||
return fromClass(clazz, FrameFormat.SIZE_UNSPECIFIED, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat fromObject(Object object, int target) {
|
||||
return object == null
|
||||
? new MutableFrameFormat(FrameFormat.TYPE_OBJECT, target)
|
||||
: fromClass(object.getClass(), FrameFormat.SIZE_UNSPECIFIED, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat fromObject(Object object, int count, int target) {
|
||||
return object == null
|
||||
? new MutableFrameFormat(FrameFormat.TYPE_OBJECT, target)
|
||||
: fromClass(object.getClass(), count, target);
|
||||
}
|
||||
|
||||
private static int bytesPerSampleForClass(Class clazz, int target) {
|
||||
// Native targets have objects manifested in a byte buffer. Thus it is important to
|
||||
// correctly determine the size of single element here.
|
||||
if (target == FrameFormat.TARGET_NATIVE) {
|
||||
if (!NativeBuffer.class.isAssignableFrom(clazz)) {
|
||||
throw new IllegalArgumentException("Native object-based formats must be of a " +
|
||||
"NativeBuffer subclass! (Received class: " + clazz + ").");
|
||||
}
|
||||
try {
|
||||
return ((NativeBuffer)clazz.newInstance()).getElementSize();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not determine the size of an element in a "
|
||||
+ "native object-based frame of type " + clazz + "! Perhaps it is missing a "
|
||||
+ "default constructor?");
|
||||
}
|
||||
} else {
|
||||
return FrameFormat.BYTES_PER_SAMPLE_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class getBoxedClass(Class type) {
|
||||
// Check if type is primitive
|
||||
if (type.isPrimitive()) {
|
||||
// Yes -> box it
|
||||
if (type == boolean.class) {
|
||||
return java.lang.Boolean.class;
|
||||
} else if (type == byte.class) {
|
||||
return java.lang.Byte.class;
|
||||
} else if (type == char.class) {
|
||||
return java.lang.Character.class;
|
||||
} else if (type == short.class) {
|
||||
return java.lang.Short.class;
|
||||
} else if (type == int.class) {
|
||||
return java.lang.Integer.class;
|
||||
} else if (type == long.class) {
|
||||
return java.lang.Long.class;
|
||||
} else if (type == float.class) {
|
||||
return java.lang.Float.class;
|
||||
} else if (type == double.class) {
|
||||
return java.lang.Double.class;
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unknown primitive type: " + type.getSimpleName() + "!");
|
||||
}
|
||||
} else {
|
||||
// No -> return it
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.format;
|
||||
|
||||
import android.filterfw.core.FrameFormat;
|
||||
import android.filterfw.core.MutableFrameFormat;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class PrimitiveFormat {
|
||||
|
||||
public static MutableFrameFormat createByteFormat(int count, int target) {
|
||||
return createFormat(FrameFormat.TYPE_BYTE, count, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createInt16Format(int count, int target) {
|
||||
return createFormat(FrameFormat.TYPE_INT16, count, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createInt32Format(int count, int target) {
|
||||
return createFormat(FrameFormat.TYPE_INT32, count, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createFloatFormat(int count, int target) {
|
||||
return createFormat(FrameFormat.TYPE_FLOAT, count, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createDoubleFormat(int count, int target) {
|
||||
return createFormat(FrameFormat.TYPE_DOUBLE, count, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createByteFormat(int target) {
|
||||
return createFormat(FrameFormat.TYPE_BYTE, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createInt16Format(int target) {
|
||||
return createFormat(FrameFormat.TYPE_INT16, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createInt32Format(int target) {
|
||||
return createFormat(FrameFormat.TYPE_INT32, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createFloatFormat(int target) {
|
||||
return createFormat(FrameFormat.TYPE_FLOAT, target);
|
||||
}
|
||||
|
||||
public static MutableFrameFormat createDoubleFormat(int target) {
|
||||
return createFormat(FrameFormat.TYPE_DOUBLE, target);
|
||||
}
|
||||
|
||||
private static MutableFrameFormat createFormat(int baseType, int count, int target) {
|
||||
MutableFrameFormat result = new MutableFrameFormat(baseType, target);
|
||||
result.setDimensions(count);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MutableFrameFormat createFormat(int baseType, int target) {
|
||||
MutableFrameFormat result = new MutableFrameFormat(baseType, target);
|
||||
result.setDimensionCount(1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
package android.filterfw.format;
|
||||
113
media/mca/filterfw/java/android/filterfw/geometry/Point.java
Normal file
113
media/mca/filterfw/java/android/filterfw/geometry/Point.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.geometry;
|
||||
|
||||
import java.lang.Math;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class Point {
|
||||
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public Point() {
|
||||
}
|
||||
|
||||
public Point(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public boolean IsInUnitRange() {
|
||||
return x >= 0.0f && x <= 1.0f &&
|
||||
y >= 0.0f && y <= 1.0f;
|
||||
}
|
||||
|
||||
public Point plus(float x, float y) {
|
||||
return new Point(this.x + x, this.y + y);
|
||||
}
|
||||
|
||||
public Point plus(Point point) {
|
||||
return this.plus(point.x, point.y);
|
||||
}
|
||||
|
||||
public Point minus(float x, float y) {
|
||||
return new Point(this.x - x, this.y - y);
|
||||
}
|
||||
|
||||
public Point minus(Point point) {
|
||||
return this.minus(point.x, point.y);
|
||||
}
|
||||
|
||||
public Point times(float s) {
|
||||
return new Point(this.x * s, this.y * s);
|
||||
}
|
||||
|
||||
public Point mult(float x, float y) {
|
||||
return new Point(this.x * x, this.y * y);
|
||||
}
|
||||
|
||||
public float length() {
|
||||
return (float)Math.sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
public float distanceTo(Point p) {
|
||||
return p.minus(this).length();
|
||||
}
|
||||
|
||||
public Point scaledTo(float length) {
|
||||
return this.times(length / this.length());
|
||||
}
|
||||
|
||||
public Point normalize() {
|
||||
return this.scaledTo(1.0f);
|
||||
}
|
||||
|
||||
public Point rotated90(int count) {
|
||||
float nx = this.x;
|
||||
float ny = this.y;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
float ox = nx;
|
||||
nx = ny;
|
||||
ny = -ox;
|
||||
}
|
||||
return new Point(nx, ny);
|
||||
}
|
||||
|
||||
public Point rotated(float radians) {
|
||||
// TODO(renn): Optimize: Keep cache of cos/sin values
|
||||
return new Point((float)(Math.cos(radians) * x - Math.sin(radians) * y),
|
||||
(float)(Math.sin(radians) * x + Math.cos(radians) * y));
|
||||
}
|
||||
|
||||
public Point rotatedAround(Point center, float radians) {
|
||||
return this.minus(center).rotated(radians).plus(center);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + y + ")";
|
||||
}
|
||||
}
|
||||
94
media/mca/filterfw/java/android/filterfw/geometry/Quad.java
Normal file
94
media/mca/filterfw/java/android/filterfw/geometry/Quad.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.geometry;
|
||||
|
||||
import android.filterfw.geometry.Point;
|
||||
|
||||
import java.lang.Float;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class Quad {
|
||||
|
||||
public Point p0;
|
||||
public Point p1;
|
||||
public Point p2;
|
||||
public Point p3;
|
||||
|
||||
public Quad() {
|
||||
}
|
||||
|
||||
public Quad(Point p0, Point p1, Point p2, Point p3) {
|
||||
this.p0 = p0;
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.p3 = p3;
|
||||
}
|
||||
|
||||
public boolean IsInUnitRange() {
|
||||
return p0.IsInUnitRange() &&
|
||||
p1.IsInUnitRange() &&
|
||||
p2.IsInUnitRange() &&
|
||||
p3.IsInUnitRange();
|
||||
}
|
||||
|
||||
public Quad translated(Point t) {
|
||||
return new Quad(p0.plus(t), p1.plus(t), p2.plus(t), p3.plus(t));
|
||||
}
|
||||
|
||||
public Quad translated(float x, float y) {
|
||||
return new Quad(p0.plus(x, y), p1.plus(x, y), p2.plus(x, y), p3.plus(x, y));
|
||||
}
|
||||
|
||||
public Quad scaled(float s) {
|
||||
return new Quad(p0.times(s), p1.times(s), p2.times(s), p3.times(s));
|
||||
}
|
||||
|
||||
public Quad scaled(float x, float y) {
|
||||
return new Quad(p0.mult(x, y), p1.mult(x, y), p2.mult(x, y), p3.mult(x, y));
|
||||
}
|
||||
|
||||
public Rectangle boundingBox() {
|
||||
List<Float> xs = Arrays.asList(p0.x, p1.x, p2.x, p3.x);
|
||||
List<Float> ys = Arrays.asList(p0.y, p1.y, p2.y, p3.y);
|
||||
float x0 = Collections.min(xs);
|
||||
float y0 = Collections.min(ys);
|
||||
float x1 = Collections.max(xs);
|
||||
float y1 = Collections.max(ys);
|
||||
return new Rectangle(x0, y0, x1 - x0, y1 - y0);
|
||||
}
|
||||
|
||||
public float getBoundingWidth() {
|
||||
List<Float> xs = Arrays.asList(p0.x, p1.x, p2.x, p3.x);
|
||||
return Collections.max(xs) - Collections.min(xs);
|
||||
}
|
||||
|
||||
public float getBoundingHeight() {
|
||||
List<Float> ys = Arrays.asList(p0.y, p1.y, p2.y, p3.y);
|
||||
return Collections.max(ys) - Collections.min(ys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + p0 + ", " + p1 + ", " + p2 + ", " + p3 + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.geometry;
|
||||
|
||||
import android.filterfw.geometry.Point;
|
||||
import android.filterfw.geometry.Quad;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class Rectangle extends Quad {
|
||||
|
||||
public Rectangle() {
|
||||
}
|
||||
|
||||
public Rectangle(float x, float y, float width, float height) {
|
||||
super(new Point(x, y),
|
||||
new Point(x + width, y),
|
||||
new Point(x, y + height),
|
||||
new Point(x + width, y + height));
|
||||
}
|
||||
|
||||
public Rectangle(Point origin, Point size) {
|
||||
super(origin,
|
||||
origin.plus(size.x, 0.0f),
|
||||
origin.plus(0.0f, size.y),
|
||||
origin.plus(size.x, size.y));
|
||||
}
|
||||
|
||||
public static Rectangle fromRotatedRect(Point center, Point size, float rotation) {
|
||||
Point p0 = new Point(center.x - size.x/2f, center.y - size.y/2f);
|
||||
Point p1 = new Point(center.x + size.x/2f, center.y - size.y/2f);
|
||||
Point p2 = new Point(center.x - size.x/2f, center.y + size.y/2f);
|
||||
Point p3 = new Point(center.x + size.x/2f, center.y + size.y/2f);
|
||||
return new Rectangle(p0.rotatedAround(center, rotation),
|
||||
p1.rotatedAround(center, rotation),
|
||||
p2.rotatedAround(center, rotation),
|
||||
p3.rotatedAround(center, rotation));
|
||||
}
|
||||
|
||||
private Rectangle(Point p0, Point p1, Point p2, Point p3) {
|
||||
super(p0, p1, p2, p3);
|
||||
}
|
||||
|
||||
public static Rectangle fromCenterVerticalAxis(Point center, Point vAxis, Point size) {
|
||||
Point dy = vAxis.scaledTo(size.y / 2.0f);
|
||||
Point dx = vAxis.rotated90(1).scaledTo(size.x / 2.0f);
|
||||
return new Rectangle(center.minus(dx).minus(dy),
|
||||
center.plus(dx).minus(dy),
|
||||
center.minus(dx).plus(dy),
|
||||
center.plus(dx).plus(dy));
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return p1.minus(p0).length();
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return p2.minus(p0).length();
|
||||
}
|
||||
|
||||
public Point center() {
|
||||
return p0.plus(p1).plus(p2).plus(p3).times(0.25f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle scaled(float s) {
|
||||
return new Rectangle(p0.times(s), p1.times(s), p2.times(s), p3.times(s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle scaled(float x, float y) {
|
||||
return new Rectangle(p0.mult(x, y), p1.mult(x, y), p2.mult(x, y), p3.mult(x, y));
|
||||
}
|
||||
|
||||
//public Rectangle rotated(float radians) {
|
||||
// TODO: Implement this.
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
package android.filterfw.geometry;
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.filterfw.io;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class GraphIOException extends Exception {
|
||||
|
||||
public GraphIOException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public GraphIOException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user