import android.filterfw.core.FilterContext;
import android.filterfw.core.Frame;
import android.filterfw.core.FrameFormat;
+import android.filterfw.core.GenerateFieldPort;
import android.filterfw.core.GenerateFinalPort;
-import android.filterfw.core.KeyValueMap;
-// TODO: Rename to FixedFrameSource and also add a (dynamic) FrameSource?
/**
* @hide
*/
-public class StaticFrameFilter extends Filter {
+public class FrameSource extends Filter {
- @GenerateFinalPort(name = "frame")
- private Frame mFrame;
+ @GenerateFinalPort(name = "format")
+ private FrameFormat mFormat;
- public StaticFrameFilter(String name) {
+ @GenerateFieldPort(name = "frame", hasDefault = true)
+ private Frame mFrame = null;
+
+ @GenerateFieldPort(name = "repeatFrame", hasDefault = true)
+ private boolean mRepeatFrame = false;
+
+ public FrameSource(String name) {
super(name);
}
@Override
public void setupPorts() {
- addOutputPort("frame", mFrame.getFormat());
+ addOutputPort("frame", mFormat);
}
@Override
public void process(FilterContext context) {
- // Push output
- pushOutput("frame", mFrame);
-
- // Close output port as we are done here
- closeOutputPort("frame");
+ if (mFrame != null) {
+ // Push output
+ pushOutput("frame", mFrame);
+ }
+
+ if (!mRepeatFrame) {
+ // Close output port as we are done here
+ closeOutputPort("frame");
+ }
}
}
package android.filterpacks.base;
-import android.content.Context;
-import android.content.res.Resources;
-
import android.filterfw.core.Filter;
import android.filterfw.core.FilterContext;
import android.filterfw.core.Frame;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.Set;
-
-import android.util.Log;
/**
* @hide
*/
-public class FileReadFilter extends Filter {
+public class InputStreamSource extends Filter {
@GenerateFinalPort(name = "target")
private String mTarget;
- @GenerateFieldPort(name = "context")
- private Context mActivityContext;
-
- @GenerateFieldPort(name = "format")
- private FrameFormat mFrameFormat;
-
- // TODO: Split this into two (subclass) filters: FileReadFilter and ResourceReadFilter.
- @GenerateFieldPort(name = "resourceId", hasDefault = true)
- private int mResourceId = -1;
-
- @GenerateFieldPort(name = "fileName", hasDefault = true)
- private String mFileInputName;
-
- private final int FILE_MODE_FILE = 0;
- private final int FILE_MODE_RESOURCE = 1;
-
- private MutableFrameFormat mOutputFormat;
-
+ @GenerateFieldPort(name = "stream")
private InputStream mInputStream;
- private int mFileMode = FILE_MODE_FILE;
- public FileReadFilter(String name) {
+ @GenerateFinalPort(name = "format", hasDefault = true)
+ private MutableFrameFormat mOutputFormat = null;
+
+ public InputStreamSource(String name) {
super(name);
}
@Override
public void setupPorts() {
int target = FrameFormat.readTargetString(mTarget);
- mOutputFormat = PrimitiveFormat.createByteFormat(target);
- addOutputPort("data", mOutputFormat);
- }
-
- @Override
- public void open(FilterContext context) {
- // Read file input parameter
- if (mFileInputName != null) {
- mFileMode = FILE_MODE_FILE;
- } else if (mResourceId >= 0) {
- mFileMode = FILE_MODE_RESOURCE;
- } else {
- throw new RuntimeException("No input file specified! Please set fileName or resourceId!");
- }
-
- // Open the file
- try {
- switch (mFileMode) {
- case FILE_MODE_FILE:
- mInputStream = mActivityContext.openFileInput(mFileInputName);
- break;
- case FILE_MODE_RESOURCE:
- mInputStream = mActivityContext.getResources().openRawResource(mResourceId);
- break;
- }
- Log.i("FileReadFilter", "InputStream = " + mInputStream);
- } catch (FileNotFoundException exception) {
- throw new RuntimeException("FileReader: Could not open file: " + mFileInputName + "!");
+ if (mOutputFormat == null) {
+ mOutputFormat = PrimitiveFormat.createByteFormat(target);
}
+ addOutputPort("data", mOutputFormat);
}
@Override
}
byteBuffer = ByteBuffer.wrap(byteStream.toByteArray());
} catch (IOException exception) {
- throw new RuntimeException("FileReader: Could not read from file: " +
- mFileInputName + "!");
+ throw new RuntimeException(
+ "InputStreamSource: Could not read stream: " + exception.getMessage() + "!");
}
// Put it into a frame
try {
mInputStream.close();
} catch (IOException exception) {
- throw new RuntimeException("FileReader: Could not close file!");
+ throw new RuntimeException("InputStreamSource: Could not close stream!");
}
}
}
import android.filterfw.core.Frame;
import android.filterfw.core.FrameFormat;
import android.filterfw.core.GenerateFieldPort;
+import android.filterfw.core.GenerateFinalPort;
import android.filterfw.core.MutableFrameFormat;
import android.filterfw.format.ObjectFormat;
@GenerateFieldPort(name = "object")
private Object mObject;
+ @GenerateFinalPort(name = "format", hasDefault = true)
+ private FrameFormat mOutputFormat = FrameFormat.unspecified();
+
@GenerateFieldPort(name = "repeatFrame", hasDefault = true)
boolean mRepeatFrame = false;
@Override
public void setupPorts() {
- addOutputPort("frame", FrameFormat.unspecified());
+ addOutputPort("frame", mOutputFormat);
}
@Override
package android.filterpacks.base;
-import android.content.Context;
-
import android.filterfw.core.Filter;
import android.filterfw.core.FilterContext;
import android.filterfw.core.Frame;
import android.filterfw.core.FrameFormat;
-import android.filterfw.core.KeyValueMap;
import android.filterfw.core.GenerateFieldPort;
-import java.io.BufferedOutputStream;
-import java.io.FileOutputStream;
-import java.io.FileNotFoundException;
+import java.io.OutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.util.Set;
/**
* @hide
*/
-public class FileWriteFilter extends Filter {
-
- @GenerateFieldPort(name = "fileName")
- private String mOutputName;
-
- @GenerateFieldPort(name = "context")
- private Context mActivityContext;
+public class OutputStreamTarget extends Filter {
- private BufferedOutputStream mWriter;
+ @GenerateFieldPort(name = "stream")
+ private OutputStream mOutputStream;
- public FileWriteFilter(String name) {
+ public OutputStreamTarget(String name) {
super(name);
}
}
@Override
- public void fieldPortValueUpdated(String name, FilterContext context) {
- if (isOpen()) {
- throw new RuntimeException("Cannot update parameters while filter is open!");
- }
- }
-
- @Override
- public void open(FilterContext context) {
- FileOutputStream outStream = null;
- try {
- outStream = mActivityContext.openFileOutput(mOutputName, Context.MODE_PRIVATE);
- } catch (FileNotFoundException exception) {
- throw new RuntimeException("FileWriter: Could not open file: " + mOutputName + ": " +
- exception.getMessage());
- }
- mWriter = new BufferedOutputStream(outStream);
- }
-
- @Override
public void process(FilterContext context) {
Frame input = pullInput("data");
ByteBuffer data;
data = input.getData();
}
try {
- mWriter.write(data.array(), 0, data.limit());
- mWriter.flush();
+ mOutputStream.write(data.array(), 0, data.limit());
+ mOutputStream.flush();
} catch (IOException exception) {
- throw new RuntimeException("FileWriter: Could not write to file: " + mOutputName + "!");
+ throw new RuntimeException(
+ "OutputStreamTarget: Could not write to stream: " + exception.getMessage() + "!");
}
}
@Override
public void close(FilterContext context) {
try {
- mWriter.close();
+ mOutputStream.close();
} catch (IOException exception) {
- throw new RuntimeException("FileWriter: Could not close file!");
+ throw new RuntimeException("OutputStreamTarget: Could not close stream!");
}
}
}
}
// Make sure GL environment is active
- if (mFilterContext.getGLEnvironment() != null) {
- mFilterContext.getGLEnvironment().activate();
+ boolean didActivateGLEnv = false;
+ GLEnvironment glEnv = mFilterContext.getGLEnvironment();
+ if (glEnv != null && !glEnv.isActive()) {
+ glEnv.activate();
+ didActivateGLEnv = true;
}
// Setup the inputs
result = mResultHolders[0].pullFrame();
}
+ // Deactivate GL environment if activated
+ if (didActivateGLEnv) {
+ glEnv.deactivate();
+ }
+
return result;
}
using android::filterfw::GLFrame;
using android::filterfw::NativeFrame;
+// Helper functions ////////////////////////////////////////////////////////////////////////////////
+void ConvertFloatsToRGBA(const float* floats, int length, uint8_t* result) {
+ for (int i = 0; i < length; ++i) {
+ result[i] = static_cast<uint8_t>(floats[i] * 255.0);
+ }
+}
+
+void ConvertRGBAToFloats(const uint8_t* rgba, int length, float* result) {
+ for (int i = 0; i < length; ++i) {
+ result[i] = rgba[i] / 255.0;
+ }
+}
+
+void ConvertIntsToRGBA(const int* ints, int length, uint8_t* result) {
+ for (int i = 0; i < length; ++i) {
+ result[i] = static_cast<uint8_t>(ints[i]);
+ }
+}
+
+void ConvertRGBAToInts(const uint8_t* rgba, int length, int* result) {
+ for (int i = 0; i < length; ++i) {
+ result[i] = rgba[i];
+ }
+}
+// GLFrame JNI implementation //////////////////////////////////////////////////////////////////////
jboolean Java_android_filterfw_core_GLFrame_allocate(JNIEnv* env,
jobject thiz,
jint width,
}
jboolean Java_android_filterfw_core_GLFrame_setNativeData(JNIEnv* env,
- jobject thiz,
- jbyteArray data,
- jint offset,
- jint length) {
+ jobject thiz,
+ jbyteArray data,
+ jint offset,
+ jint length) {
GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
if (frame && data) {
jbyte* bytes = env->GetByteArrayElements(data, NULL);
jint* int_ptr = env->GetIntArrayElements(ints, NULL);
const int length = env->GetArrayLength(ints);
if (int_ptr) {
- const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(int_ptr),
- length * sizeof(jint));
+ // Convert ints to RGBA buffer
+ uint8_t* rgba_buffer = new uint8_t[length];
+ ConvertIntsToRGBA(int_ptr, length, rgba_buffer);
env->ReleaseIntArrayElements(ints, int_ptr, JNI_ABORT);
+
+ // Write RGBA buffer to frame
+ const bool success = frame->WriteData(rgba_buffer, length);
+
+ // Clean-up
+ delete[] rgba_buffer;
return ToJBool(success);
}
}
jintArray Java_android_filterfw_core_GLFrame_getNativeInts(JNIEnv* env, jobject thiz) {
GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
- if (frame && frame->Size() > 0 && (frame->Size() % sizeof(jint) == 0)) {
- jintArray result = env->NewIntArray(frame->Size() / sizeof(jint));
- jint* data = env->GetIntArrayElements(result, NULL);
- frame->CopyDataTo(reinterpret_cast<uint8_t*>(data), frame->Size());
- env->ReleaseIntArrayElements(result, data, 0);
+ if (frame && frame->Size() > 0) {
+ // Create the result array
+ jintArray result = env->NewIntArray(frame->Size());
+ jint* int_array = env->GetIntArrayElements(result, NULL);
+
+ // Read the frame pixels
+ uint8_t* pixels = new uint8_t[frame->Size()];
+ frame->CopyDataTo(pixels, frame->Size());
+
+ // Convert them to integers
+ ConvertRGBAToInts(pixels, frame->Size(), int_array);
+
+ // Clean-up
+ delete[] pixels;
+ env->ReleaseIntArrayElements(result, int_array, 0);
return result;
}
return NULL;
jfloat* float_ptr = env->GetFloatArrayElements(floats, NULL);
const int length = env->GetArrayLength(floats);
if (float_ptr) {
- const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(float_ptr),
- length * sizeof(jfloat));
+ // Convert floats to RGBA buffer
+ uint8_t* rgba_buffer = new uint8_t[length];
+ ConvertFloatsToRGBA(float_ptr, length, rgba_buffer);
env->ReleaseFloatArrayElements(floats, float_ptr, JNI_ABORT);
+
+ // Write RGBA buffer to frame
+ const bool success = frame->WriteData(rgba_buffer, length);
+
+ // Clean-up
+ delete[] rgba_buffer;
return ToJBool(success);
}
}
jfloatArray Java_android_filterfw_core_GLFrame_getNativeFloats(JNIEnv* env, jobject thiz) {
GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz);
- if (frame && frame->Size() > 0 && (frame->Size() % sizeof(jfloat) == 0)) {
- jfloatArray result = env->NewFloatArray(frame->Size() / sizeof(jfloat));
- jfloat* data = env->GetFloatArrayElements(result, NULL);
- frame->CopyDataTo(reinterpret_cast<uint8_t*>(data), frame->Size());
- env->ReleaseFloatArrayElements(result, data, 0);
+ if (frame && frame->Size() > 0) {
+ // Create the result array
+ jfloatArray result = env->NewFloatArray(frame->Size());
+ jfloat* float_array = env->GetFloatArrayElements(result, NULL);
+
+ // Read the frame pixels
+ uint8_t* pixels = new uint8_t[frame->Size()];
+ frame->CopyDataTo(pixels, frame->Size());
+
+ // Convert them to floats
+ ConvertRGBAToFloats(pixels, frame->Size(), float_array);
+
+ // Clean-up
+ delete[] pixels;
+ env->ReleaseFloatArrayElements(result, float_array, 0);
return result;
}
return NULL;
import android.filterfw.core.NativeFrame;
import android.filterfw.format.ImageFormat;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
/**
* @hide
*/
-public class ImageDecoder extends Filter {
+public class BitmapSource extends Filter {
@GenerateFinalPort(name = "target")
String mTargetString;
- @GenerateFieldPort(name = "resourceName")
- String mResourceName;
-
- @GenerateFieldPort(name = "context")
- Context mContext;
+ @GenerateFieldPort(name = "bitmap")
+ private Bitmap mBitmap;
@GenerateFieldPort(name = "repeatFrame", hasDefault = true)
boolean mRepeatFrame = false;
private int mTarget;
private Frame mImageFrame;
- public ImageDecoder(String name) {
+ public BitmapSource(String name) {
super(name);
}
}
public void loadImage(FilterContext filterContext) {
- // Load image
- int resourceId = mContext.getResources().getIdentifier(mResourceName,
- null,
- mContext.getPackageName());
- Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), resourceId);
-
- // Wrap in frame
- FrameFormat outputFormat = ImageFormat.create(bitmap.getWidth(),
- bitmap.getHeight(),
+ FrameFormat outputFormat = ImageFormat.create(mBitmap.getWidth(),
+ mBitmap.getHeight(),
ImageFormat.COLORSPACE_RGBA,
mTarget);
mImageFrame = filterContext.getFrameManager().newFrame(outputFormat);
- mImageFrame.setBitmap(bitmap);
+ mImageFrame.setBitmap(mBitmap);
+ mBitmap = null;
}
@Override
public void fieldPortValueUpdated(String name, FilterContext context) {
// Clear image (to trigger reload) in case parameters have been changed
- if (name.equals("resourceName") || name.equals("context")) {
+ if (name.equals("bitmap") || name.equals("target")) {
if (mImageFrame != null) {
mImageFrame.release();
mImageFrame = null;
import android.util.Log;
-import java.io.FileOutputStream;
-import java.io.BufferedOutputStream;
-import java.io.FileNotFoundException;
+import java.io.OutputStream;
import java.io.IOException;
/**
*/
public class ImageEncoder extends Filter {
- @GenerateFieldPort(name = "fileName")
- private String mOutputName;
+ @GenerateFieldPort(name = "stream")
+ private OutputStream mOutputStream;
- @GenerateFieldPort(name = "context")
- private Context mContext;
+ @GenerateFieldPort(name = "quality", hasDefault = true)
+ private int mQuality = 80;
public ImageEncoder(String name) {
super(name);
public void process(FilterContext env) {
Frame input = pullInput("image");
Bitmap bitmap = input.getBitmap();
- FileOutputStream outStream = null;
-
- try {
- outStream = mContext.openFileOutput(mOutputName, Context.MODE_PRIVATE);
- } catch (FileNotFoundException exception) {
- throw new RuntimeException("ImageEncoder: Could not open file: " + mOutputName + "!");
- }
-
- BufferedOutputStream bufferedStream = new BufferedOutputStream(outStream);
- bitmap.compress(CompressFormat.JPEG, 80, bufferedStream);
-
- try {
- bufferedStream.flush();
- bufferedStream.close();
- } catch (IOException exception) {
- throw new RuntimeException("ImageEncoder: Could not write to file: " +
- mOutputName + "!");
- }
+ bitmap.compress(CompressFormat.JPEG, mQuality, mOutputStream);
}
}
// See if we need to copy to GPU
Frame gpuFrame = null;
if (mLogVerbose) Log.v("SurfaceRenderFilter", "Got input format: " + input.getFormat());
- if (input.getFormat().getTarget() == FrameFormat.TARGET_NATIVE) {
- MutableFrameFormat gpuFormat = input.getFormat().mutableCopy();
- gpuFormat.setTarget(FrameFormat.TARGET_GPU);
- gpuFrame = context.getFrameManager().newFrame(gpuFormat);
- gpuFrame.setData(input.getData());
+ int target = input.getFormat().getTarget();
+ if (target != FrameFormat.TARGET_GPU) {
+ gpuFrame = context.getFrameManager().duplicateFrameToTarget(input,
+ FrameFormat.TARGET_GPU);
createdFrame = true;
} else {
gpuFrame = input;