diff options
-rw-r--r-- | core/jni/android/graphics/SurfaceTexture.cpp | 124 | ||||
-rw-r--r-- | graphics/java/android/graphics/SurfaceTexture.java | 67 | ||||
-rw-r--r-- | include/gui/SurfaceTexture.h | 13 | ||||
-rw-r--r-- | libs/gui/SurfaceTexture.cpp | 10 |
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; |