Replace test::FrameGenerator::ChromaGenerator with new FrameGenerator::SquareGenerator The problem with the ChromaGenerator is that the VP8 encoder produce a too low bitrate for each frame. The squaregenerator make the VP8 encoder produce about 600kbit/s at VGA.

SquareGenerator is a FrameGenerator that draws 10 randomly sized and colored
squares. Between each new generated frame, the squares are moved slightly
towards the lower right corner.

BUG=webrtc:7192

Review-Url: https://codereview.webrtc.org/2705973002
Cr-Commit-Position: refs/heads/master@{#16870}
diff --git a/webrtc/modules/video_coding/video_sender_unittest.cc b/webrtc/modules/video_coding/video_sender_unittest.cc
index 50e17bf..81eca3b 100644
--- a/webrtc/modules/video_coding/video_sender_unittest.cc
+++ b/webrtc/modules/video_coding/video_sender_unittest.cc
@@ -404,9 +404,9 @@
     const char* input_video = "foreman_cif";
     const int width = 352;
     const int height = 288;
-    generator_.reset(FrameGenerator::CreateFromYuvFile(
+    generator_ = FrameGenerator::CreateFromYuvFile(
         std::vector<std::string>(1, test::ResourcePath(input_video, "yuv")),
-        width, height, 1));
+        width, height, 1);
 
     codec_ = MakeVp8VideoCodec(width, height, 3);
     codec_.minBitrate = 10;
diff --git a/webrtc/test/frame_generator.cc b/webrtc/test/frame_generator.cc
index 1375ba3..cd0bcc6 100644
--- a/webrtc/test/frame_generator.cc
+++ b/webrtc/test/frame_generator.cc
@@ -18,6 +18,7 @@
 #include "webrtc/api/video/i420_buffer.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/keep_ref_until_done.h"
+#include "webrtc/base/random.h"
 #include "webrtc/common_video/include/video_frame_buffer.h"
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 #include "webrtc/system_wrappers/include/clock.h"
@@ -27,16 +28,22 @@
 namespace test {
 namespace {
 
-class ChromaGenerator : public FrameGenerator {
+// SquareGenerator is a FrameGenerator that draws 10 randomly sized and colored
+// squares. Between each new generated frame, the squares are moved slightly
+// towards the lower right corner.
+class SquareGenerator : public FrameGenerator {
  public:
-  ChromaGenerator(size_t width, size_t height) : angle_(0.0) {
+  SquareGenerator(int width, int height) {
     ChangeResolution(width, height);
+    for (int i = 0; i < 10; ++i) {
+      squares_.emplace_back(new Square(width, height, i + 1));
+    }
   }
 
   void ChangeResolution(size_t width, size_t height) override {
     rtc::CritScope lock(&crit_);
-    width_ = width;
-    height_ = height;
+    width_ = static_cast<int>(width);
+    height_ = static_cast<int>(height);
     RTC_CHECK(width_ > 0);
     RTC_CHECK(height_ > 0);
     half_width_ = (width_ + 1) / 2;
@@ -46,32 +53,67 @@
 
   VideoFrame* NextFrame() override {
     rtc::CritScope lock(&crit_);
-    angle_ += 30.0;
-    uint8_t u = fabs(sin(angle_)) * 0xFF;
-    uint8_t v = fabs(cos(angle_)) * 0xFF;
 
     // Ensure stride == width.
-    rtc::scoped_refptr<I420Buffer> buffer(I420Buffer::Create(
-        static_cast<int>(width_), static_cast<int>(height_),
-        static_cast<int>(width_), static_cast<int>(half_width_),
-        static_cast<int>(half_width_)));
+    rtc::scoped_refptr<I420Buffer> buffer(
+        I420Buffer::Create(width_, height_, width_, half_width_, half_width_));
+    memset(buffer->MutableDataY(), 127, y_size_);
+    memset(buffer->MutableDataU(), 127, uv_size_);
+    memset(buffer->MutableDataV(), 127, uv_size_);
 
-    memset(buffer->MutableDataY(), 0x80, y_size_);
-    memset(buffer->MutableDataU(), u, uv_size_);
-    memset(buffer->MutableDataV(), v, uv_size_);
+    for (const auto& square : squares_)
+      square->Draw(buffer);
 
     frame_.reset(new VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0));
     return frame_.get();
   }
 
  private:
+  class Square {
+   public:
+    Square(int width, int height, int seed)
+        : random_generator_(seed),
+          x_(random_generator_.Rand(0, width)),
+          y_(random_generator_.Rand(0, height)),
+          length_(random_generator_.Rand(1, width > 4 ? width / 4 : 1)),
+          yuv_y_(random_generator_.Rand(0, 255)),
+          yuv_u_(random_generator_.Rand(0, 255)),
+          yuv_v_(random_generator_.Rand(0, 255)) {}
+
+    void Draw(const rtc::scoped_refptr<I420Buffer>& buffer) {
+      x_ = (x_ + random_generator_.Rand(0, 4)) % (buffer->width() - length_);
+      y_ = (y_ + random_generator_.Rand(0, 4)) % (buffer->height() - length_);
+      for (int x = x_; x < x_ + length_; ++x) {
+        for (int y = y_; y < y_ + length_; ++y) {
+          uint8_t* pos_y = (buffer->MutableDataY() + x + y * buffer->StrideY());
+          *pos_y = yuv_y_;
+          uint8_t* pos_u =
+              (buffer->MutableDataU() + x / 2 + y / 2 * buffer->StrideU());
+          *pos_u = yuv_u_;
+          uint8_t* pos_v =
+              (buffer->MutableDataV() + x / 2 + y / 2 * buffer->StrideV());
+          *pos_v = yuv_v_;
+        }
+      }
+    }
+
+   private:
+    Random random_generator_;
+    int x_;
+    int y_;
+    const int length_;
+    const uint8_t yuv_y_;
+    const uint8_t yuv_u_;
+    const uint8_t yuv_v_;
+  };
+
   rtc::CriticalSection crit_;
-  double angle_ GUARDED_BY(&crit_);
-  size_t width_ GUARDED_BY(&crit_);
-  size_t height_ GUARDED_BY(&crit_);
-  size_t half_width_ GUARDED_BY(&crit_);
+  int width_ GUARDED_BY(&crit_);
+  int height_ GUARDED_BY(&crit_);
+  int half_width_ GUARDED_BY(&crit_);
   size_t y_size_ GUARDED_BY(&crit_);
   size_t uv_size_ GUARDED_BY(&crit_);
+  std::vector<std::unique_ptr<Square>> squares_ GUARDED_BY(&crit_);
   std::unique_ptr<VideoFrame> frame_ GUARDED_BY(&crit_);
 };
 
@@ -280,12 +322,13 @@
   return sink_ != nullptr;
 }
 
-FrameGenerator* FrameGenerator::CreateChromaGenerator(size_t width,
-                                                      size_t height) {
-  return new ChromaGenerator(width, height);
+std::unique_ptr<FrameGenerator> FrameGenerator::CreateSquareGenerator(
+    int width,
+    int height) {
+  return std::unique_ptr<FrameGenerator>(new SquareGenerator(width, height));
 }
 
-FrameGenerator* FrameGenerator::CreateFromYuvFile(
+std::unique_ptr<FrameGenerator> FrameGenerator::CreateFromYuvFile(
     std::vector<std::string> filenames,
     size_t width,
     size_t height,
@@ -298,10 +341,12 @@
     files.push_back(file);
   }
 
-  return new YuvFileGenerator(files, width, height, frame_repeat_count);
+  return std::unique_ptr<FrameGenerator>(
+      new YuvFileGenerator(files, width, height, frame_repeat_count));
 }
 
-FrameGenerator* FrameGenerator::CreateScrollingInputFromYuvFiles(
+std::unique_ptr<FrameGenerator>
+FrameGenerator::CreateScrollingInputFromYuvFiles(
     Clock* clock,
     std::vector<std::string> filenames,
     size_t source_width,
@@ -318,9 +363,9 @@
     files.push_back(file);
   }
 
-  return new ScrollingImageFrameGenerator(
+  return std::unique_ptr<FrameGenerator>(new ScrollingImageFrameGenerator(
       clock, files, source_width, source_height, target_width, target_height,
-      scroll_time_ms, pause_time_ms);
+      scroll_time_ms, pause_time_ms));
 }
 
 }  // namespace test
diff --git a/webrtc/test/frame_generator.h b/webrtc/test/frame_generator.h
index e2519c1..95b0798 100644
--- a/webrtc/test/frame_generator.h
+++ b/webrtc/test/frame_generator.h
@@ -10,6 +10,7 @@
 #ifndef WEBRTC_TEST_FRAME_GENERATOR_H_
 #define WEBRTC_TEST_FRAME_GENERATOR_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -47,8 +48,7 @@
 
 class FrameGenerator {
  public:
-  FrameGenerator() {}
-  virtual ~FrameGenerator() {}
+  virtual ~FrameGenerator() = default;
 
   // Returns video frame that remains valid until next call.
   virtual VideoFrame* NextFrame() = 0;
@@ -58,17 +58,19 @@
     RTC_NOTREACHED();
   }
 
-  // Creates a test frame generator that creates fully saturated frames with
-  // varying U, V values over time.
-  static FrameGenerator* CreateChromaGenerator(size_t width, size_t height);
+  // Creates a frame generator that produces frames with small squares that
+  // move randomly towards the lower right corner.
+  static std::unique_ptr<FrameGenerator> CreateSquareGenerator(int width,
+                                                               int height);
 
   // Creates a frame generator that repeatedly plays a set of yuv files.
   // The frame_repeat_count determines how many times each frame is shown,
   // with 1 = show each frame once, etc.
-  static FrameGenerator* CreateFromYuvFile(std::vector<std::string> files,
-                                           size_t width,
-                                           size_t height,
-                                           int frame_repeat_count);
+  static std::unique_ptr<FrameGenerator> CreateFromYuvFile(
+      std::vector<std::string> files,
+      size_t width,
+      size_t height,
+      int frame_repeat_count);
 
   // Creates a frame generator which takes a set of yuv files (wrapping a
   // frame generator created by CreateFromYuvFile() above), but outputs frames
@@ -78,7 +80,7 @@
   // be scrolled top to bottom/left to right for scroll_tim_ms milliseconds.
   // After that the image will stay in place for pause_time_ms milliseconds,
   // and then this will be repeated with the next file from the input set.
-  static FrameGenerator* CreateScrollingInputFromYuvFiles(
+  static std::unique_ptr<FrameGenerator> CreateScrollingInputFromYuvFiles(
       Clock* clock,
       std::vector<std::string> filenames,
       size_t source_width,
diff --git a/webrtc/test/frame_generator_capturer.cc b/webrtc/test/frame_generator_capturer.cc
index 65be956..00efbc8 100644
--- a/webrtc/test/frame_generator_capturer.cc
+++ b/webrtc/test/frame_generator_capturer.cc
@@ -21,12 +21,12 @@
 namespace webrtc {
 namespace test {
 
-FrameGeneratorCapturer* FrameGeneratorCapturer::Create(size_t width,
-                                                       size_t height,
+FrameGeneratorCapturer* FrameGeneratorCapturer::Create(int width,
+                                                       int height,
                                                        int target_fps,
                                                        Clock* clock) {
   FrameGeneratorCapturer* capturer = new FrameGeneratorCapturer(
-      clock, FrameGenerator::CreateChromaGenerator(width, height), target_fps);
+      clock, FrameGenerator::CreateSquareGenerator(width, height), target_fps);
   if (!capturer->Init()) {
     delete capturer;
     return NULL;
@@ -53,19 +53,20 @@
   return capturer;
 }
 
-FrameGeneratorCapturer::FrameGeneratorCapturer(Clock* clock,
-                                               FrameGenerator* frame_generator,
-                                               int target_fps)
+FrameGeneratorCapturer::FrameGeneratorCapturer(
+    Clock* clock,
+    std::unique_ptr<FrameGenerator> frame_generator,
+    int target_fps)
     : clock_(clock),
       sending_(false),
       sink_(nullptr),
       sink_wants_observer_(nullptr),
       tick_(EventTimerWrapper::Create()),
       thread_(FrameGeneratorCapturer::Run, this, "FrameGeneratorCapturer"),
-      frame_generator_(frame_generator),
+      frame_generator_(std::move(frame_generator)),
       target_fps_(target_fps),
       first_frame_capture_time_(-1) {
-  RTC_DCHECK(frame_generator);
+  RTC_DCHECK(frame_generator_);
   RTC_DCHECK_GT(target_fps, 0);
 }
 
diff --git a/webrtc/test/frame_generator_capturer.h b/webrtc/test/frame_generator_capturer.h
index 3a1b6c9..dfd1271 100644
--- a/webrtc/test/frame_generator_capturer.h
+++ b/webrtc/test/frame_generator_capturer.h
@@ -41,8 +41,8 @@
     virtual ~SinkWantsObserver() {}
   };
 
-  static FrameGeneratorCapturer* Create(size_t width,
-                                        size_t height,
+  static FrameGeneratorCapturer* Create(int width,
+                                        int height,
                                         int target_fps,
                                         Clock* clock);
 
@@ -69,7 +69,7 @@
   int64_t first_frame_capture_time() const { return first_frame_capture_time_; }
 
   FrameGeneratorCapturer(Clock* clock,
-                         FrameGenerator* frame_generator,
+                         std::unique_ptr<FrameGenerator> frame_generator,
                          int target_fps);
   bool Init();
 
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index f427471..cb7edd4 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -229,7 +229,7 @@
   // Create frames that are smaller than the send width/height, this is done to
   // check that the callbacks are done after processing video.
   std::unique_ptr<test::FrameGenerator> frame_generator(
-      test::FrameGenerator::CreateChromaGenerator(kWidth, kHeight));
+      test::FrameGenerator::CreateSquareGenerator(kWidth, kHeight));
   test::FrameForwarder frame_forwarder;
   video_send_stream_->SetSource(
       &frame_forwarder, VideoSendStream::DegradationPreference::kBalanced);
@@ -273,7 +273,7 @@
   Start();
 
   std::unique_ptr<test::FrameGenerator> frame_generator(
-      test::FrameGenerator::CreateChromaGenerator(kDefaultWidth,
+      test::FrameGenerator::CreateSquareGenerator(kDefaultWidth,
                                                   kDefaultHeight));
   test::FrameForwarder frame_forwarder;
   video_send_stream_->SetSource(
@@ -1669,11 +1669,7 @@
             drop_packet = true;
           }
 
-          size_t payload_length =
-              length - (header.headerLength + header.paddingLength);
-          if (payload_length == 0) {
-            padding_observed_ = true;
-          } else if (header.payloadType == kSendRtxPayloadType) {
+          if (header.payloadType == kSendRtxPayloadType) {
             uint16_t original_sequence_number =
                 ByteReader<uint16_t>::ReadBigEndian(&data[header.headerLength]);
             uint32_t original_ssrc =
@@ -1704,7 +1700,7 @@
     bool IsDone() {
       bool observed_types_ok =
           streams_observed_.size() == MultiStreamTest::kNumStreams &&
-          padding_observed_ && retransmit_observed_ && rtx_padding_observed_;
+          retransmit_observed_ && rtx_padding_observed_;
       if (!observed_types_ok)
         return false;
       // We should not have any gaps in the sequence number range.
@@ -1759,9 +1755,11 @@
       send_config->rtp.extensions.push_back(RtpExtension(
           RtpExtension::kTransportSequenceNumberUri, kExtensionId));
 
-      // Force some padding to be sent.
+      // Force some padding to be sent. Note that since we do send media
+      // packets we can not guarantee that a padding only packet is sent.
+      // Instead, padding will most likely be send as an RTX packet.
       const int kPaddingBitrateBps = 50000;
-      encoder_config->max_bitrate_bps = 1000000;
+      encoder_config->max_bitrate_bps = 200000;
       encoder_config->min_transmit_bitrate_bps =
           encoder_config->max_bitrate_bps + kPaddingBitrateBps;
 
@@ -1953,7 +1951,7 @@
   Start();
 
   std::unique_ptr<test::FrameGenerator> frame_generator(
-      test::FrameGenerator::CreateChromaGenerator(kDefaultWidth,
+      test::FrameGenerator::CreateSquareGenerator(kDefaultWidth,
                                                   kDefaultHeight));
   test::FrameForwarder forwarder;
   video_send_stream_->SetSource(
diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc
index c227075..8389cfc 100644
--- a/webrtc/video/video_quality_test.cc
+++ b/webrtc/video/video_quality_test.cc
@@ -1343,9 +1343,9 @@
 
     if (params_.screenshare.scroll_duration == 0) {
       // Cycle image every slide_change_interval seconds.
-      frame_generator_.reset(test::FrameGenerator::CreateFromYuvFile(
+      frame_generator_ = test::FrameGenerator::CreateFromYuvFile(
           slides, kWidth, kHeight,
-          params_.screenshare.slide_change_interval * params_.video.fps));
+          params_.screenshare.slide_change_interval * params_.video.fps);
     } else {
       RTC_CHECK_LE(params_.video.width, kWidth);
       RTC_CHECK_LE(params_.video.height, kHeight);
@@ -1356,11 +1356,10 @@
       RTC_CHECK_LE(params_.screenshare.scroll_duration,
                    params_.screenshare.slide_change_interval);
 
-      frame_generator_.reset(
-          test::FrameGenerator::CreateScrollingInputFromYuvFiles(
-              clock_, slides, kWidth, kHeight, params_.video.width,
-              params_.video.height, params_.screenshare.scroll_duration * 1000,
-              kPauseDurationMs));
+      frame_generator_ = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
+          clock_, slides, kWidth, kHeight, params_.video.width,
+          params_.video.height, params_.screenshare.scroll_duration * 1000,
+          kPauseDurationMs);
     }
   } else if (params_.ss.num_spatial_layers > 1) {  // For non-screenshare case.
     RTC_CHECK(params_.video.codec == "VP9");
@@ -1377,7 +1376,7 @@
 void VideoQualityTest::CreateCapturer() {
   if (params_.screenshare.enabled) {
     test::FrameGeneratorCapturer* frame_generator_capturer =
-        new test::FrameGeneratorCapturer(clock_, frame_generator_.release(),
+        new test::FrameGeneratorCapturer(clock_, std::move(frame_generator_),
                                          params_.video.fps);
     EXPECT_TRUE(frame_generator_capturer->Init());
     video_capturer_.reset(frame_generator_capturer);
@@ -1388,8 +1387,8 @@
       if (!video_capturer_) {
         // Failed to get actual camera, use chroma generator as backup.
         video_capturer_.reset(test::FrameGeneratorCapturer::Create(
-            params_.video.width, params_.video.height, params_.video.fps,
-            clock_));
+            static_cast<int>(params_.video.width),
+            static_cast<int>(params_.video.height), params_.video.fps, clock_));
       }
     } else {
       video_capturer_.reset(test::FrameGeneratorCapturer::CreateFromYuvFile(