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