Fallback to software decoders on consequtive decode errors on key-frames

Bug: webrtc:11575
Change-Id: I09be17ab5155e9f610c8f7c451ca52d7d65e24d1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/175222
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31295}
This commit is contained in:
Ilya Nikolaevskiy
2020-05-15 14:25:59 +02:00
committed by Commit Bot
parent 222598d1bf
commit 35fc1537af
2 changed files with 80 additions and 4 deletions

View File

@ -218,6 +218,68 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
fallback_wrapper_->Release();
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, FallbacksOnTooManyErrors) {
VideoCodec codec = {};
fallback_wrapper_->InitDecode(&codec, 2);
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
// Doesn't fallback from a single error.
fallback_wrapper_->Decode(encoded_image, false, -1);
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
// However, many frames with the same error, fallback should happen.
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
fallback_wrapper_->Decode(encoded_image, false, -1);
}
// Hard coded expected value since libvpx is the software implementation name
// for VP8. Change accordingly if the underlying implementation does.
EXPECT_STREQ("libvpx (fallback from: fake-decoder)",
fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
DoesNotFallbackOnDeltaFramesErrors) {
VideoCodec codec = {};
fallback_wrapper_->InitDecode(&codec, 2);
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
// Many decoded frames with the same error
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
fallback_wrapper_->Decode(encoded_image, false, -1);
}
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
DoesNotFallbacksOnNonConsequtiveErrors) {
VideoCodec codec = {};
fallback_wrapper_->InitDecode(&codec, 2);
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
// Interleaved errors and successful decodes.
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
fallback_wrapper_->Decode(encoded_image, false, -1);
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
fallback_wrapper_->Decode(encoded_image, false, -1);
}
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
class ForcedSoftwareDecoderFallbackTest
: public VideoDecoderSoftwareFallbackWrapperTest {
public:

View File

@ -30,6 +30,8 @@ namespace webrtc {
namespace {
constexpr size_t kMaxConsequtiveHwErrors = 4;
class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
public:
VideoDecoderSoftwareFallbackWrapper(
@ -74,6 +76,7 @@ class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
const std::string fallback_implementation_name_;
DecodedImageCallback* callback_;
int32_t hw_decoded_frames_since_last_fallback_;
size_t hw_consequtive_generic_errors_;
};
VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
@ -86,7 +89,8 @@ VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
std::string(fallback_decoder_->ImplementationName()) +
" (fallback from: " + hw_decoder_->ImplementationName() + ")"),
callback_(nullptr),
hw_decoded_frames_since_last_fallback_(0) {}
hw_decoded_frames_since_last_fallback_(0),
hw_consequtive_generic_errors_(0) {}
VideoDecoderSoftwareFallbackWrapper::~VideoDecoderSoftwareFallbackWrapper() =
default;
@ -196,14 +200,24 @@ int32_t VideoDecoderSoftwareFallbackWrapper::Decode(
int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
ret = hw_decoder_->Decode(input_image, missing_frames, render_time_ms);
if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) {
if (ret == WEBRTC_VIDEO_CODEC_OK) {
if (ret != WEBRTC_VIDEO_CODEC_ERROR) {
++hw_decoded_frames_since_last_fallback_;
}
hw_consequtive_generic_errors_ = 0;
return ret;
}
if (input_image._frameType == VideoFrameType::kVideoFrameKey) {
// Only count errors on key-frames, since generic errors can happen
// with hw decoder due to many arbitrary reasons.
// However, requesting a key-frame is supposed to fix the issue.
++hw_consequtive_generic_errors_;
}
if (hw_consequtive_generic_errors_ < kMaxConsequtiveHwErrors) {
return ret;
}
}
// HW decoder returned WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE or
// initialization failed, fallback to software.
// too many generic errors on key-frames encountered.
if (!InitFallbackDecoder()) {
return ret;
}