Allow software fallback on lowest simulcast stream for temporal support
Bug: webrtc:11324
Change-Id: Ie505be0cda74c0444065d86c3727671c62bd4842
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/167527
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Commit-Queue: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30437}
diff --git a/api/video_codecs/video_encoder_software_fallback_wrapper.cc b/api/video_codecs/video_encoder_software_fallback_wrapper.cc
index fe32741..9edc9b0 100644
--- a/api/video_codecs/video_encoder_software_fallback_wrapper.cc
+++ b/api/video_codecs/video_encoder_software_fallback_wrapper.cc
@@ -15,7 +15,6 @@
#include <cstdio>
#include <memory>
#include <string>
-#include <utility>
#include <vector>
#include "absl/types/optional.h"
@@ -25,6 +24,7 @@
#include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_encoder.h"
#include "modules/video_coding/include/video_error_codes.h"
+#include "modules/video_coding/utility/simulcast_utility.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/field_trial.h"
@@ -33,52 +33,89 @@
namespace {
+// If forced fallback is allowed, either:
+//
+// 1) The forced fallback is requested if the resolution is less than or equal
+// to |max_pixels_|. The resolution is allowed to be scaled down to
+// |min_pixels_|.
+//
+// 2) The forced fallback is requested if temporal support is preferred and the
+// SW fallback supports temporal layers while the HW encoder does not.
+
+struct ForcedFallbackParams {
+ public:
+ bool SupportsResolutionBasedSwitch(const VideoCodec& codec) const {
+ return enable_resolution_based_switch &&
+ codec.codecType == kVideoCodecVP8 &&
+ codec.numberOfSimulcastStreams <= 1 &&
+ codec.VP8().numberOfTemporalLayers == 1 &&
+ codec.width * codec.height <= max_pixels;
+ }
+
+ bool SupportsTemporalBasedSwitch(const VideoCodec& codec) const {
+ return enable_temporal_based_switch &&
+ SimulcastUtility::NumberOfTemporalLayers(codec, 0) > 1;
+ }
+
+ bool enable_temporal_based_switch = false;
+ bool enable_resolution_based_switch = false;
+ int min_pixels = 320 * 180;
+ int max_pixels = 320 * 240;
+};
+
const char kVp8ForceFallbackEncoderFieldTrial[] =
"WebRTC-VP8-Forced-Fallback-Encoder-v2";
-bool EnableForcedFallback() {
- return field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial);
-}
-
-bool IsForcedFallbackPossible(const VideoCodec& codec_settings) {
- return codec_settings.codecType == kVideoCodecVP8 &&
- codec_settings.numberOfSimulcastStreams <= 1 &&
- codec_settings.VP8().numberOfTemporalLayers == 1;
-}
-
-void GetForcedFallbackParamsFromFieldTrialGroup(int* param_min_pixels,
- int* param_max_pixels,
- int minimum_max_pixels) {
- RTC_DCHECK(param_min_pixels);
- RTC_DCHECK(param_max_pixels);
- std::string group =
+absl::optional<ForcedFallbackParams> ParseFallbackParamsFromFieldTrials(
+ const VideoEncoder& main_encoder) {
+ const std::string field_trial =
webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial);
- if (group.empty())
- return;
+ if (field_trial.find("Enabled") != 0) {
+ return absl::nullopt;
+ }
- int min_pixels;
- int max_pixels;
- int min_bps;
- if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels,
- &min_bps) != 3) {
+ int max_pixels_lower_bound =
+ main_encoder.GetEncoderInfo().scaling_settings.min_pixels_per_frame - 1;
+
+ ForcedFallbackParams params;
+ params.enable_resolution_based_switch = true;
+
+ int min_bps = 0;
+ if (sscanf(field_trial.c_str(), "Enabled-%d,%d,%d", ¶ms.min_pixels,
+ ¶ms.max_pixels, &min_bps) != 3) {
RTC_LOG(LS_WARNING)
<< "Invalid number of forced fallback parameters provided.";
- return;
- }
- if (min_pixels <= 0 || max_pixels < minimum_max_pixels ||
- max_pixels < min_pixels || min_bps <= 0) {
+ return absl::nullopt;
+ } else if (params.min_pixels <= 0 ||
+ params.max_pixels < max_pixels_lower_bound ||
+ params.max_pixels < params.min_pixels || min_bps <= 0) {
RTC_LOG(LS_WARNING) << "Invalid forced fallback parameter value provided.";
- return;
+ return absl::nullopt;
}
- *param_min_pixels = min_pixels;
- *param_max_pixels = max_pixels;
+
+ return params;
+}
+
+absl::optional<ForcedFallbackParams> GetForcedFallbackParams(
+ bool prefer_temporal_support,
+ const VideoEncoder& main_encoder) {
+ absl::optional<ForcedFallbackParams> params =
+ ParseFallbackParamsFromFieldTrials(main_encoder);
+ if (prefer_temporal_support) {
+ if (!params.has_value()) {
+ params.emplace();
+ }
+ params->enable_temporal_based_switch = prefer_temporal_support;
+ }
+ return params;
}
class VideoEncoderSoftwareFallbackWrapper final : public VideoEncoder {
public:
VideoEncoderSoftwareFallbackWrapper(
std::unique_ptr<webrtc::VideoEncoder> sw_encoder,
- std::unique_ptr<webrtc::VideoEncoder> hw_encoder);
+ std::unique_ptr<webrtc::VideoEncoder> hw_encoder,
+ bool prefer_temporal_support);
~VideoEncoderSoftwareFallbackWrapper() override;
void SetFecControllerOverride(
@@ -106,28 +143,28 @@
EncoderInfo GetEncoderInfo() const override;
private:
- bool InitFallbackEncoder();
-
- // If |forced_fallback_possible_| is true:
- // The forced fallback is requested if the resolution is less than or equal to
- // |max_pixels_|. The resolution is allowed to be scaled down to
- // |min_pixels_|.
- class ForcedFallbackParams {
- public:
- bool IsValid(const VideoCodec& codec) const {
- return codec.width * codec.height <= max_pixels_;
- }
-
- bool active_ = false;
- int min_pixels_ = 320 * 180;
- int max_pixels_ = 320 * 240;
- };
-
+ bool InitFallbackEncoder(bool is_forced);
bool TryInitForcedFallbackEncoder();
- bool TryReInitForcedFallbackEncoder();
- void ValidateSettingsForForcedFallback();
- bool IsForcedFallbackActive() const;
- void MaybeModifyCodecForFallback();
+ bool IsFallbackActive() const;
+
+ VideoEncoder* current_encoder() {
+ switch (encoder_state_) {
+ case EncoderState::kUninitialized:
+ RTC_LOG(LS_WARNING)
+ << "Trying to access encoder in uninitialized fallback wrapper.";
+ // Return main encoder to preserve previous behavior.
+ ABSL_FALLTHROUGH_INTENDED;
+ case EncoderState::kMainEncoderUsed:
+ return encoder_.get();
+ case EncoderState::kFallbackDueToFailure:
+ case EncoderState::kForcedFallback:
+ return fallback_encoder_.get();
+ }
+ }
+
+ // Updates encoder with last observed parameters, such as callbacks, rates,
+ // etc.
+ void PrimeEncoder(VideoEncoder* encoder) const;
// Settings used in the last InitEncode call and used if a dynamic fallback to
// software is required.
@@ -137,65 +174,95 @@
// The last rate control settings, if set.
absl::optional<RateControlParameters> rate_control_parameters_;
- // The last channel parameters set, and a flag for noting they are set.
- bool channel_parameters_set_;
- uint32_t packet_loss_;
- int64_t rtt_;
+ // The last channel parameters set.
+ absl::optional<float> packet_loss_;
+ absl::optional<int64_t> rtt_;
+ FecControllerOverride* fec_controller_override_;
+ absl::optional<LossNotification> loss_notification_;
- bool use_fallback_encoder_;
+ enum class EncoderState {
+ kUninitialized,
+ kMainEncoderUsed,
+ kFallbackDueToFailure,
+ kForcedFallback
+ };
+
+ EncoderState encoder_state_;
const std::unique_ptr<webrtc::VideoEncoder> encoder_;
-
const std::unique_ptr<webrtc::VideoEncoder> fallback_encoder_;
+
EncodedImageCallback* callback_;
- bool forced_fallback_possible_;
- ForcedFallbackParams forced_fallback_;
+ const absl::optional<ForcedFallbackParams> fallback_params_;
};
VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
std::unique_ptr<webrtc::VideoEncoder> sw_encoder,
- std::unique_ptr<webrtc::VideoEncoder> hw_encoder)
- : channel_parameters_set_(false),
- packet_loss_(0),
- rtt_(0),
- use_fallback_encoder_(false),
+ std::unique_ptr<webrtc::VideoEncoder> hw_encoder,
+ bool prefer_temporal_support)
+ : fec_controller_override_(nullptr),
+ encoder_state_(EncoderState::kUninitialized),
encoder_(std::move(hw_encoder)),
fallback_encoder_(std::move(sw_encoder)),
callback_(nullptr),
- forced_fallback_possible_(EnableForcedFallback()) {
+ fallback_params_(
+ GetForcedFallbackParams(prefer_temporal_support, *encoder_)) {
RTC_DCHECK(fallback_encoder_);
- if (forced_fallback_possible_) {
- GetForcedFallbackParamsFromFieldTrialGroup(
- &forced_fallback_.min_pixels_, &forced_fallback_.max_pixels_,
- encoder_->GetEncoderInfo().scaling_settings.min_pixels_per_frame -
- 1); // No HW below.
- }
}
+
VideoEncoderSoftwareFallbackWrapper::~VideoEncoderSoftwareFallbackWrapper() =
default;
-bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
+void VideoEncoderSoftwareFallbackWrapper::PrimeEncoder(
+ VideoEncoder* encoder) const {
+ RTC_DCHECK(encoder);
+ // Replay callback, rates, and channel parameters.
+ if (callback_) {
+ encoder->RegisterEncodeCompleteCallback(callback_);
+ }
+ if (rate_control_parameters_) {
+ encoder->SetRates(*rate_control_parameters_);
+ }
+ if (rtt_.has_value()) {
+ encoder->OnRttUpdate(rtt_.value());
+ }
+ if (packet_loss_.has_value()) {
+ encoder->OnPacketLossRateUpdate(packet_loss_.value());
+ }
+ if (fec_controller_override_) {
+ encoder->SetFecControllerOverride(fec_controller_override_);
+ }
+ if (loss_notification_.has_value()) {
+ encoder->OnLossNotification(loss_notification_.value());
+ }
+}
+
+bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder(bool is_forced) {
RTC_LOG(LS_WARNING) << "Encoder falling back to software encoding.";
RTC_DCHECK(encoder_settings_.has_value());
const int ret = fallback_encoder_->InitEncode(&codec_settings_,
encoder_settings_.value());
- use_fallback_encoder_ = (ret == WEBRTC_VIDEO_CODEC_OK);
- if (!use_fallback_encoder_) {
+
+ if (ret != WEBRTC_VIDEO_CODEC_OK) {
RTC_LOG(LS_ERROR) << "Failed to initialize software-encoder fallback.";
fallback_encoder_->Release();
return false;
}
- // Replay callback, rates, and channel parameters.
- if (callback_)
- fallback_encoder_->RegisterEncodeCompleteCallback(callback_);
- if (rate_control_parameters_)
- fallback_encoder_->SetRates(*rate_control_parameters_);
- // Since we're switching to the fallback encoder, Release the real encoder. It
- // may be re-initialized via InitEncode later, and it will continue to get
- // Set calls for rates and channel parameters in the meantime.
- encoder_->Release();
+ if (encoder_state_ == EncoderState::kMainEncoderUsed) {
+ // Since we're switching to the fallback encoder, Release the real encoder.
+ // It may be re-initialized via InitEncode later, and it will continue to
+ // get Set calls for rates and channel parameters in the meantime.
+ encoder_->Release();
+ }
+
+ if (is_forced) {
+ encoder_state_ = EncoderState::kForcedFallback;
+ } else {
+ encoder_state_ = EncoderState::kFallbackDueToFailure;
+ }
+
return true;
}
@@ -204,8 +271,9 @@
// It is important that only one of those would ever interact with the
// |fec_controller_override| at a given time. This is the responsibility
// of |this| to maintain.
- encoder_->SetFecControllerOverride(fec_controller_override);
- fallback_encoder_->SetFecControllerOverride(fec_controller_override);
+
+ fec_controller_override_ = fec_controller_override;
+ current_encoder()->SetFecControllerOverride(fec_controller_override);
}
int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode(
@@ -217,93 +285,94 @@
encoder_settings_ = settings;
// Clear stored rate/channel parameters.
rate_control_parameters_ = absl::nullopt;
- ValidateSettingsForForcedFallback();
- // Try to reinit forced software codec if it is in use.
- if (TryReInitForcedFallbackEncoder()) {
- return WEBRTC_VIDEO_CODEC_OK;
- }
+ RTC_DCHECK_EQ(encoder_state_, EncoderState::kUninitialized)
+ << "InitEncode() should never be called on an active instance!";
+
// Try to init forced software codec if it should be used.
if (TryInitForcedFallbackEncoder()) {
+ PrimeEncoder(current_encoder());
return WEBRTC_VIDEO_CODEC_OK;
}
- forced_fallback_.active_ = false;
int32_t ret = encoder_->InitEncode(codec_settings, settings);
if (ret == WEBRTC_VIDEO_CODEC_OK) {
- if (use_fallback_encoder_) {
- RTC_LOG(LS_WARNING)
- << "InitEncode OK, no longer using the software fallback encoder.";
- fallback_encoder_->Release();
- use_fallback_encoder_ = false;
- }
- if (callback_)
- encoder_->RegisterEncodeCompleteCallback(callback_);
+ encoder_state_ = EncoderState::kMainEncoderUsed;
+ PrimeEncoder(current_encoder());
return ret;
}
+
// Try to instantiate software codec.
- if (InitFallbackEncoder()) {
+ if (InitFallbackEncoder(/*is_forced=*/false)) {
+ PrimeEncoder(current_encoder());
return WEBRTC_VIDEO_CODEC_OK;
}
- // Software encoder failed, use original return code.
+
+ // Software encoder failed too, use original return code.
+ encoder_state_ = EncoderState::kUninitialized;
return ret;
}
int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback(
EncodedImageCallback* callback) {
callback_ = callback;
- int32_t ret = encoder_->RegisterEncodeCompleteCallback(callback);
- if (use_fallback_encoder_)
- return fallback_encoder_->RegisterEncodeCompleteCallback(callback);
- return ret;
+ return current_encoder()->RegisterEncodeCompleteCallback(callback);
}
int32_t VideoEncoderSoftwareFallbackWrapper::Release() {
- return use_fallback_encoder_ ? fallback_encoder_->Release()
- : encoder_->Release();
+ if (encoder_state_ == EncoderState::kUninitialized) {
+ return WEBRTC_VIDEO_CODEC_OK;
+ }
+ int32_t ret = current_encoder()->Release();
+ encoder_state_ = EncoderState::kUninitialized;
+ return ret;
}
int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
const VideoFrame& frame,
const std::vector<VideoFrameType>* frame_types) {
- if (use_fallback_encoder_)
- return fallback_encoder_->Encode(frame, frame_types);
- int32_t ret = encoder_->Encode(frame, frame_types);
- // If requested, try a software fallback.
- bool fallback_requested = (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
- if (fallback_requested && InitFallbackEncoder()) {
- // Start using the fallback with this frame.
- return fallback_encoder_->Encode(frame, frame_types);
+ switch (encoder_state_) {
+ case EncoderState::kUninitialized:
+ return WEBRTC_VIDEO_CODEC_ERROR;
+ case EncoderState::kMainEncoderUsed: {
+ int32_t ret = encoder_->Encode(frame, frame_types);
+ // If requested, try a software fallback.
+ bool fallback_requested = (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
+ if (fallback_requested && InitFallbackEncoder(/*is_forced=*/false)) {
+ // Start using the fallback with this frame.
+ PrimeEncoder(current_encoder());
+ return fallback_encoder_->Encode(frame, frame_types);
+ }
+ // Fallback encoder failed too, return original error code.
+ return ret;
+ }
+ case EncoderState::kFallbackDueToFailure:
+ case EncoderState::kForcedFallback:
+ return fallback_encoder_->Encode(frame, frame_types);
}
- return ret;
}
void VideoEncoderSoftwareFallbackWrapper::SetRates(
const RateControlParameters& parameters) {
rate_control_parameters_ = parameters;
- encoder_->SetRates(parameters);
- if (use_fallback_encoder_)
- fallback_encoder_->SetRates(parameters);
+ return current_encoder()->SetRates(parameters);
}
void VideoEncoderSoftwareFallbackWrapper::OnPacketLossRateUpdate(
float packet_loss_rate) {
- VideoEncoder* encoder =
- use_fallback_encoder_ ? fallback_encoder_.get() : encoder_.get();
- encoder->OnPacketLossRateUpdate(packet_loss_rate);
+ packet_loss_ = packet_loss_rate;
+ current_encoder()->OnPacketLossRateUpdate(packet_loss_rate);
}
void VideoEncoderSoftwareFallbackWrapper::OnRttUpdate(int64_t rtt_ms) {
- VideoEncoder* encoder =
- use_fallback_encoder_ ? fallback_encoder_.get() : encoder_.get();
- encoder->OnRttUpdate(rtt_ms);
+ rtt_ = rtt_ms;
+ current_encoder()->OnRttUpdate(rtt_ms);
}
void VideoEncoderSoftwareFallbackWrapper::OnLossNotification(
const LossNotification& loss_notification) {
- VideoEncoder* encoder =
- use_fallback_encoder_ ? fallback_encoder_.get() : encoder_.get();
- encoder->OnLossNotification(loss_notification);
+ loss_notification_ = loss_notification;
+ current_encoder()->OnLossNotification(loss_notification);
}
VideoEncoder::EncoderInfo VideoEncoderSoftwareFallbackWrapper::GetEncoderInfo()
@@ -312,17 +381,17 @@
EncoderInfo default_encoder_info = encoder_->GetEncoderInfo();
EncoderInfo info =
- use_fallback_encoder_ ? fallback_encoder_info : default_encoder_info;
+ IsFallbackActive() ? fallback_encoder_info : default_encoder_info;
- if (forced_fallback_possible_) {
- const auto settings = forced_fallback_.active_
+ if (fallback_params_.has_value()) {
+ const auto settings = (encoder_state_ == EncoderState::kForcedFallback)
? fallback_encoder_info.scaling_settings
: default_encoder_info.scaling_settings;
info.scaling_settings =
settings.thresholds
? VideoEncoder::ScalingSettings(settings.thresholds->low,
settings.thresholds->high,
- forced_fallback_.min_pixels_)
+ fallback_params_->min_pixels)
: VideoEncoder::ScalingSettings::kOff;
} else {
info.scaling_settings = default_encoder_info.scaling_settings;
@@ -331,72 +400,82 @@
return info;
}
-bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const {
- return (forced_fallback_possible_ && use_fallback_encoder_ &&
- forced_fallback_.active_);
+bool VideoEncoderSoftwareFallbackWrapper::IsFallbackActive() const {
+ return encoder_state_ == EncoderState::kForcedFallback ||
+ encoder_state_ == EncoderState::kFallbackDueToFailure;
}
bool VideoEncoderSoftwareFallbackWrapper::TryInitForcedFallbackEncoder() {
- if (!forced_fallback_possible_ || use_fallback_encoder_) {
- return false;
- }
- // Fallback not active.
- if (!forced_fallback_.IsValid(codec_settings_)) {
- return false;
- }
- // Settings valid, try to instantiate software codec.
- RTC_LOG(LS_INFO) << "Request forced SW encoder fallback: "
- << codec_settings_.width << "x" << codec_settings_.height;
- if (!InitFallbackEncoder()) {
- return false;
- }
- forced_fallback_.active_ = true;
- return true;
-}
-
-bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() {
- if (!IsForcedFallbackActive()) {
+ if (!fallback_params_) {
return false;
}
- // Forced fallback active.
- if (!forced_fallback_.IsValid(codec_settings_)) {
- RTC_LOG(LS_INFO) << "Stop forced SW encoder fallback, max pixels exceeded.";
- return false;
+ RTC_DCHECK_EQ(encoder_state_, EncoderState::kUninitialized);
+
+ if (fallback_params_->SupportsResolutionBasedSwitch(codec_settings_)) {
+ // Settings valid, try to instantiate software codec.
+ RTC_LOG(LS_INFO) << "Request forced SW encoder fallback: "
+ << codec_settings_.width << "x" << codec_settings_.height;
+ return InitFallbackEncoder(/*is_forced=*/true);
}
- // Settings valid, reinitialize the forced fallback encoder.
- RTC_DCHECK(encoder_settings_.has_value());
- if (fallback_encoder_->InitEncode(&codec_settings_,
- encoder_settings_.value()) !=
- WEBRTC_VIDEO_CODEC_OK) {
- RTC_LOG(LS_ERROR) << "Failed to init forced SW encoder fallback.";
- return false;
- }
- return true;
-}
-
-void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() {
- if (!forced_fallback_possible_)
- return;
-
- if (!IsForcedFallbackPossible(codec_settings_)) {
- if (IsForcedFallbackActive()) {
- fallback_encoder_->Release();
- use_fallback_encoder_ = false;
+ if (fallback_params_->SupportsTemporalBasedSwitch(codec_settings_)) {
+ // First init main encoder to see if that supports temporal layers.
+ if (encoder_->InitEncode(&codec_settings_, encoder_settings_.value()) ==
+ WEBRTC_VIDEO_CODEC_OK) {
+ encoder_state_ = EncoderState::kMainEncoderUsed;
}
- RTC_LOG(LS_INFO) << "Disable forced_fallback_possible_ due to settings.";
- forced_fallback_possible_ = false;
+
+ if (encoder_state_ == EncoderState::kMainEncoderUsed &&
+ encoder_->GetEncoderInfo().fps_allocation[0].size() > 1) {
+ // Primary encoder already supports temporal layers, use that instead.
+ return true;
+ }
+
+ // Try to initialize fallback and check if it supports temporal layers.
+ if (fallback_encoder_->InitEncode(&codec_settings_,
+ encoder_settings_.value()) ==
+ WEBRTC_VIDEO_CODEC_OK) {
+ if (fallback_encoder_->GetEncoderInfo().fps_allocation[0].size() > 1) {
+ // Fallback encoder available and supports temporal layers, use it!
+ if (encoder_state_ == EncoderState::kMainEncoderUsed) {
+ // Main encoder initialized but does not support temporal layers,
+ // release it again.
+ encoder_->Release();
+ }
+ encoder_state_ = EncoderState::kForcedFallback;
+ RTC_LOG(LS_INFO)
+ << "Forced switch to SW encoder due to temporal support.";
+ return true;
+ } else {
+ // Fallback encoder intialization succeeded, but it does not support
+ // temporal layers either - release it.
+ fallback_encoder_->Release();
+ }
+ }
+
+ if (encoder_state_ == EncoderState::kMainEncoderUsed) {
+ // Main encoder already initialized - make use of it.
+ RTC_LOG(LS_INFO)
+ << "Cannot fall back for temporal support since fallback that "
+ "supports is not available. Using main encoder instead.";
+ return true;
+ }
}
+
+ // Neither forced fallback mode supported.
+ return false;
}
} // namespace
std::unique_ptr<VideoEncoder> CreateVideoEncoderSoftwareFallbackWrapper(
std::unique_ptr<VideoEncoder> sw_fallback_encoder,
- std::unique_ptr<VideoEncoder> hw_encoder) {
+ std::unique_ptr<VideoEncoder> hw_encoder,
+ bool prefer_temporal_support) {
return std::make_unique<VideoEncoderSoftwareFallbackWrapper>(
- std::move(sw_fallback_encoder), std::move(hw_encoder));
+ std::move(sw_fallback_encoder), std::move(hw_encoder),
+ prefer_temporal_support);
}
} // namespace webrtc