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  producer;
     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->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 
     68 static 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 
     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->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 
     97 sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
     98     return (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture);
     99 }
    100 
    101 sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
    102     return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
    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 = {
    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 
    157 void 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 
    165 JNISurfaceTextureContext::~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 
    180 void 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 
    202 static 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 
    230 static 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 
    272 static 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 
    281 static 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 
    287 static 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 
    299 static 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 
    311 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
    312 {
    313     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    314     return surfaceTexture->detachFromContext();
    315 }
    316 
    317 static 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 
    323 static 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 
    332 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
    333 {
    334     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    335     return surfaceTexture->getTimestamp();
    336 }
    337 
    338 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
    339 {
    340     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
    341     surfaceTexture->abandon();
    342 }
    343 
    344 // ----------------------------------------------------------------------------
    345 
    346 static 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 
    360 int register_android_graphics_SurfaceTexture(JNIEnv* env)
    361 {
    362     int err = 0;
    363     err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
    364             gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
    365     return err;
    366 }
    367 
    368 } // namespace android
    369