| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| // #define LOG_NDEBUG 0 |
| |
| #include <stdint.h> |
| #include <android/native_window_jni.h> |
| |
| #include "jni/jni_gl_environment.h" |
| #include "jni/jni_util.h" |
| #include "native/core/gl_env.h" |
| #include <media/mediarecorder.h> |
| |
| #include <gui/IGraphicBufferProducer.h> |
| #include <gui/Surface.h> |
| #include <utils/Errors.h> |
| #include <system/window.h> |
| |
| |
| using android::filterfw::GLEnv; |
| using android::filterfw::WindowHandle; |
| using android::MediaRecorder; |
| using android::sp; |
| using android::IGraphicBufferProducer; |
| using android::Surface; |
| |
| |
| class NativeWindowHandle : public WindowHandle { |
| public: |
| explicit NativeWindowHandle(ANativeWindow* window) : window_(window) { |
| } |
| |
| virtual ~NativeWindowHandle() { |
| } |
| |
| virtual void Destroy() { |
| ALOGI("Releasing ANativeWindow!"); |
| ANativeWindow_release(window_); |
| } |
| |
| virtual const void* InternalHandle() const { |
| return window_; |
| } |
| |
| virtual void* InternalHandle() { |
| return window_; |
| } |
| |
| private: |
| ANativeWindow* window_; |
| }; |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeAllocate(JNIEnv* env, jobject thiz) { |
| std::unique_ptr<GLEnv> glEnv(new GLEnv()); |
| return ToJBool(WrapOwnedObjectInJava(std::move(glEnv), env, thiz, true)); |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeDeallocate(JNIEnv* env, jobject thiz) { |
| return ToJBool(DeleteNativeObject<GLEnv>(env, thiz)); |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeInitWithNewContext(JNIEnv* env, |
| jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->InitWithNewContext()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeInitWithCurrentContext(JNIEnv* env, |
| jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->InitWithCurrentContext()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeIsActive(JNIEnv* env, jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->IsActive()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeIsContextActive(JNIEnv* env, jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->IsContextActive()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeIsAnyContextActive(JNIEnv* /* env */, |
| jclass /* clazz */) { |
| return ToJBool(GLEnv::IsAnyContextActive()); |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeActivate(JNIEnv* env, jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->Activate()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeDeactivate(JNIEnv* env, jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->Deactivate()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeSwapBuffers(JNIEnv* env, jobject thiz) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->SwapBuffers()) : JNI_FALSE; |
| } |
| |
| // Get the native mediarecorder object corresponding to the java object |
| static sp<MediaRecorder> getMediaRecorder(JNIEnv* env, jobject jmediarecorder) { |
| jclass clazz = env->FindClass("android/media/MediaRecorder"); |
| if (clazz == NULL) { |
| return NULL; |
| } |
| |
| jfieldID context = env->GetFieldID(clazz, "mNativeContext", "J"); |
| if (context == NULL) { |
| return NULL; |
| } |
| |
| MediaRecorder* const p = (MediaRecorder*)env->GetLongField(jmediarecorder, context); |
| env->DeleteLocalRef(clazz); |
| return sp<MediaRecorder>(p); |
| } |
| |
| |
| jint Java_android_filterfw_core_GLEnvironment_nativeAddSurface(JNIEnv* env, |
| jobject thiz, |
| jobject surface) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| if (!surface) { |
| ALOGE("GLEnvironment: Null Surface passed!"); |
| return -1; |
| } else if (gl_env) { |
| // Get the ANativeWindow |
| ANativeWindow* window = ANativeWindow_fromSurface(env, surface); |
| if (!window) { |
| ALOGE("GLEnvironment: Error creating window!"); |
| return -1; |
| } |
| |
| NativeWindowHandle* winHandle = new NativeWindowHandle(window); |
| int result = gl_env->FindSurfaceIdForWindow(winHandle); |
| if (result == -1) { |
| // Configure surface |
| EGLConfig config; |
| EGLint numConfigs = -1; |
| EGLint configAttribs[] = { |
| EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
| EGL_RED_SIZE, 8, |
| EGL_GREEN_SIZE, 8, |
| EGL_BLUE_SIZE, 8, |
| EGL_RECORDABLE_ANDROID, EGL_TRUE, |
| EGL_NONE |
| }; |
| |
| |
| |
| eglChooseConfig(gl_env->display(), configAttribs, &config, 1, &numConfigs); |
| if (numConfigs < 1) { |
| ALOGE("GLEnvironment: No suitable EGL configuration found for surface!"); |
| return -1; |
| } |
| |
| // Create the EGL surface |
| EGLSurface egl_surface = eglCreateWindowSurface(gl_env->display(), |
| config, |
| window, |
| NULL); |
| |
| if (GLEnv::CheckEGLError("eglCreateWindowSurface")) { |
| ALOGE("GLEnvironment: Error creating window surface!"); |
| return -1; |
| } |
| |
| // Add it to GL Env and assign ID |
| result = gl_env->AddWindowSurface(egl_surface, winHandle); |
| } else { |
| delete winHandle; |
| } |
| return result; |
| } |
| return -1; |
| } |
| |
| jint Java_android_filterfw_core_GLEnvironment_nativeAddSurfaceWidthHeight(JNIEnv* env, |
| jobject thiz, |
| jobject surface, |
| jint width, |
| jint height) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| if (!surface) { |
| ALOGE("GLEnvironment: Null SurfaceTexture passed!"); |
| return -1; |
| } else if (gl_env) { |
| // Get the ANativeWindow |
| ANativeWindow* window = ANativeWindow_fromSurface(env, surface); |
| if (!window) { |
| ALOGE("GLEnvironment: Error creating window!"); |
| return -1; |
| } |
| |
| // Don't care about format (will get overridden by SurfaceTexture |
| // anyway), but do care about width and height |
| // TODO: Probably, this should be just be |
| // ANativeWindow_setBuffersDimensions. The pixel format is |
| // set during the eglCreateWindowSurface |
| ANativeWindow_setBuffersGeometry(window, width, height, 0); |
| |
| NativeWindowHandle* winHandle = new NativeWindowHandle(window); |
| int result = gl_env->FindSurfaceIdForWindow(winHandle); |
| if (result == -1) { |
| // Configure surface |
| EGLConfig config; |
| EGLint numConfigs = -1; |
| EGLint configAttribs[] = { |
| EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
| EGL_RED_SIZE, 8, |
| EGL_GREEN_SIZE, 8, |
| EGL_BLUE_SIZE, 8, |
| EGL_RECORDABLE_ANDROID, EGL_TRUE, |
| EGL_NONE |
| }; |
| |
| |
| |
| eglChooseConfig(gl_env->display(), configAttribs, &config, 1, &numConfigs); |
| if (numConfigs < 1) { |
| ALOGE("GLEnvironment: No suitable EGL configuration found for surface texture!"); |
| return -1; |
| } |
| |
| // Create the EGL surface |
| EGLSurface egl_surface = eglCreateWindowSurface(gl_env->display(), |
| config, |
| window, |
| NULL); |
| |
| if (GLEnv::CheckEGLError("eglCreateWindowSurface")) { |
| ALOGE("GLEnvironment: Error creating window surface!"); |
| return -1; |
| } |
| |
| // Add it to GL Env and assign ID |
| result = gl_env->AddWindowSurface(egl_surface, winHandle); |
| } else { |
| delete winHandle; |
| } |
| return result; |
| } |
| return -1; |
| } |
| |
| // nativeAddSurfaceFromMediaRecorder gets an EGLSurface |
| // using a MediaRecorder object. |
| // When Mediarecorder is used for recording GL Frames, it |
| // will have a reference to a Native Handle (a SurfaceTexureClient) |
| // which talks to the StageFrightRecorder in mediaserver via |
| // a binder interface. |
| jint Java_android_filterfw_core_GLEnvironment_nativeAddSurfaceFromMediaRecorder( |
| JNIEnv* env, |
| jobject thiz, |
| jobject jmediarecorder) { |
| ALOGV("GLEnv Jni: nativeAddSurfaceFromMediaRecorder"); |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| if (!gl_env) { |
| return -1; |
| } |
| // get a native mediarecorder object from the java object |
| sp<MediaRecorder> mr = getMediaRecorder(env, jmediarecorder); |
| if (mr == NULL) { |
| ALOGE("GLEnvironment: Error- MediaRecorder could not be initialized!"); |
| return -1; |
| } |
| |
| // Ask the mediarecorder to return a handle to a surfacemediasource |
| // This will talk to the StageFrightRecorder via MediaRecorderClient |
| // over binder calls |
| sp<IGraphicBufferProducer> surfaceMS = mr->querySurfaceMediaSourceFromMediaServer(); |
| if (surfaceMS == NULL) { |
| ALOGE("GLEnvironment: Error- MediaRecorder returned a null \ |
| <IGraphicBufferProducer> handle."); |
| return -1; |
| } |
| sp<Surface> surfaceTC = new Surface(surfaceMS); |
| // Get the ANativeWindow |
| sp<ANativeWindow> window = surfaceTC; |
| |
| |
| if (window == NULL) { |
| ALOGE("GLEnvironment: Error creating window!"); |
| return -1; |
| } |
| window->incStrong((void*)ANativeWindow_acquire); |
| |
| // In case of encoding, no need to set the dimensions |
| // on the buffers. The dimensions for the final encoding are set by |
| // the consumer side. |
| // The pixel format is dictated by the GL, and set during the |
| // eglCreateWindowSurface |
| |
| NativeWindowHandle* winHandle = new NativeWindowHandle(window.get()); |
| int result = gl_env->FindSurfaceIdForWindow(winHandle); |
| // If we find a surface with that window handle, just return that id |
| if (result != -1) { |
| delete winHandle; |
| return result; |
| } |
| // If we do not find a surface with that window handle, create |
| // one and assign to it the handle |
| // Configure surface |
| EGLConfig config; |
| EGLint numConfigs = -1; |
| EGLint configAttribs[] = { |
| EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
| EGL_RED_SIZE, 8, |
| EGL_GREEN_SIZE, 8, |
| EGL_BLUE_SIZE, 8, |
| EGL_RECORDABLE_ANDROID, EGL_TRUE, |
| EGL_NONE |
| }; |
| |
| |
| eglChooseConfig(gl_env->display(), configAttribs, &config, 1, &numConfigs); |
| if (numConfigs < 1) { |
| ALOGE("GLEnvironment: No suitable EGL configuration found for surface texture!"); |
| delete winHandle; |
| return -1; |
| } |
| |
| // Create the EGL surface |
| EGLSurface egl_surface = eglCreateWindowSurface(gl_env->display(), |
| config, |
| window.get(), |
| NULL); |
| |
| if (GLEnv::CheckEGLError("eglCreateWindowSurface")) { |
| ALOGE("GLEnvironment: Error creating window surface!"); |
| delete winHandle; |
| return -1; |
| } |
| |
| // Add it to GL Env and assign ID |
| result = gl_env->AddWindowSurface(egl_surface, winHandle); |
| return result; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeActivateSurfaceId(JNIEnv* env, |
| jobject thiz, |
| jint surfaceId) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->SwitchToSurfaceId(surfaceId) && gl_env->Activate()) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeRemoveSurfaceId(JNIEnv* env, |
| jobject thiz, |
| jint surfaceId) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| return gl_env ? ToJBool(gl_env->ReleaseSurfaceId(surfaceId)) : JNI_FALSE; |
| } |
| |
| jboolean Java_android_filterfw_core_GLEnvironment_nativeSetSurfaceTimestamp(JNIEnv* env, |
| jobject thiz, |
| jlong timestamp) { |
| GLEnv* gl_env = ConvertFromJava<GLEnv>(env, thiz); |
| int64_t timestamp_native = timestamp; |
| return gl_env ? ToJBool(gl_env->SetSurfaceTimestamp(timestamp_native)) : JNI_FALSE; |
| } |