AlignmentAdjuster: take reduced layers into account for default downscaling.

Bug: none
Change-Id: Id70f7763d2e1b11c24ad98774f1bf6a661728437
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/202257
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33038}
diff --git a/video/alignment_adjuster.cc b/video/alignment_adjuster.cc
index b08f2f1..6b1db92 100644
--- a/video/alignment_adjuster.cc
+++ b/video/alignment_adjuster.cc
@@ -66,7 +66,8 @@
 
 int AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
     const VideoEncoder::EncoderInfo& encoder_info,
-    VideoEncoderConfig* config) {
+    VideoEncoderConfig* config,
+    absl::optional<size_t> max_layers) {
   const int requested_alignment = encoder_info.requested_resolution_alignment;
   if (!encoder_info.apply_alignment_to_all_simulcast_layers) {
     return requested_alignment;
@@ -85,7 +86,11 @@
 
   if (!has_scale_resolution_down_by) {
     // Default resolution downscaling used (scale factors: 1, 2, 4, ...).
-    return requested_alignment * (1 << (config->simulcast_layers.size() - 1));
+    size_t size = config->simulcast_layers.size();
+    if (max_layers && *max_layers > 0 && *max_layers < size) {
+      size = *max_layers;
+    }
+    return requested_alignment * (1 << (size - 1));
   }
 
   // Get alignment for downscaled layers.
diff --git a/video/alignment_adjuster.h b/video/alignment_adjuster.h
index 53d7927..4b72623 100644
--- a/video/alignment_adjuster.h
+++ b/video/alignment_adjuster.h
@@ -28,9 +28,13 @@
   // |scale_resolution_down_by| may be adjusted to a common multiple to limit
   // the alignment value to avoid largely cropped frames and possibly with an
   // aspect ratio far from the original.
+
+  // Note: |max_layers| currently only taken into account when using default
+  // scale factors.
   static int GetAlignmentAndMaybeAdjustScaleFactors(
       const VideoEncoder::EncoderInfo& info,
-      VideoEncoderConfig* config);
+      VideoEncoderConfig* config,
+      absl::optional<size_t> max_layers);
 };
 
 }  // namespace webrtc
diff --git a/video/alignment_adjuster_unittest.cc b/video/alignment_adjuster_unittest.cc
index 07c7de5..28e4bc0 100644
--- a/video/alignment_adjuster_unittest.cc
+++ b/video/alignment_adjuster_unittest.cc
@@ -86,6 +86,30 @@
                             std::vector<double>{1.5, 2.5},
                             15))));
 
+class AlignmentAdjusterTestTwoLayers : public AlignmentAdjusterTest {
+ protected:
+  const int kMaxLayers = 2;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    ScaleFactorsAndAlignmentWithMaxLayers,
+    AlignmentAdjusterTestTwoLayers,
+    ::testing::Combine(
+        ::testing::Values(2),  // kRequestedAlignment
+        ::testing::Values(
+            std::make_tuple(std::vector<double>{-1.0},  // kScaleFactors
+                            std::vector<double>{-1.0},  // kAdjustedScaleFactors
+                            2),  // default: {1.0}      // kAdjustedAlignment
+            std::make_tuple(std::vector<double>{-1.0, -1.0},
+                            std::vector<double>{-1.0, -1.0},
+                            4),  // default: {1.0, 2.0}
+            std::make_tuple(std::vector<double>{-1.0, -1.0, -1.0},
+                            std::vector<double>{-1.0, -1.0, -1.0},
+                            4),  // default: {1.0, 2.0, 4.0}
+            std::make_tuple(std::vector<double>{1.0, 2.0, 4.0},
+                            std::vector<double>{1.0, 2.0, 4.0},
+                            8))));
+
 TEST_P(AlignmentAdjusterTest, AlignmentAppliedToAllLayers) {
   const bool kApplyAlignmentToAllLayers = true;
 
@@ -100,8 +124,8 @@
   // Verify requested alignment from sink.
   VideoEncoder::EncoderInfo info =
       GetEncoderInfo(kRequestedAlignment, kApplyAlignmentToAllLayers);
-  int alignment =
-      AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(info, &config);
+  int alignment = AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
+      info, &config, absl::nullopt);
   EXPECT_EQ(alignment, kAdjustedAlignment);
 
   // Verify adjusted scale factors.
@@ -125,8 +149,8 @@
   // Verify requested alignment from sink, alignment is not adjusted.
   VideoEncoder::EncoderInfo info =
       GetEncoderInfo(kRequestedAlignment, kApplyAlignmentToAllLayers);
-  int alignment =
-      AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(info, &config);
+  int alignment = AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
+      info, &config, absl::nullopt);
   EXPECT_EQ(alignment, kRequestedAlignment);
 
   // Verify that scale factors are not adjusted.
@@ -136,5 +160,30 @@
   }
 }
 
+TEST_P(AlignmentAdjusterTestTwoLayers, AlignmentAppliedToAllLayers) {
+  const bool kApplyAlignmentToAllLayers = true;
+
+  // Fill config with the scaling factor by which to reduce encoding size.
+  const int num_streams = kScaleFactors.size();
+  VideoEncoderConfig config;
+  test::FillEncoderConfiguration(kVideoCodecVP8, num_streams, &config);
+  for (int i = 0; i < num_streams; ++i) {
+    config.simulcast_layers[i].scale_resolution_down_by = kScaleFactors[i];
+  }
+
+  // Verify requested alignment from sink, alignment is not adjusted.
+  VideoEncoder::EncoderInfo info =
+      GetEncoderInfo(kRequestedAlignment, kApplyAlignmentToAllLayers);
+  int alignment = AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
+      info, &config, absl::optional<size_t>(kMaxLayers));
+  EXPECT_EQ(alignment, kAdjustedAlignment);
+
+  // Verify adjusted scale factors.
+  for (int i = 0; i < num_streams; ++i) {
+    EXPECT_EQ(config.simulcast_layers[i].scale_resolution_down_by,
+              kAdjustedScaleFactors[i]);
+  }
+}
+
 }  // namespace test
 }  // namespace webrtc
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index 1cfb280..3d87379 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -726,13 +726,17 @@
 
   // Possibly adjusts scale_resolution_down_by in |encoder_config_| to limit the
   // alignment value.
-  int alignment = AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
-      encoder_->GetEncoderInfo(), &encoder_config_);
+  AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
+      encoder_->GetEncoderInfo(), &encoder_config_, absl::nullopt);
 
   std::vector<VideoStream> streams =
       encoder_config_.video_stream_factory->CreateEncoderStreams(
           last_frame_info_->width, last_frame_info_->height, encoder_config_);
 
+  // Get alignment when actual number of layers are known.
+  int alignment = AlignmentAdjuster::GetAlignmentAndMaybeAdjustScaleFactors(
+      encoder_->GetEncoderInfo(), &encoder_config_, streams.size());
+
   // Check that the higher layers do not try to set number of temporal layers
   // to less than 1.
   // TODO(brandtr): Get rid of the wrapping optional as it serves no purpose