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