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 <GLES2/gl2.h> 22 #include <GLES2/gl2ext.h> 23 24 #include <gui/GLConsumer.h> 25 #include <gui/Surface.h> 26 27 #include <android_runtime/AndroidRuntime.h> 28 29 #include <utils/Log.h> 30 #include <utils/misc.h> 31 32 #include "jni.h" 33 #include "JNIHelp.h" 34 35 // ---------------------------------------------------------------------------- 36 37 namespace android { 38 39 static const char* const OutOfResourcesException = 40 "android/view/Surface$OutOfResourcesException"; 41 static const char* const IllegalStateException = "java/lang/IllegalStateException"; 42 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; 43 44 struct fields_t { 45 jfieldID surfaceTexture; 46 jfieldID bufferQueue; 47 jfieldID frameAvailableListener; 48 jmethodID postEvent; 49 }; 50 static fields_t fields; 51 52 // ---------------------------------------------------------------------------- 53 54 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz, 55 const sp<GLConsumer>& surfaceTexture) 56 { 57 GLConsumer* const p = 58 (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture); 59 if (surfaceTexture.get()) { 60 surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture); 61 } 62 if (p) { 63 p->decStrong((void*)SurfaceTexture_setSurfaceTexture); 64 } 65 env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get()); 66 } 67 68 static void SurfaceTexture_setBufferQueue(JNIEnv* env, jobject thiz, 69 const sp<BufferQueue>& bq) 70 { 71 BufferQueue* const p = 72 (BufferQueue*)env->GetIntField(thiz, fields.bufferQueue); 73 if (bq.get()) { 74 bq->incStrong((void*)SurfaceTexture_setBufferQueue); 75 } 76 if (p) { 77 p->decStrong((void*)SurfaceTexture_setBufferQueue); 78 } 79 env->SetIntField(thiz, fields.bufferQueue, (int)bq.get()); 80 } 81 82 static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env, 83 jobject thiz, sp<GLConsumer::FrameAvailableListener> listener) 84 { 85 GLConsumer::FrameAvailableListener* const p = 86 (GLConsumer::FrameAvailableListener*) 87 env->GetIntField(thiz, fields.frameAvailableListener); 88 if (listener.get()) { 89 listener->incStrong((void*)SurfaceTexture_setSurfaceTexture); 90 } 91 if (p) { 92 p->decStrong((void*)SurfaceTexture_setSurfaceTexture); 93 } 94 env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get()); 95 } 96 97 sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) { 98 return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture); 99 } 100 101 sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) { 102 return (BufferQueue*)env->GetIntField(thiz, fields.bufferQueue); 103 } 104 105 sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz) { 106 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 107 sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz)); 108 sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL); 109 return surfaceTextureClient; 110 } 111 112 bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) { 113 jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName); 114 return env->IsInstanceOf(thiz, surfaceTextureClass); 115 } 116 117 // ---------------------------------------------------------------------------- 118 119 class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener 120 { 121 public: 122 JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz); 123 virtual ~JNISurfaceTextureContext(); 124 virtual void onFrameAvailable(); 125 126 private: 127 static JNIEnv* getJNIEnv(bool* needsDetach); 128 static void detachJNI(); 129 130 jobject mWeakThiz; 131 jclass mClazz; 132 }; 133 134 JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env, 135 jobject weakThiz, jclass clazz) : 136 mWeakThiz(env->NewGlobalRef(weakThiz)), 137 mClazz((jclass)env->NewGlobalRef(clazz)) 138 {} 139 140 JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) { 141 *needsDetach = false; 142 JNIEnv* env = AndroidRuntime::getJNIEnv(); 143 if (env == NULL) { 144 JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL}; 145 JavaVM* vm = AndroidRuntime::getJavaVM(); 146 int result = vm->AttachCurrentThread(&env, (void*) &args); 147 if (result != JNI_OK) { 148 ALOGE("thread attach failed: %#x", result); 149 return NULL; 150 } 151 *needsDetach = true; 152 } 153 return env; 154 } 155 156 void JNISurfaceTextureContext::detachJNI() { 157 JavaVM* vm = AndroidRuntime::getJavaVM(); 158 int result = vm->DetachCurrentThread(); 159 if (result != JNI_OK) { 160 ALOGE("thread detach failed: %#x", result); 161 } 162 } 163 164 JNISurfaceTextureContext::~JNISurfaceTextureContext() 165 { 166 bool needsDetach = false; 167 JNIEnv* env = getJNIEnv(&needsDetach); 168 if (env != NULL) { 169 env->DeleteGlobalRef(mWeakThiz); 170 env->DeleteGlobalRef(mClazz); 171 } else { 172 ALOGW("leaking JNI object references"); 173 } 174 if (needsDetach) { 175 detachJNI(); 176 } 177 } 178 179 void JNISurfaceTextureContext::onFrameAvailable() 180 { 181 bool needsDetach = false; 182 JNIEnv* env = getJNIEnv(&needsDetach); 183 if (env != NULL) { 184 env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz); 185 } else { 186 ALOGW("onFrameAvailable event will not posted"); 187 } 188 if (needsDetach) { 189 detachJNI(); 190 } 191 } 192 193 // ---------------------------------------------------------------------------- 194 195 196 #define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture" 197 #define ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID "mBufferQueue" 198 #define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \ 199 "mFrameAvailableListener" 200 201 static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) 202 { 203 fields.surfaceTexture = env->GetFieldID(clazz, 204 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I"); 205 if (fields.surfaceTexture == NULL) { 206 ALOGE("can't find android/graphics/SurfaceTexture.%s", 207 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID); 208 } 209 fields.bufferQueue = env->GetFieldID(clazz, 210 ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID, "I"); 211 if (fields.bufferQueue == NULL) { 212 ALOGE("can't find android/graphics/SurfaceTexture.%s", 213 ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID); 214 } 215 fields.frameAvailableListener = env->GetFieldID(clazz, 216 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "I"); 217 if (fields.frameAvailableListener == NULL) { 218 ALOGE("can't find android/graphics/SurfaceTexture.%s", 219 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID); 220 } 221 222 fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative", 223 "(Ljava/lang/Object;)V"); 224 if (fields.postEvent == NULL) { 225 ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative"); 226 } 227 } 228 229 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, 230 jint texName, jboolean singleBufferMode, jobject weakThiz) 231 { 232 sp<BufferQueue> bq = new BufferQueue(); 233 234 if (singleBufferMode) { 235 bq->disableAsyncBuffer(); 236 bq->setDefaultMaxBufferCount(1); 237 } 238 239 sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName, GL_TEXTURE_EXTERNAL_OES, true, true)); 240 if (surfaceTexture == 0) { 241 jniThrowException(env, OutOfResourcesException, 242 "Unable to create native SurfaceTexture"); 243 return; 244 } 245 SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture); 246 SurfaceTexture_setBufferQueue(env, thiz, bq); 247 248 jclass clazz = env->GetObjectClass(thiz); 249 if (clazz == NULL) { 250 jniThrowRuntimeException(env, 251 "Can't find android/graphics/SurfaceTexture"); 252 return; 253 } 254 255 sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz, 256 clazz)); 257 surfaceTexture->setFrameAvailableListener(ctx); 258 SurfaceTexture_setFrameAvailableListener(env, thiz, ctx); 259 } 260 261 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) 262 { 263 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 264 surfaceTexture->setFrameAvailableListener(0); 265 SurfaceTexture_setFrameAvailableListener(env, thiz, 0); 266 SurfaceTexture_setSurfaceTexture(env, thiz, 0); 267 SurfaceTexture_setBufferQueue(env, thiz, 0); 268 } 269 270 static void SurfaceTexture_setDefaultBufferSize( 271 JNIEnv* env, jobject thiz, jint width, jint height) { 272 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 273 surfaceTexture->setDefaultBufferSize(width, height); 274 } 275 276 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) 277 { 278 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 279 status_t err = surfaceTexture->updateTexImage(); 280 if (err == INVALID_OPERATION) { 281 jniThrowException(env, IllegalStateException, "Unable to update texture contents (see " 282 "logcat for details)"); 283 } else if (err < 0) { 284 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)"); 285 } 286 } 287 288 static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz) 289 { 290 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 291 status_t err = surfaceTexture->releaseTexImage(); 292 if (err == INVALID_OPERATION) { 293 jniThrowException(env, IllegalStateException, "Unable to release texture contents (see " 294 "logcat for details)"); 295 } else if (err < 0) { 296 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)"); 297 } 298 } 299 300 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz) 301 { 302 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 303 return surfaceTexture->detachFromContext(); 304 } 305 306 static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex) 307 { 308 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 309 return surfaceTexture->attachToContext((GLuint)tex); 310 } 311 312 static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, 313 jfloatArray jmtx) 314 { 315 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 316 float* mtx = env->GetFloatArrayElements(jmtx, NULL); 317 surfaceTexture->getTransformMatrix(mtx); 318 env->ReleaseFloatArrayElements(jmtx, mtx, 0); 319 } 320 321 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz) 322 { 323 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 324 return surfaceTexture->getTimestamp(); 325 } 326 327 static void SurfaceTexture_release(JNIEnv* env, jobject thiz) 328 { 329 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 330 surfaceTexture->abandon(); 331 } 332 333 // ---------------------------------------------------------------------------- 334 335 static JNINativeMethod gSurfaceTextureMethods[] = { 336 {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, 337 {"nativeInit", "(IZLjava/lang/Object;)V", (void*)SurfaceTexture_init }, 338 {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, 339 {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize }, 340 {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, 341 {"nativeReleaseTexImage", "()V", (void*)SurfaceTexture_releaseTexImage }, 342 {"nativeDetachFromGLContext", "()I", (void*)SurfaceTexture_detachFromGLContext }, 343 {"nativeAttachToGLContext", "(I)I", (void*)SurfaceTexture_attachToGLContext }, 344 {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, 345 {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp }, 346 {"nativeRelease", "()V", (void*)SurfaceTexture_release }, 347 }; 348 349 int register_android_graphics_SurfaceTexture(JNIEnv* env) 350 { 351 int err = 0; 352 err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName, 353 gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods)); 354 return err; 355 } 356 357 } // namespace android 358