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