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(¤t_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);
}