• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 namespace android {
35 
36 static const char* const OutOfResourcesException =
37     "android/graphics/SurfaceTexture$OutOfResourcesException";
38 static const char* const IllegalStateException = "java/lang/IllegalStateException";
39 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
40 
41 struct fields_t {
42     jfieldID  surfaceTexture;
43     jfieldID  frameAvailableListener;
44     jmethodID postEvent;
45 };
46 static fields_t fields;
47 
48 // ----------------------------------------------------------------------------
49 
SurfaceTexture_setSurfaceTexture(JNIEnv * env,jobject thiz,const sp<GLConsumer> & surfaceTexture)50 static 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 
SurfaceTexture_setFrameAvailableListener(JNIEnv * env,jobject thiz,sp<GLConsumer::FrameAvailableListener> listener)64 static 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 
SurfaceTexture_getSurfaceTexture(JNIEnv * env,jobject thiz)79 sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env,
80         jobject thiz)
81 {
82     return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
83 }
84 
android_SurfaceTexture_getNativeWindow(JNIEnv * env,jobject thiz)85 sp<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 
android_SurfaceTexture_isInstanceOf(JNIEnv * env,jobject thiz)94 bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz)
95 {
96     jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
97     return env->IsInstanceOf(thiz, surfaceTextureClass);
98 }
99 
100 // ----------------------------------------------------------------------------
101 
102 class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener
103 {
104 public:
105     JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
106     virtual ~JNISurfaceTextureContext();
107     virtual void onFrameAvailable();
108 
109 private:
110     static JNIEnv* getJNIEnv(bool* needsDetach);
111     static void detachJNI();
112 
113     jobject mWeakThiz;
114     jclass mClazz;
115 };
116 
JNISurfaceTextureContext(JNIEnv * env,jobject weakThiz,jclass clazz)117 JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
118         jobject weakThiz, jclass clazz) :
119     mWeakThiz(env->NewGlobalRef(weakThiz)),
120     mClazz((jclass)env->NewGlobalRef(clazz))
121 {}
122 
getJNIEnv(bool * needsDetach)123 JNIEnv* 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 
detachJNI()139 void 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 
~JNISurfaceTextureContext()147 JNISurfaceTextureContext::~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 
onFrameAvailable()162 void 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 
SurfaceTexture_classInit(JNIEnv * env,jclass clazz)178 static 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 
SurfaceTexture_init(JNIEnv * env,jobject thiz,jint texName,jobject weakThiz,jboolean allowSynchronous)200 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
201         jobject weakThiz, jboolean allowSynchronous)
202 {
203     sp<GLConsumer> surfaceTexture(new GLConsumer(texName, allowSynchronous));
204     if (surfaceTexture == 0) {
205         jniThrowException(env, OutOfResourcesException,
206                 "Unable to create native SurfaceTexture");
207         return;
208     }
209     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
210 
211     jclass clazz = env->GetObjectClass(thiz);
212     if (clazz == NULL) {
213         jniThrowRuntimeException(env,
214                 "Can't find android/graphics/SurfaceTexture");
215         return;
216     }
217 
218     sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
219             clazz));
220     surfaceTexture->setFrameAvailableListener(ctx);
221     SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
222 }
223 
SurfaceTexture_finalize(JNIEnv * env,jobject thiz)224 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
225 {
226     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
227     surfaceTexture->setFrameAvailableListener(0);
228     SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
229     SurfaceTexture_setSurfaceTexture(env, thiz, 0);
230 }
231 
SurfaceTexture_setDefaultBufferSize(JNIEnv * env,jobject thiz,jint width,jint height)232 static void SurfaceTexture_setDefaultBufferSize(
233         JNIEnv* env, jobject thiz, jint width, jint height)
234 {
235     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
236     surfaceTexture->setDefaultBufferSize(width, height);
237 }
238 
SurfaceTexture_updateTexImage(JNIEnv * env,jobject thiz)239 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
240 {
241     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
242     status_t err = surfaceTexture->updateTexImage();
243     if (err == INVALID_OPERATION) {
244         jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
245                 "logcat for details)");
246     } else if (err < 0) {
247         jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
248     }
249 }
250 
SurfaceTexture_detachFromGLContext(JNIEnv * env,jobject thiz)251 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
252 {
253     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
254     return surfaceTexture->detachFromContext();
255 }
256 
SurfaceTexture_attachToGLContext(JNIEnv * env,jobject thiz,jint tex)257 static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
258 {
259     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
260     return surfaceTexture->attachToContext((GLuint)tex);
261 }
262 
SurfaceTexture_getTransformMatrix(JNIEnv * env,jobject thiz,jfloatArray jmtx)263 static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
264         jfloatArray jmtx)
265 {
266     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
267     float* mtx = env->GetFloatArrayElements(jmtx, NULL);
268     surfaceTexture->getTransformMatrix(mtx);
269     env->ReleaseFloatArrayElements(jmtx, mtx, 0);
270 }
271 
SurfaceTexture_getTimestamp(JNIEnv * env,jobject thiz)272 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
273 {
274     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
275     return surfaceTexture->getTimestamp();
276 }
277 
SurfaceTexture_release(JNIEnv * env,jobject thiz)278 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
279 {
280     sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
281     surfaceTexture->abandon();
282 }
283 
284 // ----------------------------------------------------------------------------
285 
286 static JNINativeMethod gSurfaceTextureMethods[] = {
287     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
288     {"nativeInit",                 "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
289     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
290     {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
291     {"nativeUpdateTexImage",       "()V",   (void*)SurfaceTexture_updateTexImage },
292     {"nativeDetachFromGLContext",  "()I",   (void*)SurfaceTexture_detachFromGLContext },
293     {"nativeAttachToGLContext",    "(I)I",   (void*)SurfaceTexture_attachToGLContext },
294     {"nativeGetTransformMatrix",   "([F)V", (void*)SurfaceTexture_getTransformMatrix },
295     {"nativeGetTimestamp",         "()J",   (void*)SurfaceTexture_getTimestamp },
296     {"nativeRelease",              "()V",   (void*)SurfaceTexture_release },
297 };
298 
register_android_graphics_SurfaceTexture(JNIEnv * env)299 int register_android_graphics_SurfaceTexture(JNIEnv* env)
300 {
301     int err = 0;
302     err = AndroidRuntime::registerNativeMethods(env, kSurfaceTextureClassPathName,
303             gSurfaceTextureMethods, NELEM(gSurfaceTextureMethods));
304     return err;
305 }
306 
307 } // namespace android
308