blob: b64004e478e4a04f3cd3525302b8e32306642f98 [file] [log] [blame]
/*
* 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 <media/mediarecorder.h>
#include "native/core/gl_env.h"
#include <gui/IGraphicBufferProducer.h>
#include <gui/SurfaceTextureClient.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::SurfaceTextureClient;
class NativeWindowHandle : public WindowHandle {
public:
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) {
return ToJBool(WrapObjectInJava(new 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", "I");
if (context == NULL) {
return NULL;
}
MediaRecorder* const p = (MediaRecorder*)env->GetIntField(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<SurfaceTextureClient> surfaceTC = new SurfaceTextureClient(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;
}