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