Chromium Code Reviews| Index: webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc |
| diff --git a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc |
| index d9d6f32935d946bae3ac3c74107dc799f94b4139..dee2ef4174621411aa2c764dcce2a4d21826157a 100644 |
| --- a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc |
| +++ b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc |
| @@ -12,9 +12,58 @@ |
| #include "webrtc/media/engine/internalencoderfactory.h" |
| #include "webrtc/modules/video_coding/include/video_error_codes.h" |
| +#include "webrtc/rtc_base/checks.h" |
| #include "webrtc/rtc_base/logging.h" |
| +#include "webrtc/rtc_base/timeutils.h" |
| +#include "webrtc/system_wrappers/include/field_trial.h" |
| namespace webrtc { |
| +namespace { |
| +const char kVp8ForceFallbackEncoderFieldTrial[] = |
| + "WebRTC-VP8-Forced-Fallback-Encoder"; |
| + |
| +bool EnableForcedFallback(const cricket::VideoCodec& codec) { |
| + if (!webrtc::field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial)) |
| + return false; |
| + |
| + return (PayloadNameToCodecType(codec.name).value_or(kVideoCodecUnknown) == |
| + kVideoCodecVP8); |
| +} |
| + |
| +bool IsForcedFallbackPossible(const VideoCodec& codec_settings) { |
| + return codec_settings.codecType == kVideoCodecVP8 && |
| + codec_settings.numberOfSimulcastStreams <= 1 && |
| + codec_settings.VP8().numberOfTemporalLayers == 1; |
| +} |
| + |
| +void GetForcedFallbackParamsFromFieldTrialGroup(uint32_t* param_low_kbps, |
| + uint32_t* param_high_kbps, |
| + int64_t* param_min_low_ms) { |
| + RTC_DCHECK(param_low_kbps); |
| + RTC_DCHECK(param_high_kbps); |
| + RTC_DCHECK(param_min_low_ms); |
| + std::string group = |
| + webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial); |
| + if (group.empty()) |
| + return; |
| + |
| + int low_kbps; |
| + int high_kbps; |
| + int min_low_ms; |
| + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &low_kbps, &high_kbps, |
| + &min_low_ms) != 3) { |
| + LOG(LS_WARNING) << "Invalid number of forced fallback parameters provided."; |
| + return; |
| + } |
| + if (min_low_ms <= 0 || low_kbps <= 0 || high_kbps <= low_kbps) { |
| + LOG(LS_WARNING) << "Invalid forced fallback parameter value provided."; |
| + return; |
| + } |
| + *param_low_kbps = low_kbps; |
| + *param_high_kbps = high_kbps; |
| + *param_min_low_ms = min_low_ms; |
| +} |
| +} // namespace |
| VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( |
| const cricket::VideoCodec& codec, |
| @@ -28,7 +77,14 @@ VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( |
| rtt_(0), |
| codec_(codec), |
| encoder_(encoder), |
| - callback_(nullptr) {} |
| + callback_(nullptr), |
| + forced_fallback_possible_(EnableForcedFallback(codec)) { |
| + if (forced_fallback_possible_) { |
| + GetForcedFallbackParamsFromFieldTrialGroup(&forced_fallback_.low_kbps, |
| + &forced_fallback_.high_kbps, |
| + &forced_fallback_.min_low_ms); |
| + } |
| +} |
| bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { |
| cricket::InternalEncoderFactory internal_factory; |
| @@ -76,6 +132,13 @@ int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode( |
| // Clear stored rate/channel parameters. |
| rates_set_ = false; |
| channel_parameters_set_ = false; |
| + ValidateSettingsForForcedFallback(); |
| + |
| + // Try to reinit forced software codec if it is in use. |
| + if (TryReInitForcedFallbackEncoder()) { |
| + return WEBRTC_VIDEO_CODEC_OK; |
| + } |
| + forced_fallback_.Reset(); |
| int32_t ret = |
| encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); |
| @@ -117,11 +180,26 @@ int32_t VideoEncoderSoftwareFallbackWrapper::Encode( |
| const VideoFrame& frame, |
| const CodecSpecificInfo* codec_specific_info, |
| const std::vector<FrameType>* frame_types) { |
| + if (TryReleaseForcedFallbackEncoder()) { |
| + // Frame may have been converted from kNative to kI420 during fallback. |
| + if (encoder_->SupportsNativeHandle() && |
| + frame.video_frame_buffer()->type() != VideoFrameBuffer::Type::kNative) { |
| + LOG(LS_WARNING) << "Encoder supports native frames, dropping one frame " |
| + << "to avoid possible reconfig due to format change."; |
| + return WEBRTC_VIDEO_CODEC_ERROR; |
| + } |
| + } |
| if (fallback_encoder_) |
| return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); |
| int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types); |
| // If requested, try a software fallback. |
| - if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) { |
| + bool fallback_requested = |
| + (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) || |
| + (ret == WEBRTC_VIDEO_CODEC_OK && RequestForcedFallback()); |
| + if (fallback_requested && InitFallbackEncoder()) { |
| + // Fallback was successful. |
| + if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) |
| + forced_fallback_.Reset(); // Not a forced fallback. |
| if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && |
| !fallback_encoder_->SupportsNativeHandle()) { |
| LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " |
| @@ -129,7 +207,7 @@ int32_t VideoEncoderSoftwareFallbackWrapper::Encode( |
| return WEBRTC_VIDEO_CODEC_ERROR; |
| } |
| - // Fallback was successful, so start using it with this frame. |
| + // Start using the fallback with this frame. |
| return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); |
| } |
| return ret; |
| @@ -176,4 +254,87 @@ const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { |
| return encoder_->ImplementationName(); |
| } |
| +bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const { |
| + return (forced_fallback_possible_ && fallback_encoder_ && |
| + forced_fallback_.start_ms); |
| +} |
| + |
| +bool VideoEncoderSoftwareFallbackWrapper::RequestForcedFallback() { |
| + if (!forced_fallback_possible_ || fallback_encoder_ || !rates_set_) |
| + return false; |
| + |
| + // No fallback encoder. |
| + if (forced_fallback_.Start(bitrate_allocation_.get_sum_kbps(), |
| + codec_settings_)) { |
| + LOG(LS_INFO) << "Request forced SW encoder fallback."; |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() { |
| + if (!IsForcedFallbackActive()) |
| + return false; |
| + |
| + if (!forced_fallback_.Stop(bitrate_allocation_.get_sum_kbps())) |
| + return false; |
| + |
| + // Release the forced fallback encoder. |
| + if (encoder_->InitEncode(&codec_settings_, number_of_cores_, |
| + max_payload_size_) == WEBRTC_VIDEO_CODEC_OK) { |
| + LOG(LS_INFO) << "Stop forced SW encoder fallback, max bitrate exceeded."; |
| + fallback_encoder_->Release(); |
| + fallback_encoder_.reset(); |
| + forced_fallback_.Reset(); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() { |
| + if (!IsForcedFallbackActive()) |
| + return false; |
| + |
| + // Encoder reconfigured. |
| + if (!forced_fallback_.IsValid(codec_settings_)) { |
| + LOG(LS_INFO) << "Stop forced SW encoder fallback, max pixels exceeded."; |
| + return false; |
| + } |
| + // Settings valid, reinitialize the forced fallback encoder. |
| + if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_, |
| + max_payload_size_) != |
| + WEBRTC_VIDEO_CODEC_OK) { |
| + 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(); |
| + fallback_encoder_.reset(); |
| + } |
| + LOG(LS_INFO) << "Disable forced_fallback_possible_ due to settings."; |
| + forced_fallback_possible_ = false; |
| + } |
| +} |
| + |
| +bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::Start( |
| + uint32_t kbps, |
|
brandtr
2017/08/09 09:05:02
bitrate_kbps?
åsapersson
2017/08/09 09:50:36
Done.
|
| + const VideoCodec& codec) { |
| + if (kbps > low_kbps || !IsValid(codec)) { |
| + start_ms.reset(); |
| + return false; |
| + } |
| + // Has bitrate been below |low_kbps| for long enough duration. |
| + if (!start_ms) |
| + start_ms.emplace(rtc::TimeMillis()); |
| + 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.
|
| +} |
| + |
| } // namespace webrtc |