SurfaceTexture.cpp revision b550929b7a4b0d5f9645a7a1ebf287d3f13cf1af
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "SurfaceTexture"
18
19#include <stdio.h>
20
21#include <gui/GLConsumer.h>
22#include <gui/Surface.h>
23
24#include <android_runtime/AndroidRuntime.h>
25
26#include <utils/Log.h>
27#include <utils/misc.h>
28
29#include "jni.h"
30#include "JNIHelp.h"
31
32// ----------------------------------------------------------------------------
33
34namespace android {
35
36static const char* const OutOfResourcesException =
37    "android/graphics/SurfaceTexture$OutOfResourcesException";
38static const char* const IllegalStateException = "java/lang/IllegalStateException";
39const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
40
41struct fields_t {
42    jfieldID  surfaceTexture;
43    jfieldID  frameAvailableListener;
44    jmethodID postEvent;
45};
46static fields_t fields;
47
48// ----------------------------------------------------------------------------
49
50static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
51        const sp<GLConsumer>& surfaceTexture)
52{
53    GLConsumer* const p =
54        (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
55    if (surfaceTexture.get()) {
56        surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture);
57    }
58    if (p) {
59        p->decStrong((void*)SurfaceTexture_setSurfaceTexture);
60    }
61    env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
62}
63
64static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
65        jobject thiz, sp<GLConsumer::FrameAvailableListener> listener)
66{
67    GLConsumer::FrameAvailableListener* const p =
68        (GLConsumer::FrameAvailableListener*)
69            env->GetIntField(thiz, fields.frameAvailableListener);
70    if (listener.get()) {
71        listener->incStrong((void*)SurfaceTexture_setSurfaceTexture);
72    }
73    if (p) {
74        p->decStrong((void*)SurfaceTexture_setSurfaceTexture);
75    }
76    env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get());
77}
78
79sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env,
80        jobject thiz)
81{
82    return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
83}
84
85sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
86        JNIEnv* env, jobject thiz)
87{
88    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
89    sp<Surface> surfaceTextureClient(surfaceTexture != NULL ?
90            new Surface(surfaceTexture->getBufferQueue()) : NULL);
91    return surfaceTextureClient;
92}
93
94bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz)
95{
96    jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
97    return env->IsInstanceOf(thiz, surfaceTextureClass);
98}
99
100// ----------------------------------------------------------------------------
101
102class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener
103{
104public:
105    JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
106    virtual ~JNISurfaceTextureContext();
107    virtual void onFrameAvailable();
108
109private:
110    static JNIEnv* getJNIEnv(bool* needsDetach);
111    static void detachJNI();
112
113    jobject mWeakThiz;
114    jclass mClazz;
115};
116
117JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
118        jobject weakThiz, jclass clazz) :
119    mWeakThiz(env->NewGlobalRef(weakThiz)),
120    mClazz((jclass)env->NewGlobalRef(clazz))
121{}
122
123JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) {
124    *needsDetach = false;
125    JNIEnv* env = AndroidRuntime::getJNIEnv();
126    if (env == NULL) {
127        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
128        JavaVM* vm = AndroidRuntime::getJavaVM();
129        int result = vm->AttachCurrentThread(&env, (void*) &args);
130        if (result != JNI_OK) {
131            ALOGE("thread attach failed: %#x", result);
132            return NULL;
133        }
134        *needsDetach = true;
135    }
136    return env;
137}
138
139void JNISurfaceTextureContext::detachJNI() {
140    JavaVM* vm = AndroidRuntime::getJavaVM();
141    int result = vm->DetachCurrentThread();
142    if (result != JNI_OK) {
143        ALOGE("thread detach failed: %#x", result);
144    }
145}
146
147JNISurfaceTextureContext::~JNISurfaceTextureContext()
148{
149    bool needsDetach = false;
150    JNIEnv* env = getJNIEnv(&needsDetach);
151    if (env != NULL) {
152        env->DeleteGlobalRef(mWeakThiz);
153        env->DeleteGlobalRef(mClazz);
154    } else {
155        ALOGW("leaking JNI object references");
156    }
157    if (needsDetach) {
158        detachJNI();
159    }
160}
161
162void JNISurfaceTextureContext::onFrameAvailable()
163{
164    bool needsDetach = false;
165    JNIEnv* env = getJNIEnv(&needsDetach);
166    if (env != NULL) {
167        env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
168    } else {
169        ALOGW("onFrameAvailable event will not posted");
170    }
171    if (needsDetach) {
172        detachJNI();
173    }
174}
175
176// ----------------------------------------------------------------------------
177
178static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
179{
180    fields.surfaceTexture = env->GetFieldID(clazz,
181            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
182    if (fields.surfaceTexture == NULL) {
183        ALOGE("can't find android/graphics/SurfaceTexture.%s",
184                ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
185    }
186    fields.frameAvailableListener = env->GetFieldID(clazz,
187            ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "I");
188    if (fields.frameAvailableListener == NULL) {
189        ALOGE("can't find android/graphics/SurfaceTexture.%s",
190                ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID);
191    }
192
193    fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
194            "(Ljava/lang/Object;)V");
195    if (fields.postEvent == NULL) {
196        ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
197    }
198}
199
200static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
201        jobject weakThiz, jboolean allowSynchronous)
202{
203    sp<BufferQueue> bq = new BufferQueue(allowSynchronous);
204    sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName));
205    if (surfaceTexture == 0) {
206        jniThrowException(env, OutOfResourcesException,
207                "Unable to create native SurfaceTexture");
208        return;
209    }
210    SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
211
212    jclass clazz = env->GetObjectClass(thiz);
213    if (clazz == NULL) {
214        jniThrowRuntimeException(env,
215                "Can't find android/graphics/SurfaceTexture");
216        return;
217    }
218
219    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
220            clazz));
221    surfaceTexture->setFrameAvailableListener(ctx);
222    SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
223}
224
225static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
226{
227    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
228    surfaceTexture->setFrameAvailableListener(0);
229    SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
230    SurfaceTexture_setSurfaceTexture(env, thiz, 0);
231}
232
233static void SurfaceTexture_setDefaultBufferSize(
234        JNIEnv* env, jobject thiz, jint width, jint height)
235{
236    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
237    surfaceTexture->setDefaultBufferSize(width, height);
238}
239
240static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
241{
242    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
243    status_t err = surfaceTexture->updateTexImage();
244    if (err == INVALID_OPERATION) {
245        jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
246                "logcat for details)");
247    } else if (err < 0) {
248        jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
249    }
250}
251
252static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
253{
254    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
255    return surfaceTexture->detachFromContext();
256}
257
258static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
259{
260    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
261    return surfaceTexture->attachToContext((GLuint)tex);
262}
263
264static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
265        jfloatArray jmtx)
266{
267    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
268    float* mtx = env->GetFloatArrayElements(jmtx, NULL);
269    surfaceTexture->getTransformMatrix(mtx);
270    env->ReleaseFloatArrayElements(jmtx, mtx, 0);
271}
272
273static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
274{
275    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
276    return surfaceTexture->getTimestamp();
277}
278
279static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
280{
281    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
282    surfaceTexture->abandon();
283}
284
285// ----------------------------------------------------------------------------
286
287static JNINativeMethod gSurfaceTextureMethods[] = {
288    {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
289    {"nativeInit",                 "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
290    {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
291    {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
292    {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
293    {"nativeDetachFromGLContext",  "()I",   (void*)SurfaceTexture_detachFromGLContext },
294    {"nativeAttachToGLContext",    "(I)I",   (void*)SurfaceTexture_attachToGLContext },
295    {"nativeGetTransformMatrix",   "([F)V", (void*)SurfaceTexture_getTransformMatrix },
296    {"nativeGetTimestamp",         "()J",   (void*)SurfaceTexture_getTimestamp },
297    {"nativeRelease",              "()V",   (void*)SurfaceTexture_release },
298};
299
300int register_android_graphics_SurfaceTexture(JNIEnv* env)
301{
302    int err = 0;
303    err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
304            gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
305    return err;
306}
307
308} // namespace android
309