Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Unified Diff: webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc

Issue 2988963002: Add support for a forced software encoder fallback. (Closed)
Patch Set: address comments Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc
diff --git a/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc b/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc
index d9d6f32935d946bae3ac3c74107dc799f94b4139..9f5dedabc0451820b3990362720c508c2d6ecf3a 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,97 @@ 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.
+ return forced_fallback_.ShouldStart(bitrate_allocation_.get_sum_kbps(),
+ codec_settings_);
+}
+
+bool VideoEncoderSoftwareFallbackWrapper::TryReleaseForcedFallbackEncoder() {
+ if (!IsForcedFallbackActive())
+ return false;
+
+ if (!forced_fallback_.ShouldStop(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::ShouldStart(
+ uint32_t bitrate_kbps,
+ const VideoCodec& codec) {
+ if (bitrate_kbps > low_kbps || !IsValid(codec)) {
+ start_ms.reset();
+ return false;
+ }
+
+ // Has bitrate been below |low_kbps| for long enough duration.
+ int64_t now_ms = rtc::TimeMillis();
+ if (!start_ms)
+ start_ms.emplace(now_ms);
+
+ if ((now_ms - *start_ms) >= min_low_ms) {
+ LOG(LS_INFO) << "Request forced SW encoder fallback.";
+ // In case the request fails, update time to avoid too frequent requests.
+ start_ms.emplace(now_ms);
+ return true;
+ }
+ return false;
+}
+
+bool VideoEncoderSoftwareFallbackWrapper::ForcedFallbackParams::ShouldStop(
+ uint32_t bitrate_kbps) const {
+ return bitrate_kbps >= high_kbps;
+}
+
} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698