Description
System information (version)
- OpenCV => 3.4.1
- Operating System / Platform => Windows 64 Bit
- Compiler => Android Studio 3.1 (Clang NDK 16)
Detailed description
My Android activity creates a GL surface view that derives from CameraGLSurfaceView. During execution everything works as expected, but when I switch to another running app, forcing the activity to pause, the activity crashes. Logcat indicates that a thread was trying to work with an EGL context that didn't exist.
Steps to reproduce
-
Using Android Studio, create an Android app based on OpenCV Android Tutorial 4.
-
Install and run the app on your phone.
-
Use Android Studio's Logcat view to inspect the applications log while it executes.
-
Press the Android app switching button.
-
Your list of running applications appear.
-
After a few short moments, your app crashes.
-
Verify with Logcat that an EGL context error occurred.
Fix
The crash is caused by trying to access the EGL context from different threads. It happens in CameraGLRenderBase's updateState method. It typically calls doStart in the correct thread (the GLThread), but doStop sometimes gets called from the main thread. The solution entails doing proper thread management.
To solve the problem, the code can be changed in the following ways (using Kotlin in this example):
-
CameraGLRenderBase:
@MainThread @Synchronized fun enableView() { mEnabled = true mView.queueEvent( { updateState() } ) // this is the fix } ... @MainThread @Synchronized fun disableView() { mEnabled = false mView.queueEvent( { updateState() } ) // this is the fix } ... @WorkerThread protected fun updateState() { ... // keep body as is } @WorkerThread @Synchronized protected open fun doStart() { ... // keep body as is } @WorkerThread protected open fun doStop() { ... // keep body as is } ... @MainThread fun onPause() { mHaveSurface = false mView.queueEvent( { updateState() } ) // this is the fix mCameraHeight = -1 mCameraWidth = mCameraHeight } ... @WorkerThread override fun onSurfaceChanged(gl: GL10, surfaceWidth: Int, surfaceHeight: Int) { ... // keep body as is }
-
CameraGLSurfaceView.java: Call setCameraIndex after setRenderer is called. This will satisfy the conditions for the mView.queueEvent function.