Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf18c478 authored by Jamie Gennis's avatar Jamie Gennis Committed by Android (Google) Code Review
Browse files

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

parents 41424ade 376590d6
Loading
Loading
Loading
Loading
+94 −30
Original line number Diff line number Diff line
@@ -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 {
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;
+60 −7
Original line number Diff line number Diff line
@@ -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);
    }

    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 native void getTransformMatrixImpl(float[] mtx);
    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
+13 −0
Original line number Diff line number Diff line
@@ -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.
+10 −0
Original line number Diff line number Diff line
@@ -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;