Merge "Implement SurfaceTexture frame-available callback." into honeycomb
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user