SurfaceTexture.cpp revision b550929b7a4b0d5f9645a7a1ebf287d3f13cf1af
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 <gui/GLConsumer.h> 22#include <gui/Surface.h> 23 24#include <android_runtime/AndroidRuntime.h> 25 26#include <utils/Log.h> 27#include <utils/misc.h> 28 29#include "jni.h" 30#include "JNIHelp.h" 31 32// ---------------------------------------------------------------------------- 33 34namespace android { 35 36static const char* const OutOfResourcesException = 37 "android/graphics/SurfaceTexture$OutOfResourcesException"; 38static const char* const IllegalStateException = "java/lang/IllegalStateException"; 39const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; 40 41struct fields_t { 42 jfieldID surfaceTexture; 43 jfieldID frameAvailableListener; 44 jmethodID postEvent; 45}; 46static fields_t fields; 47 48// ---------------------------------------------------------------------------- 49 50static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz, 51 const sp<GLConsumer>& surfaceTexture) 52{ 53 GLConsumer* const p = 54 (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture); 55 if (surfaceTexture.get()) { 56 surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture); 57 } 58 if (p) { 59 p->decStrong((void*)SurfaceTexture_setSurfaceTexture); 60 } 61 env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get()); 62} 63 64static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env, 65 jobject thiz, sp<GLConsumer::FrameAvailableListener> listener) 66{ 67 GLConsumer::FrameAvailableListener* const p = 68 (GLConsumer::FrameAvailableListener*) 69 env->GetIntField(thiz, fields.frameAvailableListener); 70 if (listener.get()) { 71 listener->incStrong((void*)SurfaceTexture_setSurfaceTexture); 72 } 73 if (p) { 74 p->decStrong((void*)SurfaceTexture_setSurfaceTexture); 75 } 76 env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get()); 77} 78 79sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, 80 jobject thiz) 81{ 82 return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture); 83} 84 85sp<ANativeWindow> android_SurfaceTexture_getNativeWindow( 86 JNIEnv* env, jobject thiz) 87{ 88 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 89 sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? 90 new Surface(surfaceTexture->getBufferQueue()) : NULL); 91 return surfaceTextureClient; 92} 93 94bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) 95{ 96 jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName); 97 return env->IsInstanceOf(thiz, surfaceTextureClass); 98} 99 100// ---------------------------------------------------------------------------- 101 102class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener 103{ 104public: 105 JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz); 106 virtual ~JNISurfaceTextureContext(); 107 virtual void onFrameAvailable(); 108 109private: 110 static JNIEnv* getJNIEnv(bool* needsDetach); 111 static void detachJNI(); 112 113 jobject mWeakThiz; 114 jclass mClazz; 115}; 116 117JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env, 118 jobject weakThiz, jclass clazz) : 119 mWeakThiz(env->NewGlobalRef(weakThiz)), 120 mClazz((jclass)env->NewGlobalRef(clazz)) 121{} 122 123JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) { 124 *needsDetach = false; 125 JNIEnv* env = AndroidRuntime::getJNIEnv(); 126 if (env == NULL) { 127 JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL}; 128 JavaVM* vm = AndroidRuntime::getJavaVM(); 129 int result = vm->AttachCurrentThread(&env, (void*) &args); 130 if (result != JNI_OK) { 131 ALOGE("thread attach failed: %#x", result); 132 return NULL; 133 } 134 *needsDetach = true; 135 } 136 return env; 137} 138 139void JNISurfaceTextureContext::detachJNI() { 140 JavaVM* vm = AndroidRuntime::getJavaVM(); 141 int result = vm->DetachCurrentThread(); 142 if (result != JNI_OK) { 143 ALOGE("thread detach failed: %#x", result); 144 } 145} 146 147JNISurfaceTextureContext::~JNISurfaceTextureContext() 148{ 149 bool needsDetach = false; 150 JNIEnv* env = getJNIEnv(&needsDetach); 151 if (env != NULL) { 152 env->DeleteGlobalRef(mWeakThiz); 153 env->DeleteGlobalRef(mClazz); 154 } else { 155 ALOGW("leaking JNI object references"); 156 } 157 if (needsDetach) { 158 detachJNI(); 159 } 160} 161 162void JNISurfaceTextureContext::onFrameAvailable() 163{ 164 bool needsDetach = false; 165 JNIEnv* env = getJNIEnv(&needsDetach); 166 if (env != NULL) { 167 env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz); 168 } else { 169 ALOGW("onFrameAvailable event will not posted"); 170 } 171 if (needsDetach) { 172 detachJNI(); 173 } 174} 175 176// ---------------------------------------------------------------------------- 177 178static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) 179{ 180 fields.surfaceTexture = env->GetFieldID(clazz, 181 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I"); 182 if (fields.surfaceTexture == NULL) { 183 ALOGE("can't find android/graphics/SurfaceTexture.%s", 184 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID); 185 } 186 fields.frameAvailableListener = env->GetFieldID(clazz, 187 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "I"); 188 if (fields.frameAvailableListener == NULL) { 189 ALOGE("can't find android/graphics/SurfaceTexture.%s", 190 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID); 191 } 192 193 fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative", 194 "(Ljava/lang/Object;)V"); 195 if (fields.postEvent == NULL) { 196 ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative"); 197 } 198} 199 200static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName, 201 jobject weakThiz, jboolean allowSynchronous) 202{ 203 sp<BufferQueue> bq = new BufferQueue(allowSynchronous); 204 sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName)); 205 if (surfaceTexture == 0) { 206 jniThrowException(env, OutOfResourcesException, 207 "Unable to create native SurfaceTexture"); 208 return; 209 } 210 SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture); 211 212 jclass clazz = env->GetObjectClass(thiz); 213 if (clazz == NULL) { 214 jniThrowRuntimeException(env, 215 "Can't find android/graphics/SurfaceTexture"); 216 return; 217 } 218 219 sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz, 220 clazz)); 221 surfaceTexture->setFrameAvailableListener(ctx); 222 SurfaceTexture_setFrameAvailableListener(env, thiz, ctx); 223} 224 225static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) 226{ 227 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 228 surfaceTexture->setFrameAvailableListener(0); 229 SurfaceTexture_setFrameAvailableListener(env, thiz, 0); 230 SurfaceTexture_setSurfaceTexture(env, thiz, 0); 231} 232 233static void SurfaceTexture_setDefaultBufferSize( 234 JNIEnv* env, jobject thiz, jint width, jint height) 235{ 236 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 237 surfaceTexture->setDefaultBufferSize(width, height); 238} 239 240static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) 241{ 242 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 243 status_t err = surfaceTexture->updateTexImage(); 244 if (err == INVALID_OPERATION) { 245 jniThrowException(env, IllegalStateException, "Unable to update texture contents (see " 246 "logcat for details)"); 247 } else if (err < 0) { 248 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)"); 249 } 250} 251 252static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz) 253{ 254 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 255 return surfaceTexture->detachFromContext(); 256} 257 258static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex) 259{ 260 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 261 return surfaceTexture->attachToContext((GLuint)tex); 262} 263 264static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, 265 jfloatArray jmtx) 266{ 267 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 268 float* mtx = env->GetFloatArrayElements(jmtx, NULL); 269 surfaceTexture->getTransformMatrix(mtx); 270 env->ReleaseFloatArrayElements(jmtx, mtx, 0); 271} 272 273static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz) 274{ 275 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 276 return surfaceTexture->getTimestamp(); 277} 278 279static void SurfaceTexture_release(JNIEnv* env, jobject thiz) 280{ 281 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 282 surfaceTexture->abandon(); 283} 284 285// ---------------------------------------------------------------------------- 286 287static JNINativeMethod gSurfaceTextureMethods[] = { 288 {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, 289 {"nativeInit", "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init }, 290 {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, 291 {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize }, 292 {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, 293 {"nativeDetachFromGLContext", "()I", (void*)SurfaceTexture_detachFromGLContext }, 294 {"nativeAttachToGLContext", "(I)I", (void*)SurfaceTexture_attachToGLContext }, 295 {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, 296 {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp }, 297 {"nativeRelease", "()V", (void*)SurfaceTexture_release }, 298}; 299 300int register_android_graphics_SurfaceTexture(JNIEnv* env) 301{ 302 int err = 0; 303 err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName, 304 gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods)); 305 return err; 306} 307 308} // namespace android 309