/* * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "test/testsupport/fixed_fps_video_frame_writer_adapter.h" #include #include #include #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "api/video/i420_buffer.h" #include "api/video/video_frame.h" #include "rtc_base/synchronization/mutex.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/testsupport/video_frame_writer.h" #include "test/time_controller/simulated_time_controller.h" namespace webrtc { namespace test { namespace { constexpr TimeDelta kOneSecond = TimeDelta::Seconds(1); using ::testing::ElementsAre; class InMemoryVideoWriter : public VideoFrameWriter { public: ~InMemoryVideoWriter() override = default; bool WriteFrame(const webrtc::VideoFrame& frame) override { MutexLock lock(&mutex_); received_frames_.push_back(frame); return true; } void Close() override {} std::vector received_frames() const { MutexLock lock(&mutex_); return received_frames_; } private: mutable Mutex mutex_; std::vector received_frames_ RTC_GUARDED_BY(mutex_); }; VideoFrame EmptyFrameWithId(uint16_t frame_id) { return VideoFrame::Builder() .set_video_frame_buffer(I420Buffer::Create(1, 1)) .set_id(frame_id) .build(); } std::vector FrameIds(const std::vector& frames) { std::vector out; for (const VideoFrame& frame : frames) { out.push_back(frame.id()); } return out; } std::unique_ptr CreateSimulatedTimeController() { // Using an offset of 100000 to get nice fixed width and readable // timestamps in typical test scenarios. const Timestamp kSimulatedStartTime = Timestamp::Seconds(100000); return std::make_unique(kSimulatedStartTime); } TEST(FixedFpsVideoFrameWriterAdapterTest, WhenWrittenWithSameFpsVideoIsCorrect) { auto time_controller = CreateSimulatedTimeController(); int fps = 25; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer(fps, time_controller->GetClock(), std::move(inmemory_writer)); for (int i = 1; i <= 30; ++i) { video_writer.WriteFrame(EmptyFrameWithId(i)); time_controller->AdvanceTime(kOneSecond / fps); } video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT( FrameIds(received_frames), ElementsAre(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30)); } TEST(FixedFpsVideoFrameWriterAdapterTest, FrameIsRepeatedWhenThereIsAFreeze) { auto time_controller = CreateSimulatedTimeController(); int fps = 25; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer(fps, time_controller->GetClock(), std::move(inmemory_writer)); // Write 10 frames for (int i = 1; i <= 10; ++i) { video_writer.WriteFrame(EmptyFrameWithId(i)); time_controller->AdvanceTime(kOneSecond / fps); } // Freeze for 4 frames time_controller->AdvanceTime(4 * kOneSecond / fps); // Write 10 more frames for (int i = 11; i <= 20; ++i) { video_writer.WriteFrame(EmptyFrameWithId(i)); time_controller->AdvanceTime(kOneSecond / fps); } video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)); } TEST(FixedFpsVideoFrameWriterAdapterTest, NoFramesWritten) { auto time_controller = CreateSimulatedTimeController(); int fps = 25; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer(fps, time_controller->GetClock(), std::move(inmemory_writer)); time_controller->AdvanceTime(TimeDelta::Millis(100)); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); ASSERT_TRUE(received_frames.empty()); } TEST(FixedFpsVideoFrameWriterAdapterTest, FreezeInTheMiddleAndNewFrameReceivedBeforeMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(2.3 * kInterval); video_writer.WriteFrame(EmptyFrameWithId(2)); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1, 1, 2)); } TEST(FixedFpsVideoFrameWriterAdapterTest, FreezeInTheMiddleAndNewFrameReceivedAfterMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(2.5 * kInterval); video_writer.WriteFrame(EmptyFrameWithId(2)); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1, 1, 1, 2)); } TEST(FixedFpsVideoFrameWriterAdapterTest, NewFrameReceivedBeforeMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(0.3 * kInterval); video_writer.WriteFrame(EmptyFrameWithId(2)); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(2)); } TEST(FixedFpsVideoFrameWriterAdapterTest, NewFrameReceivedAfterMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(0.5 * kInterval); video_writer.WriteFrame(EmptyFrameWithId(2)); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1, 2)); } TEST(FixedFpsVideoFrameWriterAdapterTest, FreeezeAtTheEndAndDestroyBeforeMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(2.3 * kInterval); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1, 1, 1)); } TEST(FixedFpsVideoFrameWriterAdapterTest, FreeezeAtTheEndAndDestroyAfterMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(2.5 * kInterval); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1, 1, 1)); } TEST(FixedFpsVideoFrameWriterAdapterTest, DestroyBeforeMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(0.3 * kInterval); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1)); } TEST(FixedFpsVideoFrameWriterAdapterTest, DestroyAfterMiddleOfExpectedInterval) { auto time_controller = CreateSimulatedTimeController(); constexpr int kFps = 10; constexpr TimeDelta kInterval = kOneSecond / kFps; auto inmemory_writer = std::make_unique(); InMemoryVideoWriter* inmemory_writer_ref = inmemory_writer.get(); FixedFpsVideoFrameWriterAdapter video_writer( kFps, time_controller->GetClock(), std::move(inmemory_writer)); video_writer.WriteFrame(EmptyFrameWithId(1)); time_controller->AdvanceTime(0.5 * kInterval); video_writer.Close(); std::vector received_frames = inmemory_writer_ref->received_frames(); EXPECT_THAT(FrameIds(received_frames), ElementsAre(1)); } } // namespace } // namespace test } // namespace webrtc