diff --git a/webrtc/modules/video_coding/video_sender_unittest.cc b/webrtc/modules/video_coding/video_sender_unittest.cc index 50e17bfe70..81eca3bc05 100644 --- a/webrtc/modules/video_coding/video_sender_unittest.cc +++ b/webrtc/modules/video_coding/video_sender_unittest.cc @@ -404,9 +404,9 @@ class TestVideoSenderWithVp8 : public TestVideoSender { const char* input_video = "foreman_cif"; const int width = 352; const int height = 288; - generator_.reset(FrameGenerator::CreateFromYuvFile( + generator_ = FrameGenerator::CreateFromYuvFile( std::vector(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 1375ba33cf..cd0bcc6d04 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 webrtc { 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(width); + height_ = static_cast(height); RTC_CHECK(width_ > 0); RTC_CHECK(height_ > 0); half_width_ = (width_ + 1) / 2; @@ -46,32 +53,67 @@ class ChromaGenerator : public FrameGenerator { 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 buffer(I420Buffer::Create( - static_cast(width_), static_cast(height_), - static_cast(width_), static_cast(half_width_), - static_cast(half_width_))); + rtc::scoped_refptr 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& 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> squares_ GUARDED_BY(&crit_); std::unique_ptr frame_ GUARDED_BY(&crit_); }; @@ -280,12 +322,13 @@ bool FrameForwarder::has_sinks() const { return sink_ != nullptr; } -FrameGenerator* FrameGenerator::CreateChromaGenerator(size_t width, - size_t height) { - return new ChromaGenerator(width, height); +std::unique_ptr FrameGenerator::CreateSquareGenerator( + int width, + int height) { + return std::unique_ptr(new SquareGenerator(width, height)); } -FrameGenerator* FrameGenerator::CreateFromYuvFile( +std::unique_ptr FrameGenerator::CreateFromYuvFile( std::vector filenames, size_t width, size_t height, @@ -298,10 +341,12 @@ FrameGenerator* FrameGenerator::CreateFromYuvFile( files.push_back(file); } - return new YuvFileGenerator(files, width, height, frame_repeat_count); + return std::unique_ptr( + new YuvFileGenerator(files, width, height, frame_repeat_count)); } -FrameGenerator* FrameGenerator::CreateScrollingInputFromYuvFiles( +std::unique_ptr +FrameGenerator::CreateScrollingInputFromYuvFiles( Clock* clock, std::vector filenames, size_t source_width, @@ -318,9 +363,9 @@ FrameGenerator* FrameGenerator::CreateScrollingInputFromYuvFiles( files.push_back(file); } - return new ScrollingImageFrameGenerator( + return std::unique_ptr(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 e2519c15d9..95b0798bf6 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 #include #include @@ -47,8 +48,7 @@ class FrameForwarder : public rtc::VideoSourceInterface { 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 @@ class FrameGenerator { 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 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 files, - size_t width, - size_t height, - int frame_repeat_count); + static std::unique_ptr CreateFromYuvFile( + std::vector 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 @@ class FrameGenerator { // 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 CreateScrollingInputFromYuvFiles( Clock* clock, std::vector filenames, size_t source_width, diff --git a/webrtc/test/frame_generator_capturer.cc b/webrtc/test/frame_generator_capturer.cc index 65be9562c5..00efbc8b40 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 @@ FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile( return capturer; } -FrameGeneratorCapturer::FrameGeneratorCapturer(Clock* clock, - FrameGenerator* frame_generator, - int target_fps) +FrameGeneratorCapturer::FrameGeneratorCapturer( + Clock* clock, + std::unique_ptr 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 3a1b6c9151..dfd12711d1 100644 --- a/webrtc/test/frame_generator_capturer.h +++ b/webrtc/test/frame_generator_capturer.h @@ -41,8 +41,8 @@ class FrameGeneratorCapturer : public VideoCapturer { 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 @@ class FrameGeneratorCapturer : public VideoCapturer { int64_t first_frame_capture_time() const { return first_frame_capture_time_; } FrameGeneratorCapturer(Clock* clock, - FrameGenerator* frame_generator, + std::unique_ptr 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 f427471193..cb7edd422f 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -229,7 +229,7 @@ TEST_P(EndToEndTest, RendersSingleDelayedFrame) { // 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 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 @@ TEST_P(EndToEndTest, TransmitsFirstFrame) { Start(); std::unique_ptr frame_generator( - test::FrameGenerator::CreateChromaGenerator(kDefaultWidth, + test::FrameGenerator::CreateSquareGenerator(kDefaultWidth, kDefaultHeight)); test::FrameForwarder frame_forwarder; video_send_stream_->SetSource( @@ -1669,11 +1669,7 @@ TEST_P(EndToEndTest, AssignsTransportSequenceNumbers) { 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::ReadBigEndian(&data[header.headerLength]); uint32_t original_ssrc = @@ -1704,7 +1700,7 @@ TEST_P(EndToEndTest, AssignsTransportSequenceNumbers) { 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 @@ TEST_P(EndToEndTest, AssignsTransportSequenceNumbers) { 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 @@ TEST_P(EndToEndTest, ObserversEncodedFrames) { Start(); std::unique_ptr 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 c227075410..8389cfcc5f 100644 --- a/webrtc/video/video_quality_test.cc +++ b/webrtc/video/video_quality_test.cc @@ -1343,9 +1343,9 @@ void VideoQualityTest::SetupScreenshareOrSVC() { 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 @@ void VideoQualityTest::SetupScreenshareOrSVC() { 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::SetupScreenshareOrSVC() { 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 @@ void VideoQualityTest::CreateCapturer() { 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(params_.video.width), + static_cast(params_.video.height), params_.video.fps, clock_)); } } else { video_capturer_.reset(test::FrameGeneratorCapturer::CreateFromYuvFile(