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