summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/android/graphics/SurfaceTexture.cpp124
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java67
-rw-r--r--include/gui/SurfaceTexture.h13
-rw-r--r--libs/gui/SurfaceTexture.cpp10
4 files changed, 177 insertions, 37 deletions
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index c1229f3..88de94f 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -25,8 +25,8 @@
#include <utils/Log.h>
#include <utils/misc.h>
-#include "android/graphics/GraphicsJNI.h"
#include "jni.h"
+#include "JNIHelp.h"
// ----------------------------------------------------------------------------
@@ -35,57 +35,127 @@ namespace android {
static const char* const OutOfResourcesException =
"android/graphics/SurfaceTexture$OutOfResourcesException";
-struct st_t {
- jfieldID surfaceTexture;
+struct fields_t {
+ jfieldID surfaceTexture;
+ jmethodID postEvent;
};
-static st_t st;
+static fields_t fields;
// ----------------------------------------------------------------------------
-static void setSurfaceTexture(JNIEnv* env, jobject clazz,
+static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
const sp<SurfaceTexture>& surfaceTexture)
{
SurfaceTexture* const p =
- (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture);
+ (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
if (surfaceTexture.get()) {
- surfaceTexture->incStrong(clazz);
+ surfaceTexture->incStrong(thiz);
}
if (p) {
- p->decStrong(clazz);
+ p->decStrong(thiz);
}
- env->SetIntField(clazz, st.surfaceTexture, (int)surfaceTexture.get());
+ env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
}
-sp<SurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
+sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz)
{
sp<SurfaceTexture> surfaceTexture(
- (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture));
+ (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture));
return surfaceTexture;
}
// ----------------------------------------------------------------------------
-static void SurfaceTexture_init(JNIEnv* env, jobject clazz, jint texName)
+class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
{
- sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+public:
+ JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
+ virtual ~JNISurfaceTextureContext();
+ virtual void onFrameAvailable();
+
+private:
+ jobject mWeakThiz;
+ jclass mClazz;
+};
+
+JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
+ jobject weakThiz, jclass clazz) :
+ mWeakThiz(env->NewGlobalRef(weakThiz)),
+ mClazz((jclass)env->NewGlobalRef(clazz))
+{}
+
+JNISurfaceTextureContext::~JNISurfaceTextureContext()
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mWeakThiz);
+ env->DeleteGlobalRef(mClazz);
+}
+
+void JNISurfaceTextureContext::onFrameAvailable()
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
+}
+
+// ----------------------------------------------------------------------------
+
+static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
+{
+ fields.surfaceTexture = env->GetFieldID(clazz,
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
+ if (fields.surfaceTexture == NULL) {
+ LOGE("can't find android/graphics/SurfaceTexture.%s",
+ ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
+ }
+
+ fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;)V");
+ if (fields.postEvent == NULL) {
+ LOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
+ }
+
+}
+static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
+ jobject weakThiz)
+{
+ sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
if (surfaceTexture == 0) {
- doThrow(env, OutOfResourcesException);
+ jniThrowException(env, OutOfResourcesException,
+ "Unable to create native SurfaceTexture");
+ return;
+ }
+ SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
+
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ jniThrowRuntimeException(env,
+ "Can't find android/graphics/SurfaceTexture");
return;
}
- setSurfaceTexture(env, clazz, surfaceTexture);
+
+ sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
+ clazz));
+ surfaceTexture->setFrameAvailableListener(ctx);
+}
+
+static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
+{
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ surfaceTexture->setFrameAvailableListener(0);
+ SurfaceTexture_setSurfaceTexture(env, thiz, 0);
}
-static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz)
+static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
{
- sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->updateTexImage();
}
-static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz,
+static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
jfloatArray jmtx)
{
- sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
float* mtx = env->GetFloatArrayElements(jmtx, NULL);
surfaceTexture->getTransformMatrix(mtx);
env->ReleaseFloatArrayElements(jmtx, mtx, 0);
@@ -94,21 +164,15 @@ static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz,
// ----------------------------------------------------------------------------
const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
-static void nativeClassInit(JNIEnv* env, jclass clazz);
static JNINativeMethod gSurfaceTextureMethods[] = {
- {"nativeClassInit", "()V", (void*)nativeClassInit },
- {"init", "(I)V", (void*)SurfaceTexture_init },
- {"updateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
- {"getTransformMatrixImpl", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
+ {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
+ {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init },
+ {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
+ {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
+ {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
};
-static void nativeClassInit(JNIEnv* env, jclass clazz)
-{
- st.surfaceTexture = env->GetFieldID(clazz,
- ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
-}
-
int register_android_graphics_SurfaceTexture(JNIEnv* env)
{
int err = 0;
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 3eb0b03..64c209a 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -16,6 +16,11 @@
package android.graphics;
+import java.lang.ref.WeakReference;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
/**
* Captures frames from an image stream as an OpenGL ES texture.
*
@@ -32,6 +37,9 @@ package android.graphics;
*/
public class SurfaceTexture {
+ private EventHandler mEventHandler;
+ private OnFrameAvailableListener mOnFrameAvailableListener;
+
@SuppressWarnings("unused")
private int mSurfaceTexture;
@@ -59,7 +67,15 @@ public class SurfaceTexture {
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*/
public SurfaceTexture(int texName) {
- init(texName);
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(looper);
+ } else {
+ mEventHandler = null;
+ }
+ nativeInit(texName, new WeakReference<SurfaceTexture>(this));
}
/**
@@ -69,7 +85,7 @@ public class SurfaceTexture {
* thread invoking the callback.
*/
public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
- // TODO: Implement this!
+ mOnFrameAvailableListener = l;
}
/**
@@ -77,8 +93,9 @@ public class SurfaceTexture {
* called while the OpenGL ES context that owns the texture is bound to the thread. It will
* implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
*/
- public native void updateTexImage();
-
+ public void updateTexImage() {
+ nativeUpdateTexImage();
+ }
/**
* Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
@@ -99,12 +116,48 @@ public class SurfaceTexture {
if (mtx.length != 16) {
throw new IllegalArgumentException();
}
- getTransformMatrixImpl(mtx);
+ nativeGetTransformMatrix(mtx);
}
- private native void getTransformMatrixImpl(float[] mtx);
+ protected void finalize() throws Throwable {
+ try {
+ nativeFinalize();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private class EventHandler extends Handler {
+ public EventHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mOnFrameAvailableListener != null) {
+ mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
+ }
+ return;
+ }
+ }
+
+ private static void postEventFromNative(Object selfRef) {
+ WeakReference weakSelf = (WeakReference)selfRef;
+ SurfaceTexture st = (SurfaceTexture)weakSelf.get();
+ if (st == null) {
+ return;
+ }
+
+ if (st.mEventHandler != null) {
+ Message m = st.mEventHandler.obtainMessage();
+ st.mEventHandler.sendMessage(m);
+ }
+ }
- private native void init(int texName);
+ private native void nativeInit(int texName, Object weakSelf);
+ private native void nativeFinalize();
+ private native void nativeGetTransformMatrix(float[] mtx);
+ private native void nativeUpdateTexImage();
/*
* We use a class initializer to allow the native code to cache some
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 002e48b..79c33f5 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -40,6 +40,10 @@ public:
enum { MIN_BUFFER_SLOTS = 3 };
enum { NUM_BUFFER_SLOTS = 32 };
+ struct FrameAvailableListener : public virtual RefBase {
+ virtual void onFrameAvailable() = 0;
+ };
+
// tex indicates the name OpenGL texture to which images are to be streamed.
// This texture name cannot be changed once the SurfaceTexture is created.
SurfaceTexture(GLuint tex);
@@ -93,6 +97,10 @@ public:
// functions.
void getTransformMatrix(float mtx[16]);
+ // setFrameAvailableListener sets the listener object that will be notified
+ // when a new frame becomes available.
+ void setFrameAvailableListener(const sp<FrameAvailableListener>& l);
+
private:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -195,6 +203,11 @@ private:
// to a buffer, but other processes do.
Vector<sp<GraphicBuffer> > mAllocdBuffers;
+ // mFrameAvailableListener is the listener object that will be called when a
+ // new frame becomes available. If it is not NULL it will be called from
+ // queueBuffer.
+ sp<FrameAvailableListener> mFrameAvailableListener;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 88f1728..1dadd53 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -166,6 +166,9 @@ status_t SurfaceTexture::queueBuffer(int buf) {
mLastQueued = buf;
mLastQueuedCrop = mNextCrop;
mLastQueuedTransform = mNextTransform;
+ if (mFrameAvailableListener != 0) {
+ mFrameAvailableListener->onFrameAvailable();
+ }
return OK;
}
@@ -294,6 +297,13 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) {
mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
}
+void SurfaceTexture::setFrameAvailableListener(
+ const sp<FrameAvailableListener>& l) {
+ LOGV("SurfaceTexture::setFrameAvailableListener");
+ Mutex::Autolock lock(mMutex);
+ mFrameAvailableListener = l;
+}
+
void SurfaceTexture::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].mGraphicBuffer = 0;