| /* |
| * Copyright (c) 2026 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 "modules/video_coding/utility/reference_buffer_tracker.h" |
| |
| #include <optional> |
| |
| #include "api/units/timestamp.h" |
| #include "test/gmock.h" |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| namespace { |
| |
| using ::testing::ElementsAre; |
| using ::testing::IsEmpty; |
| |
| TEST(ReferenceBufferTrackerTest, InitializesWithCustomBufferCount) { |
| ReferenceBufferTracker tracker3(/*num_buffers=*/3); |
| EXPECT_EQ(tracker3.num_buffers(), 3); |
| for (int i = 0; i < 3; ++i) { |
| EXPECT_EQ(tracker3.GetTimestamp(i), std::nullopt); |
| } |
| |
| ReferenceBufferTracker tracker8(/*num_buffers=*/8); |
| EXPECT_EQ(tracker8.num_buffers(), 8); |
| for (int i = 0; i < 8; ++i) { |
| EXPECT_EQ(tracker8.GetTimestamp(i), std::nullopt); |
| } |
| } |
| |
| TEST(ReferenceBufferTrackerTest, UpdateAndGetTimestamp) { |
| ReferenceBufferTracker tracker(/*num_buffers=*/4); |
| |
| tracker.Update(/*buffer_id=*/1, Timestamp::Millis(100)); |
| tracker.Update(/*buffer_id=*/3, Timestamp::Millis(250)); |
| |
| EXPECT_EQ(tracker.GetTimestamp(0), std::nullopt); |
| EXPECT_EQ(tracker.GetTimestamp(1), Timestamp::Millis(100)); |
| EXPECT_EQ(tracker.GetTimestamp(2), std::nullopt); |
| EXPECT_EQ(tracker.GetTimestamp(3), Timestamp::Millis(250)); |
| |
| // Overwrite buffer 1. |
| tracker.Update(/*buffer_id=*/1, Timestamp::Millis(300)); |
| EXPECT_EQ(tracker.GetTimestamp(1), Timestamp::Millis(300)); |
| } |
| |
| TEST(ReferenceBufferTrackerTest, ResetClearsAllTimestamps) { |
| ReferenceBufferTracker tracker(/*num_buffers=*/4); |
| |
| tracker.Update(0, Timestamp::Millis(100)); |
| tracker.Update(1, Timestamp::Millis(200)); |
| tracker.Update(2, Timestamp::Millis(300)); |
| tracker.Update(3, Timestamp::Millis(400)); |
| |
| tracker.Reset(); |
| |
| for (int i = 0; i < 4; ++i) { |
| EXPECT_EQ(tracker.GetTimestamp(i), std::nullopt); |
| } |
| } |
| |
| TEST(ReferenceBufferTrackerTest, OrderByTimestampAllBuffersHaveTimestamps) { |
| ReferenceBufferTracker tracker(/*num_buffers=*/4); |
| tracker.Update(0, Timestamp::Millis(100)); |
| tracker.Update(1, Timestamp::Millis(400)); |
| tracker.Update(2, Timestamp::Millis(200)); |
| tracker.Update(3, Timestamp::Millis(300)); |
| |
| // Full set, out of order. Most recent should be first: 1 (400ms), 3 (300ms), |
| // 2 (200ms), 0 (100ms). |
| const int buffers[] = {0, 1, 2, 3}; |
| EXPECT_THAT(tracker.OrderByTimestamp(buffers), ElementsAre(1, 3, 2, 0)); |
| |
| // Subset of buffers. |
| const int subset[] = {0, 2, 3}; |
| EXPECT_THAT(tracker.OrderByTimestamp(subset), ElementsAre(3, 2, 0)); |
| |
| // Single buffer. |
| const int single[] = {2}; |
| EXPECT_THAT(tracker.OrderByTimestamp(single), ElementsAre(2)); |
| |
| // Empty list. |
| EXPECT_THAT(tracker.OrderByTimestamp({}), IsEmpty()); |
| } |
| |
| TEST(ReferenceBufferTrackerTest, OrderByTimestampWithUnsetBuffers) { |
| ReferenceBufferTracker tracker(/*num_buffers=*/5); |
| // Only buffers 0 and 2 have timestamps. |
| tracker.Update(0, Timestamp::Millis(100)); |
| tracker.Update(2, Timestamp::Millis(200)); |
| |
| // Buffers with timestamps should precede unset buffers. |
| const int buffers[] = {0, 1, 2, 3, 4}; |
| EXPECT_THAT(tracker.OrderByTimestamp(buffers), ElementsAre(2, 0, 1, 3, 4)); |
| |
| // When all requested buffers are unset, stable order is preserved. |
| const int unset_buffers[] = {4, 3, 1}; |
| EXPECT_THAT(tracker.OrderByTimestamp(unset_buffers), ElementsAre(4, 3, 1)); |
| } |
| |
| TEST(ReferenceBufferTrackerTest, |
| OrderByTimestampPreservesOrderForEqualTimestamps) { |
| ReferenceBufferTracker tracker(/*num_buffers=*/4); |
| tracker.Update(0, Timestamp::Millis(200)); |
| tracker.Update(1, Timestamp::Millis(200)); |
| tracker.Update(2, Timestamp::Millis(100)); |
| tracker.Update(3, Timestamp::Millis(200)); |
| |
| const int buffers[] = {0, 1, 2, 3}; |
| // Buffers 0, 1, 3 all have 200ms, buffer 2 has 100ms. |
| // Stable sort must preserve 0, 1, 3 relative order. |
| EXPECT_THAT(tracker.OrderByTimestamp(buffers), ElementsAre(0, 1, 3, 2)); |
| |
| const int reversed[] = {3, 1, 0, 2}; |
| EXPECT_THAT(tracker.OrderByTimestamp(reversed), ElementsAre(3, 1, 0, 2)); |
| } |
| |
| } // namespace |
| } // namespace webrtc |