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/logging.h" | 15 #include "webrtc/rtc_base/logging.h" |
| 16 #include "webrtc/rtc_base/timeutils.h" | |
| 17 #include "webrtc/system_wrappers/include/field_trial.h" | |
| 16 | 18 |
| 17 namespace webrtc { | 19 namespace webrtc { |
| 20 namespace { | |
| 21 const char kVp8ForceFallbackEncoderFieldTrial[] = | |
| 22 "WebRTC-VP8-Forced-Fallback-Encoder"; | |
| 23 | |
| 24 bool EnableForcedFallback(const cricket::VideoCodec& codec) { | |
| 25 if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial)) | |
| 26 return false; | |
| 27 | |
| 28 return (PayloadNameToCodecType(codec.name).value_or(kVideoCodecUnknown) == | |
| 29 kVideoCodecVP8); | |
| 30 } | |
| 31 | |
| 32 void GetForcedFallbackParamsFromFieldTrialGroup( | |
| 33 VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams* params) { | |
|
brandtr
2017/08/04 11:16:23
RTC_DCHECK(params) ?
åsapersson
2017/08/08 10:40:53
Done.
| |
| 34 std::string group = | |
| 35 webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial); | |
| 36 if (group.empty()) | |
| 37 return; | |
| 38 | |
| 39 int low_kbps; | |
| 40 int high_kbps; | |
| 41 int min_low_ms; | |
| 42 if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps, | |
| 43 &min_low_ms) != 3) { | |
| 44 return; | |
|
sprang_webrtc
2017/08/07 08:59:12
Maybe log a warning if parsing fails?
åsapersson
2017/08/08 10:40:54
Done.
| |
| 45 } | |
| 46 | |
| 47 if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps) | |
| 48 return; | |
| 49 | |
| 50 params->low_kbps = low_kbps; | |
| 51 params->high_kbps = high_kbps; | |
| 52 params->min_low_ms = min_low_ms; | |
| 53 } | |
| 54 } // namespace | |
| 18 | 55 |
| 19 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( | 56 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( |
| 20 const cricket::VideoCodec& codec, | 57 const cricket::VideoCodec& codec, |
| 21 webrtc::VideoEncoder* encoder) | 58 webrtc::VideoEncoder* encoder) |
| 22 : number_of_cores_(0), | 59 : number_of_cores_(0), |
| 23 max_payload_size_(0), | 60 max_payload_size_(0), |
| 24 rates_set_(false), | 61 rates_set_(false), |
| 25 framerate_(0), | 62 framerate_(0), |
| 26 channel_parameters_set_(false), | 63 channel_parameters_set_(false), |
| 27 packet_loss_(0), | 64 packet_loss_(0), |
| 28 rtt_(0), | 65 rtt_(0), |
| 29 codec_(codec), | 66 codec_(codec), |
| 30 encoder_(encoder), | 67 encoder_(encoder), |
| 31 callback_(nullptr) {} | 68 callback_(nullptr), |
| 69 forced_fallback_enabled_(EnableForcedFallback(codec)) { | |
| 70 if (forced_fallback_enabled_) | |
|
brandtr
2017/08/04 11:16:23
I'd add {} here, to make it a bit more readable.
åsapersson
2017/08/08 10:40:53
Done.
| |
| 71 GetForcedFallbackParamsFromFieldTrialGroup(&forced_fallback_); | |
| 72 } | |
| 32 | 73 |
| 33 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { | 74 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { |
| 34 cricket::InternalEncoderFactory internal_factory; | 75 cricket::InternalEncoderFactory internal_factory; |
| 35 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) { | 76 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) { |
| 36 LOG(LS_WARNING) | 77 LOG(LS_WARNING) |
| 37 << "Encoder requesting fallback to codec not supported in software."; | 78 << "Encoder requesting fallback to codec not supported in software."; |
| 38 return false; | 79 return false; |
| 39 } | 80 } |
| 40 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_)); | 81 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_)); |
| 41 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, | 82 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 69 int32_t number_of_cores, | 110 int32_t number_of_cores, |
| 70 size_t max_payload_size) { | 111 size_t max_payload_size) { |
| 71 // Store settings, in case we need to dynamically switch to the fallback | 112 // Store settings, in case we need to dynamically switch to the fallback |
| 72 // encoder after a failed Encode call. | 113 // encoder after a failed Encode call. |
| 73 codec_settings_ = *codec_settings; | 114 codec_settings_ = *codec_settings; |
| 74 number_of_cores_ = number_of_cores; | 115 number_of_cores_ = number_of_cores; |
| 75 max_payload_size_ = max_payload_size; | 116 max_payload_size_ = max_payload_size; |
| 76 // Clear stored rate/channel parameters. | 117 // Clear stored rate/channel parameters. |
| 77 rates_set_ = false; | 118 rates_set_ = false; |
| 78 channel_parameters_set_ = false; | 119 channel_parameters_set_ = false; |
| 120 ValidateSettingsForForcedFallback(); | |
| 121 | |
| 122 if (TryReInitForcedFallbackEncoder()) { | |
| 123 return WEBRTC_VIDEO_CODEC_OK; | |
| 124 } | |
| 125 forced_fallback_.start_ms.reset(); | |
| 79 | 126 |
| 80 int32_t ret = | 127 int32_t ret = |
| 81 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); | 128 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); |
| 82 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) { | 129 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) { |
| 83 if (fallback_encoder_) | 130 if (fallback_encoder_) |
| 84 fallback_encoder_->Release(); | 131 fallback_encoder_->Release(); |
| 85 fallback_encoder_.reset(); | 132 fallback_encoder_.reset(); |
| 86 if (callback_) | 133 if (callback_) |
| 87 encoder_->RegisterEncodeCompleteCallback(callback_); | 134 encoder_->RegisterEncodeCompleteCallback(callback_); |
| 88 return ret; | 135 return ret; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 110 // need to Release() whichever one is active. | 157 // need to Release() whichever one is active. |
| 111 if (fallback_encoder_) | 158 if (fallback_encoder_) |
| 112 return fallback_encoder_->Release(); | 159 return fallback_encoder_->Release(); |
| 113 return encoder_->Release(); | 160 return encoder_->Release(); |
| 114 } | 161 } |
| 115 | 162 |
| 116 int32_t VideoEncoderSoftwareFallbackWrapper::Encode( | 163 int32_t VideoEncoderSoftwareFallbackWrapper::Encode( |
| 117 const VideoFrame& frame, | 164 const VideoFrame& frame, |
| 118 const CodecSpecificInfo* codec_specific_info, | 165 const CodecSpecificInfo* codec_specific_info, |
| 119 const std::vector<FrameType>* frame_types) { | 166 const std::vector<FrameType>* frame_types) { |
| 167 if (TryReleaseForcedFallbackEncoder() && encoder_->SupportsNativeHandle() && | |
| 168 frame.video_frame_buffer()->type() != VideoFrameBuffer::Type::kNative) { | |
| 169 LOG(LS_WARNING) << "Encoder supports native frames, dropping one frame " | |
| 170 << "to avoid possible reconfig due to format change."; | |
| 171 return WEBRTC_VIDEO_CODEC_ERROR; | |
|
sprang_webrtc
2017/08/07 08:59:12
I know this code isn't new, but I'm not entirely s
åsapersson
2017/08/08 10:40:53
Done.
| |
| 172 } | |
| 120 if (fallback_encoder_) | 173 if (fallback_encoder_) |
| 121 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); | 174 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); |
| 122 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); | 175 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); |
| 123 // If requested, try a software fallback. | 176 // If requested, try a software fallback. |
| 124 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) { | 177 if ((ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE || |
| 178 (ret == WEBRTC_VIDEO_CODEC_OK && StartForcedFallback())) && | |
|
brandtr
2017/08/04 11:16:23
These conditions are a bit complicated. Could it b
åsapersson
2017/08/08 10:40:54
Done.
| |
| 179 InitFallbackEncoder()) { | |
| 180 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) | |
| 181 forced_fallback_.start_ms.reset(); | |
| 125 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && | 182 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && |
| 126 !fallback_encoder_->SupportsNativeHandle()) { | 183 !fallback_encoder_->SupportsNativeHandle()) { |
| 127 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " | 184 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " |
| 128 << "dropping one frame."; | 185 << "dropping one frame."; |
| 129 return WEBRTC_VIDEO_CODEC_ERROR; | 186 return WEBRTC_VIDEO_CODEC_ERROR; |
| 130 } | 187 } |
| 131 | 188 |
| 132 // Fallback was successful, so start using it with this frame. | 189 // Fallback was successful, so start using it with this frame. |
| 133 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); | 190 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); |
| 134 } | 191 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { | 226 VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { |
| 170 return encoder_->GetScalingSettings(); | 227 return encoder_->GetScalingSettings(); |
| 171 } | 228 } |
| 172 | 229 |
| 173 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { | 230 const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { |
| 174 if (fallback_encoder_) | 231 if (fallback_encoder_) |
| 175 return fallback_encoder_->ImplementationName(); | 232 return fallback_encoder_->ImplementationName(); |
| 176 return encoder_->ImplementationName(); | 233 return encoder_->ImplementationName(); |
| 177 } | 234 } |
| 178 | 235 |
| 236 bool VideoEncoderSoftwareFallbackWrapper::StartForcedFallback() { | |
|
sprang_webrtc
2017/08/07 08:59:12
Maybe you can make this something liek a ShouldUse
åsapersson
2017/08/08 10:40:53
Changed the code a bit, ptal.
| |
| 237 if (!forced_fallback_enabled_ || fallback_encoder_) | |
| 238 return false; | |
| 239 | |
| 240 if (bitrate_allocation_.get_sum_kbps() > forced_fallback_.low_kbps || | |
| 241 (codec_settings_.width * codec_settings_.height > | |
| 242 forced_fallback_.max_pixels)) { | |
| 243 forced_fallback_.start_ms.reset(); | |
| 244 return false; | |
| 245 } | |
| 246 if (!forced_fallback_.start_ms) { | |
| 247 forced_fallback_.start_ms.emplace(rtc::TimeMillis()); | |
| 248 return false; | |
| 249 } | |
| 250 if ((rtc::TimeMillis() - *forced_fallback_.start_ms) >= | |
| 251 forced_fallback_.min_low_ms) { | |
| 252 LOG(LS_INFO) << "Start forced sw-encoder fallback."; | |
| 253 return true; | |
| 254 } | |
| 255 return false; | |
| 256 } | |
| 257 | |
| 258 bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() { | |
| 259 if (!forced_fallback_enabled_ || !fallback_encoder_ || | |
| 260 !forced_fallback_.start_ms) { | |
| 261 return false; | |
| 262 } | |
| 263 | |
| 264 if (bitrate_allocation_.get_sum_kbps() < forced_fallback_.high_kbps) | |
| 265 return false; | |
| 266 | |
| 267 if (encoder_->InitEncode(&codec_settings_, number_of_cores_, | |
| 268 max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) { | |
| 269 LOG(LS_INFO) << "Stop forced sw-encoder fallback, max bitrate exceeded."; | |
| 270 fallback_encoder_->Release(); | |
| 271 fallback_encoder_.reset(); | |
| 272 forced_fallback_.start_ms.reset(); | |
| 273 if (callback_) | |
| 274 encoder_->RegisterEncodeCompleteCallback(callback_); | |
| 275 return true; | |
| 276 } | |
| 277 return false; | |
| 278 } | |
| 279 | |
| 280 bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() { | |
| 281 if (!forced_fallback_enabled_ || !fallback_encoder_ || | |
| 282 !forced_fallback_.start_ms) { | |
|
brandtr
2017/08/04 11:16:23
Why do we need to check start_ms here?
åsapersson
2017/08/08 10:40:53
Checks if it is the forced fallback that is in use
| |
| 283 return false; | |
| 284 } | |
| 285 if (codec_settings_.width * codec_settings_.height > | |
| 286 forced_fallback_.max_pixels) { | |
| 287 LOG(LS_INFO) << "Stop forced sw-encoder fallback, max pixels exceeded."; | |
| 288 return false; | |
| 289 } | |
| 290 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, | |
| 291 max_payload_size_) != | |
| 292 WEBRTC_VIDEO_CODEC_OK) { | |
| 293 LOG(LS_ERROR) << "Failed to re-init forced sw-encoder fallback."; | |
| 294 fallback_encoder_->Release(); | |
| 295 fallback_encoder_.reset(); | |
| 296 return false; | |
| 297 } | |
| 298 return true; | |
| 299 } | |
| 300 | |
| 301 void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() { | |
| 302 if (!forced_fallback_enabled_) | |
| 303 return; | |
| 304 | |
| 305 bool valid = codec_settings_.codecType == kVideoCodecVP8 && | |
| 306 codec_settings_.numberOfSimulcastStreams <= 1 && | |
| 307 codec_settings_.VP8()->numberOfTemporalLayers == 1; | |
| 308 | |
| 309 if (!valid) { | |
| 310 forced_fallback_enabled_ = false; | |
| 311 LOG(LS_INFO) << "Disable forced sw-encoder fallback due to settings."; | |
| 312 if (fallback_encoder_ && forced_fallback_.start_ms) { | |
| 313 fallback_encoder_->Release(); | |
| 314 fallback_encoder_.reset(); | |
| 315 } | |
| 316 } | |
| 317 } | |
| 318 | |
| 179 } // namespace webrtc | 319 } // namespace webrtc |
| OLD | NEW |