Index: webrtc/api/android/jni/androidmediaencoder_jni.cc |
diff --git a/webrtc/api/android/jni/androidmediaencoder_jni.cc b/webrtc/api/android/jni/androidmediaencoder_jni.cc |
index 8d0d3b54bd512557401dcf652b94d62d930388f4..b75ba8fc5608d5a5295041697f7b942b01706256 100644 |
--- a/webrtc/api/android/jni/androidmediaencoder_jni.cc |
+++ b/webrtc/api/android/jni/androidmediaencoder_jni.cc |
@@ -86,6 +86,9 @@ namespace { |
// Maximum time limit between incoming frames before requesting a key frame. |
const size_t kFrameDiffThresholdMs = 1100; |
const int kMinKeyFrameInterval = 2; |
+// Maximum number of encoder resets before falling back to a software |
+// implementation. |
+const int kMaxEncoderResetsBeforeFallback = 3; |
magjed_webrtc
2016/08/23 12:09:50
Now it will fall back to software the fourth time,
sakal
2016/08/23 12:26:51
Resetting the encoder is fairly quick so 3 resets
|
} // namespace |
// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses |
@@ -282,6 +285,9 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder, |
int64_t last_frame_received_ms_; |
int frames_received_since_last_key_; |
webrtc::VideoCodecMode codec_mode_; |
+ |
+ bool software_fallback_needed_; |
+ int encoder_reset_counter_; |
}; |
MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { |
@@ -307,7 +313,9 @@ MediaCodecVideoEncoder::MediaCodecVideoEncoder( |
inited_(false), |
use_surface_(false), |
picture_id_(0), |
- egl_context_(egl_context) { |
+ egl_context_(egl_context), |
+ software_fallback_needed_(false), |
+ encoder_reset_counter_(0) { |
ScopedLocalRefFrame local_ref_frame(jni); |
// It would be nice to avoid spinning up a new thread per MediaCodec, and |
// instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug |
@@ -494,12 +502,21 @@ void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) { |
bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { |
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
ALOGE << "ResetOnCodecThread"; |
- if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || |
- InitEncodeOnCodecThread(width_, height_, 0, 0, false) != |
- WEBRTC_VIDEO_CODEC_OK) { |
- // TODO(fischman): wouldn't it be nice if there was a way to gracefully |
- // degrade to a SW encoder at this point? There isn't one AFAICT :( |
- // https://code.google.com/p/webrtc/issues/detail?id=2920 |
+ encoder_reset_counter_++; |
+ if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK) { |
+ LOG(LS_ERROR) << "Releasing codec failed. Fallback to SW encoder."; |
+ software_fallback_needed_ = true; |
magjed_webrtc
2016/08/23 12:09:50
Is it possible to remove |software_fallback_needed
sakal
2016/08/23 12:26:51
There would be some trouble. The codec might not b
|
+ return false; |
+ } |
+ if (encoder_reset_counter_ > kMaxEncoderResetsBeforeFallback) { |
+ LOG(LS_ERROR) << "Codec has failed too many times. Fallback to SW encoder."; |
+ software_fallback_needed_ = true; |
+ return false; |
+ } |
+ if (InitEncodeOnCodecThread(width_, height_, 0, 0, false) != |
+ WEBRTC_VIDEO_CODEC_OK) { |
+ LOG(LS_ERROR) << "Init encode failed. Fallback to SW encoder."; |
+ software_fallback_needed_ = true; |
return false; |
} |
return true; |
@@ -508,6 +525,9 @@ bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { |
int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( |
int width, int height, int kbps, int fps, bool use_surface) { |
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
+ if (software_fallback_needed_) { |
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
+ } |
RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; |
JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
ScopedLocalRefFrame local_ref_frame(jni); |
@@ -610,6 +630,9 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
const std::vector<webrtc::FrameType>* frame_types, |
const int64_t frame_input_time_ms) { |
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
+ if (software_fallback_needed_) { |
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
+ } |
JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
ScopedLocalRefFrame local_ref_frame(jni); |
@@ -852,6 +875,9 @@ bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, |
int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( |
webrtc::EncodedImageCallback* callback) { |
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
+ if (software_fallback_needed_) { |
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
+ } |
JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
ScopedLocalRefFrame local_ref_frame(jni); |
callback_ = callback; |
@@ -883,6 +909,9 @@ int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { |
int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, |
uint32_t frame_rate) { |
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
+ if (software_fallback_needed_) { |
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
+ } |
frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ? |
frame_rate : MAX_ALLOWED_VIDEO_FPS; |
if (last_set_bitrate_kbps_ == new_bit_rate && |