mirror of
https://github.com/OpenShot/libopenshot.git
synced 2026-10-14 03:30:59 -07:00
88 lines
3.3 KiB
C++
88 lines
3.3 KiB
C++
/**
|
|
* @file
|
|
* @brief Unit tests for adaptive preview pre-roll
|
|
* @author OpenShot Studios, LLC
|
|
*
|
|
* @ref License
|
|
*/
|
|
|
|
// Copyright (c) 2026 OpenShot Studios, LLC
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
#include "openshot_catch.h"
|
|
#include "Qt/AdaptivePreroll.h"
|
|
using openshot::AdaptivePreroll;
|
|
|
|
TEST_CASE("adaptive startup uses first cheap samples", "[preroll]") {
|
|
AdaptivePreroll policy;
|
|
policy.Reset(1000);
|
|
CHECK(policy.Target(30, 1, 100, 30, 60) == 30);
|
|
CHECK_FALSE(policy.Ready(2000, 2, true, 30));
|
|
for (int i = 0; i < 3; ++i) policy.Observe(1000);
|
|
CHECK(policy.Target(30, 1, 100, 30, 60) == 2);
|
|
CHECK(policy.Ready(4000, 2, true, 2));
|
|
CHECK_FALSE(policy.Ready(5000, 0, false, 2));
|
|
CHECK(policy.Ready(6000, 1, true, 2));
|
|
}
|
|
TEST_CASE("adaptive variability increases headroom with hysteresis", "[preroll]") {
|
|
AdaptivePreroll policy;
|
|
policy.Reset(0);
|
|
for (int i = 0; i < 3; ++i) policy.Observe(1000);
|
|
CHECK(policy.Target(30, 1, 100, 30, 60) == 2);
|
|
policy.Observe(60000);
|
|
const auto peak = policy.Target(30, 1, 100, 30, 60);
|
|
CHECK(peak > 2);
|
|
policy.Observe(1000);
|
|
const auto next = policy.Target(30, 1, 100, 30, 60);
|
|
CHECK(next <= peak);
|
|
CHECK(next >= 2);
|
|
for (int i = 0; i < 30; ++i) policy.Observe(1000);
|
|
CHECK(policy.Target(30, 1, 100, 30, 60) == 2);
|
|
}
|
|
TEST_CASE("slow producer cannot wait indefinitely for optional headroom", "[preroll]") {
|
|
AdaptivePreroll policy;
|
|
policy.Reset(100);
|
|
for (int i = 0; i < 3; ++i) policy.Observe(90000);
|
|
const auto required = policy.Target(30, 1, 100, 30, 60);
|
|
CHECK(required > 2);
|
|
CHECK_FALSE(policy.Ready(499999, 1, true, required));
|
|
CHECK(policy.Ready(500100, 1, true, required));
|
|
CHECK(policy.TimedOut());
|
|
CHECK_FALSE(policy.Ready(600100, 0, true, required));
|
|
CHECK_FALSE(policy.Ready(600100, 1, false, required));
|
|
}
|
|
TEST_CASE("capacity speed boundary and discontinuity clamp adaptive target", "[preroll]") {
|
|
AdaptivePreroll policy;
|
|
policy.Reset(0);
|
|
for (int i = 0; i < 3; ++i) policy.Observe(1000);
|
|
CHECK(policy.Target(30, -3, 100, 30, 60) == 6);
|
|
CHECK(policy.Target(30, 3, 1, 30, 60) == 1);
|
|
CHECK(policy.Target(30, 3, 0, 30, 60) == 0);
|
|
CHECK(policy.Ready(1, 0, true, 0, 0));
|
|
policy.Reset(1000000);
|
|
CHECK_FALSE(policy.Ready(1000001, 2, true, 30));
|
|
CHECK(policy.Target(30, 1, 100, 30, 60) == 30);
|
|
CHECK(policy.Target(30, 1, 10000, 10000, 10000) == AdaptivePreroll::MaxProbeFrames);
|
|
CHECK(policy.Target(30, 1, 100, -1, 60) == 0);
|
|
}
|
|
|
|
TEST_CASE("fake-clock startup comparison separates latency from sustained throughput", "[preroll]") {
|
|
auto startup = [](int64_t decode_us, bool adaptive) {
|
|
AdaptivePreroll policy;
|
|
policy.Reset(0);
|
|
int64_t now = 0;
|
|
for (int64_t frames = 1; frames < 100; ++frames) {
|
|
now += decode_us;
|
|
policy.Observe(decode_us);
|
|
const auto target = policy.Target(30,1,100,30,60);
|
|
if (adaptive ? policy.Ready(now,frames-1,true,target) : frames >= 31) return now;
|
|
}
|
|
return int64_t(-1);
|
|
};
|
|
CHECK(startup(1000,false) == 31000);
|
|
CHECK(startup(1000,true) == 3000);
|
|
CHECK(startup(55000,false) == 1705000);
|
|
CHECK(startup(55000,true) <= AdaptivePreroll::StartupLimitUs + 55000);
|
|
// 55ms production still exceeds 33ms consumption after either start.
|
|
}
|