Android: Handle SurfaceTextureHelper ctor failure for decoder and capturer

BUG=webrtc:5874
TEST=Manually throw an exception inside the SurfaceTextureHelper ctor and run AppRTCDemo.

Review-Url: https://codereview.webrtc.org/1840193007
Cr-Commit-Position: refs/heads/master@{#12665}
This commit is contained in:
magjed
2016-05-09 08:28:45 -07:00
committed by Commit bot
parent d040480f69
commit 2aa84260d8
6 changed files with 77 additions and 41 deletions

View File

@ -50,7 +50,8 @@ class SurfaceTextureHelper {
/** /**
* Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|. A dedicated * 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( public static SurfaceTextureHelper create(
final String threadName, final EglBase.Context sharedContext) { final String threadName, final EglBase.Context sharedContext) {
@ -65,7 +66,12 @@ class SurfaceTextureHelper {
return ThreadUtils.invokeUninterruptibly(handler, new Callable<SurfaceTextureHelper>() { return ThreadUtils.invokeUninterruptibly(handler, new Callable<SurfaceTextureHelper>() {
@Override @Override
public SurfaceTextureHelper call() { 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; this.handler = handler;
eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PIXEL_BUFFER); eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PIXEL_BUFFER);
eglBase.createDummyPbufferSurface(); try {
eglBase.makeCurrent(); // 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); oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
surfaceTexture = new SurfaceTexture(oesTextureId); surfaceTexture = new SurfaceTexture(oesTextureId);

View File

@ -369,7 +369,11 @@ public class VideoCapturerAndroid implements
final CapturerObserver frameObserver) { final CapturerObserver frameObserver) {
Logging.d(TAG, "startCapture requested: " + width + "x" + height + "@" + framerate); Logging.d(TAG, "startCapture requested: " + width + "x" + height + "@" + framerate);
if (surfaceTextureHelper == null) { 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) { if (applicationContext == null) {
throw new IllegalArgumentException("applicationContext not set."); throw new IllegalArgumentException("applicationContext not set.");

View File

@ -345,8 +345,13 @@ int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
ResetVariables(); ResetVariables();
if (use_surface_) { if (use_surface_) {
surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>( surface_texture_helper_ = SurfaceTextureHelper::create(
jni, "Decoder SurfaceTextureHelper", render_egl_context_); 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( jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(

View File

@ -30,18 +30,16 @@ int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni,
return 0; return 0;
} }
AndroidVideoCapturerJni::AndroidVideoCapturerJni( AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni,
JNIEnv* jni, jobject j_video_capturer,
jobject j_video_capturer, jobject j_egl_context)
jobject j_egl_context)
: j_video_capturer_(jni, j_video_capturer), : j_video_capturer_(jni, j_video_capturer),
j_video_capturer_class_( j_video_capturer_class_(jni, FindClass(jni, "org/webrtc/VideoCapturer")),
jni, FindClass(jni, "org/webrtc/VideoCapturer")),
j_observer_class_( j_observer_class_(
jni, jni,
FindClass(jni, FindClass(jni,
"org/webrtc/VideoCapturer$NativeObserver")), "org/webrtc/VideoCapturer$NativeObserver")),
surface_texture_helper_(new rtc::RefCountedObject<SurfaceTextureHelper>( surface_texture_helper_(SurfaceTextureHelper::create(
jni, "Camera SurfaceTextureHelper", j_egl_context)), jni, "Camera SurfaceTextureHelper", j_egl_context)),
capturer_(nullptr) { capturer_(nullptr) {
LOG(LS_INFO) << "AndroidVideoCapturerJni ctor"; LOG(LS_INFO) << "AndroidVideoCapturerJni ctor";
@ -54,10 +52,12 @@ AndroidVideoCapturerJni::~AndroidVideoCapturerJni() {
*j_video_capturer_, *j_video_capturer_,
GetMethodID(jni(), *j_video_capturer_class_, "dispose", "()V")); GetMethodID(jni(), *j_video_capturer_class_, "dispose", "()V"));
CHECK_EXCEPTION(jni()) << "error during VideoCapturer.dispose()"; CHECK_EXCEPTION(jni()) << "error during VideoCapturer.dispose()";
jni()->CallVoidMethod( if (surface_texture_helper_) {
surface_texture_helper_->GetJavaSurfaceTextureHelper(), jni()->CallVoidMethod(
GetMethodID(jni(), FindClass(jni(), "org/webrtc/SurfaceTextureHelper"), surface_texture_helper_->GetJavaSurfaceTextureHelper(),
"dispose", "()V")); GetMethodID(jni(), FindClass(jni(), "org/webrtc/SurfaceTextureHelper"),
"dispose", "()V"));
}
CHECK_EXCEPTION(jni()) << "error during SurfaceTextureHelper.dispose()"; 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", jni(), *j_video_capturer_class_, "startCapture",
"(IIILorg/webrtc/SurfaceTextureHelper;Landroid/content/Context;" "(IIILorg/webrtc/SurfaceTextureHelper;Landroid/content/Context;"
"Lorg/webrtc/VideoCapturer$CapturerObserver;)V"); "Lorg/webrtc/VideoCapturer$CapturerObserver;)V");
jni()->CallVoidMethod(*j_video_capturer_, jni()->CallVoidMethod(
m, width, height, *j_video_capturer_, m, width, height, framerate,
framerate, surface_texture_helper_
surface_texture_helper_->GetJavaSurfaceTextureHelper(), ? surface_texture_helper_->GetJavaSurfaceTextureHelper()
application_context_, : nullptr,
j_frame_observer); application_context_, j_frame_observer);
CHECK_EXCEPTION(jni()) << "error during VideoCapturer.startCapture"; CHECK_EXCEPTION(jni()) << "error during VideoCapturer.startCapture";
} }

View File

@ -17,21 +17,33 @@
namespace webrtc_jni { namespace webrtc_jni {
SurfaceTextureHelper::SurfaceTextureHelper( rtc::scoped_refptr<SurfaceTextureHelper> SurfaceTextureHelper::create(
JNIEnv* jni, const char* thread_name, jobject j_egl_context) JNIEnv* jni,
: j_surface_texture_helper_(jni, jni->CallStaticObjectMethod( const char* thread_name,
FindClass(jni, "org/webrtc/SurfaceTextureHelper"), jobject j_egl_context) {
GetStaticMethodID(jni, jobject j_surface_texture_helper = jni->CallStaticObjectMethod(
FindClass(jni, "org/webrtc/SurfaceTextureHelper"), FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
"create", GetStaticMethodID(jni, FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
"(Ljava/lang/String;Lorg/webrtc/EglBase$Context;)" "create",
"Lorg/webrtc/SurfaceTextureHelper;"), "(Ljava/lang/String;Lorg/webrtc/EglBase$Context;)"
jni->NewStringUTF(thread_name), j_egl_context)), "Lorg/webrtc/SurfaceTextureHelper;"),
j_return_texture_method_( jni->NewStringUTF(thread_name), j_egl_context);
GetMethodID(jni, CHECK_EXCEPTION(jni)
FindClass(jni, "org/webrtc/SurfaceTextureHelper"), << "error during initialization of Java SurfaceTextureHelper";
"returnTextureFrame", if (IsNull(jni, j_surface_texture_helper))
"()V")) { return nullptr;
return new rtc::RefCountedObject<SurfaceTextureHelper>(
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"; CHECK_EXCEPTION(jni) << "error during initialization of SurfaceTextureHelper";
} }

View File

@ -38,9 +38,9 @@ namespace webrtc_jni {
// 4. Call CreateTextureFrame to wrap the Java texture in a VideoFrameBuffer. // 4. Call CreateTextureFrame to wrap the Java texture in a VideoFrameBuffer.
class SurfaceTextureHelper : public rtc::RefCountInterface { class SurfaceTextureHelper : public rtc::RefCountInterface {
public: public:
SurfaceTextureHelper(JNIEnv* jni, // Might return null if creating the Java SurfaceTextureHelper fails.
const char* thread_name, static rtc::scoped_refptr<SurfaceTextureHelper> create(
jobject j_egl_context); JNIEnv* jni, const char* thread_name, jobject j_egl_context);
jobject GetJavaSurfaceTextureHelper() const; jobject GetJavaSurfaceTextureHelper() const;
@ -51,6 +51,7 @@ class SurfaceTextureHelper : public rtc::RefCountInterface {
protected: protected:
~SurfaceTextureHelper(); ~SurfaceTextureHelper();
SurfaceTextureHelper(JNIEnv* jni, jobject j_surface_texture_helper);
private: private:
// May be called on arbitrary thread. // May be called on arbitrary thread.