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