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}
This commit is contained in:
@ -104,6 +104,10 @@ public abstract class EglBase {
|
||||
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.
|
||||
|
||||
@ -286,6 +286,9 @@ final class EglBase10 extends EglBase {
|
||||
// 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;
|
||||
|
||||
@ -241,6 +241,9 @@ public final class EglBase14 extends EglBase {
|
||||
// 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;
|
||||
|
||||
@ -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 @@ static inline void AllowBlockingCalls() {
|
||||
|
||||
// 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()),
|
||||
|
||||
@ -347,7 +347,7 @@ int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
|
||||
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 @@ void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
|
||||
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() :
|
||||
|
||||
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 @@ webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
|
||||
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(
|
||||
|
||||
@ -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 @@ class MediaCodecVideoDecoderFactory
|
||||
void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) override;
|
||||
|
||||
private:
|
||||
jobject render_egl_context_; // Render EGL context.
|
||||
EglBase egl_;
|
||||
std::vector<webrtc::VideoCodecType> supported_codec_types_;
|
||||
};
|
||||
|
||||
|
||||
@ -134,7 +134,7 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
|
||||
|
||||
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 @@ int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
|
||||
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 @@ const char* MediaCodecVideoEncoder::ImplementationName() const {
|
||||
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() {}
|
||||
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 @@ webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
|
||||
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 @@ webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
|
||||
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>&
|
||||
|
||||
@ -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 @@ class MediaCodecVideoEncoderFactory
|
||||
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_;
|
||||
};
|
||||
|
||||
90
talk/app/webrtc/java/jni/eglbase_jni.cc
Normal file
90
talk/app/webrtc/java/jni/eglbase_jni.cc
Normal file
@ -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
|
||||
60
talk/app/webrtc/java/jni/eglbase_jni.h
Normal file
60
talk/app/webrtc/java/jni/eglbase_jni.h
Normal file
@ -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_
|
||||
@ -176,18 +176,12 @@ public class PeerConnectionFactory {
|
||||
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) {
|
||||
|
||||
@ -89,6 +89,8 @@
|
||||
'app/webrtc/java/jni/androidnetworkmonitor_jni.h',
|
||||
'app/webrtc/java/jni/androidvideocapturer_jni.cc',
|
||||
'app/webrtc/java/jni/androidvideocapturer_jni.h',
|
||||
'app/webrtc/java/jni/eglbase_jni.cc',
|
||||
'app/webrtc/java/jni/eglbase_jni.h',
|
||||
'app/webrtc/java/jni/surfacetexturehelper_jni.cc',
|
||||
'app/webrtc/java/jni/surfacetexturehelper_jni.h',
|
||||
]
|
||||
|
||||
@ -225,7 +225,7 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
|
||||
PeerConnectionClient createPeerConnectionClient(
|
||||
MockRenderer localRenderer, MockRenderer remoteRenderer,
|
||||
PeerConnectionParameters peerConnectionParameters, boolean useTexures) {
|
||||
PeerConnectionParameters peerConnectionParameters, EglBase.Context eglContext) {
|
||||
List<PeerConnection.IceServer> iceServers =
|
||||
new LinkedList<PeerConnection.IceServer>();
|
||||
SignalingParameters signalingParameters = new SignalingParameters(
|
||||
@ -240,8 +240,7 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
client.setPeerConnectionFactoryOptions(options);
|
||||
client.createPeerConnectionFactory(
|
||||
getInstrumentation().getContext(), peerConnectionParameters, this);
|
||||
client.createPeerConnection(useTexures ? eglBase.getEglBaseContext() : null,
|
||||
localRenderer, remoteRenderer, signalingParameters);
|
||||
client.createPeerConnection(eglContext, localRenderer, remoteRenderer, signalingParameters);
|
||||
client.createOffer();
|
||||
return client;
|
||||
}
|
||||
@ -288,7 +287,7 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME);
|
||||
pcClient = createPeerConnectionClient(
|
||||
localRenderer, new MockRenderer(0, null),
|
||||
createParametersForVideoCall(VIDEO_CODEC_VP8, false), false);
|
||||
createParametersForVideoCall(VIDEO_CODEC_VP8, false), null);
|
||||
|
||||
// Wait for local SDP and ice candidates set events.
|
||||
assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
|
||||
@ -317,8 +316,8 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
} else {
|
||||
Log.d(TAG, "testLoopback for audio.");
|
||||
}
|
||||
pcClient = createPeerConnectionClient(
|
||||
localRenderer, remoteRenderer, parameters, decodeToTexure);
|
||||
pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, parameters,
|
||||
decodeToTexure ? eglBase.getEglBaseContext() : null);
|
||||
|
||||
// Wait for local SDP, rename it to answer and set as remote SDP.
|
||||
assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
|
||||
@ -401,6 +400,62 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
doLoopbackTest(createParametersForVideoCall(VIDEO_CODEC_VP8, true), true);
|
||||
}
|
||||
|
||||
|
||||
// Test that a call can be setup even if a released EGL context is used during setup.
|
||||
// The HW encoder and decoder will fallback to encode and decode from byte buffers.
|
||||
public void testLoopbackEglContextReleasedBeforeSetup() throws InterruptedException {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
Log.i(TAG, "Decode to textures is not supported, requires SDK version 19.");
|
||||
return;
|
||||
}
|
||||
eglBase.release();
|
||||
doLoopbackTest(createParametersForVideoCall(VIDEO_CODEC_VP8, false), true);
|
||||
eglBase = null;
|
||||
}
|
||||
|
||||
// Test that a call can be setup even if the EGL context used during initialization is
|
||||
// released before the Video codecs are created. The HW encoder and decoder is setup to use
|
||||
// textures.
|
||||
public void testLoopbackEglContextReleasedAfterCreatingPc() throws InterruptedException {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
Log.i(TAG, "Decode to textures is not supported. Requires SDK version 19");
|
||||
return;
|
||||
}
|
||||
|
||||
loopback = true;
|
||||
PeerConnectionParameters parameters = createParametersForVideoCall(VIDEO_CODEC_VP8, false);
|
||||
MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME);
|
||||
MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
|
||||
pcClient = createPeerConnectionClient(
|
||||
localRenderer, remoteRenderer, parameters, eglBase.getEglBaseContext());
|
||||
|
||||
// Wait for local SDP, rename it to answer and set as remote SDP.
|
||||
assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
|
||||
|
||||
// Release the EGL context used for creating the PeerConnectionClient.
|
||||
// Since createPeerConnectionClient is asynchronous, we must wait for the local
|
||||
// SessionDescription.
|
||||
eglBase.release();
|
||||
eglBase = null;
|
||||
|
||||
SessionDescription remoteSdp = new SessionDescription(
|
||||
SessionDescription.Type.fromCanonicalForm("answer"),
|
||||
localSdp.description);
|
||||
pcClient.setRemoteDescription(remoteSdp);
|
||||
|
||||
// Wait for ICE connection.
|
||||
assertTrue("ICE connection failure.", waitForIceConnected(ICE_CONNECTION_WAIT_TIMEOUT));
|
||||
// Check that local and remote video frames were rendered.
|
||||
assertTrue("Local video frames were not rendered.",
|
||||
localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
|
||||
assertTrue("Remote video frames were not rendered.",
|
||||
remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
|
||||
|
||||
pcClient.close();
|
||||
assertTrue(waitForPeerConnectionClosed(WAIT_TIMEOUT));
|
||||
Log.d(TAG, "testLoopback done.");
|
||||
}
|
||||
|
||||
public void testLoopbackH264CaptureToTexture() throws InterruptedException {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
Log.i(TAG, "Encode to textures is not supported. Requires KITKAT");
|
||||
@ -426,7 +481,7 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
|
||||
|
||||
pcClient = createPeerConnectionClient(
|
||||
localRenderer, remoteRenderer, createParametersForVideoCall(VIDEO_CODEC_VP8, false), false);
|
||||
localRenderer, remoteRenderer, createParametersForVideoCall(VIDEO_CODEC_VP8, false), null);
|
||||
|
||||
// Wait for local SDP, rename it to answer and set as remote SDP.
|
||||
assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
|
||||
@ -472,7 +527,7 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
|
||||
|
||||
pcClient = createPeerConnectionClient(
|
||||
localRenderer, remoteRenderer, createParametersForVideoCall(VIDEO_CODEC_VP8, false), false);
|
||||
localRenderer, remoteRenderer, createParametersForVideoCall(VIDEO_CODEC_VP8, false), null);
|
||||
|
||||
// Wait for local SDP, rename it to answer and set as remote SDP.
|
||||
assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
|
||||
@ -509,5 +564,4 @@ public class PeerConnectionClientTest extends InstrumentationTestCase
|
||||
assertTrue(waitForPeerConnectionClosed(WAIT_TIMEOUT));
|
||||
Log.d(TAG, "testVideoSourceRestart done.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user