Reland "Make SimulcastIndex() and SpatialIndex() distinct (remove fallback)."

This is a reland of commit 8ad4924936dea2bd97990b0a951df93f7526f0ff

See diff between latest Patch Set and PS1. Fixes include:
- VideoStreamEncoder's call to bitrate_adjuster_->OnEncodedFrame()
  is updated to take stream index (spatial or simulcast index) instead
  of only looking at SpatialIndex().
- Migrate test-only helpers to use Spatial/SimulcastIndex correctly.

The fixes are to migrate
some test-only helpers that we had forgot to fix that are used by
external tests.

Original change's description:
> Make SimulcastIndex() and SpatialIndex() distinct (remove fallback).
>
> This CL removes the fallback logic to return the other index when the
> one requested has not been set. This means we can remove the codec gates
> that was previously needed because SpatialIndex() had multiple meanings,
> resolving the TODOs previously added in
> https://webrtc-review.googlesource.com/c/src/+/293343.
>
> We have already migrated all known external dependencies from
> SpatialIndex() to SimulcastIndex() where necessary, unblocking this CL.
>
> PSA: https://groups.google.com/g/discuss-webrtc/c/SDAVg6xJ3gY
>
> Bug: webrtc:14884
> Change-Id: I82787505ab10be151e5f64965b270c45465d63a9
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/293740
> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
> Reviewed-by: Erik Språng <sprang@webrtc.org>
> Commit-Queue: Henrik Boström <hbos@webrtc.org>
> Reviewed-by: Philip Eliasson <philipel@webrtc.org>
> Reviewed-by: Evan Shrubsole <eshr@webrtc.org>
> Cr-Commit-Position: refs/heads/main@{#39343}

Bug: webrtc:14884
Change-Id: Ib966924efca1a040dae881599f0789a7f2ab24a2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/294284
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39358}
diff --git a/api/video/encoded_image.h b/api/video/encoded_image.h
index 5fdd2c6..9046167 100644
--- a/api/video/encoded_image.h
+++ b/api/video/encoded_image.h
@@ -91,15 +91,7 @@
 
   // Every simulcast layer (= encoding) has its own encoder and RTP stream.
   // There can be no dependencies between different simulcast layers.
-  absl::optional<int> SimulcastIndex() const {
-    // Historically, SpatialIndex() has been used as both simulcast and spatial
-    // index (one or the other depending on codec). As to not break old code
-    // which doesn't call SetSimulcastIndex(), SpatialLayer() is used when the
-    // simulcast index is missing.
-    // TODO(https://crbug.com/webrtc/14884): When old code has been updated,
-    // never return `spatial_index_` here.
-    return simulcast_index_.has_value() ? simulcast_index_ : spatial_index_;
-  }
+  absl::optional<int> SimulcastIndex() const { return simulcast_index_; }
   void SetSimulcastIndex(absl::optional<int> simulcast_index) {
     RTC_DCHECK_GE(simulcast_index.value_or(0), 0);
     RTC_DCHECK_LT(simulcast_index.value_or(0), kMaxSimulcastStreams);
@@ -109,15 +101,7 @@
   // Encoded images can have dependencies between spatial and/or temporal
   // layers, depending on the scalability mode used by the encoder. See diagrams
   // at https://w3c.github.io/webrtc-svc/#dependencydiagrams*.
-  absl::optional<int> SpatialIndex() const {
-    // Historically, SpatialIndex() has been used as both simulcast and spatial
-    // index (one or the other depending on codec). As to not break old code
-    // that still uses the SpatialIndex() getter instead of SimulcastIndex()
-    // we fall back to `simulcast_index_` if `spatial_index_` is not set.
-    // TODO(https://crbug.com/webrtc/14884): When old code has been updated,
-    // never return `simulcast_index_` here.
-    return spatial_index_.has_value() ? spatial_index_ : simulcast_index_;
-  }
+  absl::optional<int> SpatialIndex() const { return spatial_index_; }
   void SetSpatialIndex(absl::optional<int> spatial_index) {
     RTC_DCHECK_GE(spatial_index.value_or(0), 0);
     RTC_DCHECK_LT(spatial_index.value_or(0), kMaxSpatialLayers);
diff --git a/call/rtp_payload_params.cc b/call/rtp_payload_params.cc
index b692abd..18e6d91 100644
--- a/call/rtp_payload_params.cc
+++ b/call/rtp_payload_params.cc
@@ -202,15 +202,8 @@
   if (codec_specific_info) {
     PopulateRtpWithCodecSpecifics(*codec_specific_info, image.SpatialIndex(),
                                   &rtp_video_header);
-    // Currently, SimulcastIndex() could return the SpatialIndex() if not set
-    // correctly so gate on codec type.
-    // TODO(https://crbug.com/webrtc/14884): Delete this gating logic when
-    // SimulcastIndex() is guaranteed to be the stream index.
-    if (codec_specific_info->codecType != kVideoCodecVP9 &&
-        codec_specific_info->codecType != kVideoCodecAV1) {
-      rtp_video_header.simulcastIdx = image.SimulcastIndex().value_or(0);
-    }
   }
+  rtp_video_header.simulcastIdx = image.SimulcastIndex().value_or(0);
   rtp_video_header.frame_type = image._frameType;
   rtp_video_header.rotation = image.rotation_;
   rtp_video_header.content_type = image.content_type_;
diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc
index 52714a5..98739a5 100644
--- a/call/rtp_video_sender.cc
+++ b/call/rtp_video_sender.cc
@@ -571,18 +571,7 @@
     return Result(Result::ERROR_SEND_FAILED);
 
   shared_frame_id_++;
-  size_t simulcast_index = 0;
-  // Currently, SimulcastIndex() could return the SpatialIndex() if not set
-  // correctly so gate on codec type.
-  // TODO(https://crbug.com/webrtc/14884): Delete this gating logic when
-  // SimulcastIndex() is guaranteed to be the stream index.
-  if (codec_specific_info &&
-      (codec_specific_info->codecType == kVideoCodecVP8 ||
-       codec_specific_info->codecType == kVideoCodecH264 ||
-       codec_specific_info->codecType == kVideoCodecGeneric)) {
-    // Map spatial index to simulcast.
-    simulcast_index = encoded_image.SimulcastIndex().value_or(0);
-  }
+  size_t simulcast_index = encoded_image.SimulcastIndex().value_or(0);
   RTC_DCHECK_LT(simulcast_index, rtp_streams_.size());
 
   uint32_t rtp_timestamp =
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc
index 5914458..a5c9dd7 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc
@@ -347,10 +347,15 @@
   used_encoder.last_frame_id = frame_id;
   used_encoder.switched_on_at = now;
   used_encoder.switched_from_at = now;
+  // We could either have simulcast layers or spatial layers.
+  // TODO(https://crbug.com/webrtc/14891): If we want to support a mix of
+  // simulcast and SVC we'll also need to consider the case where we have both
+  // simulcast and spatial indices.
+  size_t stream_index = encoded_image.SpatialIndex().value_or(
+      encoded_image.SimulcastIndex().value_or(0));
   frame_in_flight.OnFrameEncoded(
       now, encoded_image._frameType, DataSize::Bytes(encoded_image.size()),
-      stats.target_encode_bitrate, encoded_image.SpatialIndex().value_or(0),
-      stats.qp, used_encoder);
+      stats.target_encode_bitrate, stream_index, stats.qp, used_encoder);
 
   if (options_.report_infra_metrics) {
     analyzer_stats_.on_frame_encoded_processing_time_ms.AddSample(
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc
index df34dad..fb87fd5 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.cc
@@ -88,14 +88,14 @@
                                    VideoFrameType frame_type,
                                    DataSize encoded_image_size,
                                    uint32_t target_encode_bitrate,
-                                   int spatial_layer,
+                                   int stream_index,
                                    int qp,
                                    StreamCodecInfo used_encoder) {
   encoded_time_ = time;
   frame_type_ = frame_type;
   encoded_image_size_ = encoded_image_size;
   target_encode_bitrate_ += target_encode_bitrate;
-  spatial_layers_qp_[spatial_layer].AddSample(SamplesStatsCounter::StatsSample{
+  stream_layers_qp_[stream_index].AddSample(SamplesStatsCounter::StatsSample{
       .value = static_cast<double>(qp), .time = time});
   // Update used encoder info. If simulcast/SVC is used, this method can
   // be called multiple times, in such case we should preserve the value
@@ -186,7 +186,7 @@
   stats.encoded_frame_type = frame_type_;
   stats.encoded_image_size = encoded_image_size_;
   stats.used_encoder = used_encoder_;
-  stats.spatial_layers_qp = spatial_layers_qp_;
+  stats.spatial_layers_qp = stream_layers_qp_;
 
   absl::optional<ReceiverFrameStats> receiver_stats =
       MaybeGetValue<ReceiverFrameStats>(receiver_stats_, peer);
diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h
index 52a526d0..3c5bc95 100644
--- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h
+++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_frame_in_flight.h
@@ -88,7 +88,7 @@
                       VideoFrameType frame_type,
                       DataSize encoded_image_size,
                       uint32_t target_encode_bitrate,
-                      int spatial_layer,
+                      int stream_index,
                       int qp,
                       StreamCodecInfo used_encoder);
 
@@ -155,9 +155,9 @@
   VideoFrameType frame_type_ = VideoFrameType::kEmptyFrame;
   DataSize encoded_image_size_ = DataSize::Bytes(0);
   uint32_t target_encode_bitrate_ = 0;
-  // Sender side qp values per spatial layer. In case when spatial layer is not
-  // set for `webrtc::EncodedImage`, 0 is used as default.
-  std::map<int, SamplesStatsCounter> spatial_layers_qp_;
+  // Sender side qp values per spatial or simulcast layer. If neither the
+  // spatial or simulcast index is set in `webrtc::EncodedImage`, 0 is used.
+  std::map<int, SamplesStatsCounter> stream_layers_qp_;
   // Can be not set if frame was dropped by encoder.
   absl::optional<StreamCodecInfo> used_encoder_ = absl::nullopt;
   // Map from the receiver peer's index to frame stats for that peer.
diff --git a/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc b/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc
index e814ba8..7a2b316 100644
--- a/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc
+++ b/test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.cc
@@ -279,8 +279,14 @@
 
     discard = ShouldDiscard(frame_id, encoded_image);
     if (!discard) {
-      target_encode_bitrate = bitrate_allocation_.GetSpatialLayerSum(
-          encoded_image.SpatialIndex().value_or(0));
+      // We could either have simulcast layers or spatial layers.
+      // TODO(https://crbug.com/webrtc/14891): If we want to support a mix of
+      // simulcast and SVC we'll also need to consider the case where we have
+      // both simulcast and spatial indices.
+      size_t stream_index = encoded_image.SpatialIndex().value_or(
+          encoded_image.SimulcastIndex().value_or(0));
+      target_encode_bitrate =
+          bitrate_allocation_.GetSpatialLayerSum(stream_index);
     }
     codec_name =
         std::string(CodecTypeToPayloadString(codec_settings_.codecType)) + "_" +
@@ -326,7 +332,12 @@
   if (!emulated_sfu_config)
     return false;
 
-  int cur_spatial_index = encoded_image.SpatialIndex().value_or(0);
+  // We could either have simulcast layers or spatial layers.
+  // TODO(https://crbug.com/webrtc/14891): If we want to support a mix of
+  // simulcast and SVC we'll also need to consider the case where we have both
+  // simulcast and spatial indices.
+  int cur_stream_index = encoded_image.SpatialIndex().value_or(
+      encoded_image.SimulcastIndex().value_or(0));
   int cur_temporal_index = encoded_image.TemporalIndex().value_or(0);
 
   if (emulated_sfu_config->target_temporal_index &&
@@ -338,12 +349,12 @@
       case SimulcastMode::kSimulcast:
         // In simulcast mode only encoded images with required spatial index are
         // interested, so all others have to be discarded.
-        return cur_spatial_index != *emulated_sfu_config->target_layer_index;
+        return cur_stream_index != *emulated_sfu_config->target_layer_index;
       case SimulcastMode::kSVC:
         // In SVC mode encoded images with spatial indexes that are equal or
         // less than required one are interesting, so all above have to be
         // discarded.
-        return cur_spatial_index > *emulated_sfu_config->target_layer_index;
+        return cur_stream_index > *emulated_sfu_config->target_layer_index;
       case SimulcastMode::kKSVC:
         // In KSVC mode for key frame encoded images with spatial indexes that
         // are equal or less than required one are interesting, so all above
@@ -353,8 +364,8 @@
         // all of temporal layer 0 for now.
         if (encoded_image._frameType == VideoFrameType::kVideoFrameKey ||
             cur_temporal_index == 0)
-          return cur_spatial_index > *emulated_sfu_config->target_layer_index;
-        return cur_spatial_index != *emulated_sfu_config->target_layer_index;
+          return cur_stream_index > *emulated_sfu_config->target_layer_index;
+        return cur_stream_index != *emulated_sfu_config->target_layer_index;
       case SimulcastMode::kNormal:
         RTC_DCHECK_NOTREACHED() << "Analyzing encoder is in kNormal mode, but "
                                    "target_layer_index is set";
diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc
index a64ab22..12e88ac 100644
--- a/video/send_statistics_proxy.cc
+++ b/video/send_statistics_proxy.cc
@@ -937,18 +937,7 @@
 void SendStatisticsProxy::OnSendEncodedImage(
     const EncodedImage& encoded_image,
     const CodecSpecificInfo* codec_info) {
-  // Simulcast is used for VP8, H264 and Generic.
-  // Currently, SimulcastIndex() could return the SpatialIndex() if not set
-  // correctly so gate on codec type.
-  // TODO(https://crbug.com/webrtc/14884): Delete this gating logic when
-  // SimulcastIndex() is guaranteed to be the stream index.
-  int simulcast_idx =
-      (codec_info && (codec_info->codecType == kVideoCodecVP8 ||
-                      codec_info->codecType == kVideoCodecH264 ||
-                      codec_info->codecType == kVideoCodecGeneric))
-          ? encoded_image.SimulcastIndex().value_or(0)
-          : 0;
-
+  int simulcast_idx = encoded_image.SimulcastIndex().value_or(0);
   MutexLock lock(&mutex_);
   ++stats_.frames_encoded;
   // The current encode frame rate is based on previously encoded frames.
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index a903c21..583bb8c 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -241,12 +241,7 @@
   Result OnEncodedImage(const EncodedImage& encoded_image,
                         const CodecSpecificInfo* codec_specific_info) override {
     if (codec_specific_info) {
-      int simulcast_index;
-      if (codec_specific_info->codecType == kVideoCodecVP9) {
-        simulcast_index = 0;
-      } else {
-        simulcast_index = encoded_image.SpatialIndex().value_or(0);
-      }
+      int simulcast_index = encoded_image.SimulcastIndex().value_or(0);
       RTC_DCHECK_GE(simulcast_index, 0);
       if (analyzer_) {
         analyzer_->PostEncodeOnFrame(simulcast_index,
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index 65aa076..b0666a4 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -2434,8 +2434,13 @@
   stream_resource_manager_.OnEncodeCompleted(encoded_image, time_sent_us,
                                              encode_duration_us, frame_size);
   if (bitrate_adjuster_) {
-    bitrate_adjuster_->OnEncodedFrame(
-        frame_size, encoded_image.SpatialIndex().value_or(0), temporal_index);
+    // We could either have simulcast layers or spatial layers.
+    // TODO(https://crbug.com/webrtc/14891): If we want to support a mix of
+    // simulcast and SVC we'll also need to consider the case where we have both
+    // simulcast and spatial indices.
+    int stream_index = encoded_image.SpatialIndex().value_or(
+        encoded_image.SimulcastIndex().value_or(0));
+    bitrate_adjuster_->OnEncodedFrame(frame_size, stream_index, temporal_index);
   }
 }
 
diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc
index 908c96f..c451b6f 100644
--- a/video/video_stream_encoder_unittest.cc
+++ b/video/video_stream_encoder_unittest.cc
@@ -9473,10 +9473,10 @@
   EXPECT_CALL(factory.GetMockFakeEncoder(), EncodeHook)
       .WillRepeatedly(Invoke([](EncodedImage& encoded_image,
                                 rtc::scoped_refptr<EncodedImageBuffer> buffer) {
-        // This sets spatial index 0 content to be at target quality, while
+        // This sets simulcast index 0 content to be at target quality, while
         // index 1 content is not.
         encoded_image.qp_ = kVp8SteadyStateQpThreshold +
-                            (encoded_image.SpatialIndex() == 0 ? 0 : 1);
+                            (encoded_image.SimulcastIndex() == 0 ? 0 : 1);
         CodecSpecificInfo codec_specific;
         codec_specific.codecType = kVideoCodecVP8;
         return codec_specific;