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