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