Change PeerConnectionFactory.setVideoHwAccelerationOptions to create shared Egl context for harware encoders and decoders.
Before this fix, it was required that the EGL context used as an argument was kept open until all PeerConnections using the context had been closed. With this fix, that is no longer required.
Also, if a released EGLContext (EGL_NO_CONTEXT) is used, harware codecs will fallback to use byte buffers for encoding and decoding.
BUG=b/26583522
R=glaznev@webrtc.org
Review URL: https://codereview.webrtc.org/1615153002 .
Cr-Commit-Position: refs/heads/master@{#11398}
diff --git a/talk/app/webrtc/java/android/org/webrtc/EglBase.java b/talk/app/webrtc/java/android/org/webrtc/EglBase.java
index 035645b..b675d09 100644
--- a/talk/app/webrtc/java/android/org/webrtc/EglBase.java
+++ b/talk/app/webrtc/java/android/org/webrtc/EglBase.java
@@ -104,6 +104,10 @@
return create(null, CONFIG_PLAIN);
}
+ public static EglBase create(Context sharedContext) {
+ return create(sharedContext, CONFIG_PLAIN);
+ }
+
public abstract void createSurface(Surface surface);
// Create EGLSurface from the Android SurfaceTexture.
diff --git a/talk/app/webrtc/java/android/org/webrtc/EglBase10.java b/talk/app/webrtc/java/android/org/webrtc/EglBase10.java
index f2aa985..d11292d 100644
--- a/talk/app/webrtc/java/android/org/webrtc/EglBase10.java
+++ b/talk/app/webrtc/java/android/org/webrtc/EglBase10.java
@@ -286,6 +286,9 @@
// Return an EGLConfig, or die trying.
private EGLContext createEglContext(
Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ if (sharedContext != null && sharedContext.eglContext == EGL10.EGL_NO_CONTEXT) {
+ throw new RuntimeException("Invalid sharedContext");
+ }
int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
EGLContext rootContext =
sharedContext == null ? EGL10.EGL_NO_CONTEXT : sharedContext.eglContext;
diff --git a/talk/app/webrtc/java/android/org/webrtc/EglBase14.java b/talk/app/webrtc/java/android/org/webrtc/EglBase14.java
index 5d65201..8768ed4 100644
--- a/talk/app/webrtc/java/android/org/webrtc/EglBase14.java
+++ b/talk/app/webrtc/java/android/org/webrtc/EglBase14.java
@@ -241,6 +241,9 @@
// Return an EGLConfig, or die trying.
private static EGLContext createEglContext(
EglBase14.Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ if (sharedContext != null && sharedContext.egl14Context == EGL14.EGL_NO_CONTEXT) {
+ throw new RuntimeException("Invalid sharedContext");
+ }
int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
EGLContext rootContext =
sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext.egl14Context;
diff --git a/talk/app/webrtc/java/jni/androidmediacodeccommon.h b/talk/app/webrtc/java/jni/androidmediacodeccommon.h
index 6fa1817..4f91da4 100644
--- a/talk/app/webrtc/java/jni/androidmediacodeccommon.h
+++ b/talk/app/webrtc/java/jni/androidmediacodeccommon.h
@@ -30,7 +30,10 @@
#define TALK_APP_WEBRTC_JAVA_JNI_ANDROIDMEDIACODECCOMMON_H_
#include <android/log.h>
+#include <string>
+
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
+#include "talk/app/webrtc/java/jni/jni_helpers.h"
#include "webrtc/base/thread.h"
#include "webrtc/base/logging.h"
#include "webrtc/system_wrappers/include/tick_util.h"
@@ -85,7 +88,7 @@
// Return the (singleton) Java Enum object corresponding to |index|;
// |state_class_fragment| is something like "MediaSource$State".
-static inline jobject JavaEnumFromIndex(
+static inline jobject JavaEnumFromIndexAndClassName(
JNIEnv* jni, const std::string& state_class_fragment, int index) {
const std::string state_class = "org/webrtc/" + state_class_fragment;
return JavaEnumFromIndex(jni, FindClass(jni, state_class.c_str()),
diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
index e46750f..ed75933 100644
--- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
+++ b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
@@ -347,7 +347,7 @@
jni, java_surface_texture_helper_);
}
- jobject j_video_codec_enum = JavaEnumFromIndex(
+ jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
bool success = jni->CallBooleanMethod(
*j_media_codec_video_decoder_,
@@ -819,8 +819,7 @@
codec_thread_->PostDelayed(kMediaCodecPollMs, this);
}
-MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
- render_egl_context_(NULL) {
+MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
ALOGD << "MediaCodecVideoDecoderFactory ctor";
JNIEnv* jni = AttachCurrentThreadIfNeeded();
ScopedLocalRefFrame local_ref_frame(jni);
@@ -863,37 +862,13 @@
MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
ALOGD << "MediaCodecVideoDecoderFactory dtor";
- if (render_egl_context_) {
- JNIEnv* jni = AttachCurrentThreadIfNeeded();
- jni->DeleteGlobalRef(render_egl_context_);
- render_egl_context_ = NULL;
- }
}
void MediaCodecVideoDecoderFactory::SetEGLContext(
JNIEnv* jni, jobject render_egl_context) {
ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
- if (render_egl_context_) {
- jni->DeleteGlobalRef(render_egl_context_);
- render_egl_context_ = NULL;
- }
- if (!IsNull(jni, render_egl_context)) {
- render_egl_context_ = jni->NewGlobalRef(render_egl_context);
- if (CheckException(jni)) {
- ALOGE << "error calling NewGlobalRef for EGL Context.";
- render_egl_context_ = NULL;
- } else {
- jclass j_egl_context_class =
- FindClass(jni, "org/webrtc/EglBase$Context");
- if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
- ALOGE << "Wrong EGL Context.";
- jni->DeleteGlobalRef(render_egl_context_);
- render_egl_context_ = NULL;
- }
- }
- }
- if (render_egl_context_ == NULL) {
- ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled.";
+ if (!egl_.CreateEglBase(jni, render_egl_context)) {
+ ALOGW << "Invalid EGL context - HW surface decoding is disabled.";
}
}
@@ -901,17 +876,17 @@
VideoCodecType type) {
if (supported_codec_types_.empty()) {
ALOGW << "No HW video decoder for type " << (int)type;
- return NULL;
+ return nullptr;
}
for (VideoCodecType codec_type : supported_codec_types_) {
if (codec_type == type) {
ALOGD << "Create HW video decoder for type " << (int)type;
- return new MediaCodecVideoDecoder(
- AttachCurrentThreadIfNeeded(), type, render_egl_context_);
+ return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
+ egl_.egl_base_context());
}
}
ALOGW << "Can not find HW video decoder for type " << (int)type;
- return NULL;
+ return nullptr;
}
void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.h b/talk/app/webrtc/java/jni/androidmediadecoder_jni.h
index 673f998..85a61c1 100644
--- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.h
+++ b/talk/app/webrtc/java/jni/androidmediadecoder_jni.h
@@ -29,7 +29,7 @@
#ifndef TALK_APP_WEBRTC_JAVA_JNI_ANDROIDMEDIADECODER_JNI_H_
#define TALK_APP_WEBRTC_JAVA_JNI_ANDROIDMEDIADECODER_JNI_H_
-#include "talk/app/webrtc/java/jni/jni_helpers.h"
+#include "talk/app/webrtc/java/jni/eglbase_jni.h"
#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
namespace webrtc_jni {
@@ -50,7 +50,7 @@
void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) override;
private:
- jobject render_egl_context_; // Render EGL context.
+ EglBase egl_;
std::vector<webrtc::VideoCodecType> supported_codec_types_;
};
diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
index e87abaf..4452e34 100644
--- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
+++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
@@ -134,7 +134,7 @@
int GetTargetFramerate() override;
- bool SupportsNativeHandle() const override { return true; }
+ bool SupportsNativeHandle() const override { return egl_context_ != nullptr; }
const char* ImplementationName() const override;
private:
@@ -537,7 +537,7 @@
frames_received_since_last_key_ = kMinKeyFrameInterval;
// We enforce no extra stride/padding in the format creation step.
- jobject j_video_codec_enum = JavaEnumFromIndex(
+ jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_);
const bool encode_status = jni->CallBooleanMethod(
*j_media_codec_video_encoder_, j_init_encode_method_,
@@ -1149,8 +1149,7 @@
return "MediaCodec";
}
-MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory()
- : egl_context_(nullptr) {
+MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
JNIEnv* jni = AttachCurrentThreadIfNeeded();
ScopedLocalRefFrame local_ref_frame(jni);
jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
@@ -1187,32 +1186,15 @@
}
}
-MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
+MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {
+ ALOGD << "MediaCodecVideoEncoderFactory dtor";
+}
void MediaCodecVideoEncoderFactory::SetEGLContext(
JNIEnv* jni, jobject render_egl_context) {
ALOGD << "MediaCodecVideoEncoderFactory::SetEGLContext";
- if (egl_context_) {
- jni->DeleteGlobalRef(egl_context_);
- egl_context_ = NULL;
- }
- if (!IsNull(jni, render_egl_context)) {
- egl_context_ = jni->NewGlobalRef(render_egl_context);
- if (CheckException(jni)) {
- ALOGE << "error calling NewGlobalRef for EGL Context.";
- egl_context_ = NULL;
- } else {
- jclass j_egl_context_class =
- FindClass(jni, "org/webrtc/EglBase14$Context");
- if (!jni->IsInstanceOf(egl_context_, j_egl_context_class)) {
- ALOGE << "Wrong EGL Context.";
- jni->DeleteGlobalRef(egl_context_);
- egl_context_ = NULL;
- }
- }
- }
- if (egl_context_ == NULL) {
- ALOGW << "NULL VideoDecoder EGL context - HW surface encoding is disabled.";
+ if (!egl_base_.CreateEglBase(jni, render_egl_context)) {
+ ALOGW << "Invalid EGL context - HW surface encoding is disabled.";
}
}
@@ -1220,7 +1202,7 @@
VideoCodecType type) {
if (supported_codecs_.empty()) {
ALOGW << "No HW video encoder for type " << (int)type;
- return NULL;
+ return nullptr;
}
for (std::vector<VideoCodec>::const_iterator it = supported_codecs_.begin();
it != supported_codecs_.end(); ++it) {
@@ -1228,11 +1210,11 @@
ALOGD << "Create HW video encoder for type " << (int)type <<
" (" << it->name << ").";
return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded(), type,
- egl_context_);
+ egl_base_.egl_base_context());
}
}
ALOGW << "Can not find HW video encoder for type " << (int)type;
- return NULL;
+ return nullptr;
}
const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.h b/talk/app/webrtc/java/jni/androidmediaencoder_jni.h
index 8ff8164..8b5f413 100644
--- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.h
+++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.h
@@ -31,7 +31,7 @@
#include <vector>
-#include "talk/app/webrtc/java/jni/jni_helpers.h"
+#include "talk/app/webrtc/java/jni/eglbase_jni.h"
#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
namespace webrtc_jni {
@@ -52,7 +52,8 @@
void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override;
private:
- jobject egl_context_;
+ EglBase egl_base_;
+
// Empty if platform support is lacking, const after ctor returns.
std::vector<VideoCodec> supported_codecs_;
};
diff --git a/talk/app/webrtc/java/jni/eglbase_jni.cc b/talk/app/webrtc/java/jni/eglbase_jni.cc
new file mode 100644
index 0000000..b91aa39
--- /dev/null
+++ b/talk/app/webrtc/java/jni/eglbase_jni.cc
@@ -0,0 +1,90 @@
+/*
+ * libjingle
+ * Copyright 2016 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "talk/app/webrtc/java/jni/eglbase_jni.h"
+
+#include "talk/app/webrtc/java/jni/androidmediacodeccommon.h"
+#include "talk/app/webrtc/java/jni/classreferenceholder.h"
+#include "talk/app/webrtc/java/jni/jni_helpers.h"
+
+namespace webrtc_jni {
+
+EglBase::EglBase() {
+}
+
+EglBase::~EglBase() {
+ if (egl_base_) {
+ JNIEnv* jni = AttachCurrentThreadIfNeeded();
+ jni->DeleteGlobalRef(egl_base_context_);
+ egl_base_context_ = nullptr;
+ jni->CallVoidMethod(egl_base_,
+ GetMethodID(jni,
+ FindClass(jni, "org/webrtc/EglBase"),
+ "release", "()V"));
+ jni->DeleteGlobalRef(egl_base_);
+ }
+}
+
+bool EglBase::CreateEglBase(JNIEnv* jni, jobject egl_context) {
+ if (egl_base_) {
+ jni->DeleteGlobalRef(egl_base_context_);
+ egl_base_context_ = nullptr;
+ jni->CallVoidMethod(egl_base_,
+ GetMethodID(jni,
+ FindClass(jni, "org/webrtc/EglBase"),
+ "release", "()V"));
+ jni->DeleteGlobalRef(egl_base_);
+ egl_base_ = nullptr;
+ }
+
+ if (IsNull(jni, egl_context))
+ return false;
+
+ jobject egl_base = jni->CallStaticObjectMethod(
+ FindClass(jni, "org/webrtc/EglBase"),
+ GetStaticMethodID(jni,
+ FindClass(jni, "org/webrtc/EglBase"),
+ "create",
+ "(Lorg/webrtc/EglBase$Context;)Lorg/webrtc/EglBase;"),
+ egl_context);
+ if (CheckException(jni))
+ return false;
+
+ egl_base_ = jni->NewGlobalRef(egl_base);
+ egl_base_context_ = jni->NewGlobalRef(
+ jni->CallObjectMethod(
+ egl_base_,
+ GetMethodID(jni,
+ FindClass(jni, "org/webrtc/EglBase"),
+ "getEglBaseContext",
+ "()Lorg/webrtc/EglBase$Context;")));
+ RTC_CHECK(egl_base_context_);
+ return true;
+}
+
+} // namespace webrtc_jni
diff --git a/talk/app/webrtc/java/jni/eglbase_jni.h b/talk/app/webrtc/java/jni/eglbase_jni.h
new file mode 100644
index 0000000..1015d90
--- /dev/null
+++ b/talk/app/webrtc/java/jni/eglbase_jni.h
@@ -0,0 +1,60 @@
+/*
+ * libjingle
+ * Copyright 2016 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TALK_APP_WEBRTC_JAVA_JNI_EGLBASE_JNI_H_
+#define TALK_APP_WEBRTC_JAVA_JNI_EGLBASE_JNI_H_
+
+#include <jni.h>
+
+#include "webrtc/base/constructormagic.h"
+
+namespace webrtc_jni {
+
+// Helper class used for creating a Java instance of org/webrtc/EglBase.
+class EglBase {
+ public:
+ EglBase();
+ ~EglBase();
+
+ // Creates an new java EglBase instance. |egl_base_context| must be a valid
+ // EglBase$Context.
+ // Returns false if |egl_base_context| is a null Java object or if an
+ // exception occur in Java.
+ bool CreateEglBase(JNIEnv* jni, jobject egl_base_context);
+ jobject egl_base_context() const { return egl_base_context_; }
+
+ private:
+ jobject egl_base_ = nullptr; // instance of org/webrtc/EglBase
+ jobject egl_base_context_ = nullptr; // instance of EglBase$Context
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(EglBase);
+};
+
+} // namespace webrtc_jni
+
+#endif // TALK_APP_WEBRTC_JAVA_JNI_EGLBASE_JNI_H_
diff --git a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
index 6ee062b..e6b3205 100644
--- a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
+++ b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
@@ -176,18 +176,12 @@
nativeSetOptions(nativeFactory, options);
}
- @Deprecated
- public void setVideoHwAccelerationOptions(Object renderEGLContext) {
- nativeSetVideoHwAccelerationOptions(nativeFactory, renderEGLContext, renderEGLContext);
- }
-
/** Set the EGL context used by HW Video encoding and decoding.
*
- *
- * @param localEGLContext An instance of javax.microedition.khronos.egl.EGLContext.
+ * @param localEGLContext An instance of EglBase.Context.
* Must be the same as used by VideoCapturerAndroid and any local
* video renderer.
- * @param remoteEGLContext An instance of javax.microedition.khronos.egl.EGLContext.
+ * @param remoteEGLContext An instance of EglBase.Context.
* Must be the same as used by any remote video renderer.
*/
public void setVideoHwAccelerationOptions(Object localEGLContext, Object remoteEGLContext) {