From f812e45d8f1b876a52787884fc529feb37ba6135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Mon, 13 Feb 2017 17:11:08 -0500 Subject: [PATCH] Handle InitDecode and reset in fallback decoder. Makes sure video decoder software fallback handles InitDecode() failures, and properly releases the pointer after ::Release() so that another decode failure will properly reinitialize the decoder. Also makes sure to not call Decode() without a previous InitDecode() succeeding. BUG=webrtc:7154 R=noahric@chromium.org, sophiechang@chromium.org Review-Url: https://codereview.webrtc.org/2690183004 . Cr-Commit-Position: refs/heads/master@{#16594} --- .../videodecodersoftwarefallbackwrapper.cc | 46 ++++++++++++++++--- .../videodecodersoftwarefallbackwrapper.h | 1 + ...decodersoftwarefallbackwrapper_unittest.cc | 29 +++++++++++- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc b/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc index cd6eef9b64..00f3ea7f3f 100644 --- a/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc +++ b/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc @@ -12,6 +12,7 @@ #include +#include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/media/engine/internaldecoderfactory.h" #include "webrtc/modules/video_coding/include/video_error_codes.h" @@ -21,14 +22,30 @@ namespace webrtc { VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper( VideoCodecType codec_type, VideoDecoder* decoder) - : codec_type_(codec_type), decoder_(decoder), callback_(nullptr) {} + : codec_type_(codec_type), + decoder_(decoder), + decoder_initialized_(false), + callback_(nullptr) {} int32_t VideoDecoderSoftwareFallbackWrapper::InitDecode( const VideoCodec* codec_settings, int32_t number_of_cores) { + RTC_DCHECK(!fallback_decoder_) << "Fallback decoder should never be " + "initialized here, it should've been " + "released."; codec_settings_ = *codec_settings; number_of_cores_ = number_of_cores; - return decoder_->InitDecode(codec_settings, number_of_cores); + int32_t ret = decoder_->InitDecode(codec_settings, number_of_cores); + if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) { + decoder_initialized_ = (ret == WEBRTC_VIDEO_CODEC_OK); + return ret; + } + decoder_initialized_ = false; + + // Try to initialize fallback decoder. + if (InitFallbackDecoder()) + return WEBRTC_VIDEO_CODEC_OK; + return ret; } bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() { @@ -58,14 +75,25 @@ int32_t VideoDecoderSoftwareFallbackWrapper::Decode( const RTPFragmentationHeader* fragmentation, const CodecSpecificInfo* codec_specific_info, int64_t render_time_ms) { - // Try decoding with the provided decoder on every keyframe or when there's no - // fallback decoder. This is the normal case. + // Try initializing and decoding with the provided decoder on every keyframe + // or when there's no fallback decoder. This is the normal case. if (!fallback_decoder_ || input_image._frameType == kVideoFrameKey) { - int32_t ret = decoder_->Decode(input_image, missing_frames, fragmentation, - codec_specific_info, render_time_ms); + int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; + // Try reinitializing the decoder if it had failed before. + if (!decoder_initialized_) { + decoder_initialized_ = + decoder_->InitDecode(&codec_settings_, number_of_cores_) == + WEBRTC_VIDEO_CODEC_OK; + } + if (decoder_initialized_) { + ret = decoder_->Decode(input_image, missing_frames, fragmentation, + codec_specific_info, render_time_ms); + } if (ret == WEBRTC_VIDEO_CODEC_OK) { if (fallback_decoder_) { // Decode OK -> stop using fallback decoder. + LOG(LS_INFO) + << "Decode OK, no longer using the software fallback decoder."; fallback_decoder_->Release(); fallback_decoder_.reset(); return WEBRTC_VIDEO_CODEC_OK; @@ -93,8 +121,12 @@ int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback( } int32_t VideoDecoderSoftwareFallbackWrapper::Release() { - if (fallback_decoder_) + if (fallback_decoder_) { + LOG(LS_INFO) << "Releasing software fallback decoder."; fallback_decoder_->Release(); + fallback_decoder_.reset(); + } + decoder_initialized_ = false; return decoder_->Release(); } diff --git a/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h b/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h index 93c9278a8f..80d91f4663 100644 --- a/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h +++ b/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h @@ -48,6 +48,7 @@ class VideoDecoderSoftwareFallbackWrapper : public webrtc::VideoDecoder { const VideoCodecType codec_type_; VideoDecoder* const decoder_; + bool decoder_initialized_; VideoCodec codec_settings_; int32_t number_of_cores_; diff --git a/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc b/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc index de42545954..16991d21b7 100644 --- a/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc +++ b/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc @@ -27,7 +27,7 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { int32_t InitDecode(const VideoCodec* codec_settings, int32_t number_of_cores) override { ++init_decode_count_; - return WEBRTC_VIDEO_CODEC_OK; + return init_decode_return_code_; } int32_t Decode(const EncodedImage& input_image, @@ -56,6 +56,7 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { int init_decode_count_ = 0; int decode_count_ = 0; + int32_t init_decode_return_code_ = WEBRTC_VIDEO_CODEC_OK; int32_t decode_return_code_ = WEBRTC_VIDEO_CODEC_OK; DecodedImageCallback* decode_complete_callback_ = nullptr; int release_count_ = 0; @@ -69,6 +70,32 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest, InitializesDecoder) { VideoCodec codec = {}; fallback_wrapper_.InitDecode(&codec, 2); EXPECT_EQ(1, fake_decoder_.init_decode_count_); + + EncodedImage encoded_image; + encoded_image._frameType = kVideoFrameKey; + fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); + EXPECT_EQ(1, fake_decoder_.init_decode_count_) + << "Initialized decoder should not be reinitialized."; + EXPECT_EQ(1, fake_decoder_.decode_count_); +} + +TEST_F(VideoDecoderSoftwareFallbackWrapperTest, + UsesFallbackDecoderAfterOnInitDecodeFailure) { + VideoCodec codec = {}; + fake_decoder_.init_decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; + fallback_wrapper_.InitDecode(&codec, 2); + EXPECT_EQ(1, fake_decoder_.init_decode_count_); + + EncodedImage encoded_image; + encoded_image._frameType = kVideoFrameKey; + fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); + EXPECT_EQ(2, fake_decoder_.init_decode_count_) + << "Should have attempted reinitializing the fallback decoder on " + "keyframe."; + // Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW + // decoder. + EXPECT_EQ(0, fake_decoder_.decode_count_) + << "Decoder used even though no InitDecode had succeeded."; } TEST_F(VideoDecoderSoftwareFallbackWrapperTest,