diff options
Diffstat (limited to 'third_party/libwebrtc/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc')
-rw-r--r-- | third_party/libwebrtc/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/third_party/libwebrtc/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc b/third_party/libwebrtc/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc new file mode 100644 index 0000000000..69254f5fb5 --- /dev/null +++ b/third_party/libwebrtc/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "media/engine/videoencodersoftwarefallbackwrapper.h" + +#include <utility> + +#include "media/base/h264_profile_level_id.h" +#include "media/engine/internalencoderfactory.h" +#include "modules/video_coding/include/video_error_codes.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/timeutils.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace { +const char kVp8ForceFallbackEncoderFieldTrial[] = + "WebRTC-VP8-Forced-Fallback-Encoder-v2"; + +bool EnableForcedFallback() { + return field_trial::IsEnabled(kVp8ForceFallbackEncoderFieldTrial); +} + +bool IsForcedFallbackPossible(const VideoCodec& codec_settings) { + return codec_settings.codecType == kVideoCodecVP8 && + codec_settings.numberOfSimulcastStreams <= 1 && + codec_settings.VP8().numberOfTemporalLayers == 1; +} + +void GetForcedFallbackParamsFromFieldTrialGroup(int* param_min_pixels, + int* param_max_pixels, + int minimum_max_pixels) { + RTC_DCHECK(param_min_pixels); + RTC_DCHECK(param_max_pixels); + std::string group = + webrtc::field_trial::FindFullName(kVp8ForceFallbackEncoderFieldTrial); + if (group.empty()) + return; + + int min_pixels; + int max_pixels; + int min_bps; + if (sscanf(group.c_str(), "Enabled-%d,%d,%d", &min_pixels, &max_pixels, + &min_bps) != 3) { + RTC_LOG(LS_WARNING) + << "Invalid number of forced fallback parameters provided."; + return; + } + if (min_pixels <= 0 || max_pixels < minimum_max_pixels || + max_pixels < min_pixels || min_bps <= 0) { + RTC_LOG(LS_WARNING) << "Invalid forced fallback parameter value provided."; + return; + } + *param_min_pixels = min_pixels; + *param_max_pixels = max_pixels; +} +} // namespace + +VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( + std::unique_ptr<webrtc::VideoEncoder> sw_encoder, + std::unique_ptr<webrtc::VideoEncoder> hw_encoder) + : number_of_cores_(0), + max_payload_size_(0), + rates_set_(false), + framerate_(0), + channel_parameters_set_(false), + packet_loss_(0), + rtt_(0), + use_fallback_encoder_(false), + encoder_(std::move(hw_encoder)), + fallback_encoder_(std::move(sw_encoder)), + callback_(nullptr), + forced_fallback_possible_(EnableForcedFallback()) { + if (forced_fallback_possible_) { + GetForcedFallbackParamsFromFieldTrialGroup( + &forced_fallback_.min_pixels_, &forced_fallback_.max_pixels_, + encoder_->GetScalingSettings().min_pixels_per_frame - + 1); // No HW below. + } +} + +bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { + RTC_LOG(LS_WARNING) << "Encoder falling back to software encoding."; + + const int ret = fallback_encoder_->InitEncode( + &codec_settings_, number_of_cores_, max_payload_size_); + use_fallback_encoder_ = (ret == WEBRTC_VIDEO_CODEC_OK); + if (!use_fallback_encoder_) { + RTC_LOG(LS_ERROR) << "Failed to initialize software-encoder fallback."; + fallback_encoder_->Release(); + return false; + } + // Replay callback, rates, and channel parameters. + if (callback_) + fallback_encoder_->RegisterEncodeCompleteCallback(callback_); + if (rates_set_) + fallback_encoder_->SetRateAllocation(bitrate_allocation_, framerate_); + if (channel_parameters_set_) + fallback_encoder_->SetChannelParameters(packet_loss_, rtt_); + + // Since we're switching to the fallback encoder, Release the real encoder. It + // may be re-initialized via InitEncode later, and it will continue to get + // Set calls for rates and channel parameters in the meantime. + encoder_->Release(); + return true; +} + +int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode( + const VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) { + // Store settings, in case we need to dynamically switch to the fallback + // encoder after a failed Encode call. + codec_settings_ = *codec_settings; + number_of_cores_ = number_of_cores; + max_payload_size_ = max_payload_size; + // 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; + } + // Try to init forced software codec if it should be used. + if (TryInitForcedFallbackEncoder()) { + return WEBRTC_VIDEO_CODEC_OK; + } + forced_fallback_.active_ = false; + + int32_t ret = + encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size); + if (ret == WEBRTC_VIDEO_CODEC_OK) { + if (use_fallback_encoder_) { + RTC_LOG(LS_WARNING) + << "InitEncode OK, no longer using the software fallback encoder."; + fallback_encoder_->Release(); + use_fallback_encoder_ = false; + } + if (callback_) + encoder_->RegisterEncodeCompleteCallback(callback_); + return ret; + } + // Try to instantiate software codec. + if (InitFallbackEncoder()) { + return WEBRTC_VIDEO_CODEC_OK; + } + // Software encoder failed, use original return code. + return ret; +} + +int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) { + callback_ = callback; + int32_t ret = encoder_->RegisterEncodeCompleteCallback(callback); + if (use_fallback_encoder_) + return fallback_encoder_->RegisterEncodeCompleteCallback(callback); + return ret; +} + +int32_t VideoEncoderSoftwareFallbackWrapper::Release() { + return use_fallback_encoder_ ? fallback_encoder_->Release() + : encoder_->Release(); +} + +int32_t VideoEncoderSoftwareFallbackWrapper::Encode( + const VideoFrame& frame, + const CodecSpecificInfo* codec_specific_info, + const std::vector<FrameType>* frame_types) { + if (use_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. + bool fallback_requested = (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); + if (fallback_requested && InitFallbackEncoder()) { + if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && + !fallback_encoder_->SupportsNativeHandle()) { + RTC_LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " + << "dropping one frame."; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + // Start using the fallback with this frame. + return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); + } + return ret; +} + +int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters( + uint32_t packet_loss, + int64_t rtt) { + channel_parameters_set_ = true; + packet_loss_ = packet_loss; + rtt_ = rtt; + int32_t ret = encoder_->SetChannelParameters(packet_loss, rtt); + if (use_fallback_encoder_) + return fallback_encoder_->SetChannelParameters(packet_loss, rtt); + return ret; +} + +int32_t VideoEncoderSoftwareFallbackWrapper::SetRateAllocation( + const BitrateAllocation& bitrate_allocation, + uint32_t framerate) { + rates_set_ = true; + bitrate_allocation_ = bitrate_allocation; + framerate_ = framerate; + int32_t ret = encoder_->SetRateAllocation(bitrate_allocation_, framerate); + if (use_fallback_encoder_) + return fallback_encoder_->SetRateAllocation(bitrate_allocation_, framerate); + return ret; +} + +bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const { + return use_fallback_encoder_ ? fallback_encoder_->SupportsNativeHandle() + : encoder_->SupportsNativeHandle(); +} + +VideoEncoder::ScalingSettings +VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { + if (forced_fallback_possible_) { + if (forced_fallback_.active_) { + return VideoEncoder::ScalingSettings( + codec_settings_.VP8().automaticResizeOn, + forced_fallback_.min_pixels_); + } + const auto settings = encoder_->GetScalingSettings(); + if (settings.thresholds) { + return VideoEncoder::ScalingSettings( + settings.enabled, settings.thresholds->low, settings.thresholds->high, + forced_fallback_.min_pixels_); + } + return VideoEncoder::ScalingSettings(settings.enabled, + forced_fallback_.min_pixels_); + } + return encoder_->GetScalingSettings(); +} + +const char* VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { + return use_fallback_encoder_ ? fallback_encoder_->ImplementationName() + : encoder_->ImplementationName(); +} + +bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const { + return (forced_fallback_possible_ && use_fallback_encoder_ && + forced_fallback_.active_); +} + +bool VideoEncoderSoftwareFallbackWrapper::TryInitForcedFallbackEncoder() { + if (!forced_fallback_possible_ || use_fallback_encoder_) { + return false; + } + // Fallback not active. + if (!forced_fallback_.IsValid(codec_settings_)) { + return false; + } + // Settings valid, try to instantiate software codec. + RTC_LOG(LS_INFO) << "Request forced SW encoder fallback: " + << codec_settings_.width << "x" << codec_settings_.height; + if (!InitFallbackEncoder()) { + return false; + } + forced_fallback_.active_ = true; + return true; +} + +bool VideoEncoderSoftwareFallbackWrapper::TryReInitForcedFallbackEncoder() { + if (!IsForcedFallbackActive()) { + return false; + } + // Forced fallback active. + if (!forced_fallback_.IsValid(codec_settings_)) { + RTC_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) { + RTC_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(); + use_fallback_encoder_ = false; + } + RTC_LOG(LS_INFO) << "Disable forced_fallback_possible_ due to settings."; + forced_fallback_possible_ = false; + } +} + +} // namespace webrtc |