Skip to content

Commit

Permalink
Merge to M84: Fallback to software decoders on consequtive decode err…
Browse files Browse the repository at this point in the history
…ors on key-frames

TBR=brandtr@webrtc.org
(cherry picked from commit 35fc153)

Bug: webrtc:11575, chromium:1084963
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-Original-Commit-Position: refs/heads/master@{#31295}
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/175902
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/branch-heads/4147@{#1}
Cr-Branched-From: 2b7d969-refs/heads/master@{#31262}
  • Loading branch information
Ilya Nikolaevskiy authored and Commit Bot committed May 21, 2020
1 parent 2b7d969 commit 6e3510f
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
22 changes: 18 additions & 4 deletions api/video_codecs/video_decoder_software_fallback_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ namespace webrtc {

namespace {

constexpr size_t kMaxConsequtiveHwErrors = 4;

class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
public:
VideoDecoderSoftwareFallbackWrapper(
Expand Down Expand Up @@ -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(
Expand All @@ -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;

Expand Down Expand Up @@ -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;
}
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;
}
Expand Down

0 comments on commit 6e3510f

Please sign in to comment.