| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/media/engine/videoencodersoftwarefallbackwrapper.h" | 11 #include "webrtc/media/engine/videoencodersoftwarefallbackwrapper.h" |
| 12 | 12 |
| 13 #include "webrtc/media/engine/internalencoderfactory.h" | 13 #include "webrtc/media/engine/internalencoderfactory.h" |
| 14 #include "webrtc/modules/video_coding/include/video_error_codes.h" | 14 #include "webrtc/modules/video_coding/include/video_error_codes.h" |
| 15 #include "webrtc/rtc_base/checks.h" |
| 15 #include "webrtc/rtc_base/logging.h" | 16 #include "webrtc/rtc_base/logging.h" |
| 17 #include "webrtc/rtc_base/timeutils.h" |
| 18 #include "webrtc/system_wrappers/include/field_trial.h" |
| 16 | 19 |
| 17 namespace webrtc { | 20 namespace webrtc { |
| 21 namespace { |
| 22 const char kVp8ForceFallbackEncoderFieldTrial[] = |
| 23 "WebRTC-VP8-Forced-Fallback-Encoder"; |
| 24 |
| 25 bool EnableForcedFallback(const cricket::VideoCodec& codec) { |
| 26 if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial)) |
| 27 return false; |
| 28 |
| 29 return (PayloadNameToCodecType(codec.name).value_or(kVideoCodecUnknown) == |
| 30 kVideoCodecVP8); |
| 31 } |
| 32 |
| 33 bool IsForcedFallbackPossible(const VideoCodec& codec_settings) { |
| 34 return codec_settings.codecType == kVideoCodecVP8 && |
| 35 codec_settings.numberOfSimulcastStreams <= 1 && |
| 36 codec_settings.VP8().numberOfTemporalLayers == 1; |
| 37 } |
| 38 |
| 39 void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps, |
| 40 uint32_t* param_high_kbps, |
| 41 int64_t* param_min_low_ms) { |
| 42 RTC_DCHECK(param_low_kbps); |
| 43 RTC_DCHECK(param_high_kbps); |
| 44 RTC_DCHECK(param_min_low_ms); |
| 45 std::string group = |
| 46 webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial); |
| 47 if (group.empty()) |
| 48 return; |
| 49 |
| 50 int low_kbps; |
| 51 int high_kbps; |
| 52 int min_low_ms; |
| 53 if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps, |
| 54 &min_low_ms) != 3) { |
| 55 LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided."; |
| 56 return; |
| 57 } |
| 58 if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps) { |
| 59 LOG(LS_WARNING) << "Invalid forced fallback parameter value provided."; |
| 60 return; |
| 61 } |
| 62 *param_low_kbps = low_kbps; |
| 63 *param_high_kbps = high_kbps; |
| 64 *param_min_low_ms = min_low_ms; |
| 65 } |
| 66 } // namespace |
| 18 | 67 |
| 19 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( | 68 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( |
| 20 const cricket::VideoCodec& codec, | 69 const cricket::VideoCodec& codec, |
| 21 webrtc::VideoEncoder* encoder) | 70 webrtc::VideoEncoder* encoder) |
| 22 : number_of_cores_(0), | 71 : number_of_cores_(0), |
| 23 max_payload_size_(0), | 72 max_payload_size_(0), |
| 24 rates_set_(false), | 73 rates_set_(false), |
| 25 framerate_(0), | 74 framerate_(0), |
| 26 channel_parameters_set_(false), | 75 channel_parameters_set_(false), |
| 27 packet_loss_(0), | 76 packet_loss_(0), |
| 28 rtt_(0), | 77 rtt_(0), |
| 29 codec_(codec), | 78 codec_(codec), |
| 30 encoder_(encoder), | 79 encoder_(encoder), |
| 31 callback_(nullptr) {} | 80 callback_(nullptr), |
| 81 forced_fallback_possible_(EnableForcedFallback(codec)) { |
| 82 if (forced_fallback_possible_) { |
| 83 GetForcedFallbackParamsFromFieldTrialGroup(&forced_fallback_.low_kbps, |
| 84 &forced_fallback_.high_kbps, |
| 85 &forced_fallback_.min_low_ms); |
| 86 } |
| 87 } |
| 32 | 88 |
| 33 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { | 89 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { |
| 34 cricket::InternalEncoderFactory internal_factory; | 90 cricket::InternalEncoderFactory internal_factory; |
| 35 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) { | 91 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) { |
| 36 LOG(LS_WARNING) | 92 LOG(LS_WARNING) |
| 37 << "Encoder requesting fallback to codec not supported in software."; | 93 << "Encoder requesting fallback to codec not supported in software."; |
| 38 return false; | 94 return false; |
| 39 } | 95 } |
| 40 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_)); | 96 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_)); |
| 41 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, | 97 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 69 int32_t number_of_cores, | 125 int32_t number_of_cores, |
| 70 size_t max_payload_size) { | 126 size_t max_payload_size) { |
| 71 // Store settings, in case we need to dynamically switch to the fallback | 127 // Store settings, in case we need to dynamically switch to the fallback |
| 72 // encoder after a failed Encode call. | 128 // encoder after a failed Encode call. |
| 73 codec_settings_ = *codec_settings; | 129 codec_settings_ = *codec_settings; |
| 74 number_of_cores_ = number_of_cores; | 130 number_of_cores_ = number_of_cores; |
| 75 max_payload_size_ = max_payload_size; | 131 max_payload_size_ = max_payload_size; |
| 76 // Clear stored rate/channel parameters. | 132 // Clear stored rate/channel parameters. |
| 77 rates_set_ = false; | 133 rates_set_ = false; |
| 78 channel_parameters_set_ = false; | 134 channel_parameters_set_ = false; |
| 135 ValidateSettingsForForcedFallback(); |
| 136 |
| 137 // Try to reinit forced software codec if it is in use. |
| 138 if (TryReInitForcedFallbackEncoder()) { |
| 139 return WEBRTC_VIDEO_CODEC_OK; |
| 140 } |
| 141 forced_fallback_.Reset(); |
| 79 | 142 |
| 80 int32_t ret = | 143 int32_t ret = |
| 81 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); | 144 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); |
| 82 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) { | 145 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) { |
| 83 if (fallback_encoder_) | 146 if (fallback_encoder_) |
| 84 fallback_encoder_->Release(); | 147 fallback_encoder_->Release(); |
| 85 fallback_encoder_.reset(); | 148 fallback_encoder_.reset(); |
| 86 if (callback_) | 149 if (callback_) |
| 87 encoder_->RegisterEncodeCompleteCallback(callback_); | 150 encoder_->RegisterEncodeCompleteCallback(callback_); |
| 88 return ret; | 151 return ret; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 110 // need to Release() whichever one is active. | 173 // need to Release() whichever one is active. |
| 111 if (fallback_encoder_) | 174 if (fallback_encoder_) |
| 112 return fallback_encoder_->Release(); | 175 return fallback_encoder_->Release(); |
| 113 return encoder_->Release(); | 176 return encoder_->Release(); |
| 114 } | 177 } |
| 115 | 178 |
| 116 int32_t VideoEncoderSoftwareFallbackWrapper::Encode( | 179 int32_t VideoEncoderSoftwareFallbackWrapper::Encode( |
| 117 const VideoFrame& frame, | 180 const VideoFrame& frame, |
| 118 const CodecSpecificInfo* codec_specific_info, | 181 const CodecSpecificInfo* codec_specific_info, |
| 119 const std::vector<FrameType>* frame_types) { | 182 const std::vector<FrameType>* frame_types) { |
| 183 if (TryReleaseForcedFallbackEncoder()) { |
| 184 // Frame may have been converted from kNative to kI420 during fallback. |
| 185 if (encoder_->SupportsNativeHandle() && |
| 186 frame.video_frame_buffer()->type() != VideoFrameBuffer::Type::kNative) { |
| 187 LOG(LS_WARNING) << "Encoder supports native frames, dropping one frame " |
| 188 << "to avoid possible reconfig due to format change."; |
| 189 return WEBRTC_VIDEO_CODEC_ERROR; |
| 190 } |
| 191 } |
| 120 if (fallback_encoder_) | 192 if (fallback_encoder_) |
| 121 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); | 193 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); |
| 122 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); | 194 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); |
| 123 // If requested, try a software fallback. | 195 // If requested, try a software fallback. |
| 124 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) { | 196 bool fallback_requested = |
| 197 (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) || |
| 198 (ret == WEBRTC_VIDEO_CODEC_OK && RequestForcedFallback()); |
| 199 if (fallback_requested && InitFallbackEncoder()) { |
| 200 // Fallback was successful. |
| 201 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) |
| 202 forced_fallback_.Reset(); // Not a forced fallback. |
| 125 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && | 203 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && |
| 126 !fallback_encoder_->SupportsNativeHandle()) { | 204 !fallback_encoder_->SupportsNativeHandle()) { |
| 127 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " | 205 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " |
| 128 << "dropping one frame."; | 206 << "dropping one frame."; |
| 129 return WEBRTC_VIDEO_CODEC_ERROR; | 207 return WEBRTC_VIDEO_CODEC_ERROR; |
| 130 } | 208 } |
| 131 | 209 |
| 132 // Fallback was successful, so start using it with this frame. | 210 // Start using the fallback with this frame. |
| 133 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); | 211 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); |
| 134 } | 212 } |
| 135 return ret; | 213 return ret; |
| 136 } | 214 } |
| 137 | 215 |
| 138 int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters( | 216 int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters( |
| 139 uint32_t packet_loss, | 217 uint32_t packet_loss, |
| 140 int64_t rtt) { | 218 int64_t rtt) { |
| 141 channel_parameters_set_ = true; | 219 channel_parameters_set_ = true; |
| 142 packet_loss_ = packet_loss; | 220 packet_loss_ = packet_loss; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 169 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { | 247 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { |
| 170 return encoder_->GetScalingSettings(); | 248 return encoder_->GetScalingSettings(); |
| 171 } | 249 } |
| 172 | 250 |
| 173 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { | 251 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { |
| 174 if (fallback_encoder_) | 252 if (fallback_encoder_) |
| 175 return fallback_encoder_->ImplementationName(); | 253 return fallback_encoder_->ImplementationName(); |
| 176 return encoder_->ImplementationName(); | 254 return encoder_->ImplementationName(); |
| 177 } | 255 } |
| 178 | 256 |
| 257 bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const { |
| 258 return (forced_fallback_possible_ && fallback_encoder_ && |
| 259 forced_fallback_.start_ms); |
| 260 } |
| 261 |
| 262 bool VideoEncoderSoftwareFallbackWrapper::RequestForcedFallback() { |
| 263 if (!forced_fallback_possible_ || fallback_encoder_ || !rates_set_) |
| 264 return false; |
| 265 |
| 266 // No fallback encoder. |
| 267 return forced_fallback_.ShouldStart(bitrate_allocation_.get_sum_kbps(), |
| 268 codec_settings_); |
| 269 } |
| 270 |
| 271 bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() { |
| 272 if (!IsForcedFallbackActive()) |
| 273 return false; |
| 274 |
| 275 if (!forced_fallback_.ShouldStop(bitrate_allocation_.get_sum_kbps())) |
| 276 return false; |
| 277 |
| 278 // Release the forced fallback encoder. |
| 279 if (encoder_->InitEncode(&codec_settings_, number_of_cores_, |
| 280 max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) { |
| 281 LOG(LS_INFO) << "Stop forced SW encoder fallback, max bitrate exceeded."; |
| 282 fallback_encoder_->Release(); |
| 283 fallback_encoder_.reset(); |
| 284 forced_fallback_.Reset(); |
| 285 return true; |
| 286 } |
| 287 return false; |
| 288 } |
| 289 |
| 290 bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() { |
| 291 if (!IsForcedFallbackActive()) |
| 292 return false; |
| 293 |
| 294 // Encoder reconfigured. |
| 295 if (!forced_fallback_.IsValid(codec_settings_)) { |
| 296 LOG(LS_INFO) << "Stop forced SW encoder fallback, max pixels exceeded."; |
| 297 return false; |
| 298 } |
| 299 // Settings valid, reinitialize the forced fallback encoder. |
| 300 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, |
| 301 max_payload_size_) != |
| 302 WEBRTC_VIDEO_CODEC_OK) { |
| 303 LOG(LS_ERROR) << "Failed to init forced SW encoder fallback."; |
| 304 return false; |
| 305 } |
| 306 return true; |
| 307 } |
| 308 |
| 309 void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() { |
| 310 if (!forced_fallback_possible_) |
| 311 return; |
| 312 |
| 313 if (!IsForcedFallbackPossible(codec_settings_)) { |
| 314 if (IsForcedFallbackActive()) { |
| 315 fallback_encoder_->Release(); |
| 316 fallback_encoder_.reset(); |
| 317 } |
| 318 LOG(LS_INFO) << "Disable forced_fallback_possible_ due to settings."; |
| 319 forced_fallback_possible_ = false; |
| 320 } |
| 321 } |
| 322 |
| 323 bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStart( |
| 324 uint32_t bitrate_kbps, |
| 325 const VideoCodec& codec) { |
| 326 if (bitrate_kbps > low_kbps || !IsValid(codec)) { |
| 327 start_ms.reset(); |
| 328 return false; |
| 329 } |
| 330 |
| 331 // Has bitrate been below |low_kbps| for long enough duration. |
| 332 int64_t now_ms = rtc::TimeMillis(); |
| 333 if (!start_ms) |
| 334 start_ms.emplace(now_ms); |
| 335 |
| 336 if ((now_ms - *start_ms) >= min_low_ms) { |
| 337 LOG(LS_INFO) << "Request forced SW encoder fallback."; |
| 338 // In case the request fails, update time to avoid too frequent requests. |
| 339 start_ms.emplace(now_ms); |
| 340 return true; |
| 341 } |
| 342 return false; |
| 343 } |
| 344 |
| 345 bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop( |
| 346 uint32_t bitrate_kbps) const { |
| 347 return bitrate_kbps >= high_kbps; |
| 348 } |
| 349 |
| 179 } // namespace webrtc | 350 } // namespace webrtc |
| OLD | NEW |