Skip to content

Commit b093c9f

Browse files
committed
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. Originally from: https://webrtc.googlesource.com/src/+/9b2a7461f099e3b732993925b24fd4752fd9c9a3
1 parent 16af4e1 commit b093c9f

File tree

2 files changed

+81
-11
lines changed

2 files changed

+81
-11
lines changed

media/engine/simulcast_encoder_adapter.cc

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -684,40 +684,61 @@ void SimulcastEncoderAdapter::DestroyStoredEncoders() {
684684
}
685685
}
686686

687+
687688
std::unique_ptr<SimulcastEncoderAdapter::EncoderContext>
688689
SimulcastEncoderAdapter::FetchOrCreateEncoderContext(
689-
bool is_lowest_quality_stream) {
690+
bool is_lowest_quality_stream) const {
690691
bool prefer_temporal_support = fallback_encoder_factory_ != nullptr &&
691692
is_lowest_quality_stream &&
692693
prefer_temporal_support_on_base_layer_;
693-
694-
// Toggling of |prefer_temporal_support| requires encoder recreation. Find
695-
// and reuse encoder with desired |prefer_temporal_support|. Otherwise, if
694+
// Toggling of `prefer_temporal_support` requires encoder recreation. Find
695+
// and reuse encoder with desired `prefer_temporal_support`. Otherwise, if
696696
// there is no such encoder in the cache, create a new instance.
697697
auto encoder_context_iter =
698698
std::find_if(cached_encoder_contexts_.begin(),
699699
cached_encoder_contexts_.end(), [&](auto& encoder_context) {
700700
return encoder_context->prefer_temporal_support() ==
701701
prefer_temporal_support;
702702
});
703-
704703
std::unique_ptr<SimulcastEncoderAdapter::EncoderContext> encoder_context;
705704
if (encoder_context_iter != cached_encoder_contexts_.end()) {
706705
encoder_context = std::move(*encoder_context_iter);
707706
cached_encoder_contexts_.erase(encoder_context_iter);
708707
} else {
709-
std::unique_ptr<VideoEncoder> encoder =
708+
std::unique_ptr<VideoEncoder> primary_encoder =
710709
primary_encoder_factory_->CreateVideoEncoder(video_format_);
710+
std::unique_ptr<VideoEncoder> fallback_encoder;
711711
if (fallback_encoder_factory_ != nullptr) {
712-
encoder = CreateVideoEncoderSoftwareFallbackWrapper(
713-
fallback_encoder_factory_->CreateVideoEncoder(video_format_),
714-
std::move(encoder), prefer_temporal_support);
712+
fallback_encoder =
713+
fallback_encoder_factory_->CreateVideoEncoder(video_format_);
714+
}
715+
std::unique_ptr<VideoEncoder> encoder;
716+
VideoEncoder::EncoderInfo primary_info;
717+
VideoEncoder::EncoderInfo fallback_info;
718+
if (primary_encoder != nullptr) {
719+
primary_info = primary_encoder->GetEncoderInfo();
720+
fallback_info = primary_info;
721+
if (fallback_encoder == nullptr) {
722+
encoder = std::move(primary_encoder);
723+
} else {
724+
encoder = CreateVideoEncoderSoftwareFallbackWrapper(
725+
std::move(fallback_encoder), std::move(primary_encoder),
726+
prefer_temporal_support);
727+
}
728+
} else if (fallback_encoder != nullptr) {
729+
RTC_LOG(LS_WARNING) << "Failed to create primary " << video_format_.name
730+
<< " encoder. Use fallback encoder.";
731+
fallback_info = fallback_encoder->GetEncoderInfo();
732+
primary_info = fallback_info;
733+
encoder = std::move(fallback_encoder);
734+
} else {
735+
RTC_LOG(LS_ERROR) << "Failed to create primary and fallback "
736+
<< video_format_.name << " encoders.";
737+
return nullptr;
715738
}
716-
717739
encoder_context = std::make_unique<SimulcastEncoderAdapter::EncoderContext>(
718740
std::move(encoder), prefer_temporal_support);
719741
}
720-
721742
encoder_context->encoder().RegisterEncodeCompleteCallback(
722743
encoded_complete_callback_);
723744
return encoder_context;

media/engine/simulcast_encoder_adapter_unittest.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ class MockVideoEncoderFactory : public VideoEncoderFactory {
171171

172172
const std::vector<MockVideoEncoder*>& encoders() const;
173173
void SetEncoderNames(const std::vector<const char*>& encoder_names);
174+
void set_create_video_encode_return_nullptr(bool return_nullptr) {
175+
create_video_encoder_return_nullptr_ = return_nullptr;
176+
}
174177
void set_init_encode_return_value(int32_t value);
175178
void set_requested_resolution_alignments(
176179
std::vector<int> requested_resolution_alignments) {
@@ -183,6 +186,7 @@ class MockVideoEncoderFactory : public VideoEncoderFactory {
183186
void DestroyVideoEncoder(VideoEncoder* encoder);
184187

185188
private:
189+
bool create_video_encoder_return_nullptr_ = false;
186190
int32_t init_encode_return_value_ = 0;
187191
std::vector<MockVideoEncoder*> encoders_;
188192
std::vector<const char*> encoder_names_;
@@ -340,6 +344,10 @@ std::vector<SdpVideoFormat> MockVideoEncoderFactory::GetSupportedFormats()
340344

341345
std::unique_ptr<VideoEncoder> MockVideoEncoderFactory::CreateVideoEncoder(
342346
const SdpVideoFormat& format) {
347+
if (create_video_encoder_return_nullptr_) {
348+
return nullptr;
349+
}
350+
343351
auto encoder = std::make_unique<::testing::NiceMock<MockVideoEncoder>>(this);
344352
encoder->set_init_encode_return_value(init_encode_return_value_);
345353
const char* encoder_name = encoder_names_.empty()
@@ -1683,5 +1691,46 @@ TEST_F(TestSimulcastEncoderAdapterFake,
16831691
EXPECT_NE(helper_->factory()->encoders()[0], prev_encoder);
16841692
}
16851693

1694+
TEST_F(TestSimulcastEncoderAdapterFake,
1695+
UseFallbackEncoderIfCreatePrimaryEncoderFailed) {
1696+
// Enable support for fallback encoder factory and re-setup.
1697+
use_fallback_factory_ = true;
1698+
SetUp();
1699+
SimulcastTestFixtureImpl::DefaultSettings(
1700+
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
1701+
kVideoCodecVP8);
1702+
codec_.numberOfSimulcastStreams = 1;
1703+
helper_->factory()->SetEncoderNames({"primary"});
1704+
helper_->fallback_factory()->SetEncoderNames({"fallback"});
1705+
1706+
// Emulate failure at creating of primary encoder and verify that SEA switches
1707+
// to fallback encoder.
1708+
helper_->factory()->set_create_video_encode_return_nullptr(true);
1709+
EXPECT_EQ(0, adapter_->InitEncode(&codec_, kSettings));
1710+
ASSERT_EQ(0u, helper_->factory()->encoders().size());
1711+
ASSERT_EQ(1u, helper_->fallback_factory()->encoders().size());
1712+
EXPECT_EQ("fallback", adapter_->GetEncoderInfo().implementation_name);
1713+
}
1714+
1715+
TEST_F(TestSimulcastEncoderAdapterFake,
1716+
InitEncodeReturnsErrorIfEncoderCannotBeCreated) {
1717+
// Enable support for fallback encoder factory and re-setup.
1718+
use_fallback_factory_ = true;
1719+
SetUp();
1720+
SimulcastTestFixtureImpl::DefaultSettings(
1721+
&codec_, static_cast<const int*>(kTestTemporalLayerProfile),
1722+
kVideoCodecVP8);
1723+
codec_.numberOfSimulcastStreams = 1;
1724+
helper_->factory()->SetEncoderNames({"primary"});
1725+
helper_->fallback_factory()->SetEncoderNames({"fallback"});
1726+
1727+
// Emulate failure at creating of primary and fallback encoders and verify
1728+
// that `InitEncode` returns an error.
1729+
helper_->factory()->set_create_video_encode_return_nullptr(true);
1730+
helper_->fallback_factory()->set_create_video_encode_return_nullptr(true);
1731+
EXPECT_EQ(WEBRTC_VIDEO_CODEC_MEMORY,
1732+
adapter_->InitEncode(&codec_, kSettings));
1733+
}
1734+
16861735
} // namespace test
16871736
} // namespace webrtc

0 commit comments

Comments
 (0)