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