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