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_;