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