Chromium Code Reviews| 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 if (forced_fallback_.Start(bitrate_allocation_.get_sum_kbps(), | |
| 268 codec_settings_)) { | |
| 269 LOG(LS_INFO) << "Request forced SW encoder fallback."; | |
| 270 return true; | |
| 271 } | |
| 272 return false; | |
| 273 } | |
| 274 | |
| 275 bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() { | |
| 276 if (!IsForcedFallbackActive()) | |
| 277 return false; | |
| 278 | |
| 279 if (!forced_fallback_.Stop(bitrate_allocation_.get_sum_kbps())) | |
| 280 return false; | |
| 281 | |
| 282 // Release the forced fallback encoder. | |
| 283 if (encoder_->InitEncode(&codec_settings_, number_of_cores_, | |
| 284 max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) { | |
| 285 LOG(LS_INFO) << "Stop forced SW encoder fallback, max bitrate exceeded."; | |
| 286 fallback_encoder_->Release(); | |
| 287 fallback_encoder_.reset(); | |
| 288 forced_fallback_.Reset(); | |
| 289 return true; | |
| 290 } | |
| 291 return false; | |
| 292 } | |
| 293 | |
| 294 bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() { | |
| 295 if (!IsForcedFallbackActive()) | |
| 296 return false; | |
| 297 | |
| 298 // Encoder reconfigured. | |
| 299 if (!forced_fallback_.IsValid(codec_settings_)) { | |
| 300 LOG(LS_INFO) << "Stop forced SW encoder fallback, max pixels exceeded."; | |
| 301 return false; | |
| 302 } | |
| 303 // Settings valid, reinitialize the forced fallback encoder. | |
| 304 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, | |
| 305 max_payload_size_) != | |
| 306 WEBRTC_VIDEO_CODEC_OK) { | |
| 307 LOG(LS_ERROR) << "Failed to init forced SW encoder fallback."; | |
| 308 return false; | |
| 309 } | |
| 310 return true; | |
| 311 } | |
| 312 | |
| 313 void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() { | |
| 314 if (!forced_fallback_possible_) | |
| 315 return; | |
| 316 | |
| 317 if (!IsForcedFallbackPossible(codec_settings_)) { | |
| 318 if (IsForcedFallbackActive()) { | |
| 319 fallback_encoder_->Release(); | |
| 320 fallback_encoder_.reset(); | |
| 321 } | |
| 322 LOG(LS_INFO) << "Disable forced_fallback_possible_ due to settings."; | |
| 323 forced_fallback_possible_ = false; | |
| 324 } | |
| 325 } | |
| 326 | |
| 327 bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::Start( | |
| 328 uint32_t kbps, | |
|
brandtr
2017/08/09 09:05:02
bitrate_kbps?
åsapersson
2017/08/09 09:50:36
Done.
| |
| 329 const VideoCodec& codec) { | |
| 330 if (kbps > low_kbps || !IsValid(codec)) { | |
| 331 start_ms.reset(); | |
| 332 return false; | |
| 333 } | |
| 334 // Has bitrate been below |low_kbps| for long enough duration. | |
| 335 if (!start_ms) | |
| 336 start_ms.emplace(rtc::TimeMillis()); | |
| 337 return (rtc::TimeMillis() - *start_ms) >= min_low_ms; | |
|
sprang_webrtc
2017/08/09 08:38:07
nit: call rtc::TimeMillis() just once and reuse th
åsapersson
2017/08/09 09:50:36
Done.
| |
| 338 } | |
| 339 | |
| 179 } // namespace webrtc | 340 } // namespace webrtc |
| OLD | NEW |