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