Ensure calls to QP convergence controller are on the same sequence
The original CL overlooked the possibility that the encoder may be
reconfigured in the middle of a stream.
Restructure the code so that all calls to QP convergence controller
happen on the encoder queue.
A side effect of this CL is that `EncodedImage::SetAtTargetQuality()`
is never called. The information is supplied to the frame cadence
adapter directly without this intermediate step.
`EncodedImage::SetAtTargetQuality()` and
`EncodedImage::IsAtTargetQuality()` are being marked as deprecated
in https://webrtc-review.googlesource.com/c/src/+/359660.
Bug: chromium:359410061
Change-Id: I941b5f60b1a9fd7694dbedf2f3e4ff5253ccf357
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/359640
Commit-Queue: Johannes Kron <kron@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Markus Handell <handellm@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42788}
diff --git a/video/quality_convergence_controller.cc b/video/quality_convergence_controller.cc
index 7a46e11..a19cb8c 100644
--- a/video/quality_convergence_controller.cc
+++ b/video/quality_convergence_controller.cc
@@ -44,6 +44,7 @@
absl::optional<int> static_qp_threshold,
VideoCodecType codec,
const FieldTrialsView& trials) {
+ RTC_DCHECK(sequence_checker_.IsCurrent());
RTC_CHECK(number_of_layers > 0);
number_of_layers_ = number_of_layers;
convergence_monitors_.clear();
@@ -61,11 +62,20 @@
int layer_index,
int qp,
bool is_refresh_frame) {
+ RTC_DCHECK(sequence_checker_.IsCurrent());
RTC_CHECK(initialized_);
if (layer_index < 0 || layer_index >= number_of_layers_) {
return false;
}
+ // TODO(kron): Remove temporary check that verifies that the initialization is
+ // working as expected. See https://crbug.com/359410061.
+ RTC_DCHECK(number_of_layers_ ==
+ static_cast<int>(convergence_monitors_.size()));
+ if (number_of_layers_ != static_cast<int>(convergence_monitors_.size())) {
+ return false;
+ }
+
convergence_monitors_[layer_index]->AddSample(qp, is_refresh_frame);
return convergence_monitors_[layer_index]->AtTargetQuality();
}
diff --git a/video/quality_convergence_controller.h b/video/quality_convergence_controller.h
index 46f8419..a09dc87 100644
--- a/video/quality_convergence_controller.h
+++ b/video/quality_convergence_controller.h
@@ -16,6 +16,7 @@
#include "absl/types/optional.h"
#include "api/field_trials_view.h"
+#include "api/sequence_checker.h"
#include "api/video/video_codec_type.h"
#include "video/quality_convergence_monitor.h"
@@ -41,6 +42,7 @@
bool initialized_ = false;
int number_of_layers_ = 0;
std::vector<std::unique_ptr<QualityConvergenceMonitor>> convergence_monitors_;
+ SequenceChecker sequence_checker_{SequenceChecker::kDetached};
};
} // namespace webrtc
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index af26db8..a9391e0 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -2090,22 +2090,11 @@
.value_or(-1);
}
- // Check if the encoded image has reached target quality.
- const size_t simulcast_index = encoded_image.SimulcastIndex().value_or(0);
- bool at_target_quality =
- quality_convergence_controller_.AddSampleAndCheckTargetQuality(
- simulcast_index, image_copy.qp_,
- image_copy.IsSteadyStateRefreshFrame());
- image_copy.SetAtTargetQuality(at_target_quality);
TRACE_EVENT2("webrtc", "VideoStreamEncoder::AugmentEncodedImage",
"stream_idx", stream_idx, "qp", image_copy.qp_);
- TRACE_EVENT_INSTANT2("webrtc", "VideoStreamEncoder::AugmentEncodedImage",
- TRACE_EVENT_SCOPE_GLOBAL, "simulcast_idx",
- simulcast_index, "at_target_quality", at_target_quality);
RTC_LOG(LS_VERBOSE) << __func__ << " ntp time " << encoded_image.NtpTimeMs()
<< " stream_idx " << stream_idx << " qp "
- << image_copy.qp_ << " at target quality "
- << at_target_quality;
+ << image_copy.qp_;
return image_copy;
}
@@ -2128,11 +2117,16 @@
unsigned int image_width = image_copy._encodedWidth;
unsigned int image_height = image_copy._encodedHeight;
encoder_queue_->PostTask([this, codec_type, image_width, image_height,
- simulcast_index,
- at_target_quality =
- image_copy.IsAtTargetQuality()] {
+ simulcast_index, qp = image_copy.qp_,
+ is_steady_state_refresh_frame =
+ image_copy.IsSteadyStateRefreshFrame()] {
RTC_DCHECK_RUN_ON(encoder_queue_.get());
+ // Check if the encoded image has reached target quality.
+ bool at_target_quality =
+ quality_convergence_controller_.AddSampleAndCheckTargetQuality(
+ simulcast_index, qp, is_steady_state_refresh_frame);
+
// Let the frame cadence adapter know about quality convergence.
if (frame_cadence_adapter_)
frame_cadence_adapter_->UpdateLayerQualityConvergence(simulcast_index,
diff --git a/video/video_stream_encoder.h b/video/video_stream_encoder.h
index 579cd32..e593f91 100644
--- a/video/video_stream_encoder.h
+++ b/video/video_stream_encoder.h
@@ -422,7 +422,8 @@
// The quality convergence controller is used to determine if a codec has
// reached its target quality. This is used for screenshare to determine when
// there's no need to continue encoding the same repeated frame.
- QualityConvergenceController quality_convergence_controller_;
+ QualityConvergenceController quality_convergence_controller_
+ RTC_GUARDED_BY(encoder_queue_);
// Enables encoder switching on initialization failures.
bool switch_encoder_on_init_failures_;