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