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