Commit 8260aa6000 for aom

commit 8260aa6000f6fba5feca7261b77be90525358310
Author: Marco Paniconi <marpan@google.com>
Date:   Thu May 28 21:42:07 2026 +0000

    rtc: Unittest for flat source chessboard artifact issue

    Bug: 382465458
    Change-Id: Ia4f4b8ec882aa7d32a97eb10ac642ce2f2fdf54d

diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc
index 2f68ba7a21..15852e461c 100644
--- a/test/svc_datarate_test.cc
+++ b/test/svc_datarate_test.cc
@@ -112,6 +112,40 @@ class ResizingVideoSource : public ::libaom_test::DummyVideoSource {
   int top_height_;
 };

+class GrayscaleFlatVideoSource : public ::libaom_test::DummyVideoSource {
+ public:
+  GrayscaleFlatVideoSource() {
+    SetSize(1280, 720);
+    SetImageFormat(AOM_IMG_FMT_I420);
+    limit_ = 1;
+  }
+
+  ~GrayscaleFlatVideoSource() override = default;
+
+  void SetValue(uint8_t val) { val_ = val; }
+
+ protected:
+  void FillFrame() override {
+    if (img_) {
+      const unsigned int y_stride = img_->stride[0];
+      const unsigned int y_height = img_->h;
+      for (unsigned int r = 0; r < y_height; ++r) {
+        memset(img_->planes[0] + r * y_stride, val_, img_->d_w);
+      }
+      const unsigned int uv_stride = img_->stride[1];
+      const unsigned int uv_height = (img_->h + 1) >> 1;
+      const unsigned int uv_width = (img_->d_w + 1) >> 1;
+      for (unsigned int r = 0; r < uv_height; ++r) {
+        memset(img_->planes[1] + r * uv_stride, 128, uv_width);
+        memset(img_->planes[2] + r * uv_stride, 128, uv_width);
+      }
+    }
+  }
+
+ private:
+  uint8_t val_ = 0;
+};
+
 class DatarateTestSVC
     : public ::libaom_test::CodecTestWith4Params<libaom_test::TestMode, int,
                                                  unsigned int, int>,
@@ -199,6 +233,10 @@ class DatarateTestSVC
                              aom_codec_pts_t pts) override {
     frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h));
     ++decoded_nframes_;
+
+    if (check_reconstruction_) {
+      CheckReconstruction(img);
+    }
   }

   std::vector<FrameInfo> frame_info_list_;
@@ -207,6 +245,7 @@ class DatarateTestSVC

   void ResetModel() override {
     DatarateTest::ResetModel();
+    abort_ = false;
     layer_frame_cnt_ = 0;
     superframe_cnt_ = 0;
     number_temporal_layers_ = 1;
@@ -248,6 +287,9 @@ class DatarateTestSVC
     dynamic_tl_ = false;
     dynamic_scale_factors_ = false;
     disable_last_ref_ = false;
+    check_reconstruction_ = false;
+    expected_val_ = 0;
+    max_allowed_error_ = 0;
   }

   void PreEncodeFrameHook(::libaom_test::VideoSource *video,
@@ -2404,6 +2446,39 @@ class DatarateTestSVC
   bool dynamic_tl_;
   bool dynamic_scale_factors_;
   bool disable_last_ref_;
+
+  void CheckReconstruction(const aom_image_t &img) {
+    const unsigned int w = img.d_w;
+    const unsigned int h = img.d_h;
+    const unsigned int stride = img.stride[0];
+    const uint8_t *y_plane = img.planes[0];
+    const unsigned int border = 256;
+    const unsigned int sb_size = 128;
+    const int bl = 16;
+    const uint8_t base_val =
+        y_plane[(border + sb_size / 2) * stride + (border + sb_size / 2)];
+
+    const int diff =
+        abs(static_cast<int>(base_val) - static_cast<int>(expected_val_));
+    EXPECT_LE(diff, max_allowed_error_);
+
+    for (unsigned int r = border; r < h - border; r += bl) {
+      for (unsigned int c = border; c < w - border; c += bl) {
+        if (y_plane[r * stride + c] != base_val) {
+          EXPECT_EQ(y_plane[r * stride + c], base_val)
+              << "Chessboard pattern detected at (" << r << ", " << c << ") "
+              << "value " << (int)y_plane[r * stride + c] << " vs base "
+              << (int)base_val;
+          abort_ = true;
+          return;
+        }
+      }
+    }
+  }
+
+  bool check_reconstruction_;
+  uint8_t expected_val_;
+  int max_allowed_error_;
 };

 // Check basic rate targeting for CBR, for 3 temporal layers, 1 spatial.
@@ -2773,6 +2848,37 @@ TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL3SLIssue433046392) {
   BasicRateTargetingSVC1TL3SLIssue433046392();
 }

+TEST_P(DatarateTestSVC, ReconstructionGrayScaleInput) {
+  if (set_cpu_used_ != 9 || aq_mode_ != 0 || GET_PARAM(4) != 0) return;
+
+  SetUpCbr();
+
+  for (int qp = 48; qp <= 63; ++qp) {
+    for (int x = 0; x <= 255; x += 10) {
+      ResetModel();
+
+      expected_val_ = static_cast<uint8_t>(x);
+      max_allowed_error_ = (qp > 60) ? 3 : (qp > 50) ? 1 : 0;
+      check_reconstruction_ = true;
+      screen_mode_ = true;
+
+      GrayscaleFlatVideoSource video;
+      video.SetValue(expected_val_);
+
+      cfg_.g_w = 1280;
+      cfg_.g_h = 720;
+      cfg_.g_profile = 0;
+      cfg_.g_lag_in_frames = 0;
+      cfg_.rc_end_usage = AOM_CBR;
+      cfg_.rc_min_quantizer = qp;
+      cfg_.rc_max_quantizer = qp;
+
+      SetTargetBitratesFor1SL1TL();
+      ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+    }
+  }
+}
+
 TEST(SvcParams, BitrateOverflow) {
   uint8_t buf[6] = { 0 };
   aom_image_t img;