Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: webrtc/api/android/jni/androidmediaencoder_jni.cc

Issue 2263043003: Make MediaCodecEncoder fallback to a software encoder on failure. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Remove empty lines. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | webrtc/video/video_encoder.cc » ('j') | webrtc/video/video_encoder.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 #define ALOGV(...) 79 #define ALOGV(...)
80 #endif 80 #endif
81 #define ALOGD LOG_TAG(rtc::LS_INFO, TAG_ENCODER) 81 #define ALOGD LOG_TAG(rtc::LS_INFO, TAG_ENCODER)
82 #define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_ENCODER) 82 #define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_ENCODER)
83 #define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_ENCODER) 83 #define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_ENCODER)
84 84
85 namespace { 85 namespace {
86 // Maximum time limit between incoming frames before requesting a key frame. 86 // Maximum time limit between incoming frames before requesting a key frame.
87 const size_t kFrameDiffThresholdMs = 1100; 87 const size_t kFrameDiffThresholdMs = 1100;
88 const int kMinKeyFrameInterval = 2; 88 const int kMinKeyFrameInterval = 2;
89 // Maximum number of encoder resets before falling back to a software
90 // implementation.
91 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
89 } // namespace 92 } // namespace
90 93
91 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses 94 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
92 // Android's MediaCodec SDK API behind the scenes to implement (hopefully) 95 // Android's MediaCodec SDK API behind the scenes to implement (hopefully)
93 // HW-backed video encode. This C++ class is implemented as a very thin shim, 96 // HW-backed video encode. This C++ class is implemented as a very thin shim,
94 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder. 97 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
95 // MediaCodecVideoEncoder is created, operated, and destroyed on a single 98 // MediaCodecVideoEncoder is created, operated, and destroyed on a single
96 // thread, currently the libjingle Worker thread. 99 // thread, currently the libjingle Worker thread.
97 class MediaCodecVideoEncoder : public webrtc::VideoEncoder, 100 class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
98 public rtc::MessageHandler { 101 public rtc::MessageHandler {
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 // EGL context - owned by factory, should not be allocated/destroyed 278 // EGL context - owned by factory, should not be allocated/destroyed
276 // by MediaCodecVideoEncoder. 279 // by MediaCodecVideoEncoder.
277 jobject egl_context_; 280 jobject egl_context_;
278 281
279 // Temporary fix for VP8. 282 // Temporary fix for VP8.
280 // Sends a key frame if frames are largely spaced apart (possibly 283 // Sends a key frame if frames are largely spaced apart (possibly
281 // corresponding to a large image change). 284 // corresponding to a large image change).
282 int64_t last_frame_received_ms_; 285 int64_t last_frame_received_ms_;
283 int frames_received_since_last_key_; 286 int frames_received_since_last_key_;
284 webrtc::VideoCodecMode codec_mode_; 287 webrtc::VideoCodecMode codec_mode_;
288
289 bool software_fallback_needed_;
290 int encoder_reset_counter_;
285 }; 291 };
286 292
287 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { 293 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
288 // Call Release() to ensure no more callbacks to us after we are deleted. 294 // Call Release() to ensure no more callbacks to us after we are deleted.
289 Release(); 295 Release();
290 } 296 }
291 297
292 MediaCodecVideoEncoder::MediaCodecVideoEncoder( 298 MediaCodecVideoEncoder::MediaCodecVideoEncoder(
293 JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : 299 JNIEnv* jni, VideoCodecType codecType, jobject egl_context) :
294 codecType_(codecType), 300 codecType_(codecType),
295 callback_(NULL), 301 callback_(NULL),
296 codec_thread_(new Thread()), 302 codec_thread_(new Thread()),
297 j_media_codec_video_encoder_class_( 303 j_media_codec_video_encoder_class_(
298 jni, 304 jni,
299 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), 305 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
300 j_media_codec_video_encoder_( 306 j_media_codec_video_encoder_(
301 jni, 307 jni,
302 jni->NewObject(*j_media_codec_video_encoder_class_, 308 jni->NewObject(*j_media_codec_video_encoder_class_,
303 GetMethodID(jni, 309 GetMethodID(jni,
304 *j_media_codec_video_encoder_class_, 310 *j_media_codec_video_encoder_class_,
305 "<init>", 311 "<init>",
306 "()V"))), 312 "()V"))),
307 inited_(false), 313 inited_(false),
308 use_surface_(false), 314 use_surface_(false),
309 picture_id_(0), 315 picture_id_(0),
310 egl_context_(egl_context) { 316 egl_context_(egl_context),
317 software_fallback_needed_(false),
318 encoder_reset_counter_(0) {
311 ScopedLocalRefFrame local_ref_frame(jni); 319 ScopedLocalRefFrame local_ref_frame(jni);
312 // It would be nice to avoid spinning up a new thread per MediaCodec, and 320 // It would be nice to avoid spinning up a new thread per MediaCodec, and
313 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug 321 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
314 // 2732 means that deadlocks abound. This class synchronously trampolines 322 // 2732 means that deadlocks abound. This class synchronously trampolines
315 // to |codec_thread_|, so if anything else can be coming to _us_ from 323 // to |codec_thread_|, so if anything else can be coming to _us_ from
316 // |codec_thread_|, or from any thread holding the |_sendCritSect| described 324 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
317 // in the bug, we have a problem. For now work around that with a dedicated 325 // in the bug, we have a problem. For now work around that with a dedicated
318 // thread. 326 // thread.
319 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); 327 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
320 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; 328 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 } 495 }
488 496
489 // Call log statistics here so it's called even if no frames are being 497 // Call log statistics here so it's called even if no frames are being
490 // delivered. 498 // delivered.
491 LogStatistics(false); 499 LogStatistics(false);
492 } 500 }
493 501
494 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { 502 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() {
495 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 503 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
496 ALOGE << "ResetOnCodecThread"; 504 ALOGE << "ResetOnCodecThread";
497 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || 505 encoder_reset_counter_++;
498 InitEncodeOnCodecThread(width_, height_, 0, 0, false) != 506 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK) {
499 WEBRTC_VIDEO_CODEC_OK) { 507 LOG(LS_ERROR) << "Releasing codec failed. Fallback to SW encoder.";
500 // TODO(fischman): wouldn't it be nice if there was a way to gracefully 508 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
501 // degrade to a SW encoder at this point? There isn't one AFAICT :( 509 return false;
502 // https://code.google.com/p/webrtc/issues/detail?id=2920 510 }
511 if (encoder_reset_counter_ > kMaxEncoderResetsBeforeFallback) {
512 LOG(LS_ERROR) << "Codec has failed too many times. Fallback to SW encoder.";
513 software_fallback_needed_ = true;
514 return false;
515 }
516 if (InitEncodeOnCodecThread(width_, height_, 0, 0, false) !=
517 WEBRTC_VIDEO_CODEC_OK) {
518 LOG(LS_ERROR) << "Init encode failed. Fallback to SW encoder.";
519 software_fallback_needed_ = true;
503 return false; 520 return false;
504 } 521 }
505 return true; 522 return true;
506 } 523 }
507 524
508 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( 525 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
509 int width, int height, int kbps, int fps, bool use_surface) { 526 int width, int height, int kbps, int fps, bool use_surface) {
510 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 527 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
528 if (software_fallback_needed_) {
529 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
530 }
511 RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; 531 RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set.";
512 JNIEnv* jni = AttachCurrentThreadIfNeeded(); 532 JNIEnv* jni = AttachCurrentThreadIfNeeded();
513 ScopedLocalRefFrame local_ref_frame(jni); 533 ScopedLocalRefFrame local_ref_frame(jni);
514 534
515 ALOGD << "InitEncodeOnCodecThread Type: " << (int)codecType_ << ", " << 535 ALOGD << "InitEncodeOnCodecThread Type: " << (int)codecType_ << ", " <<
516 width << " x " << height << ". Bitrate: " << kbps << 536 width << " x " << height << ". Bitrate: " << kbps <<
517 " kbps. Fps: " << fps; 537 " kbps. Fps: " << fps;
518 if (kbps == 0) { 538 if (kbps == 0) {
519 kbps = last_set_bitrate_kbps_; 539 kbps = last_set_bitrate_kbps_;
520 } 540 }
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 623
604 inited_ = true; 624 inited_ = true;
605 return WEBRTC_VIDEO_CODEC_OK; 625 return WEBRTC_VIDEO_CODEC_OK;
606 } 626 }
607 627
608 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( 628 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
609 const webrtc::VideoFrame& frame, 629 const webrtc::VideoFrame& frame,
610 const std::vector<webrtc::FrameType>* frame_types, 630 const std::vector<webrtc::FrameType>* frame_types,
611 const int64_t frame_input_time_ms) { 631 const int64_t frame_input_time_ms) {
612 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 632 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
633 if (software_fallback_needed_) {
634 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
635 }
613 JNIEnv* jni = AttachCurrentThreadIfNeeded(); 636 JNIEnv* jni = AttachCurrentThreadIfNeeded();
614 ScopedLocalRefFrame local_ref_frame(jni); 637 ScopedLocalRefFrame local_ref_frame(jni);
615 638
616 if (!inited_) { 639 if (!inited_) {
617 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; 640 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
618 } 641 }
619 642
620 bool send_key_frame = false; 643 bool send_key_frame = false;
621 if (codec_mode_ == webrtc::kRealtimeVideo) { 644 if (codec_mode_ == webrtc::kRealtimeVideo) {
622 ++frames_received_since_last_key_; 645 ++frames_received_since_last_key_;
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 handle->oes_texture_id, 868 handle->oes_texture_id,
846 sampling_matrix, 869 sampling_matrix,
847 current_timestamp_us_); 870 current_timestamp_us_);
848 CHECK_EXCEPTION(jni); 871 CHECK_EXCEPTION(jni);
849 return encode_status; 872 return encode_status;
850 } 873 }
851 874
852 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( 875 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
853 webrtc::EncodedImageCallback* callback) { 876 webrtc::EncodedImageCallback* callback) {
854 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 877 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
878 if (software_fallback_needed_) {
879 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
880 }
855 JNIEnv* jni = AttachCurrentThreadIfNeeded(); 881 JNIEnv* jni = AttachCurrentThreadIfNeeded();
856 ScopedLocalRefFrame local_ref_frame(jni); 882 ScopedLocalRefFrame local_ref_frame(jni);
857 callback_ = callback; 883 callback_ = callback;
858 return WEBRTC_VIDEO_CODEC_OK; 884 return WEBRTC_VIDEO_CODEC_OK;
859 } 885 }
860 886
861 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { 887 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
862 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 888 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
863 if (!inited_) { 889 if (!inited_) {
864 return WEBRTC_VIDEO_CODEC_OK; 890 return WEBRTC_VIDEO_CODEC_OK;
(...skipping 11 matching lines...) Expand all
876 rtc::MessageQueueManager::Clear(this); 902 rtc::MessageQueueManager::Clear(this);
877 inited_ = false; 903 inited_ = false;
878 use_surface_ = false; 904 use_surface_ = false;
879 ALOGD << "EncoderReleaseOnCodecThread done."; 905 ALOGD << "EncoderReleaseOnCodecThread done.";
880 return WEBRTC_VIDEO_CODEC_OK; 906 return WEBRTC_VIDEO_CODEC_OK;
881 } 907 }
882 908
883 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, 909 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
884 uint32_t frame_rate) { 910 uint32_t frame_rate) {
885 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 911 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
912 if (software_fallback_needed_) {
913 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
914 }
886 frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ? 915 frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ?
887 frame_rate : MAX_ALLOWED_VIDEO_FPS; 916 frame_rate : MAX_ALLOWED_VIDEO_FPS;
888 if (last_set_bitrate_kbps_ == new_bit_rate && 917 if (last_set_bitrate_kbps_ == new_bit_rate &&
889 last_set_fps_ == frame_rate) { 918 last_set_fps_ == frame_rate) {
890 return WEBRTC_VIDEO_CODEC_OK; 919 return WEBRTC_VIDEO_CODEC_OK;
891 } 920 }
892 if (scale_) { 921 if (scale_) {
893 quality_scaler_.ReportFramerate(frame_rate); 922 quality_scaler_.ReportFramerate(frame_rate);
894 } 923 }
895 JNIEnv* jni = AttachCurrentThreadIfNeeded(); 924 JNIEnv* jni = AttachCurrentThreadIfNeeded();
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after
1297 return supported_codecs_; 1326 return supported_codecs_;
1298 } 1327 }
1299 1328
1300 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( 1329 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1301 webrtc::VideoEncoder* encoder) { 1330 webrtc::VideoEncoder* encoder) {
1302 ALOGD << "Destroy video encoder."; 1331 ALOGD << "Destroy video encoder.";
1303 delete encoder; 1332 delete encoder;
1304 } 1333 }
1305 1334
1306 } // namespace webrtc_jni 1335 } // namespace webrtc_jni
OLDNEW
« no previous file with comments | « no previous file | webrtc/video/video_encoder.cc » ('j') | webrtc/video/video_encoder.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698