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/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();
if (surfaceTexture == 0) {
doThrow(env, OutOfResourcesException);
return;
}
setSurfaceTexture(env, clazz, surfaceTexture);
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);
}
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();
}
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;

View File

@@ -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 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

View File

@@ -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.

View File

@@ -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;