Add multithreaded fake encoder and corresponding FlexFEC VideoSendStreamTest.

This test would have found the issue that was fixed in
https://codereview.webrtc.org/2562983002/.

BUG=webrtc:5654

Review-Url: https://codereview.webrtc.org/2573453002
Cr-Commit-Position: refs/heads/master@{#15675}
diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc
index ae1788b..46b51b6 100644
--- a/webrtc/test/fake_encoder.cc
+++ b/webrtc/test/fake_encoder.cc
@@ -12,6 +12,7 @@
 
 #include <algorithm>
 
+#include "webrtc/base/atomicops.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/modules/video_coding/include/video_codec_interface.h"
 #include "webrtc/system_wrappers/include/sleep.h"
@@ -225,5 +226,61 @@
   SleepMs(delay_ms);
   return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
 }
+
+MultiThreadedFakeH264Encoder::MultiThreadedFakeH264Encoder(Clock* clock)
+    : test::FakeH264Encoder(clock),
+      current_queue_(0),
+      queue1_("Queue 1"),
+      queue2_("Queue 2") {}
+
+MultiThreadedFakeH264Encoder::~MultiThreadedFakeH264Encoder() = default;
+
+class MultiThreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask {
+ public:
+  EncodeTask(MultiThreadedFakeH264Encoder* encoder,
+             const VideoFrame& input_image,
+             const CodecSpecificInfo* codec_specific_info,
+             const std::vector<FrameType>* frame_types)
+      : encoder_(encoder),
+        input_image_(input_image),
+        codec_specific_info_(),
+        frame_types_(*frame_types) {
+    if (codec_specific_info)
+      codec_specific_info_ = *codec_specific_info;
+  }
+
+ private:
+  bool Run() override {
+    encoder_->EncodeCallback(input_image_, &codec_specific_info_,
+                             &frame_types_);
+    return true;
+  }
+
+  MultiThreadedFakeH264Encoder* const encoder_;
+  VideoFrame input_image_;
+  CodecSpecificInfo codec_specific_info_;
+  std::vector<FrameType> frame_types_;
+};
+
+int32_t MultiThreadedFakeH264Encoder::Encode(
+    const VideoFrame& input_image,
+    const CodecSpecificInfo* codec_specific_info,
+    const std::vector<FrameType>* frame_types) {
+  int current_queue = rtc::AtomicOps::Increment(&current_queue_);
+  rtc::TaskQueue& queue = (current_queue % 2 == 0) ? queue1_ : queue2_;
+
+  queue.PostTask(std::unique_ptr<rtc::QueuedTask>(
+      new EncodeTask(this, input_image, codec_specific_info, frame_types)));
+
+  return 0;
+}
+
+int32_t MultiThreadedFakeH264Encoder::EncodeCallback(
+    const VideoFrame& input_image,
+    const CodecSpecificInfo* codec_specific_info,
+    const std::vector<FrameType>* frame_types) {
+  return FakeH264Encoder::Encode(input_image, codec_specific_info, frame_types);
+}
+
 }  // namespace test
 }  // namespace webrtc
diff --git a/webrtc/test/fake_encoder.h b/webrtc/test/fake_encoder.h
index 57b39a4..b81a04b 100644
--- a/webrtc/test/fake_encoder.h
+++ b/webrtc/test/fake_encoder.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "webrtc/base/criticalsection.h"
+#include "webrtc/base/task_queue.h"
 #include "webrtc/common_types.h"
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/video_encoder.h"
@@ -86,6 +87,31 @@
   rtc::CriticalSection lock_;
   int delay_ms_ GUARDED_BY(&lock_);
 };
+
+// This class implements a multi-threaded fake encoder by posting
+// FakeH264Encoder::Encode(.) tasks to |queue1_| and |queue2_|, in an
+// alternating fashion.
+class MultiThreadedFakeH264Encoder : public test::FakeH264Encoder {
+ public:
+  MultiThreadedFakeH264Encoder(Clock* clock);
+  virtual ~MultiThreadedFakeH264Encoder() override;
+
+  int32_t Encode(const VideoFrame& input_image,
+                 const CodecSpecificInfo* codec_specific_info,
+                 const std::vector<FrameType>* frame_types) override;
+
+  int32_t EncodeCallback(const VideoFrame& input_image,
+                         const CodecSpecificInfo* codec_specific_info,
+                         const std::vector<FrameType>* frame_types);
+
+ protected:
+  class EncodeTask;
+
+  int current_queue_;
+  rtc::TaskQueue queue1_;
+  rtc::TaskQueue queue2_;
+};
+
 }  // namespace test
 }  // namespace webrtc
 
diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn
index 0161479..6975609 100644
--- a/webrtc/video/BUILD.gn
+++ b/webrtc/video/BUILD.gn
@@ -84,6 +84,7 @@
       "video_quality_test.h",
     ]
     deps = [
+      "../base:rtc_task_queue",
       "../media:rtc_media_base",
       "../system_wrappers",
       "//testing/gtest",
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index 7a11ae1..e0f9962 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -356,25 +356,17 @@
                  bool use_nack,
                  bool expect_red,
                  bool expect_ulpfec,
-                 const std::string& codec)
+                 const std::string& codec,
+                 VideoEncoder* encoder)
       : EndToEndTest(VideoSendStreamTest::kDefaultTimeoutMs),
+        encoder_(encoder),
         payload_name_(codec),
         use_nack_(use_nack),
         expect_red_(expect_red),
         expect_ulpfec_(expect_ulpfec),
         sent_media_(false),
         sent_ulpfec_(false),
-        header_extensions_enabled_(header_extensions_enabled) {
-    if (codec == "H264") {
-      encoder_.reset(new test::FakeH264Encoder(Clock::GetRealTimeClock()));
-    } else if (codec == "VP8") {
-      encoder_.reset(VP8Encoder::Create());
-    } else if (codec == "VP9") {
-      encoder_.reset(VP9Encoder::Create());
-    } else {
-      RTC_NOTREACHED();
-    }
-  }
+        header_extensions_enabled_(header_extensions_enabled) {}
 
  private:
   Action OnSendRtp(const uint8_t* packet, size_t length) override {
@@ -462,7 +454,7 @@
           (*receive_configs)[0].rtp.nack.rtp_history_ms =
               VideoSendStreamTest::kNackRtpHistoryMs;
     }
-    send_config->encoder_settings.encoder = encoder_.get();
+    send_config->encoder_settings.encoder = encoder_;
     send_config->encoder_settings.payload_name = payload_name_;
     send_config->rtp.ulpfec.red_payload_type =
         VideoSendStreamTest::kRedPayloadType;
@@ -486,8 +478,8 @@
   }
 
   std::unique_ptr<internal::TransportAdapter> transport_adapter_;
-  std::unique_ptr<VideoEncoder> encoder_;
-  const std::string payload_name_;
+  VideoEncoder* const encoder_;
+  std::string payload_name_;
   const bool use_nack_;
   const bool expect_red_;
   const bool expect_ulpfec_;
@@ -498,12 +490,14 @@
 };
 
 TEST_F(VideoSendStreamTest, SupportsUlpfecWithExtensions) {
-  UlpfecObserver test(true, false, true, true, "VP8");
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  UlpfecObserver test(true, false, true, true, "VP8", encoder.get());
   RunBaseTest(&test);
 }
 
 TEST_F(VideoSendStreamTest, SupportsUlpfecWithoutExtensions) {
-  UlpfecObserver test(false, false, true, true, "VP8");
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  UlpfecObserver test(false, false, true, true, "VP8", encoder.get());
   RunBaseTest(&test);
 }
 
@@ -512,51 +506,56 @@
 // bandwidth since the receiver has to wait for FEC retransmissions to determine
 // that the received state is actually decodable.
 TEST_F(VideoSendStreamTest, DoesNotUtilizeUlpfecForH264WithNackEnabled) {
-  UlpfecObserver test(false, true, true, false, "H264");
+  std::unique_ptr<VideoEncoder> encoder(
+      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
+  UlpfecObserver test(false, true, true, false, "H264", encoder.get());
   RunBaseTest(&test);
 }
 
 // Without retransmissions FEC for H264 is fine.
 TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForH264WithoutNackEnabled) {
-  UlpfecObserver test(false, false, true, true, "H264");
+  std::unique_ptr<VideoEncoder> encoder(
+      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
+  UlpfecObserver test(false, false, true, true, "H264", encoder.get());
   RunBaseTest(&test);
 }
 
 TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForVp8WithNackEnabled) {
-  UlpfecObserver test(false, true, true, true, "VP8");
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  UlpfecObserver test(false, true, true, true, "VP8", encoder.get());
   RunBaseTest(&test);
 }
 
 #if !defined(RTC_DISABLE_VP9)
 TEST_F(VideoSendStreamTest, DoesUtilizeUlpfecForVp9WithNackEnabled) {
-  UlpfecObserver test(false, true, true, true, "VP9");
+  std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
+  UlpfecObserver test(false, true, true, true, "VP9", encoder.get());
   RunBaseTest(&test);
 }
 #endif  // !defined(RTC_DISABLE_VP9)
 
+TEST_F(VideoSendStreamTest, SupportsUlpfecWithMultiThreadedH264) {
+  std::unique_ptr<VideoEncoder> encoder(
+      new test::MultiThreadedFakeH264Encoder(Clock::GetRealTimeClock()));
+  UlpfecObserver test(false, false, true, true, "H264", encoder.get());
+  RunBaseTest(&test);
+}
+
 // TODO(brandtr): Move these FlexFEC tests when we have created
 // FlexfecSendStream.
 class FlexfecObserver : public test::EndToEndTest {
  public:
   FlexfecObserver(bool header_extensions_enabled,
                   bool use_nack,
-                  const std::string& codec)
+                  const std::string& codec,
+                  VideoEncoder* encoder)
       : EndToEndTest(VideoSendStreamTest::kDefaultTimeoutMs),
+        encoder_(encoder),
         payload_name_(codec),
         use_nack_(use_nack),
         sent_media_(false),
         sent_flexfec_(false),
-        header_extensions_enabled_(header_extensions_enabled) {
-    if (codec == "H264") {
-      encoder_.reset(new test::FakeH264Encoder(Clock::GetRealTimeClock()));
-    } else if (codec == "VP8") {
-      encoder_.reset(VP8Encoder::Create());
-    } else if (codec == "VP9") {
-      encoder_.reset(VP9Encoder::Create());
-    } else {
-      RTC_NOTREACHED();
-    }
-  }
+        header_extensions_enabled_(header_extensions_enabled) {}
 
   size_t GetNumFlexfecStreams() const override { return 1; }
 
@@ -611,7 +610,7 @@
           (*receive_configs)[0].rtp.nack.rtp_history_ms =
               VideoSendStreamTest::kNackRtpHistoryMs;
     }
-    send_config->encoder_settings.encoder = encoder_.get();
+    send_config->encoder_settings.encoder = encoder_;
     send_config->encoder_settings.payload_name = payload_name_;
     if (header_extensions_enabled_) {
       send_config->rtp.extensions.push_back(RtpExtension(
@@ -630,8 +629,8 @@
   }
 
   std::unique_ptr<internal::TransportAdapter> transport_adapter_;
-  std::unique_ptr<VideoEncoder> encoder_;
-  const std::string payload_name_;
+  VideoEncoder* const encoder_;
+  std::string payload_name_;
   const bool use_nack_;
   bool sent_media_;
   bool sent_flexfec_;
@@ -639,39 +638,55 @@
 };
 
 TEST_F(VideoSendStreamTest, SupportsFlexfecVp8) {
-  FlexfecObserver test(false, false, "VP8");
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  FlexfecObserver test(false, false, "VP8", encoder.get());
   RunBaseTest(&test);
 }
 
 TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackVp8) {
-  FlexfecObserver test(false, true, "VP8");
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  FlexfecObserver test(false, true, "VP8", encoder.get());
   RunBaseTest(&test);
 }
 
 TEST_F(VideoSendStreamTest, SupportsFlexfecWithRtpExtensionsVp8) {
-  FlexfecObserver test(true, false, "VP8");
+  std::unique_ptr<VideoEncoder> encoder(VP8Encoder::Create());
+  FlexfecObserver test(true, false, "VP8", encoder.get());
   RunBaseTest(&test);
 }
 
 #if !defined(RTC_DISABLE_VP9)
 TEST_F(VideoSendStreamTest, SupportsFlexfecVp9) {
-  FlexfecObserver test(false, false, "VP9");
+  std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
+  FlexfecObserver test(false, false, "VP9", encoder.get());
   RunBaseTest(&test);
 }
 
 TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackVp9) {
-  FlexfecObserver test(false, true, "VP9");
+  std::unique_ptr<VideoEncoder> encoder(VP9Encoder::Create());
+  FlexfecObserver test(false, true, "VP9", encoder.get());
   RunBaseTest(&test);
 }
 #endif  // defined(RTC_DISABLE_VP9)
 
 TEST_F(VideoSendStreamTest, SupportsFlexfecH264) {
-  FlexfecObserver test(false, false, "H264");
+  std::unique_ptr<VideoEncoder> encoder(
+      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
+  FlexfecObserver test(false, false, "H264", encoder.get());
   RunBaseTest(&test);
 }
 
 TEST_F(VideoSendStreamTest, SupportsFlexfecWithNackH264) {
-  FlexfecObserver test(false, true, "H264");
+  std::unique_ptr<VideoEncoder> encoder(
+      new test::FakeH264Encoder(Clock::GetRealTimeClock()));
+  FlexfecObserver test(false, true, "H264", encoder.get());
+  RunBaseTest(&test);
+}
+
+TEST_F(VideoSendStreamTest, SupportsFlexfecWithMultiThreadedH264) {
+  std::unique_ptr<VideoEncoder> encoder(
+      new test::MultiThreadedFakeH264Encoder(Clock::GetRealTimeClock()));
+  FlexfecObserver test(false, false, "H264", encoder.get());
   RunBaseTest(&test);
 }