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