SurfaceTexture.cpp revision b89d88f531ee39927f8f554baaae5ecc9101ba9d
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/SurfaceTexture.h>
22#include <gui/SurfaceTextureClient.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";
38const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
39
40struct fields_t {
41    jfieldID  surfaceTexture;
42    jmethodID postEvent;
43};
44static fields_t fields;
45
46// ----------------------------------------------------------------------------
47
48static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
49        const sp<SurfaceTexture>& surfaceTexture)
50{
51    SurfaceTexture* const p =
52        (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
53    if (surfaceTexture.get()) {
54        surfaceTexture->incStrong(thiz);
55    }
56    if (p) {
57        p->decStrong(thiz);
58    }
59    env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
60}
61
62sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz)
63{
64    sp<SurfaceTexture> surfaceTexture(
65        (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture));
66    return surfaceTexture;
67}
68
69sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
70        JNIEnv* env, jobject thiz)
71{
72    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
73    sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
74            new SurfaceTextureClient(surfaceTexture) : NULL);
75    return surfaceTextureClient;
76}
77
78bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz)
79{
80    jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
81    return env->IsInstanceOf(thiz, surfaceTextureClass);
82}
83
84// ----------------------------------------------------------------------------
85
86class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
87{
88public:
89    JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
90    virtual ~JNISurfaceTextureContext();
91    virtual void onFrameAvailable();
92
93private:
94    static JNIEnv* getJNIEnv(bool* needsDetach);
95    static void detachJNI();
96
97    jobject mWeakThiz;
98    jclass mClazz;
99};
100
101JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
102        jobject weakThiz, jclass clazz) :
103    mWeakThiz(env->NewGlobalRef(weakThiz)),
104    mClazz((jclass)env->NewGlobalRef(clazz))
105{}
106
107JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) {
108    *needsDetach = false;
109    JNIEnv* env = AndroidRuntime::getJNIEnv();
110    if (env == NULL) {
111        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
112        JavaVM* vm = AndroidRuntime::getJavaVM();
113        int result = vm->AttachCurrentThread(&env, (void*) &args);
114        if (result != JNI_OK) {
115            LOGE("thread attach failed: %#x", result);
116            return NULL;
117        }
118        *needsDetach = true;
119    }
120    return env;
121}
122
123void JNISurfaceTextureContext::detachJNI() {
124    JavaVM* vm = AndroidRuntime::getJavaVM();
125    int result = vm->DetachCurrentThread();
126    if (result != JNI_OK) {
127        LOGE("thread detach failed: %#x", result);
128    }
129}
130
131JNISurfaceTextureContext::~JNISurfaceTextureContext()
132{
133    bool needsDetach = false;
134    JNIEnv* env = getJNIEnv(&needsDetach);
135    if (env != NULL) {
136        env->DeleteGlobalRef(mWeakThiz);
137        env->DeleteGlobalRef(mClazz);
138    } else {
139        LOGW("leaking JNI object references");
140    }
141    if (needsDetach) {
142        detachJNI();
143    }
144}
145
146void JNISurfaceTextureContext::onFrameAvailable()
147{
148    bool needsDetach = false;
149    JNIEnv* env = getJNIEnv(&needsDetach);
150    if (env != NULL) {
151        env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
152    } else {
153        LOGW("onFrameAvailable event will not posted");
154    }
155    if (needsDetach) {
156        detachJNI();
157    }
158}
159
160// ----------------------------------------------------------------------------
161
162static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
163{
164    fields.surfaceTexture = env->GetFieldID(clazz,
165            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
166    if (fields.surfaceTexture == NULL) {
167        LOGE("can't find android/graphics/SurfaceTexture.%s",
168                ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
169    }
170
171    fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
172            "(Ljava/lang/Object;)V");
173    if (fields.postEvent == NULL) {
174        LOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
175    }
176}
177
178static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
179        jobject weakThiz, jboolean allowSynchronous)
180{
181    sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName, allowSynchronous));
182    if (surfaceTexture == 0) {
183        jniThrowException(env, OutOfResourcesException,
184                "Unable to create native SurfaceTexture");
185        return;
186    }
187    SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
188
189    jclass clazz = env->GetObjectClass(thiz);
190    if (clazz == NULL) {
191        jniThrowRuntimeException(env,
192                "Can't find android/graphics/SurfaceTexture");
193        return;
194    }
195
196    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
197            clazz));
198    surfaceTexture->setFrameAvailableListener(ctx);
199}
200
201static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
202{
203    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
204    surfaceTexture->setFrameAvailableListener(0);
205    SurfaceTexture_setSurfaceTexture(env, thiz, 0);
206}
207
208static void SurfaceTexture_setDefaultBufferSize(
209        JNIEnv* env, jobject thiz, jint width, jint height)
210{
211    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
212    surfaceTexture->setDefaultBufferSize(width, height);
213}
214
215static jint SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
216{
217    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
218    return surfaceTexture->updateTexImage();
219}
220
221static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
222        jfloatArray jmtx)
223{
224    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
225    float* mtx = env->GetFloatArrayElements(jmtx, NULL);
226    surfaceTexture->getTransformMatrix(mtx);
227    env->ReleaseFloatArrayElements(jmtx, mtx, 0);
228}
229
230static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
231{
232    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
233    return surfaceTexture->getTimestamp();
234}
235
236static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
237{
238    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
239    surfaceTexture->abandon();
240}
241
242// ----------------------------------------------------------------------------
243
244static JNINativeMethod gSurfaceTextureMethods[] = {
245    {"nativeClassInit",          "()V",   (void*)SurfaceTexture_classInit },
246    {"nativeInit",               "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
247    {"nativeFinalize",           "()V",   (void*)SurfaceTexture_finalize },
248    {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
249    {"nativeUpdateTexImage",     "()I",   (void*)SurfaceTexture_updateTexImage },
250    {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
251    {"nativeGetTimestamp",       "()J",   (void*)SurfaceTexture_getTimestamp },
252    {"nativeRelease",            "()V",   (void*)SurfaceTexture_release },
253};
254
255int register_android_graphics_SurfaceTexture(JNIEnv* env)
256{
257    int err = 0;
258    err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
259            gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
260    return err;
261}
262
263} // namespace android
264