blob: def85b8e2179ca99cea2f5e18d40c75ae53c41a5 [file]
/*
* 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