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