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 #undef LOG_TAG
18 #define LOG_TAG "SurfaceTexture"
19
20 #include <stdio.h>
21
22 #include <EGL/egl.h>
23 #include <EGL/eglext.h>
24 #include <GLES2/gl2.h>
25 #include <GLES2/gl2ext.h>
26
27 #include <gui/BufferQueue.h>
28 #include <gui/Surface.h>
29 #include <surfacetexture/SurfaceTexture.h>
30 #include <surfacetexture/surface_texture_platform.h>
31
32 #include "core_jni_helpers.h"
33
34 #include <cutils/atomic.h>
35 #include <utils/Log.h>
36 #include <utils/misc.h>
37
38 #include "jni.h"
39 #include <nativehelper/JNIHelp.h>
40 #include <nativehelper/ScopedLocalRef.h>
41
42 // ----------------------------------------------------------------------------
43
44 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
45
46 namespace android {
47
48 static const char* const OutOfResourcesException =
49 "android/view/Surface$OutOfResourcesException";
50 static const char* const IllegalStateException = "java/lang/IllegalStateException";
51 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
52
53 struct fields_t {
54 jfieldID surfaceTexture;
55 jfieldID producer;
56 jfieldID frameAvailableListener;
57 jmethodID postEvent;
58 };
59 static fields_t fields;
60
61 // Get an ID that's unique within this process.
createProcessUniqueId()62 static int32_t createProcessUniqueId() {
63 static volatile int32_t globalCounter = 0;
64 return android_atomic_inc(&globalCounter);
65 }
66
67 // Check whether the current EGL context is protected.
isProtectedContext()68 static bool isProtectedContext() {
69 EGLDisplay dpy = eglGetCurrentDisplay();
70 EGLContext ctx = eglGetCurrentContext();
71
72 if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) {
73 return false;
74 }
75
76 EGLint isProtected = EGL_FALSE;
77 eglQueryContext(dpy, ctx, EGL_PROTECTED_CONTENT_EXT, &isProtected);
78
79 return isProtected;
80 }
81
82 // ----------------------------------------------------------------------------
83
SurfaceTexture_setSurfaceTexture(JNIEnv * env,jobject thiz,const sp<SurfaceTexture> & surfaceTexture)84 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
85 const sp<SurfaceTexture>& surfaceTexture)
86 {
87 SurfaceTexture* const p =
88 (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
89 if (surfaceTexture.get()) {
90 surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture);
91 }
92 if (p) {
93 p->decStrong((void*)SurfaceTexture_setSurfaceTexture);
94 }
95 env->SetLongField(thiz, fields.surfaceTexture, (jlong)surfaceTexture.get());
96 }
97
SurfaceTexture_setProducer(JNIEnv * env,jobject thiz,const sp<IGraphicBufferProducer> & producer)98 static void SurfaceTexture_setProducer(JNIEnv* env, jobject thiz,
99 const sp<IGraphicBufferProducer>& producer)
100 {
101 IGraphicBufferProducer* const p =
102 (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
103 if (producer.get()) {
104 producer->incStrong((void*)SurfaceTexture_setProducer);
105 }
106 if (p) {
107 p->decStrong((void*)SurfaceTexture_setProducer);
108 }
109 env->SetLongField(thiz, fields.producer, (jlong)producer.get());
110 }
111
SurfaceTexture_setFrameAvailableListener(JNIEnv * env,jobject thiz,sp<SurfaceTexture::FrameAvailableListener> listener)112 static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
113 jobject thiz, sp<SurfaceTexture::FrameAvailableListener> listener)
114 {
115 SurfaceTexture::FrameAvailableListener* const p =
116 (SurfaceTexture::FrameAvailableListener*)
117 env->GetLongField(thiz, fields.frameAvailableListener);
118 if (listener.get()) {
119 listener->incStrong((void*)SurfaceTexture_setSurfaceTexture);
120 }
121 if (p) {
122 p->decStrong((void*)SurfaceTexture_setSurfaceTexture);
123 }
124 env->SetLongField(thiz, fields.frameAvailableListener, (jlong)listener.get());
125 }
126
SurfaceTexture_getSurfaceTexture(JNIEnv * env,jobject thiz)127 sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
128 return (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
129 }
130
SurfaceTexture_getProducer(JNIEnv * env,jobject thiz)131 sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
132 return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
133 }
134
android_SurfaceTexture_isInstanceOf(JNIEnv * env,jobject thiz)135 bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
136 jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
137 return env->IsInstanceOf(thiz, surfaceTextureClass);
138 }
139
140 // ----------------------------------------------------------------------------
141
142 class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
143 {
144 public:
145 JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
146 virtual ~JNISurfaceTextureContext();
147 virtual void onFrameAvailable(const BufferItem& item);
148
149 private:
150 static JNIEnv* getJNIEnv(bool* needsDetach);
151 static void detachJNI();
152
153 jobject mWeakThiz;
154 jclass mClazz;
155 };
156
JNISurfaceTextureContext(JNIEnv * env,jobject weakThiz,jclass clazz)157 JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
158 jobject weakThiz, jclass clazz) :
159 mWeakThiz(env->NewGlobalRef(weakThiz)),
160 mClazz((jclass)env->NewGlobalRef(clazz))
161 {}
162
getJNIEnv(bool * needsDetach)163 JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) {
164 *needsDetach = false;
165 JNIEnv* env = AndroidRuntime::getJNIEnv();
166 if (env == NULL) {
167 JavaVMAttachArgs args = {
168 JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
169 JavaVM* vm = AndroidRuntime::getJavaVM();
170 int result = vm->AttachCurrentThread(&env, (void*) &args);
171 if (result != JNI_OK) {
172 ALOGE("thread attach failed: %#x", result);
173 return NULL;
174 }
175 *needsDetach = true;
176 }
177 return env;
178 }
179
detachJNI()180 void JNISurfaceTextureContext::detachJNI() {
181 JavaVM* vm = AndroidRuntime::getJavaVM();
182 int result = vm->DetachCurrentThread();
183 if (result != JNI_OK) {
184 ALOGE("thread detach failed: %#x", result);
185 }
186 }
187
~JNISurfaceTextureContext()188 JNISurfaceTextureContext::~JNISurfaceTextureContext()
189 {
190 bool needsDetach = false;
191 JNIEnv* env = getJNIEnv(&needsDetach);
192 if (env != NULL) {
193 env->DeleteGlobalRef(mWeakThiz);
194 env->DeleteGlobalRef(mClazz);
195 } else {
196 ALOGW("leaking JNI object references");
197 }
198 if (needsDetach) {
199 detachJNI();
200 }
201 }
202
onFrameAvailable(const BufferItem &)203 void JNISurfaceTextureContext::onFrameAvailable(const BufferItem& /* item */)
204 {
205 bool needsDetach = false;
206 JNIEnv* env = getJNIEnv(&needsDetach);
207 if (env != NULL) {
208 env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
209 } else {
210 ALOGW("onFrameAvailable event will not posted");
211 }
212 if (needsDetach) {
213 detachJNI();
214 }
215 }
216
217 // ----------------------------------------------------------------------------
218
219
220 #define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
221 #define ANDROID_GRAPHICS_PRODUCER_JNI_ID "mProducer"
222 #define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \
223 "mFrameAvailableListener"
224
SurfaceTexture_classInit(JNIEnv * env,jclass clazz)225 static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
226 {
227 fields.surfaceTexture = env->GetFieldID(clazz,
228 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "J");
229 if (fields.surfaceTexture == NULL) {
230 ALOGE("can't find android/graphics/SurfaceTexture.%s",
231 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
232 }
233 fields.producer = env->GetFieldID(clazz,
234 ANDROID_GRAPHICS_PRODUCER_JNI_ID, "J");
235 if (fields.producer == NULL) {
236 ALOGE("can't find android/graphics/SurfaceTexture.%s",
237 ANDROID_GRAPHICS_PRODUCER_JNI_ID);
238 }
239 fields.frameAvailableListener = env->GetFieldID(clazz,
240 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "J");
241 if (fields.frameAvailableListener == NULL) {
242 ALOGE("can't find android/graphics/SurfaceTexture.%s",
243 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID);
244 }
245
246 fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
247 "(Ljava/lang/ref/WeakReference;)V");
248 if (fields.postEvent == NULL) {
249 ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
250 }
251 }
252
SurfaceTexture_init(JNIEnv * env,jobject thiz,jboolean isDetached,jint texName,jboolean singleBufferMode,jobject weakThiz)253 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
254 jint texName, jboolean singleBufferMode, jobject weakThiz)
255 {
256 sp<IGraphicBufferProducer> producer;
257 sp<IGraphicBufferConsumer> consumer;
258 BufferQueue::createBufferQueue(&producer, &consumer);
259
260 if (singleBufferMode) {
261 consumer->setMaxBufferCount(1);
262 }
263
264 sp<SurfaceTexture> surfaceTexture;
265 if (isDetached) {
266 surfaceTexture = new SurfaceTexture(consumer, GL_TEXTURE_EXTERNAL_OES,
267 true, !singleBufferMode);
268 } else {
269 surfaceTexture = new SurfaceTexture(consumer, texName,
270 GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
271 }
272
273 if (surfaceTexture == 0) {
274 jniThrowException(env, OutOfResourcesException,
275 "Unable to create native SurfaceTexture");
276 return;
277 }
278 surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",
279 (isDetached ? 0 : texName),
280 getpid(),
281 createProcessUniqueId()));
282
283 // If the current context is protected, inform the producer.
284 consumer->setConsumerIsProtected(isProtectedContext());
285
286 SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
287 SurfaceTexture_setProducer(env, thiz, producer);
288
289 jclass clazz = env->GetObjectClass(thiz);
290 if (clazz == NULL) {
291 jniThrowRuntimeException(env,
292 "Can't find android/graphics/SurfaceTexture");
293 return;
294 }
295
296 sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
297 clazz));
298 surfaceTexture->setFrameAvailableListener(ctx);
299 SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
300 }
301
SurfaceTexture_finalize(JNIEnv * env,jobject thiz)302 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
303 {
304 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
305 surfaceTexture->setFrameAvailableListener(0);
306 SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
307 SurfaceTexture_setSurfaceTexture(env, thiz, 0);
308 SurfaceTexture_setProducer(env, thiz, 0);
309 }
310
SurfaceTexture_setDefaultBufferSize(JNIEnv * env,jobject thiz,jint width,jint height)311 static void SurfaceTexture_setDefaultBufferSize(
312 JNIEnv* env, jobject thiz, jint width, jint height) {
313 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
314 surfaceTexture->setDefaultBufferSize(width, height);
315 }
316
SurfaceTexture_updateTexImage(JNIEnv * env,jobject thiz)317 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
318 {
319 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
320 status_t err = surfaceTexture->updateTexImage();
321 if (err == INVALID_OPERATION) {
322 jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
323 "logcat for details)");
324 } else if (err < 0) {
325 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
326 }
327 }
328
SurfaceTexture_releaseTexImage(JNIEnv * env,jobject thiz)329 static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz)
330 {
331 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
332 status_t err = surfaceTexture->releaseTexImage();
333 if (err == INVALID_OPERATION) {
334 jniThrowException(env, IllegalStateException, "Unable to release texture contents (see "
335 "logcat for details)");
336 } else if (err < 0) {
337 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
338 }
339 }
340
SurfaceTexture_detachFromGLContext(JNIEnv * env,jobject thiz)341 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
342 {
343 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
344 return surfaceTexture->detachFromContext();
345 }
346
SurfaceTexture_attachToGLContext(JNIEnv * env,jobject thiz,jint tex)347 static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
348 {
349 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
350 return surfaceTexture->attachToContext((GLuint)tex);
351 }
352
SurfaceTexture_getTransformMatrix(JNIEnv * env,jobject thiz,jfloatArray jmtx)353 static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
354 jfloatArray jmtx)
355 {
356 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
357 float* mtx = env->GetFloatArrayElements(jmtx, NULL);
358 surfaceTexture->getTransformMatrix(mtx);
359 env->ReleaseFloatArrayElements(jmtx, mtx, 0);
360 }
361
SurfaceTexture_getTimestamp(JNIEnv * env,jobject thiz)362 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
363 {
364 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
365 return surfaceTexture->getTimestamp();
366 }
367
SurfaceTexture_release(JNIEnv * env,jobject thiz)368 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
369 {
370 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
371 surfaceTexture->abandon();
372 }
373
SurfaceTexture_isReleased(JNIEnv * env,jobject thiz)374 static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz)
375 {
376 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
377 return surfaceTexture->isAbandoned();
378 }
379
380 // ----------------------------------------------------------------------------
381
382 static const JNINativeMethod gSurfaceTextureMethods[] = {
383 {"nativeInit", "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
384 {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
385 {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
386 {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
387 {"nativeReleaseTexImage", "()V", (void*)SurfaceTexture_releaseTexImage },
388 {"nativeDetachFromGLContext", "()I", (void*)SurfaceTexture_detachFromGLContext },
389 {"nativeAttachToGLContext", "(I)I", (void*)SurfaceTexture_attachToGLContext },
390 {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
391 {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp },
392 {"nativeRelease", "()V", (void*)SurfaceTexture_release },
393 {"nativeIsReleased", "()Z", (void*)SurfaceTexture_isReleased },
394 };
395
register_android_graphics_SurfaceTexture(JNIEnv * env)396 int register_android_graphics_SurfaceTexture(JNIEnv* env)
397 {
398 // Cache some fields.
399 ScopedLocalRef<jclass> klass(env, FindClassOrDie(env, kSurfaceTextureClassPathName));
400 SurfaceTexture_classInit(env, klass.get());
401
402 return RegisterMethodsOrDie(env, kSurfaceTextureClassPathName, gSurfaceTextureMethods,
403 NELEM(gSurfaceTextureMethods));
404 }
405
406 } // namespace android
407
408 //TODO: Move this file to frameworks/base/core/jni/android_graphics_SurfaceTexture.cpp. See
409 //TODO: android_view_Surface.cpp for example.
410