Merge "Implement SurfaceTexture frame-available callback." into honeycomb

This commit is contained in:
Jamie Gennis
2011-01-16 18:15:36 -08:00
committed by Android (Google) Code Review
4 changed files with 180 additions and 40 deletions

View File

@@ -25,8 +25,8 @@
#include <utils/Log.h> #include <utils/Log.h>
#include <utils/misc.h> #include <utils/misc.h>
#include "android/graphics/GraphicsJNI.h"
#include "jni.h" #include "jni.h"
#include "JNIHelp.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -35,57 +35,127 @@ namespace android {
static const char* const OutOfResourcesException = static const char* const OutOfResourcesException =
"android/graphics/SurfaceTexture$OutOfResourcesException"; "android/graphics/SurfaceTexture$OutOfResourcesException";
struct st_t { struct fields_t {
jfieldID surfaceTexture; 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) const sp<SurfaceTexture>& surfaceTexture)
{ {
SurfaceTexture* const p = SurfaceTexture* const p =
(SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture); (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
if (surfaceTexture.get()) { if (surfaceTexture.get()) {
surfaceTexture->incStrong(clazz); surfaceTexture->incStrong(thiz);
} }
if (p) { 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( sp<SurfaceTexture> surfaceTexture(
(SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture)); (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture));
return 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();
if (surfaceTexture == 0) { private:
doThrow(env, OutOfResourcesException); jobject mWeakThiz;
return; jclass mClazz;
} };
setSurfaceTexture(env, clazz, surfaceTexture);
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);
} }
static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz) void JNISurfaceTextureContext::onFrameAvailable()
{ {
sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz)); 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) {
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;
}
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 thiz)
{
sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->updateTexImage(); surfaceTexture->updateTexImage();
} }
static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz, static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
jfloatArray jmtx) jfloatArray jmtx)
{ {
sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz)); sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
float* mtx = env->GetFloatArrayElements(jmtx, NULL); float* mtx = env->GetFloatArrayElements(jmtx, NULL);
surfaceTexture->getTransformMatrix(mtx); surfaceTexture->getTransformMatrix(mtx);
env->ReleaseFloatArrayElements(jmtx, mtx, 0); env->ReleaseFloatArrayElements(jmtx, mtx, 0);
@@ -94,21 +164,15 @@ static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz,
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
static void nativeClassInit(JNIEnv* env, jclass clazz);
static JNINativeMethod gSurfaceTextureMethods[] = { static JNINativeMethod gSurfaceTextureMethods[] = {
{"nativeClassInit", "()V", (void*)nativeClassInit }, {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
{"init", "(I)V", (void*)SurfaceTexture_init }, {"nativeInit", "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init },
{"updateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
{"getTransformMatrixImpl", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, {"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 register_android_graphics_SurfaceTexture(JNIEnv* env)
{ {
int err = 0; int err = 0;

View File

@@ -16,6 +16,11 @@
package android.graphics; 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. * Captures frames from an image stream as an OpenGL ES texture.
* *
@@ -32,6 +37,9 @@ package android.graphics;
*/ */
public class SurfaceTexture { public class SurfaceTexture {
private EventHandler mEventHandler;
private OnFrameAvailableListener mOnFrameAvailableListener;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private int mSurfaceTexture; private int mSurfaceTexture;
@@ -59,7 +67,15 @@ public class SurfaceTexture {
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures) * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*/ */
public SurfaceTexture(int texName) { 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. * thread invoking the callback.
*/ */
public void setOnFrameAvailableListener(OnFrameAvailableListener l) { 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 * 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. * 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 * 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) { if (mtx.length != 16) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
getTransformMatrixImpl(mtx); nativeGetTransformMatrix(mtx);
} }
private native void getTransformMatrixImpl(float[] mtx); protected void finalize() throws Throwable {
try {
nativeFinalize();
} finally {
super.finalize();
}
}
private native void init(int texName); 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 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 * We use a class initializer to allow the native code to cache some

View File

@@ -40,6 +40,10 @@ public:
enum { MIN_BUFFER_SLOTS = 3 }; enum { MIN_BUFFER_SLOTS = 3 };
enum { NUM_BUFFER_SLOTS = 32 }; 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. // tex indicates the name OpenGL texture to which images are to be streamed.
// This texture name cannot be changed once the SurfaceTexture is created. // This texture name cannot be changed once the SurfaceTexture is created.
SurfaceTexture(GLuint tex); SurfaceTexture(GLuint tex);
@@ -93,6 +97,10 @@ public:
// functions. // functions.
void getTransformMatrix(float mtx[16]); 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: private:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -195,6 +203,11 @@ private:
// to a buffer, but other processes do. // to a buffer, but other processes do.
Vector<sp<GraphicBuffer> > mAllocdBuffers; 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 // mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the // variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed. // member variables are accessed.

View File

@@ -166,6 +166,9 @@ status_t SurfaceTexture::queueBuffer(int buf) {
mLastQueued = buf; mLastQueued = buf;
mLastQueuedCrop = mNextCrop; mLastQueuedCrop = mNextCrop;
mLastQueuedTransform = mNextTransform; mLastQueuedTransform = mNextTransform;
if (mFrameAvailableListener != 0) {
mFrameAvailableListener->onFrameAvailable();
}
return OK; return OK;
} }
@@ -294,6 +297,13 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) {
mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
} }
void SurfaceTexture::setFrameAvailableListener(
const sp<FrameAvailableListener>& l) {
LOGV("SurfaceTexture::setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
mFrameAvailableListener = l;
}
void SurfaceTexture::freeAllBuffers() { void SurfaceTexture::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].mGraphicBuffer = 0; mSlots[i].mGraphicBuffer = 0;