Chromium Code Reviews| 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..6d9067e570d14d74d3fc1d20fb507aa034945a60 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; |
|
AlexG
2016/08/23 22:50:31
I don't think this is necessary - similarly to dec
sakal
2016/08/25 11:52:48
Done.
|
| } // 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_; |
|
AlexG
2016/08/23 22:50:31
suggest to rename it to sw_fallback_required_ so w
sakal
2016/08/25 11:52:48
Done.
|
| + 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; |
| + 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); |
| @@ -637,7 +660,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
| frames_received_++; |
| if (!DeliverPendingOutputs(jni)) { |
| if (!ResetCodecOnCodecThread()) |
| - return WEBRTC_VIDEO_CODEC_ERROR; |
| + return software_fallback_needed_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE |
| + : WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| if (frames_encoded_ < kMaxEncodedLogFrames) { |
| ALOGD << "Encoder frame in # " << (frames_received_ - 1) |
| @@ -671,7 +695,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
| ENCODER_STALL_FRAMEDROP_THRESHOLD) { |
| ALOGE << "Encoder got stuck. Reset."; |
| ResetCodecOnCodecThread(); |
| - return WEBRTC_VIDEO_CODEC_ERROR; |
| + return software_fallback_needed_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE |
| + : WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| frames_dropped_media_encoder_++; |
| OnDroppedFrameOnCodecThread(); |
| @@ -732,7 +757,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
| return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887. |
| } else if (j_input_buffer_index == -2) { |
| ResetCodecOnCodecThread(); |
| - return WEBRTC_VIDEO_CODEC_ERROR; |
| + return software_fallback_needed_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE |
| + : WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, |
| j_input_buffer_index); |
| @@ -743,7 +769,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
| if (!encode_status) { |
| ALOGE << "Failed encode frame with timestamp: " << input_frame.timestamp(); |
| ResetCodecOnCodecThread(); |
| - return WEBRTC_VIDEO_CODEC_ERROR; |
| + return software_fallback_needed_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE |
| + : WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| // Save input image timestamps for later output. |
| @@ -762,7 +789,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |
| if (!DeliverPendingOutputs(jni)) { |
| ALOGE << "Failed deliver pending outputs."; |
| ResetCodecOnCodecThread(); |
| - return WEBRTC_VIDEO_CODEC_ERROR; |
| + return software_fallback_needed_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE |
| + : WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| @@ -852,6 +880,9 @@ bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, |
| int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( |
| webrtc::EncodedImageCallback* callback) { |
| RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
| + if (software_fallback_needed_) { |
|
AlexG
2016/08/23 22:50:31
is this needed?
sakal
2016/08/25 11:52:48
I guess not. I just added it as a safety measure.
|
| + return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
| + } |
| JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
| ScopedLocalRefFrame local_ref_frame(jni); |
| callback_ = callback; |
| @@ -883,6 +914,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 && |
| @@ -907,7 +941,8 @@ int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, |
| CHECK_EXCEPTION(jni); |
|
AlexG
2016/08/23 22:50:31
Replace all CHECK_EXCEPTION(jni) with CheckExcepti
sakal
2016/08/25 11:52:48
Done.
|
| if (!ret) { |
| ResetCodecOnCodecThread(); |
| - return WEBRTC_VIDEO_CODEC_ERROR; |
| + return software_fallback_needed_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE |
| + : WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |