blob: 39c52a008181cd2cf5fb2b3589816dfd3f03a6ba [file] [log] [blame]
magjed614d5b72016-11-15 14:30:541/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Anders Carlssondd3e0ab2018-06-12 09:15:5611#include "api/video_codecs/video_encoder_software_fallback_wrapper.h"
magjed614d5b72016-11-15 14:30:5412
Yves Gerey3e707812018-11-28 15:47:4913#include <stdint.h>
Jonas Olssona4d87372019-07-05 17:08:3314
Piotr Tworek5e4833c2017-12-12 11:09:3115#include <cstdio>
Mirko Bonadei317a1f02019-09-17 15:06:1816#include <memory>
Anders Carlssondd3e0ab2018-06-12 09:15:5617#include <string>
Anders Carlssondd3e0ab2018-06-12 09:15:5618#include <vector>
Steve Antone78bcb92017-10-31 16:53:0819
Mirko Bonadei06d35592020-04-01 11:43:0820#include "absl/strings/match.h"
Yves Gerey3e707812018-11-28 15:47:4921#include "absl/types/optional.h"
Elad Alon8f01c4e2019-06-28 13:19:4322#include "api/fec_controller_override.h"
Evan Shrubsole546a9e42020-02-11 15:18:0723#include "api/video/i420_buffer.h"
Yves Gerey3e707812018-11-28 15:47:4924#include "api/video/video_bitrate_allocation.h"
25#include "api/video/video_frame.h"
26#include "api/video_codecs/video_codec.h"
Elad Alon370f93a2019-06-11 12:57:5727#include "api/video_codecs/video_encoder.h"
Ilya Nikolaevskiyc98aebb2021-07-13 14:27:1128#include "media/base/video_common.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3129#include "modules/video_coding/include/video_error_codes.h"
Erik Språng261f7922020-01-31 12:51:1230#include "modules/video_coding/utility/simulcast_utility.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3131#include "rtc_base/checks.h"
32#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3133#include "system_wrappers/include/field_trial.h"
magjed614d5b72016-11-15 14:30:5434
35namespace webrtc {
Anders Carlssondd3e0ab2018-06-12 09:15:5636
asapersson22c76c42017-08-16 07:53:5937namespace {
Anders Carlssondd3e0ab2018-06-12 09:15:5638
Erik Språng261f7922020-01-31 12:51:1239// If forced fallback is allowed, either:
40//
41// 1) The forced fallback is requested if the resolution is less than or equal
Artem Titov0e61fdd2021-07-25 19:50:1442// to `max_pixels_`. The resolution is allowed to be scaled down to
43// `min_pixels_`.
Erik Språng261f7922020-01-31 12:51:1244//
45// 2) The forced fallback is requested if temporal support is preferred and the
46// SW fallback supports temporal layers while the HW encoder does not.
47
48struct ForcedFallbackParams {
49 public:
50 bool SupportsResolutionBasedSwitch(const VideoCodec& codec) const {
51 return enable_resolution_based_switch &&
52 codec.codecType == kVideoCodecVP8 &&
53 codec.numberOfSimulcastStreams <= 1 &&
Erik Språng261f7922020-01-31 12:51:1254 codec.width * codec.height <= max_pixels;
55 }
56
57 bool SupportsTemporalBasedSwitch(const VideoCodec& codec) const {
58 return enable_temporal_based_switch &&
Jakob Ivarssona9961b32020-11-18 09:18:3559 SimulcastUtility::NumberOfTemporalLayers(codec, 0) != 1;
Erik Språng261f7922020-01-31 12:51:1260 }
61
62 bool enable_temporal_based_switch = false;
63 bool enable_resolution_based_switch = false;
64 int min_pixels = 320 * 180;
65 int max_pixels = 320 * 240;
66};
67
asapersson22c76c42017-08-16 07:53:5968const char kVp8ForceFallbackEncoderFieldTrial[] =
Åsa Persson45bbc8a2017-11-13 09:16:4769 "WebRTC-VP8-Forced-Fallback-Encoder-v2";
asapersson22c76c42017-08-16 07:53:5970
Erik Språng261f7922020-01-31 12:51:1271absl::optional<ForcedFallbackParams> ParseFallbackParamsFromFieldTrials(
72 const VideoEncoder& main_encoder) {
73 const std::string field_trial =
asapersson22c76c42017-08-16 07:53:5974 webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial);
Mirko Bonadei06d35592020-04-01 11:43:0875 if (!absl::StartsWith(field_trial, "Enabled")) {
Erik Språng261f7922020-01-31 12:51:1276 return absl::nullopt;
77 }
asapersson22c76c42017-08-16 07:53:5978
Erik Språng261f7922020-01-31 12:51:1279 int max_pixels_lower_bound =
80 main_encoder.GetEncoderInfo().scaling_settings.min_pixels_per_frame - 1;
81
82 ForcedFallbackParams params;
83 params.enable_resolution_based_switch = true;
84
85 int min_bps = 0;
86 if (sscanf(field_trial.c_str(), "Enabled-%d,%d,%d", &params.min_pixels,
87 &params.max_pixels, &min_bps) != 3) {
Mirko Bonadei675513b2017-11-09 10:09:2588 RTC_LOG(LS_WARNING)
89 << "Invalid number of forced fallback parameters provided.";
Erik Språng261f7922020-01-31 12:51:1290 return absl::nullopt;
91 } else if (params.min_pixels <= 0 ||
92 params.max_pixels < max_pixels_lower_bound ||
93 params.max_pixels < params.min_pixels || min_bps <= 0) {
Mirko Bonadei675513b2017-11-09 10:09:2594 RTC_LOG(LS_WARNING) << "Invalid forced fallback parameter value provided.";
Erik Språng261f7922020-01-31 12:51:1295 return absl::nullopt;
asapersson22c76c42017-08-16 07:53:5996 }
Erik Språng261f7922020-01-31 12:51:1297
98 return params;
99}
100
101absl::optional<ForcedFallbackParams> GetForcedFallbackParams(
102 bool prefer_temporal_support,
103 const VideoEncoder& main_encoder) {
104 absl::optional<ForcedFallbackParams> params =
105 ParseFallbackParamsFromFieldTrials(main_encoder);
106 if (prefer_temporal_support) {
107 if (!params.has_value()) {
108 params.emplace();
109 }
110 params->enable_temporal_based_switch = prefer_temporal_support;
111 }
112 return params;
asapersson22c76c42017-08-16 07:53:59113}
Anders Carlssondd3e0ab2018-06-12 09:15:56114
115class VideoEncoderSoftwareFallbackWrapper final : public VideoEncoder {
116 public:
117 VideoEncoderSoftwareFallbackWrapper(
118 std::unique_ptr<webrtc::VideoEncoder> sw_encoder,
Erik Språng261f7922020-01-31 12:51:12119 std::unique_ptr<webrtc::VideoEncoder> hw_encoder,
120 bool prefer_temporal_support);
Anders Carlssondd3e0ab2018-06-12 09:15:56121 ~VideoEncoderSoftwareFallbackWrapper() override;
122
Elad Alon8f01c4e2019-06-28 13:19:43123 void SetFecControllerOverride(
124 FecControllerOverride* fec_controller_override) override;
125
Anders Carlssondd3e0ab2018-06-12 09:15:56126 int32_t InitEncode(const VideoCodec* codec_settings,
Elad Alon370f93a2019-06-11 12:57:57127 const VideoEncoder::Settings& settings) override;
Anders Carlssondd3e0ab2018-06-12 09:15:56128
129 int32_t RegisterEncodeCompleteCallback(
130 EncodedImageCallback* callback) override;
131
132 int32_t Release() override;
Elad Alon65764e42019-06-28 16:43:44133
Anders Carlssondd3e0ab2018-06-12 09:15:56134 int32_t Encode(const VideoFrame& frame,
Niels Möller87e2d782019-03-07 09:18:23135 const std::vector<VideoFrameType>* frame_types) override;
Elad Alon65764e42019-06-28 16:43:44136
137 void OnPacketLossRateUpdate(float packet_loss_rate) override;
138
139 void OnRttUpdate(int64_t rtt_ms) override;
140
141 void OnLossNotification(const LossNotification& loss_notification) override;
142
Erik Språng16cb8f52019-04-12 11:59:09143 void SetRates(const RateControlParameters& parameters) override;
Elad Alon65764e42019-06-28 16:43:44144
Erik Språnge2fd86a72018-10-24 09:32:39145 EncoderInfo GetEncoderInfo() const override;
Anders Carlssondd3e0ab2018-06-12 09:15:56146
147 private:
Erik Språng261f7922020-01-31 12:51:12148 bool InitFallbackEncoder(bool is_forced);
Anders Carlssondd3e0ab2018-06-12 09:15:56149 bool TryInitForcedFallbackEncoder();
Erik Språng261f7922020-01-31 12:51:12150 bool IsFallbackActive() const;
151
152 VideoEncoder* current_encoder() {
153 switch (encoder_state_) {
154 case EncoderState::kUninitialized:
155 RTC_LOG(LS_WARNING)
156 << "Trying to access encoder in uninitialized fallback wrapper.";
157 // Return main encoder to preserve previous behavior.
Danil Chapovalov46cc32d2022-01-17 13:41:13158 [[fallthrough]];
Erik Språng261f7922020-01-31 12:51:12159 case EncoderState::kMainEncoderUsed:
160 return encoder_.get();
161 case EncoderState::kFallbackDueToFailure:
162 case EncoderState::kForcedFallback:
163 return fallback_encoder_.get();
164 }
Karl Wibergc95b9392020-11-07 23:49:37165 RTC_CHECK_NOTREACHED();
Erik Språng261f7922020-01-31 12:51:12166 }
167
168 // Updates encoder with last observed parameters, such as callbacks, rates,
169 // etc.
170 void PrimeEncoder(VideoEncoder* encoder) const;
Anders Carlssondd3e0ab2018-06-12 09:15:56171
172 // Settings used in the last InitEncode call and used if a dynamic fallback to
173 // software is required.
174 VideoCodec codec_settings_;
Elad Alon370f93a2019-06-11 12:57:57175 absl::optional<VideoEncoder::Settings> encoder_settings_;
Anders Carlssondd3e0ab2018-06-12 09:15:56176
Erik Språng16cb8f52019-04-12 11:59:09177 // The last rate control settings, if set.
178 absl::optional<RateControlParameters> rate_control_parameters_;
Anders Carlssondd3e0ab2018-06-12 09:15:56179
Erik Språng261f7922020-01-31 12:51:12180 // The last channel parameters set.
181 absl::optional<float> packet_loss_;
182 absl::optional<int64_t> rtt_;
Erik Språng261f7922020-01-31 12:51:12183 absl::optional<LossNotification> loss_notification_;
Anders Carlssondd3e0ab2018-06-12 09:15:56184
Erik Språng261f7922020-01-31 12:51:12185 enum class EncoderState {
186 kUninitialized,
187 kMainEncoderUsed,
188 kFallbackDueToFailure,
189 kForcedFallback
190 };
191
192 EncoderState encoder_state_;
Anders Carlssondd3e0ab2018-06-12 09:15:56193 const std::unique_ptr<webrtc::VideoEncoder> encoder_;
Anders Carlssondd3e0ab2018-06-12 09:15:56194 const std::unique_ptr<webrtc::VideoEncoder> fallback_encoder_;
Erik Språng261f7922020-01-31 12:51:12195
Anders Carlssondd3e0ab2018-06-12 09:15:56196 EncodedImageCallback* callback_;
197
Erik Språng261f7922020-01-31 12:51:12198 const absl::optional<ForcedFallbackParams> fallback_params_;
Evan Shrubsole546a9e42020-02-11 15:18:07199 int32_t EncodeWithMainEncoder(const VideoFrame& frame,
200 const std::vector<VideoFrameType>* frame_types);
Anders Carlssondd3e0ab2018-06-12 09:15:56201};
magjed614d5b72016-11-15 14:30:54202
203VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
Magnus Jedvertee92d622017-11-13 14:26:17204 std::unique_ptr<webrtc::VideoEncoder> sw_encoder,
Erik Språng261f7922020-01-31 12:51:12205 std::unique_ptr<webrtc::VideoEncoder> hw_encoder,
206 bool prefer_temporal_support)
Jiwon Jung3791d332021-10-08 09:22:57207 : encoder_state_(EncoderState::kUninitialized),
Magnus Jedvertee92d622017-11-13 14:26:17208 encoder_(std::move(hw_encoder)),
209 fallback_encoder_(std::move(sw_encoder)),
asapersson22c76c42017-08-16 07:53:59210 callback_(nullptr),
Erik Språng261f7922020-01-31 12:51:12211 fallback_params_(
212 GetForcedFallbackParams(prefer_temporal_support, *encoder_)) {
Elad Alon8f01c4e2019-06-28 13:19:43213 RTC_DCHECK(fallback_encoder_);
asapersson22c76c42017-08-16 07:53:59214}
Erik Språng261f7922020-01-31 12:51:12215
Paulina Hensmana680a6a2018-04-05 09:42:24216VideoEncoderSoftwareFallbackWrapper::~VideoEncoderSoftwareFallbackWrapper() =
217 default;
magjed614d5b72016-11-15 14:30:54218
Erik Språng261f7922020-01-31 12:51:12219void VideoEncoderSoftwareFallbackWrapper::PrimeEncoder(
220 VideoEncoder* encoder) const {
221 RTC_DCHECK(encoder);
222 // Replay callback, rates, and channel parameters.
223 if (callback_) {
224 encoder->RegisterEncodeCompleteCallback(callback_);
225 }
226 if (rate_control_parameters_) {
227 encoder->SetRates(*rate_control_parameters_);
228 }
229 if (rtt_.has_value()) {
230 encoder->OnRttUpdate(rtt_.value());
231 }
232 if (packet_loss_.has_value()) {
233 encoder->OnPacketLossRateUpdate(packet_loss_.value());
234 }
Jiwon Jung3791d332021-10-08 09:22:57235
Erik Språng261f7922020-01-31 12:51:12236 if (loss_notification_.has_value()) {
237 encoder->OnLossNotification(loss_notification_.value());
238 }
239}
240
241bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder(bool is_forced) {
Mirko Bonadei675513b2017-11-09 10:09:25242 RTC_LOG(LS_WARNING) << "Encoder falling back to software encoding.";
Magnus Jedvertee92d622017-11-13 14:26:17243
Elad Alon370f93a2019-06-11 12:57:57244 RTC_DCHECK(encoder_settings_.has_value());
245 const int ret = fallback_encoder_->InitEncode(&codec_settings_,
246 encoder_settings_.value());
Erik Språng261f7922020-01-31 12:51:12247
248 if (ret != WEBRTC_VIDEO_CODEC_OK) {
Mirko Bonadei675513b2017-11-09 10:09:25249 RTC_LOG(LS_ERROR) << "Failed to initialize software-encoder fallback.";
magjed614d5b72016-11-15 14:30:54250 fallback_encoder_->Release();
magjed614d5b72016-11-15 14:30:54251 return false;
252 }
magjed614d5b72016-11-15 14:30:54253
Erik Språng261f7922020-01-31 12:51:12254 if (encoder_state_ == EncoderState::kMainEncoderUsed) {
255 // Since we're switching to the fallback encoder, Release the real encoder.
256 // It may be re-initialized via InitEncode later, and it will continue to
257 // get Set calls for rates and channel parameters in the meantime.
258 encoder_->Release();
259 }
260
261 if (is_forced) {
262 encoder_state_ = EncoderState::kForcedFallback;
263 } else {
264 encoder_state_ = EncoderState::kFallbackDueToFailure;
265 }
266
magjed614d5b72016-11-15 14:30:54267 return true;
268}
269
Elad Alon8f01c4e2019-06-28 13:19:43270void VideoEncoderSoftwareFallbackWrapper::SetFecControllerOverride(
271 FecControllerOverride* fec_controller_override) {
272 // It is important that only one of those would ever interact with the
Artem Titov0e61fdd2021-07-25 19:50:14273 // `fec_controller_override` at a given time. This is the responsibility
274 // of `this` to maintain.
Erik Språng261f7922020-01-31 12:51:12275
Jiwon Jung3791d332021-10-08 09:22:57276 encoder_->SetFecControllerOverride(fec_controller_override);
277 fallback_encoder_->SetFecControllerOverride(fec_controller_override);
Elad Alon8f01c4e2019-06-28 13:19:43278}
279
magjed614d5b72016-11-15 14:30:54280int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode(
281 const VideoCodec* codec_settings,
Elad Alon370f93a2019-06-11 12:57:57282 const VideoEncoder::Settings& settings) {
magjed614d5b72016-11-15 14:30:54283 // Store settings, in case we need to dynamically switch to the fallback
284 // encoder after a failed Encode call.
285 codec_settings_ = *codec_settings;
Elad Alon370f93a2019-06-11 12:57:57286 encoder_settings_ = settings;
magjed614d5b72016-11-15 14:30:54287 // Clear stored rate/channel parameters.
Erik Språng16cb8f52019-04-12 11:59:09288 rate_control_parameters_ = absl::nullopt;
asapersson22c76c42017-08-16 07:53:59289
Erik Språng261f7922020-01-31 12:51:12290 RTC_DCHECK_EQ(encoder_state_, EncoderState::kUninitialized)
291 << "InitEncode() should never be called on an active instance!";
292
Åsa Persson45bbc8a2017-11-13 09:16:47293 // Try to init forced software codec if it should be used.
294 if (TryInitForcedFallbackEncoder()) {
Erik Språng261f7922020-01-31 12:51:12295 PrimeEncoder(current_encoder());
Åsa Persson45bbc8a2017-11-13 09:16:47296 return WEBRTC_VIDEO_CODEC_OK;
297 }
magjed614d5b72016-11-15 14:30:54298
Elad Alon370f93a2019-06-11 12:57:57299 int32_t ret = encoder_->InitEncode(codec_settings, settings);
Magnus Jedvertee92d622017-11-13 14:26:17300 if (ret == WEBRTC_VIDEO_CODEC_OK) {
Erik Språng261f7922020-01-31 12:51:12301 encoder_state_ = EncoderState::kMainEncoderUsed;
302 PrimeEncoder(current_encoder());
magjed614d5b72016-11-15 14:30:54303 return ret;
304 }
Erik Språng261f7922020-01-31 12:51:12305
magjed614d5b72016-11-15 14:30:54306 // Try to instantiate software codec.
Erik Språng261f7922020-01-31 12:51:12307 if (InitFallbackEncoder(/*is_forced=*/false)) {
308 PrimeEncoder(current_encoder());
magjed614d5b72016-11-15 14:30:54309 return WEBRTC_VIDEO_CODEC_OK;
310 }
Erik Språng261f7922020-01-31 12:51:12311
312 // Software encoder failed too, use original return code.
313 encoder_state_ = EncoderState::kUninitialized;
magjed614d5b72016-11-15 14:30:54314 return ret;
315}
316
317int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback(
318 EncodedImageCallback* callback) {
319 callback_ = callback;
Erik Språng261f7922020-01-31 12:51:12320 return current_encoder()->RegisterEncodeCompleteCallback(callback);
magjed614d5b72016-11-15 14:30:54321}
322
323int32_t VideoEncoderSoftwareFallbackWrapper::Release() {
Erik Språng261f7922020-01-31 12:51:12324 if (encoder_state_ == EncoderState::kUninitialized) {
325 return WEBRTC_VIDEO_CODEC_OK;
326 }
327 int32_t ret = current_encoder()->Release();
328 encoder_state_ = EncoderState::kUninitialized;
329 return ret;
magjed614d5b72016-11-15 14:30:54330}
331
332int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
333 const VideoFrame& frame,
Niels Möller87e2d782019-03-07 09:18:23334 const std::vector<VideoFrameType>* frame_types) {
Erik Språng261f7922020-01-31 12:51:12335 switch (encoder_state_) {
336 case EncoderState::kUninitialized:
337 return WEBRTC_VIDEO_CODEC_ERROR;
338 case EncoderState::kMainEncoderUsed: {
Evan Shrubsole546a9e42020-02-11 15:18:07339 return EncodeWithMainEncoder(frame, frame_types);
Erik Språng261f7922020-01-31 12:51:12340 }
341 case EncoderState::kFallbackDueToFailure:
342 case EncoderState::kForcedFallback:
343 return fallback_encoder_->Encode(frame, frame_types);
magjed614d5b72016-11-15 14:30:54344 }
Karl Wibergc95b9392020-11-07 23:49:37345 RTC_CHECK_NOTREACHED();
magjed614d5b72016-11-15 14:30:54346}
Fabien Valléef8b5bfe2020-10-22 08:08:50347
Evan Shrubsole546a9e42020-02-11 15:18:07348int32_t VideoEncoderSoftwareFallbackWrapper::EncodeWithMainEncoder(
349 const VideoFrame& frame,
350 const std::vector<VideoFrameType>* frame_types) {
351 int32_t ret = encoder_->Encode(frame, frame_types);
352 // If requested, try a software fallback.
353 bool fallback_requested = (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE);
354 if (fallback_requested && InitFallbackEncoder(/*is_forced=*/false)) {
355 // Start using the fallback with this frame.
356 PrimeEncoder(current_encoder());
357 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative &&
358 fallback_encoder_->GetEncoderInfo().supports_native_handle) {
359 return fallback_encoder_->Encode(frame, frame_types);
360 } else {
Harald Alvestrand97597c02021-11-04 12:01:23361 RTC_LOG(LS_INFO) << "Fallback encoder does not support native handle - "
362 "converting frame to I420";
Evan Shrubsole546a9e42020-02-11 15:18:07363 rtc::scoped_refptr<I420BufferInterface> src_buffer =
364 frame.video_frame_buffer()->ToI420();
365 if (!src_buffer) {
366 RTC_LOG(LS_ERROR) << "Failed to convert from to I420";
367 return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
368 }
Evan Shrubsole5089a8e2020-10-12 12:43:39369 rtc::scoped_refptr<VideoFrameBuffer> dst_buffer =
370 src_buffer->Scale(codec_settings_.width, codec_settings_.height);
371 if (!dst_buffer) {
372 RTC_LOG(LS_ERROR) << "Failed to scale video frame.";
373 return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
374 }
Evan Shrubsole546a9e42020-02-11 15:18:07375 VideoFrame scaled_frame = frame;
376 scaled_frame.set_video_frame_buffer(dst_buffer);
377 scaled_frame.set_update_rect(VideoFrame::UpdateRect{
378 0, 0, scaled_frame.width(), scaled_frame.height()});
379 return fallback_encoder_->Encode(scaled_frame, frame_types);
380 }
381 }
382 // Fallback encoder failed too, return original error code.
383 return ret;
384}
magjed614d5b72016-11-15 14:30:54385
Erik Språng16cb8f52019-04-12 11:59:09386void VideoEncoderSoftwareFallbackWrapper::SetRates(
387 const RateControlParameters& parameters) {
388 rate_control_parameters_ = parameters;
Erik Språng261f7922020-01-31 12:51:12389 return current_encoder()->SetRates(parameters);
magjed614d5b72016-11-15 14:30:54390}
391
Elad Alon65764e42019-06-28 16:43:44392void VideoEncoderSoftwareFallbackWrapper::OnPacketLossRateUpdate(
393 float packet_loss_rate) {
Erik Språng261f7922020-01-31 12:51:12394 packet_loss_ = packet_loss_rate;
395 current_encoder()->OnPacketLossRateUpdate(packet_loss_rate);
Elad Alon65764e42019-06-28 16:43:44396}
397
398void VideoEncoderSoftwareFallbackWrapper::OnRttUpdate(int64_t rtt_ms) {
Erik Språng261f7922020-01-31 12:51:12399 rtt_ = rtt_ms;
400 current_encoder()->OnRttUpdate(rtt_ms);
Elad Alon65764e42019-06-28 16:43:44401}
402
403void VideoEncoderSoftwareFallbackWrapper::OnLossNotification(
404 const LossNotification& loss_notification) {
Erik Språng261f7922020-01-31 12:51:12405 loss_notification_ = loss_notification;
406 current_encoder()->OnLossNotification(loss_notification);
Elad Alon65764e42019-06-28 16:43:44407}
408
Erik Språnge2fd86a72018-10-24 09:32:39409VideoEncoder::EncoderInfo VideoEncoderSoftwareFallbackWrapper::GetEncoderInfo()
410 const {
411 EncoderInfo fallback_encoder_info = fallback_encoder_->GetEncoderInfo();
412 EncoderInfo default_encoder_info = encoder_->GetEncoderInfo();
magjed614d5b72016-11-15 14:30:54413
Erik Språnge2fd86a72018-10-24 09:32:39414 EncoderInfo info =
Erik Språng261f7922020-01-31 12:51:12415 IsFallbackActive() ? fallback_encoder_info : default_encoder_info;
Erik Språnge2fd86a72018-10-24 09:32:39416
Ilya Nikolaevskiyc98aebb2021-07-13 14:27:11417 info.requested_resolution_alignment = cricket::LeastCommonMultiple(
418 fallback_encoder_info.requested_resolution_alignment,
419 default_encoder_info.requested_resolution_alignment);
420 info.apply_alignment_to_all_simulcast_layers =
421 fallback_encoder_info.apply_alignment_to_all_simulcast_layers ||
422 default_encoder_info.apply_alignment_to_all_simulcast_layers;
423
Erik Språng261f7922020-01-31 12:51:12424 if (fallback_params_.has_value()) {
425 const auto settings = (encoder_state_ == EncoderState::kForcedFallback)
Erik Språnge2fd86a72018-10-24 09:32:39426 ? fallback_encoder_info.scaling_settings
427 : default_encoder_info.scaling_settings;
428 info.scaling_settings =
429 settings.thresholds
430 ? VideoEncoder::ScalingSettings(settings.thresholds->low,
431 settings.thresholds->high,
Erik Språng261f7922020-01-31 12:51:12432 fallback_params_->min_pixels)
Erik Språnge2fd86a72018-10-24 09:32:39433 : VideoEncoder::ScalingSettings::kOff;
434 } else {
435 info.scaling_settings = default_encoder_info.scaling_settings;
Åsa Persson45bbc8a2017-11-13 09:16:47436 }
kthelgason876222f2016-11-29 09:44:11437
Erik Språnge2fd86a72018-10-24 09:32:39438 return info;
kthelgason535dbd32017-01-26 08:36:31439}
440
Erik Språng261f7922020-01-31 12:51:12441bool VideoEncoderSoftwareFallbackWrapper::IsFallbackActive() const {
442 return encoder_state_ == EncoderState::kForcedFallback ||
443 encoder_state_ == EncoderState::kFallbackDueToFailure;
asapersson22c76c42017-08-16 07:53:59444}
445
Åsa Persson45bbc8a2017-11-13 09:16:47446bool VideoEncoderSoftwareFallbackWrapper::TryInitForcedFallbackEncoder() {
Erik Språng261f7922020-01-31 12:51:12447 if (!fallback_params_) {
asapersson22c76c42017-08-16 07:53:59448 return false;
Åsa Persson45bbc8a2017-11-13 09:16:47449 }
Elad Alon370f93a2019-06-11 12:57:57450
Erik Språng261f7922020-01-31 12:51:12451 RTC_DCHECK_EQ(encoder_state_, EncoderState::kUninitialized);
452
453 if (fallback_params_->SupportsResolutionBasedSwitch(codec_settings_)) {
454 // Settings valid, try to instantiate software codec.
455 RTC_LOG(LS_INFO) << "Request forced SW encoder fallback: "
456 << codec_settings_.width << "x" << codec_settings_.height;
457 return InitFallbackEncoder(/*is_forced=*/true);
asapersson22c76c42017-08-16 07:53:59458 }
Elad Alon370f93a2019-06-11 12:57:57459
Erik Språng261f7922020-01-31 12:51:12460 if (fallback_params_->SupportsTemporalBasedSwitch(codec_settings_)) {
461 // First init main encoder to see if that supports temporal layers.
462 if (encoder_->InitEncode(&codec_settings_, encoder_settings_.value()) ==
463 WEBRTC_VIDEO_CODEC_OK) {
464 encoder_state_ = EncoderState::kMainEncoderUsed;
asapersson22c76c42017-08-16 07:53:59465 }
Erik Språng261f7922020-01-31 12:51:12466
467 if (encoder_state_ == EncoderState::kMainEncoderUsed &&
Jakob Ivarssona9961b32020-11-18 09:18:35468 encoder_->GetEncoderInfo().fps_allocation[0].size() != 1) {
Erik Språng261f7922020-01-31 12:51:12469 // Primary encoder already supports temporal layers, use that instead.
470 return true;
471 }
472
473 // Try to initialize fallback and check if it supports temporal layers.
474 if (fallback_encoder_->InitEncode(&codec_settings_,
475 encoder_settings_.value()) ==
476 WEBRTC_VIDEO_CODEC_OK) {
Jakob Ivarssona9961b32020-11-18 09:18:35477 if (fallback_encoder_->GetEncoderInfo().fps_allocation[0].size() != 1) {
Erik Språng261f7922020-01-31 12:51:12478 // Fallback encoder available and supports temporal layers, use it!
479 if (encoder_state_ == EncoderState::kMainEncoderUsed) {
480 // Main encoder initialized but does not support temporal layers,
481 // release it again.
482 encoder_->Release();
483 }
484 encoder_state_ = EncoderState::kForcedFallback;
485 RTC_LOG(LS_INFO)
486 << "Forced switch to SW encoder due to temporal support.";
487 return true;
488 } else {
489 // Fallback encoder intialization succeeded, but it does not support
490 // temporal layers either - release it.
491 fallback_encoder_->Release();
492 }
493 }
494
495 if (encoder_state_ == EncoderState::kMainEncoderUsed) {
496 // Main encoder already initialized - make use of it.
497 RTC_LOG(LS_INFO)
498 << "Cannot fall back for temporal support since fallback that "
499 "supports is not available. Using main encoder instead.";
500 return true;
501 }
asapersson22c76c42017-08-16 07:53:59502 }
Erik Språng261f7922020-01-31 12:51:12503
504 // Neither forced fallback mode supported.
505 return false;
asapersson22c76c42017-08-16 07:53:59506}
507
Anders Carlssondd3e0ab2018-06-12 09:15:56508} // namespace
509
510std::unique_ptr<VideoEncoder> CreateVideoEncoderSoftwareFallbackWrapper(
511 std::unique_ptr<VideoEncoder> sw_fallback_encoder,
Erik Språng261f7922020-01-31 12:51:12512 std::unique_ptr<VideoEncoder> hw_encoder,
513 bool prefer_temporal_support) {
Mirko Bonadei317a1f02019-09-17 15:06:18514 return std::make_unique<VideoEncoderSoftwareFallbackWrapper>(
Erik Språng261f7922020-01-31 12:51:12515 std::move(sw_fallback_encoder), std::move(hw_encoder),
516 prefer_temporal_support);
Anders Carlssondd3e0ab2018-06-12 09:15:56517}
518
magjed614d5b72016-11-15 14:30:54519} // namespace webrtc