| /* |
| * Copyright (c) 2023 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/pc/e2e/analyzer/video/dvqa/frames_storage.h" |
| |
| #include <cstdint> |
| #include <memory> |
| |
| #include "api/scoped_refptr.h" |
| #include "api/test/time_controller.h" |
| #include "api/units/time_delta.h" |
| #include "api/units/timestamp.h" |
| #include "api/video/i420_buffer.h" |
| #include "api/video/video_frame.h" |
| #include "system_wrappers/include/clock.h" |
| #include "test/gtest.h" |
| #include "test/time_controller/simulated_time_controller.h" |
| |
| namespace webrtc { |
| namespace { |
| |
| VideoFrame Create2x2Frame(uint16_t frame_id) { |
| rtc::scoped_refptr<I420Buffer> buffer = |
| I420Buffer::Create(/*width=*/2, /*height=*/2); |
| memset(buffer->MutableDataY(), static_cast<uint8_t>(frame_id), 4); |
| memset(buffer->MutableDataU(), static_cast<uint8_t>(frame_id + 1), 1); |
| memset(buffer->MutableDataV(), static_cast<uint8_t>(frame_id + 2), 1); |
| return VideoFrame::Builder() |
| .set_id(frame_id) |
| .set_video_frame_buffer(buffer) |
| .set_timestamp_us(1) |
| .build(); |
| } |
| |
| void AssertHasFrame(FramesStorage& storage, uint16_t frame_id) { |
| absl::optional<VideoFrame> frame = storage.Get(frame_id); |
| ASSERT_TRUE(frame.has_value()) << "Frame " << frame_id << " wasn't found"; |
| EXPECT_EQ(frame->id(), frame_id); |
| } |
| |
| class FramesStorageTest : public testing::Test { |
| protected: |
| FramesStorageTest() |
| : time_controller_(std::make_unique<GlobalSimulatedTimeController>( |
| Timestamp::Seconds(1000))) {} |
| |
| Timestamp NowPlusSeconds(int seconds) { |
| return time_controller_->GetClock()->CurrentTime() + |
| TimeDelta::Seconds(seconds); |
| } |
| |
| Clock* GetClock() { return time_controller_->GetClock(); } |
| |
| void AdvanceTime(TimeDelta time) { time_controller_->AdvanceTime(time); } |
| |
| private: |
| std::unique_ptr<TimeController> time_controller_; |
| }; |
| |
| TEST_F(FramesStorageTest, CanGetAllAddedFrames) { |
| VideoFrame frame1 = Create2x2Frame(/*frame_id=*/1); |
| VideoFrame frame2 = Create2x2Frame(/*frame_id=*/2); |
| VideoFrame frame3 = Create2x2Frame(/*frame_id=*/3); |
| VideoFrame frame4 = Create2x2Frame(/*frame_id=*/4); |
| VideoFrame frame5 = Create2x2Frame(/*frame_id=*/5); |
| |
| FramesStorage storage(TimeDelta::Seconds(1), GetClock()); |
| |
| storage.Add(frame1, /*captured_time=*/NowPlusSeconds(1)); |
| storage.Add(frame2, /*captured_time=*/NowPlusSeconds(2)); |
| storage.Add(frame3, /*captured_time=*/NowPlusSeconds(3)); |
| storage.Add(frame4, /*captured_time=*/NowPlusSeconds(2)); |
| storage.Add(frame5, /*captured_time=*/NowPlusSeconds(1)); |
| |
| AssertHasFrame(storage, /*frame_id=*/1); |
| AssertHasFrame(storage, /*frame_id=*/2); |
| AssertHasFrame(storage, /*frame_id=*/3); |
| AssertHasFrame(storage, /*frame_id=*/4); |
| AssertHasFrame(storage, /*frame_id=*/5); |
| } |
| |
| TEST_F(FramesStorageTest, CanGetRemainingAddedFramesAfterRemove) { |
| VideoFrame frame1 = Create2x2Frame(/*frame_id=*/1); |
| VideoFrame frame2 = Create2x2Frame(/*frame_id=*/2); |
| VideoFrame frame3 = Create2x2Frame(/*frame_id=*/3); |
| VideoFrame frame4 = Create2x2Frame(/*frame_id=*/4); |
| VideoFrame frame5 = Create2x2Frame(/*frame_id=*/5); |
| |
| FramesStorage storage(TimeDelta::Seconds(1), GetClock()); |
| |
| storage.Add(frame1, /*captured_time=*/NowPlusSeconds(1)); |
| storage.Add(frame2, /*captured_time=*/NowPlusSeconds(2)); |
| storage.Add(frame3, /*captured_time=*/NowPlusSeconds(3)); |
| storage.Add(frame4, /*captured_time=*/NowPlusSeconds(2)); |
| storage.Add(frame5, /*captured_time=*/NowPlusSeconds(1)); |
| |
| storage.Remove(frame1.id()); |
| storage.Remove(frame2.id()); |
| storage.Remove(frame3.id()); |
| |
| AssertHasFrame(storage, /*frame_id=*/4); |
| AssertHasFrame(storage, /*frame_id=*/5); |
| } |
| |
| TEST_F(FramesStorageTest, AutoCleanupRemovesOnlyOldFrames) { |
| VideoFrame frame1 = Create2x2Frame(/*frame_id=*/1); |
| VideoFrame frame2 = Create2x2Frame(/*frame_id=*/2); |
| VideoFrame frame3 = Create2x2Frame(/*frame_id=*/3); |
| VideoFrame frame4 = Create2x2Frame(/*frame_id=*/4); |
| VideoFrame frame5 = Create2x2Frame(/*frame_id=*/5); |
| VideoFrame frame6 = Create2x2Frame(/*frame_id=*/6); |
| |
| FramesStorage storage(TimeDelta::Seconds(1), GetClock()); |
| |
| storage.Add(frame1, /*captured_time=*/NowPlusSeconds(0)); |
| storage.Add(frame2, /*captured_time=*/NowPlusSeconds(1)); |
| storage.Add(frame3, /*captured_time=*/NowPlusSeconds(2)); |
| storage.Add(frame4, /*captured_time=*/NowPlusSeconds(1)); |
| storage.Add(frame5, /*captured_time=*/NowPlusSeconds(0)); |
| |
| AdvanceTime(TimeDelta::Millis(1001)); |
| storage.Add(frame6, /*captured_time=*/NowPlusSeconds(3)); |
| |
| AssertHasFrame(storage, /*frame_id=*/2); |
| AssertHasFrame(storage, /*frame_id=*/3); |
| AssertHasFrame(storage, /*frame_id=*/4); |
| EXPECT_FALSE(storage.Get(/*frame_id=*/1).has_value()); |
| EXPECT_FALSE(storage.Get(/*frame_id=*/5).has_value()); |
| } |
| |
| TEST_F(FramesStorageTest, AllFramesAutoCleaned) { |
| VideoFrame frame1 = Create2x2Frame(/*frame_id=*/1); |
| VideoFrame frame2 = Create2x2Frame(/*frame_id=*/2); |
| VideoFrame frame3 = Create2x2Frame(/*frame_id=*/3); |
| |
| FramesStorage storage(TimeDelta::Seconds(1), GetClock()); |
| |
| storage.Add(frame1, /*captured_time=*/NowPlusSeconds(0)); |
| storage.Add(frame2, /*captured_time=*/NowPlusSeconds(0)); |
| storage.Add(frame3, /*captured_time=*/NowPlusSeconds(0)); |
| |
| AdvanceTime(TimeDelta::Millis(1001)); |
| storage.Remove(/*frame_id=*/3); |
| |
| EXPECT_FALSE(storage.Get(/*frame_id=*/1).has_value()); |
| EXPECT_FALSE(storage.Get(/*frame_id=*/2).has_value()); |
| EXPECT_FALSE(storage.Get(/*frame_id=*/3).has_value()); |
| } |
| |
| } // namespace |
| } // namespace webrtc |