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