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