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