Avoids initial kFrameDropped burst for WGC

Bug: chromium:1412584
Change-Id: I6bfdcec98dfae0f99bfce51ace15795a044eb7d5
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/295504
Commit-Queue: Henrik Andreassson <henrika@webrtc.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#39435}
diff --git a/modules/desktop_capture/win/wgc_capture_session.cc b/modules/desktop_capture/win/wgc_capture_session.cc
index f6d4c91..fa6cf26 100644
--- a/modules/desktop_capture/win/wgc_capture_session.cc
+++ b/modules/desktop_capture/win/wgc_capture_session.cc
@@ -215,6 +215,12 @@
   // causing us to wait two frames when we mostly seem to only need to wait for
   // one. This approach should ensure that GetFrame() always delivers a valid
   // frame with a max latency of 200ms and often after sleeping only once.
+  // We also build up an `empty_frame_credit_count_` for each sleep call. As
+  // long as this credit is above zero, error logs for "empty frame" are
+  // avoided. The counter is reduced by one for each successful call to
+  // ProcessFrame() until the number of credits is zero. This counter is only
+  // expected to be above zero during a short startup phase. The scheme is
+  // heuristic and based on manual testing.
   // (*) On a modern system, the FPS / monitor refresh rate is usually larger
   //     than or equal to 60.
   const int max_sleep_count = 10;
@@ -223,6 +229,7 @@
   int sleep_count = 0;
   while (!queue_.current_frame() && sleep_count < max_sleep_count) {
     sleep_count++;
+    empty_frame_credit_count_ = sleep_count + 1;
     webrtc::SleepMs(sleep_time_ms);
     ProcessFrame();
   }
@@ -299,8 +306,12 @@
   }
 
   if (!capture_frame) {
-    RTC_DLOG(LS_WARNING) << "Frame pool was empty.";
-    RecordGetFrameResult(GetFrameResult::kFrameDropped);
+    // Avoid logging errors while we still have credits (or allowance) to
+    // consider this condition as expected and not as an error.
+    if (empty_frame_credit_count_ == 0) {
+      RTC_DLOG(LS_WARNING) << "Frame pool was empty => kFrameDropped.";
+      RecordGetFrameResult(GetFrameResult::kFrameDropped);
+    }
     return E_FAIL;
   }
 
@@ -422,6 +433,8 @@
 
   d3d_context->Unmap(mapped_texture_.Get(), 0);
 
+  if (empty_frame_credit_count_ > 0)
+    --empty_frame_credit_count_;
   size_ = new_size;
   RecordGetFrameResult(GetFrameResult::kSuccess);
   return hr;
diff --git a/modules/desktop_capture/win/wgc_capture_session.h b/modules/desktop_capture/win/wgc_capture_session.h
index 27298a3..a5c2944 100644
--- a/modules/desktop_capture/win/wgc_capture_session.h
+++ b/modules/desktop_capture/win/wgc_capture_session.h
@@ -130,6 +130,16 @@
   bool item_closed_ = false;
   bool is_capture_started_ = false;
 
+  // Counts number of "empty frame credits" which have built up in GetFrame()
+  // when a sequence of calls to ProcessFrame() was called with 20ms sleep calls
+  // between each. The counter is reduced by one (to a minimum of zero) when
+  // ProcessFrame() succeeds. As long as the counter is larger than zero, calls
+  // to RecordGetFrameResult(kTryGetNextFrameFailed) are disabled.
+  // The reason for adding this scheme is to prevent logs of
+  // kTryGetNextFrameFailed in the startup phase when some empty frames is
+  // expected and should not be seen as an error.
+  int empty_frame_credit_count_ = 0;
+
   SequenceChecker sequence_checker_;
 };