Skip to content

Commit 7ca0fa6

Browse files
authored
Use fallback encoder if primary can't be created (#11)
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 7ca0fa6

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

media/engine/simulcast_encoder_adapter.cc

Lines changed: 31 additions & 10 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(
689690
bool is_lowest_quality_stream) {
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)