Adds support for frame rate control in FrameGeneratorCapturer.

Bug: webrtc:9510
Change-Id: Idb062978a856ead994fce7e72402effcd8c719cf
Reviewed-on: https://webrtc-review.googlesource.com/95148
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24499}
diff --git a/test/frame_generator_capturer.cc b/test/frame_generator_capturer.cc
index 6a58a3f..87e9bb3 100644
--- a/test/frame_generator_capturer.cc
+++ b/test/frame_generator_capturer.cc
@@ -143,7 +143,8 @@
       sink_(nullptr),
       sink_wants_observer_(nullptr),
       frame_generator_(std::move(frame_generator)),
-      target_fps_(target_fps),
+      source_fps_(target_fps),
+      target_capture_fps_(target_fps),
       first_frame_capture_time_(-1),
       task_queue_("FrameGenCapQ", rtc::TaskQueue::Priority::HIGH) {
   RTC_DCHECK(frame_generator_);
@@ -178,6 +179,12 @@
   rtc::CritScope cs(&lock_);
   if (sending_) {
     VideoFrame* frame = frame_generator_->NextFrame();
+    // TODO(srte): Use more advanced frame rate control to allow arbritrary
+    // fractions.
+    int decimation =
+        std::round(static_cast<double>(source_fps_) / target_capture_fps_);
+    for (int i = 1; i < decimation; ++i)
+      frame = frame_generator_->NextFrame();
     frame->set_timestamp_us(clock_->TimeInMicroseconds());
     frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
     frame->set_rotation(fake_rotation_);
@@ -208,6 +215,24 @@
   frame_generator_->ChangeResolution(width, height);
 }
 
+void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
+  rtc::CritScope cs(&lock_);
+  RTC_CHECK(target_capture_fps_ > 0);
+  if (target_framerate > source_fps_)
+    RTC_LOG(LS_WARNING) << "Target framerate clamped from " << target_framerate
+                        << " to " << source_fps_;
+  if (source_fps_ % target_capture_fps_ != 0) {
+    int decimation =
+        std::round(static_cast<double>(source_fps_) / target_capture_fps_);
+    int effective_rate = target_capture_fps_ / decimation;
+    RTC_LOG(LS_WARNING) << "Target framerate, " << target_framerate
+                        << ", is an uneven fraction of the source rate, "
+                        << source_fps_
+                        << ". The framerate will be :" << effective_rate;
+  }
+  target_capture_fps_ = std::min(source_fps_, target_framerate);
+}
+
 void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
   rtc::CritScope cs(&lock_);
   RTC_DCHECK(!sink_wants_observer_);
@@ -230,7 +255,7 @@
   TestVideoCapturer::AddOrUpdateSink(sink, resolution_wants);
 
   // Ignore any requests for framerate higher than initially configured.
-  if (wants.max_framerate_fps < target_fps_) {
+  if (wants.max_framerate_fps < target_capture_fps_) {
     wanted_fps_.emplace(wants.max_framerate_fps);
   } else {
     wanted_fps_.reset();
@@ -253,9 +278,9 @@
 
 int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() {
   rtc::CritScope cs(&lock_);
-  if (wanted_fps_ && *wanted_fps_ < target_fps_)
+  if (wanted_fps_ && *wanted_fps_ < target_capture_fps_)
     return *wanted_fps_;
-  return target_fps_;
+  return target_capture_fps_;
 }
 
 }  // namespace test
diff --git a/test/frame_generator_capturer.h b/test/frame_generator_capturer.h
index ac32fa4..6b2ed69 100644
--- a/test/frame_generator_capturer.h
+++ b/test/frame_generator_capturer.h
@@ -64,6 +64,7 @@
   void Start() override;
   void Stop() override;
   void ChangeResolution(size_t width, size_t height);
+  void ChangeFramerate(int target_framerate);
 
   void SetSinkWantsObserver(SinkWantsObserver* observer);
 
@@ -96,7 +97,8 @@
   rtc::CriticalSection lock_;
   std::unique_ptr<FrameGenerator> frame_generator_;
 
-  int target_fps_ RTC_GUARDED_BY(&lock_);
+  int source_fps_ RTC_GUARDED_BY(&lock_);
+  int target_capture_fps_ RTC_GUARDED_BY(&lock_);
   absl::optional<int> wanted_fps_ RTC_GUARDED_BY(&lock_);
   VideoRotation fake_rotation_ = kVideoRotation_0;