Use fallback encoder if primary can't be created

In case if primary encoder can't be instantiated (max number of
instances has reached, for example), use fallback encoder.

Bug: none
Change-Id: I477bdeb7af4dcce50e36b1804ffc6ad2ab004dfd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/234500
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Xavier Lepaul‎ <xalep@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35161}
This commit is contained in:
Sergey Silkin 2021-10-07 11:56:19 +02:00 committed by WebRTC LUCI CQ
parent bcef6e1859
commit 9b2a7461f0
2 changed files with 83 additions and 8 deletions

View file

@ -709,17 +709,40 @@ SimulcastEncoderAdapter::FetchOrCreateEncoderContext(
encoder_context = std::move(*encoder_context_iter);
cached_encoder_contexts_.erase(encoder_context_iter);
} else {
std::unique_ptr<VideoEncoder> encoder =
std::unique_ptr<VideoEncoder> primary_encoder =
primary_encoder_factory_->CreateVideoEncoder(video_format_);
VideoEncoder::EncoderInfo primary_info = encoder->GetEncoderInfo();
VideoEncoder::EncoderInfo fallback_info = primary_info;
std::unique_ptr<VideoEncoder> fallback_encoder;
if (fallback_encoder_factory_ != nullptr) {
std::unique_ptr<VideoEncoder> fallback_encoder =
fallback_encoder =
fallback_encoder_factory_->CreateVideoEncoder(video_format_);
}
std::unique_ptr<VideoEncoder> encoder;
VideoEncoder::EncoderInfo primary_info;
VideoEncoder::EncoderInfo fallback_info;
if (primary_encoder != nullptr) {
primary_info = primary_encoder->GetEncoderInfo();
fallback_info = primary_info;
if (fallback_encoder == nullptr) {
encoder = std::move(primary_encoder);
} else {
encoder = CreateVideoEncoderSoftwareFallbackWrapper(
std::move(fallback_encoder), std::move(primary_encoder),
prefer_temporal_support);
}
} else if (fallback_encoder != nullptr) {
RTC_LOG(LS_WARNING) << "Failed to create primary " << video_format_.name
<< " encoder. Use fallback encoder.";
fallback_info = fallback_encoder->GetEncoderInfo();
encoder = CreateVideoEncoderSoftwareFallbackWrapper(
std::move(fallback_encoder), std::move(encoder),
prefer_temporal_support);
primary_info = fallback_info;
encoder = std::move(fallback_encoder);
} else {
RTC_LOG(LS_ERROR) << "Failed to create primary and fallback "
<< video_format_.name << " encoders.";
return nullptr;
}
encoder_context = std::make_unique<SimulcastEncoderAdapter::EncoderContext>(
@ -829,7 +852,10 @@ VideoEncoder::EncoderInfo SimulcastEncoderAdapter::GetEncoderInfo() const {
// Create one encoder and query it.
std::unique_ptr<SimulcastEncoderAdapter::EncoderContext> encoder_context =
FetchOrCreateEncoderContext(true);
FetchOrCreateEncoderContext(/*is_lowest_quality_stream=*/true);
if (encoder_context == nullptr) {
return encoder_info;
}
const VideoEncoder::EncoderInfo& primary_info =
encoder_context->PrimaryInfo();

View file

@ -171,6 +171,9 @@ class MockVideoEncoderFactory : public VideoEncoderFactory {
const std::vector<MockVideoEncoder*>& encoders() const;
void SetEncoderNames(const std::vector<const char*>& encoder_names);
void set_create_video_encode_return_nullptr(bool return_nullptr) {
create_video_encoder_return_nullptr_ = return_nullptr;
}
void set_init_encode_return_value(int32_t value);
void set_requested_resolution_alignments(
std::vector<int> requested_resolution_alignments) {
@ -183,6 +186,7 @@ class MockVideoEncoderFactory : public VideoEncoderFactory {
void DestroyVideoEncoder(VideoEncoder* encoder);
private:
bool create_video_encoder_return_nullptr_ = false;
int32_t init_encode_return_value_ = 0;
std::vector<MockVideoEncoder*> encoders_;
std::vector<const char*> encoder_names_;
@ -346,6 +350,10 @@ std::vector<SdpVideoFormat> MockVideoEncoderFactory::GetSupportedFormats()
std::unique_ptr<VideoEncoder> MockVideoEncoderFactory::CreateVideoEncoder(
const SdpVideoFormat& format) {
if (create_video_encoder_return_nullptr_) {
return nullptr;
}
auto encoder = std::make_unique<::testing::NiceMock<MockVideoEncoder>>(this);
encoder->set_init_encode_return_value(init_encode_return_value_);
const char* encoder_name = encoder_names_.empty()
@ -1711,5 +1719,46 @@ TEST_F(TestSimulcastEncoderAdapterFake,
EXPECT_NE(helper_->factory()->encoders()[0], prev_encoder);
}
TEST_F(TestSimulcastEncoderAdapterFake,
UseFallbackEncoderIfCreatePrimaryEncoderFailed) {
// Enable support for fallback encoder factory and re-setup.
use_fallback_factory_ = true;
SetUp();
SimulcastTestFixtureImpl::DefaultSettings(
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
kVideoCodecVP8);
codec_.numberOfSimulcastStreams = 1;
helper_->factory()->SetEncoderNames({"primary"});
helper_->fallback_factory()->SetEncoderNames({"fallback"});
// Emulate failure at creating of primary encoder and verify that SEA switches
// to fallback encoder.
helper_->factory()->set_create_video_encode_return_nullptr(true);
EXPECT_EQ(0, adapter_->InitEncode(&codec_, kSettings));
ASSERT_EQ(0u, helper_->factory()->encoders().size());
ASSERT_EQ(1u, helper_->fallback_factory()->encoders().size());
EXPECT_EQ("fallback", adapter_->GetEncoderInfo().implementation_name);
}
TEST_F(TestSimulcastEncoderAdapterFake,
InitEncodeReturnsErrorIfEncoderCannotBeCreated) {
// Enable support for fallback encoder factory and re-setup.
use_fallback_factory_ = true;
SetUp();
SimulcastTestFixtureImpl::DefaultSettings(
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
kVideoCodecVP8);
codec_.numberOfSimulcastStreams = 1;
helper_->factory()->SetEncoderNames({"primary"});
helper_->fallback_factory()->SetEncoderNames({"fallback"});
// Emulate failure at creating of primary and fallback encoders and verify
// that `InitEncode` returns an error.
helper_->factory()->set_create_video_encode_return_nullptr(true);
helper_->fallback_factory()->set_create_video_encode_return_nullptr(true);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_MEMORY,
adapter_->InitEncode(&codec_, kSettings));
}
} // namespace test
} // namespace webrtc