Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 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 // #define LOG_NDEBUG 0
     17 
     18 #include <stdint.h>
     19 #include <android/native_window_jni.h>
     20 
     21 #include "jni/jni_gl_environment.h"
     22 #include "jni/jni_util.h"
     23 #include "native/core/gl_env.h"
     24 #include <media/mediarecorder.h>
     25 
     26 #include <gui/IGraphicBufferProducer.h>
     27 #include <gui/Surface.h>
     28 #include <utils/Errors.h>
     29 #include <system/window.h>
     30 
     31 
     32 using android::filterfw::GLEnv;
     33 using android::filterfw::WindowHandle;
     34 using android::MediaRecorder;
     35 using android::sp;
     36 using android::IGraphicBufferProducer;
     37 using android::Surface;
     38 
     39 
     40 class NativeWindowHandle : public WindowHandle {
     41   public:
     42     explicit NativeWindowHandle(ANativeWindow* window) : window_(window) {
     43     }
     44 
     45     virtual ~NativeWindowHandle() {
     46     }
     47 
     48     virtual void Destroy() {
     49       ALOGI("Releasing ANativeWindow!");
     50       ANativeWindow_release(window_);
     51     }
     52 
     53     virtual const void* InternalHandle() const {
     54       return window_;
     55     }
     56 
     57     virtual void* InternalHandle() {
     58       return window_;
     59     }
     60 
     61   private:
     62     ANativeWindow* window_;
     63 };
     64 
     65 jboolean Java_android_filterfw_core_GLEnvironment_nativeAllocate(JNIEnv* env, jobject thiz) {
     66   std::unique_ptr<GLEnv> glEnv(new GLEnv());
     67   return ToJBool(WrapOwnedObjectInJava(std::move(glEnv), env, thiz, true));
     68 }
     69 
     70 jboolean Java_android_filterfw_core_GLEnvironment_nativeDeallocate(JNIEnv* env, jobject thiz) {
     71   return ToJBool(DeleteNativeObject<GLEnv>(env, thiz));
     72 }
     73 
     74 jboolean Java_android_filterfw_core_GLEnvironment_nativeInitWithNewContext(JNIEnv* env,
     75                                                                            jobject thiz) {
     76   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
     77   return gl_env ? ToJBool(gl_env->InitWithNewContext()) : JNI_FALSE;
     78 }
     79 
     80 jboolean Java_android_filterfw_core_GLEnvironment_nativeInitWithCurrentContext(JNIEnv* env,
     81                                                                                jobject thiz) {
     82   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
     83   return gl_env ? ToJBool(gl_env->InitWithCurrentContext()) : JNI_FALSE;
     84 }
     85 
     86 jboolean Java_android_filterfw_core_GLEnvironment_nativeIsActive(JNIEnv* env, jobject thiz) {
     87   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
     88   return gl_env ? ToJBool(gl_env->IsActive()) : JNI_FALSE;
     89 }
     90 
     91 jboolean Java_android_filterfw_core_GLEnvironment_nativeIsContextActive(JNIEnv* env, jobject thiz) {
     92   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
     93   return gl_env ? ToJBool(gl_env->IsContextActive()) : JNI_FALSE;
     94 }
     95 
     96 jboolean Java_android_filterfw_core_GLEnvironment_nativeIsAnyContextActive(JNIEnv* /* env */,
     97                                                                            jclass /* clazz */) {
     98   return ToJBool(GLEnv::IsAnyContextActive());
     99 }
    100 
    101 jboolean Java_android_filterfw_core_GLEnvironment_nativeActivate(JNIEnv* env, jobject thiz) {
    102   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    103   return gl_env ? ToJBool(gl_env->Activate()) : JNI_FALSE;
    104 }
    105 
    106 jboolean Java_android_filterfw_core_GLEnvironment_nativeDeactivate(JNIEnv* env, jobject thiz) {
    107   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    108   return gl_env ? ToJBool(gl_env->Deactivate()) : JNI_FALSE;
    109 }
    110 
    111 jboolean Java_android_filterfw_core_GLEnvironment_nativeSwapBuffers(JNIEnv* env, jobject thiz) {
    112   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    113   return gl_env ? ToJBool(gl_env->SwapBuffers()) : JNI_FALSE;
    114 }
    115 
    116 // Get the native mediarecorder object corresponding to the java object
    117 static sp<MediaRecorder> getMediaRecorder(JNIEnv* env, jobject jmediarecorder) {
    118     jclass clazz = env->FindClass("android/media/MediaRecorder");
    119     if (clazz == NULL) {
    120         return NULL;
    121     }
    122 
    123     jfieldID context = env->GetFieldID(clazz, "mNativeContext", "J");
    124     if (context == NULL) {
    125         return NULL;
    126     }
    127 
    128     MediaRecorder* const p = (MediaRecorder*)env->GetLongField(jmediarecorder, context);
    129     env->DeleteLocalRef(clazz);
    130     return sp<MediaRecorder>(p);
    131 }
    132 
    133 
    134 jint Java_android_filterfw_core_GLEnvironment_nativeAddSurface(JNIEnv* env,
    135                                                                jobject thiz,
    136                                                                jobject surface) {
    137   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    138   if (!surface) {
    139     ALOGE("GLEnvironment: Null Surface passed!");
    140     return -1;
    141   } else if (gl_env) {
    142     // Get the ANativeWindow
    143     ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
    144     if (!window) {
    145       ALOGE("GLEnvironment: Error creating window!");
    146       return -1;
    147     }
    148 
    149     NativeWindowHandle* winHandle = new NativeWindowHandle(window);
    150     int result = gl_env->FindSurfaceIdForWindow(winHandle);
    151     if (result == -1) {
    152       // Configure surface
    153       EGLConfig config;
    154       EGLint numConfigs = -1;
    155       EGLint configAttribs[] = {
    156         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    157         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    158         EGL_RED_SIZE, 8,
    159         EGL_GREEN_SIZE, 8,
    160         EGL_BLUE_SIZE, 8,
    161         EGL_RECORDABLE_ANDROID, EGL_TRUE,
    162         EGL_NONE
    163       };
    164 
    165 
    166 
    167       eglChooseConfig(gl_env->display(), configAttribs, &config, 1, &numConfigs);
    168       if (numConfigs < 1) {
    169         ALOGE("GLEnvironment: No suitable EGL configuration found for surface!");
    170         return -1;
    171       }
    172 
    173       // Create the EGL surface
    174       EGLSurface egl_surface = eglCreateWindowSurface(gl_env->display(),
    175                                                       config,
    176                                                       window,
    177                                                       NULL);
    178 
    179       if (GLEnv::CheckEGLError("eglCreateWindowSurface")) {
    180         ALOGE("GLEnvironment: Error creating window surface!");
    181         return -1;
    182       }
    183 
    184       // Add it to GL Env and assign ID
    185       result = gl_env->AddWindowSurface(egl_surface, winHandle);
    186     } else {
    187       delete winHandle;
    188     }
    189     return result;
    190   }
    191   return -1;
    192 }
    193 
    194 jint Java_android_filterfw_core_GLEnvironment_nativeAddSurfaceWidthHeight(JNIEnv* env,
    195                                                                       jobject thiz,
    196                                                                       jobject surface,
    197                                                                       jint width,
    198                                                                       jint height) {
    199   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    200   if (!surface) {
    201     ALOGE("GLEnvironment: Null SurfaceTexture passed!");
    202     return -1;
    203   } else if (gl_env) {
    204     // Get the ANativeWindow
    205     ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
    206     if (!window) {
    207       ALOGE("GLEnvironment: Error creating window!");
    208       return -1;
    209     }
    210 
    211     // Don't care about format (will get overridden by SurfaceTexture
    212     // anyway), but do care about width and height
    213     // TODO: Probably, this should be just be
    214     // ANativeWindow_setBuffersDimensions. The pixel format is
    215     // set during the eglCreateWindowSurface
    216     ANativeWindow_setBuffersGeometry(window, width, height, 0);
    217 
    218     NativeWindowHandle* winHandle = new NativeWindowHandle(window);
    219     int result = gl_env->FindSurfaceIdForWindow(winHandle);
    220     if (result == -1) {
    221       // Configure surface
    222       EGLConfig config;
    223       EGLint numConfigs = -1;
    224       EGLint configAttribs[] = {
    225         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    226         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    227         EGL_RED_SIZE, 8,
    228         EGL_GREEN_SIZE, 8,
    229         EGL_BLUE_SIZE, 8,
    230         EGL_RECORDABLE_ANDROID, EGL_TRUE,
    231         EGL_NONE
    232       };
    233 
    234 
    235 
    236       eglChooseConfig(gl_env->display(), configAttribs, &config, 1, &numConfigs);
    237       if (numConfigs < 1) {
    238         ALOGE("GLEnvironment: No suitable EGL configuration found for surface texture!");
    239         return -1;
    240       }
    241 
    242       // Create the EGL surface
    243       EGLSurface egl_surface = eglCreateWindowSurface(gl_env->display(),
    244                                                       config,
    245                                                       window,
    246                                                       NULL);
    247 
    248       if (GLEnv::CheckEGLError("eglCreateWindowSurface")) {
    249         ALOGE("GLEnvironment: Error creating window surface!");
    250         return -1;
    251       }
    252 
    253       // Add it to GL Env and assign ID
    254       result = gl_env->AddWindowSurface(egl_surface, winHandle);
    255     } else {
    256       delete winHandle;
    257     }
    258     return result;
    259   }
    260   return -1;
    261 }
    262 
    263 // nativeAddSurfaceFromMediaRecorder gets an EGLSurface
    264 // using a MediaRecorder object.
    265 // When Mediarecorder is used for recording GL Frames, it
    266 // will have a reference to a Native Handle (a SurfaceTexureClient)
    267 // which talks to the StageFrightRecorder in mediaserver via
    268 // a binder interface.
    269 jint Java_android_filterfw_core_GLEnvironment_nativeAddSurfaceFromMediaRecorder(
    270                                                       JNIEnv* env,
    271                                                       jobject thiz,
    272                                                       jobject jmediarecorder) {
    273     ALOGV("GLEnv Jni: nativeAddSurfaceFromMediaRecorder");
    274     GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    275     if (!gl_env) {
    276         return -1;
    277     }
    278     // get a native mediarecorder object from the java object
    279     sp<MediaRecorder> mr = getMediaRecorder(env, jmediarecorder);
    280     if (mr == NULL) {
    281         ALOGE("GLEnvironment: Error- MediaRecorder could not be initialized!");
    282         return -1;
    283     }
    284 
    285     // Ask the mediarecorder to return a handle to a surfacemediasource
    286     // This will talk to the StageFrightRecorder via MediaRecorderClient
    287     // over binder calls
    288     sp<IGraphicBufferProducer> surfaceMS = mr->querySurfaceMediaSourceFromMediaServer();
    289     if (surfaceMS == NULL) {
    290       ALOGE("GLEnvironment: Error- MediaRecorder returned a null \
    291               <IGraphicBufferProducer> handle.");
    292       return -1;
    293     }
    294     sp<Surface> surfaceTC = new Surface(surfaceMS);
    295     // Get the ANativeWindow
    296     sp<ANativeWindow> window = surfaceTC;
    297 
    298 
    299     if (window == NULL) {
    300       ALOGE("GLEnvironment: Error creating window!");
    301       return -1;
    302     }
    303     window->incStrong((void*)ANativeWindow_acquire);
    304 
    305     // In case of encoding, no need to set the dimensions
    306     // on the buffers. The dimensions for the final encoding are set by
    307     // the consumer side.
    308     // The pixel format is dictated by the GL, and set during the
    309     // eglCreateWindowSurface
    310 
    311     NativeWindowHandle* winHandle = new NativeWindowHandle(window.get());
    312     int result = gl_env->FindSurfaceIdForWindow(winHandle);
    313     // If we find a surface with that window handle, just return that id
    314     if (result != -1) {
    315         delete winHandle;
    316         return result;
    317     }
    318     // If we do not find a surface with that window handle, create
    319     // one and assign to it the handle
    320     // Configure surface
    321     EGLConfig config;
    322     EGLint numConfigs = -1;
    323     EGLint configAttribs[] = {
    324           EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    325           EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    326           EGL_RED_SIZE, 8,
    327           EGL_GREEN_SIZE, 8,
    328           EGL_BLUE_SIZE, 8,
    329           EGL_RECORDABLE_ANDROID, EGL_TRUE,
    330           EGL_NONE
    331     };
    332 
    333 
    334     eglChooseConfig(gl_env->display(), configAttribs, &config, 1, &numConfigs);
    335     if (numConfigs < 1) {
    336       ALOGE("GLEnvironment: No suitable EGL configuration found for surface texture!");
    337       delete winHandle;
    338       return -1;
    339     }
    340 
    341     // Create the EGL surface
    342     EGLSurface egl_surface = eglCreateWindowSurface(gl_env->display(),
    343                                                     config,
    344                                                     window.get(),
    345                                                     NULL);
    346 
    347     if (GLEnv::CheckEGLError("eglCreateWindowSurface")) {
    348       ALOGE("GLEnvironment: Error creating window surface!");
    349       delete winHandle;
    350       return -1;
    351     }
    352 
    353     // Add it to GL Env and assign ID
    354     result = gl_env->AddWindowSurface(egl_surface, winHandle);
    355     return result;
    356 }
    357 
    358 jboolean Java_android_filterfw_core_GLEnvironment_nativeActivateSurfaceId(JNIEnv* env,
    359                                                                           jobject thiz,
    360                                                                           jint surfaceId) {
    361   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    362   return gl_env ? ToJBool(gl_env->SwitchToSurfaceId(surfaceId) && gl_env->Activate()) : JNI_FALSE;
    363 }
    364 
    365 jboolean Java_android_filterfw_core_GLEnvironment_nativeRemoveSurfaceId(JNIEnv* env,
    366                                                                         jobject thiz,
    367                                                                         jint surfaceId) {
    368   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    369   return gl_env ? ToJBool(gl_env->ReleaseSurfaceId(surfaceId)) : JNI_FALSE;
    370 }
    371 
    372 jboolean Java_android_filterfw_core_GLEnvironment_nativeSetSurfaceTimestamp(JNIEnv* env,
    373                                                                             jobject thiz,
    374                                                                             jlong timestamp) {
    375   GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz);
    376   int64_t timestamp_native = timestamp;
    377   return gl_env ? ToJBool(gl_env->SetSurfaceTimestamp(timestamp_native)) : JNI_FALSE;
    378 }
    379