Home | History | Annotate | Download | only in graphics
      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 
     34 namespace android {
     35 
     36 static const char* const OutOfResourcesException =
     37     "android/graphics/SurfaceTexture$OutOfResourcesException";
     38 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
     39 
     40 struct fields_t {
     41     jfieldID  surfaceTexture;
     42     jmethodID postEvent;
     43 };
     44 static fields_t fields;
     45 
     46 // ----------------------------------------------------------------------------
     47 
     48 static 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 
     62 sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz)
     63 {
     64     sp<SurfaceTexture> surfaceTexture(
     65         (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture));
     66     return surfaceTexture;
     67 }
     68 
     69 sp<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 
     78 bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz)
     79 {
     80     jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
     81     return env->IsInstanceOf(thiz, surfaceTextureClass);
     82 }
     83 
     84 // ----------------------------------------------------------------------------
     85 
     86 class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
     87 {
     88 public:
     89     JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
     90     virtual ~JNISurfaceTextureContext();
     91     virtual void onFrameAvailable();
     92 
     93 private:
     94     static JNIEnv* getJNIEnv(bool* needsDetach);
     95     static void detachJNI();
     96 
     97     jobject mWeakThiz;
     98     jclass mClazz;
     99 };
    100 
    101 JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
    102         jobject weakThiz, jclass clazz) :
    103     mWeakThiz(env->NewGlobalRef(weakThiz)),
    104     mClazz((jclass)env->NewGlobalRef(clazz))
    105 {}
    106 
    107 JNIEnv* 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 
    123 void 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 
    131 JNISurfaceTextureContext::~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 
    146 void 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 
    162 static 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 
    178 static 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 
    201 static 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 
    208 static 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 
    215 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
    216 {
    217     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    218     surfaceTexture->updateTexImage();
    219 }
    220 
    221 static 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 
    230 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
    231 {
    232     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    233     return surfaceTexture->getTimestamp();
    234 }
    235 
    236 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
    237 {
    238     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    239     surfaceTexture->abandon();
    240 }
    241 
    242 // ----------------------------------------------------------------------------
    243 
    244 static 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",     "()V",   (void*)SurfaceTexture_updateTexImage },
    250     {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
    251     {"nativeGetTimestamp",       "()J",   (void*)SurfaceTexture_getTimestamp },
    252     {"nativeRelease",            "()V",   (void*)SurfaceTexture_release },
    253 };
    254 
    255 int 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