diff --git a/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java b/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java index 5a54e904ad..09f78a58f4 100644 --- a/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java +++ b/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java @@ -50,7 +50,8 @@ class SurfaceTextureHelper { /** * Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|. A dedicated - * thread and handler is created for handling the SurfaceTexture. + * thread and handler is created for handling the SurfaceTexture. May return null if EGL fails to + * initialize a pixel buffer surface and make it current. */ public static SurfaceTextureHelper create( final String threadName, final EglBase.Context sharedContext) { @@ -65,7 +66,12 @@ class SurfaceTextureHelper { return ThreadUtils.invokeUninterruptibly(handler, new Callable() { @Override public SurfaceTextureHelper call() { - return new SurfaceTextureHelper(sharedContext, handler); + try { + return new SurfaceTextureHelper(sharedContext, handler); + } catch (RuntimeException e) { + Logging.e(TAG, threadName + " create failure", e); + return null; + } } }); } @@ -315,8 +321,16 @@ class SurfaceTextureHelper { this.handler = handler; eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PIXEL_BUFFER); - eglBase.createDummyPbufferSurface(); - eglBase.makeCurrent(); + try { + // Both these statements have been observed to fail on rare occasions, see BUG=webrtc:5682. + eglBase.createDummyPbufferSurface(); + eglBase.makeCurrent(); + } catch (RuntimeException e) { + // Clean up before rethrowing the exception. + eglBase.release(); + handler.getLooper().quit(); + throw e; + } oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); surfaceTexture = new SurfaceTexture(oesTextureId); diff --git a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java index e4f2449cb9..39ed12cfa3 100644 --- a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java +++ b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java @@ -369,7 +369,11 @@ public class VideoCapturerAndroid implements final CapturerObserver frameObserver) { Logging.d(TAG, "startCapture requested: " + width + "x" + height + "@" + framerate); if (surfaceTextureHelper == null) { - throw new IllegalArgumentException("surfaceTextureHelper not set."); + frameObserver.onCapturerStarted(false /* success */); + if (eventsHandler != null) { + eventsHandler.onCameraError("No SurfaceTexture created."); + } + return; } if (applicationContext == null) { throw new IllegalArgumentException("applicationContext not set."); diff --git a/webrtc/api/java/jni/androidmediadecoder_jni.cc b/webrtc/api/java/jni/androidmediadecoder_jni.cc index a0e5579c37..11c8d66f20 100644 --- a/webrtc/api/java/jni/androidmediadecoder_jni.cc +++ b/webrtc/api/java/jni/androidmediadecoder_jni.cc @@ -345,8 +345,13 @@ int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { ResetVariables(); if (use_surface_) { - surface_texture_helper_ = new rtc::RefCountedObject( + surface_texture_helper_ = SurfaceTextureHelper::create( jni, "Decoder SurfaceTextureHelper", render_egl_context_); + if (!surface_texture_helper_) { + ALOGE << "Couldn't create SurfaceTextureHelper - fallback to SW codec"; + sw_fallback_required_ = true; + return WEBRTC_VIDEO_CODEC_ERROR; + } } jobject j_video_codec_enum = JavaEnumFromIndexAndClassName( diff --git a/webrtc/api/java/jni/androidvideocapturer_jni.cc b/webrtc/api/java/jni/androidvideocapturer_jni.cc index 7165350e7d..615fcb32d8 100644 --- a/webrtc/api/java/jni/androidvideocapturer_jni.cc +++ b/webrtc/api/java/jni/androidvideocapturer_jni.cc @@ -30,18 +30,16 @@ int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni, return 0; } -AndroidVideoCapturerJni::AndroidVideoCapturerJni( - JNIEnv* jni, - jobject j_video_capturer, - jobject j_egl_context) +AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni, + jobject j_video_capturer, + jobject j_egl_context) : j_video_capturer_(jni, j_video_capturer), - j_video_capturer_class_( - jni, FindClass(jni, "org/webrtc/VideoCapturer")), + j_video_capturer_class_(jni, FindClass(jni, "org/webrtc/VideoCapturer")), j_observer_class_( jni, FindClass(jni, "org/webrtc/VideoCapturer$NativeObserver")), - surface_texture_helper_(new rtc::RefCountedObject( + surface_texture_helper_(SurfaceTextureHelper::create( jni, "Camera SurfaceTextureHelper", j_egl_context)), capturer_(nullptr) { LOG(LS_INFO) << "AndroidVideoCapturerJni ctor"; @@ -54,10 +52,12 @@ AndroidVideoCapturerJni::~AndroidVideoCapturerJni() { *j_video_capturer_, GetMethodID(jni(), *j_video_capturer_class_, "dispose", "()V")); CHECK_EXCEPTION(jni()) << "error during VideoCapturer.dispose()"; - jni()->CallVoidMethod( - surface_texture_helper_->GetJavaSurfaceTextureHelper(), - GetMethodID(jni(), FindClass(jni(), "org/webrtc/SurfaceTextureHelper"), - "dispose", "()V")); + if (surface_texture_helper_) { + jni()->CallVoidMethod( + surface_texture_helper_->GetJavaSurfaceTextureHelper(), + GetMethodID(jni(), FindClass(jni(), "org/webrtc/SurfaceTextureHelper"), + "dispose", "()V")); + } CHECK_EXCEPTION(jni()) << "error during SurfaceTextureHelper.dispose()"; } @@ -82,12 +82,12 @@ void AndroidVideoCapturerJni::Start(int width, int height, int framerate, jni(), *j_video_capturer_class_, "startCapture", "(IIILorg/webrtc/SurfaceTextureHelper;Landroid/content/Context;" "Lorg/webrtc/VideoCapturer$CapturerObserver;)V"); - jni()->CallVoidMethod(*j_video_capturer_, - m, width, height, - framerate, - surface_texture_helper_->GetJavaSurfaceTextureHelper(), - application_context_, - j_frame_observer); + jni()->CallVoidMethod( + *j_video_capturer_, m, width, height, framerate, + surface_texture_helper_ + ? surface_texture_helper_->GetJavaSurfaceTextureHelper() + : nullptr, + application_context_, j_frame_observer); CHECK_EXCEPTION(jni()) << "error during VideoCapturer.startCapture"; } diff --git a/webrtc/api/java/jni/surfacetexturehelper_jni.cc b/webrtc/api/java/jni/surfacetexturehelper_jni.cc index 97d05f82f1..04623a791d 100644 --- a/webrtc/api/java/jni/surfacetexturehelper_jni.cc +++ b/webrtc/api/java/jni/surfacetexturehelper_jni.cc @@ -17,21 +17,33 @@ namespace webrtc_jni { -SurfaceTextureHelper::SurfaceTextureHelper( - JNIEnv* jni, const char* thread_name, jobject j_egl_context) - : j_surface_texture_helper_(jni, jni->CallStaticObjectMethod( - FindClass(jni, "org/webrtc/SurfaceTextureHelper"), - GetStaticMethodID(jni, - FindClass(jni, "org/webrtc/SurfaceTextureHelper"), - "create", - "(Ljava/lang/String;Lorg/webrtc/EglBase$Context;)" - "Lorg/webrtc/SurfaceTextureHelper;"), - jni->NewStringUTF(thread_name), j_egl_context)), - j_return_texture_method_( - GetMethodID(jni, - FindClass(jni, "org/webrtc/SurfaceTextureHelper"), - "returnTextureFrame", - "()V")) { +rtc::scoped_refptr SurfaceTextureHelper::create( + JNIEnv* jni, + const char* thread_name, + jobject j_egl_context) { + jobject j_surface_texture_helper = jni->CallStaticObjectMethod( + FindClass(jni, "org/webrtc/SurfaceTextureHelper"), + GetStaticMethodID(jni, FindClass(jni, "org/webrtc/SurfaceTextureHelper"), + "create", + "(Ljava/lang/String;Lorg/webrtc/EglBase$Context;)" + "Lorg/webrtc/SurfaceTextureHelper;"), + jni->NewStringUTF(thread_name), j_egl_context); + CHECK_EXCEPTION(jni) + << "error during initialization of Java SurfaceTextureHelper"; + if (IsNull(jni, j_surface_texture_helper)) + return nullptr; + return new rtc::RefCountedObject( + jni, j_surface_texture_helper); +} + +SurfaceTextureHelper::SurfaceTextureHelper(JNIEnv* jni, + jobject j_surface_texture_helper) + : j_surface_texture_helper_(jni, j_surface_texture_helper), + j_return_texture_method_( + GetMethodID(jni, + FindClass(jni, "org/webrtc/SurfaceTextureHelper"), + "returnTextureFrame", + "()V")) { CHECK_EXCEPTION(jni) << "error during initialization of SurfaceTextureHelper"; } diff --git a/webrtc/api/java/jni/surfacetexturehelper_jni.h b/webrtc/api/java/jni/surfacetexturehelper_jni.h index 849c66b5dd..d7a9a7707a 100644 --- a/webrtc/api/java/jni/surfacetexturehelper_jni.h +++ b/webrtc/api/java/jni/surfacetexturehelper_jni.h @@ -38,9 +38,9 @@ namespace webrtc_jni { // 4. Call CreateTextureFrame to wrap the Java texture in a VideoFrameBuffer. class SurfaceTextureHelper : public rtc::RefCountInterface { public: - SurfaceTextureHelper(JNIEnv* jni, - const char* thread_name, - jobject j_egl_context); + // Might return null if creating the Java SurfaceTextureHelper fails. + static rtc::scoped_refptr create( + JNIEnv* jni, const char* thread_name, jobject j_egl_context); jobject GetJavaSurfaceTextureHelper() const; @@ -51,6 +51,7 @@ class SurfaceTextureHelper : public rtc::RefCountInterface { protected: ~SurfaceTextureHelper(); + SurfaceTextureHelper(JNIEnv* jni, jobject j_surface_texture_helper); private: // May be called on arbitrary thread.