blob: d5bbe2a4dbdfbaafe4a1605573a98c0702eaf44c [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <memory>
#include <string>
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "media/base/media_switches.h"
#include "media/capabilities/webrtc_video_stats_db.h"
#include "media/mojo/mojom/media_types.mojom.h"
#include "media/mojo/services/webrtc_video_perf_history.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::IsNull;
namespace media {
namespace {
// Aliases for readability.
constexpr bool kIsDecode = true;
constexpr bool kIsEncode = false;
constexpr bool kHardware = true;
constexpr bool kSoftware = false;
constexpr bool kIsSmooth = true;
constexpr bool kIsNotSmooth = false;
constexpr VideoCodecProfile kKnownProfile = VP9PROFILE_PROFILE0;
constexpr int32_t kPixelsHd = 1280 * 720;
constexpr int32_t kPixelsFullHd = 1920 * 1080;
constexpr int32_t kPixels4K = 3840 * 2160;
constexpr int kFramesProcessed = 1000;
constexpr int kKeyFramesProcessed = 4;
} // namespace
class FakeWebrtcVideoStatsDB : public WebrtcVideoStatsDB {
public:
FakeWebrtcVideoStatsDB() = default;
~FakeWebrtcVideoStatsDB() override = default;
// Call CompleteInitialize(...) to run `init_cb` callback.
void Initialize(base::OnceCallback<void(bool)> init_cb) override {
EXPECT_FALSE(!!pendnding_init_cb_);
pendnding_init_cb_ = std::move(init_cb);
}
// Completes fake initialization, running `init_cb` with the supplied value
// for success.
void CompleteInitialize(bool success) {
DVLOG(2) << __func__ << " running with success = " << success;
EXPECT_TRUE(!!pendnding_init_cb_);
std::move(pendnding_init_cb_).Run(success);
}
// Simple hooks to fail the next calls to AppendDecodeStats() and
// GetDecodeStats(). Will be reset to false after the call.
void set_fail_next_append(bool fail_append) {
fail_next_append_ = fail_append;
}
void set_fail_next_get(bool fail_get) { fail_next_get_ = fail_get; }
void AppendVideoStats(const VideoDescKey& key,
const VideoStats& new_stats,
AppendVideoStatsCB append_done_cb) override {
if (fail_next_append_) {
fail_next_append_ = false;
std::move(append_done_cb).Run(false);
return;
}
std::string key_str = key.Serialize();
if (entries_.find(key_str) == entries_.end()) {
entries_.emplace(std::make_pair(key_str, VideoStatsEntry{new_stats}));
} else {
VideoStatsEntry& known_entry = entries_.at(key_str);
known_entry.insert(
known_entry.begin(),
VideoStats(new_stats.frames_processed, new_stats.key_frames_processed,
new_stats.p99_processing_time_ms));
}
std::move(append_done_cb).Run(true);
}
void GetVideoStats(const VideoDescKey& key,
GetVideoStatsCB get_stats_cb) override {
if (fail_next_get_) {
fail_next_get_ = false;
std::move(get_stats_cb).Run(false, absl::nullopt);
return;
}
auto entry_it = entries_.find(key.Serialize());
if (entry_it == entries_.end()) {
std::move(get_stats_cb).Run(true, absl::nullopt);
} else {
std::move(get_stats_cb).Run(true, entry_it->second);
}
}
void GetVideoStatsCollection(
const VideoDescKey& key,
GetVideoStatsCollectionCB get_stats_cb) override {
if (fail_next_get_) {
fail_next_get_ = false;
std::move(get_stats_cb).Run(false, absl::nullopt);
return;
}
WebrtcVideoStatsDB::VideoStatsCollection collection;
std::string key_filter = key.SerializeWithoutPixels();
for (auto const& [str, video_stats_entry] : entries_) {
if (str.rfind(key_filter, 0) == 0) {
absl::optional<int> pixels = VideoDescKey::ParsePixelsFromKey(str);
if (pixels) {
collection.insert({*pixels, std::move(video_stats_entry)});
}
}
}
if (collection.empty()) {
std::move(get_stats_cb).Run(true, absl::nullopt);
} else {
std::move(get_stats_cb).Run(true, std::move(collection));
}
}
void ClearStats(base::OnceClosure clear_done_cb) override {
entries_.clear();
std::move(clear_done_cb).Run();
}
private:
bool fail_next_append_ = false;
bool fail_next_get_ = false;
std::map<std::string, VideoStatsEntry> entries_;
base::OnceCallback<void(bool)> pendnding_init_cb_;
};
class WebrtcVideoPerfHistoryTest : public testing::Test {
public:
void SetUp() override {
perf_history_ = std::make_unique<WebrtcVideoPerfHistory>(
std::make_unique<FakeWebrtcVideoStatsDB>());
}
void TearDown() override { perf_history_.reset(); }
FakeWebrtcVideoStatsDB* GetFakeDB() {
return static_cast<FakeWebrtcVideoStatsDB*>(perf_history_->db_.get());
}
void PreInitializeDB(bool success) {
// Invoke private method to start initialization. Usually invoked by first
// API call requiring DB access.
perf_history_->InitDatabase();
// Complete initialization by firing callback from our fake DB.
GetFakeDB()->CompleteInitialize(success);
}
// Tests may set this as the callback for WebrtcVideoPerfHistory::GetPerfInfo
// to check the results of the call.
MOCK_METHOD1(MockGetPerfInfoCB, void(bool is_smooth));
// Tests may set this as the callback for
// WebrtcVideoPerfHistory::SavePerfRecord to verify that the data is stored.
MOCK_METHOD0(MockSaveDoneCB, void());
// Tests should EXPECT_CALL this method prior to ClearHistory() to know that
// the operation has completed.
MOCK_METHOD0(MockOnClearedHistory, void());
MOCK_METHOD1(MockGetWebrtcVideoStatsDBCB, void(WebrtcVideoStatsDB* db));
void SavePerfRecord(mojom::WebrtcPredictionFeatures features,
mojom::WebrtcVideoStats video_stats,
bool expect_callback) {
base::OnceClosure save_done_cb = base::BindOnce(
&WebrtcVideoPerfHistoryTest::MockSaveDoneCB, base::Unretained(this));
if (expect_callback) {
EXPECT_CALL(*this, MockSaveDoneCB());
}
perf_history_->GetSaveCallback().Run(features, video_stats,
std::move(save_done_cb));
}
void SavePerfRecord(mojom::WebrtcPredictionFeatures features,
mojom::WebrtcVideoStats video_stats) {
SavePerfRecord(std::move(features), std::move(video_stats),
/*expect_callback=*/true);
}
protected:
using VideoDescKey = WebrtcVideoStatsDB::VideoDescKey;
using VideoStatsEntry = WebrtcVideoStatsDB::VideoStatsEntry;
using Features = media::mojom::WebrtcPredictionFeatures;
using VideoStats = media::mojom::WebrtcVideoStats;
float GetSmoothnessThreshold(bool is_decode) {
return WebrtcVideoPerfHistory::GetSmoothnessThreshold(is_decode);
}
float GetSmoothDecisionRatioThreshold() {
return WebrtcVideoPerfHistory::GetSmoothDecisionRatioThreshold();
}
base::test::TaskEnvironment task_environment_;
// The WebrtcVideoStatsReporter being tested.
std::unique_ptr<WebrtcVideoPerfHistory> perf_history_;
};
struct WebrtcPerfHistoryTestParams {
const bool defer_initialize;
};
// When bool param is true, tests should wait until the end to run
// GetFakeDB()->CompleteInitialize(). Otherwise run PreInitializeDB() at the
// test start.
class WebrtcVideoPerfHistoryParamTest
: public testing::WithParamInterface<WebrtcPerfHistoryTestParams>,
public WebrtcVideoPerfHistoryTest {};
TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfo) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// First add 2 records to the history. First record with HD resolution and
// second with Full HD resolution.
constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
// Add the entries.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt30Hz));
// Verify perf history returns is_smooth = true for HD at 30 and 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
/*frames_per_second=*/30,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Verify perf history returns is_smooth = true for Full HD at 30 fps and
// is_smooth = false for Full HD at 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/30,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Verify perf history optimistically returns is_smooth = true when no entry
// can be found with the given configuration.
constexpr VideoCodecProfile kUnknownProfile = VP9PROFILE_PROFILE2;
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kUnknownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
// Test to override the smoothness threshold by setting the corresponding field
// trial parameter.
TEST_P(WebrtcVideoPerfHistoryParamTest,
GetPerfInfoSmoothnessThresholdOverride) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
base::test::ScopedFeatureList scoped_feature_list;
std::unique_ptr<base::FieldTrialList> field_trial_list;
float previousSmoothnessThresholdDecode = GetSmoothnessThreshold(kIsDecode);
float previousSmoothnessThresholdEncode = GetSmoothnessThreshold(kIsEncode);
// The 99th percentile decode time must be lower than 50% of 1/fps to be
// considered smooth.
float kNewSmoothnessThresholdDecode = 0.5f;
// The 99th percentile encode time must be lower than 120% of 1/fps to be
// considered smooth.
float kNewSmoothnessThresholdEncode = 1.2f;
// Override field trial.
base::FieldTrialParams field_trial_params;
field_trial_params["smoothness_threshold_decode"] =
base::NumberToString(kNewSmoothnessThresholdDecode);
field_trial_params["smoothness_threshold_encode"] =
base::NumberToString(kNewSmoothnessThresholdEncode);
scoped_feature_list.InitAndEnableFeatureWithParameters(
media::kWebrtcMediaCapabilitiesParameters, field_trial_params);
EXPECT_NE(kNewSmoothnessThresholdDecode, previousSmoothnessThresholdDecode);
EXPECT_NE(kNewSmoothnessThresholdEncode, previousSmoothnessThresholdEncode);
EXPECT_EQ(kNewSmoothnessThresholdDecode, GetSmoothnessThreshold(kIsDecode));
EXPECT_EQ(kNewSmoothnessThresholdEncode, GetSmoothnessThreshold(kIsEncode));
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
constexpr int kFramesPerSecond = 30;
// Add a Full HD decode entry just above the new threshold.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
/*p99_processing_time_ms=*/1.01 *
kNewSmoothnessThresholdDecode * 1000.0 /
kFramesPerSecond));
// Add an HD decode entry just below the new threshold.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
/*p99_processing_time_ms=*/0.99 *
kNewSmoothnessThresholdDecode * 1000.0 /
kFramesPerSecond));
// Verify that Full HD is not smooth and HD is smooth.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
kFramesPerSecond,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
kFramesPerSecond,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Add a Full HD encdde entry just above the new threshold.
SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
/*p99_processing_time_ms=*/1.01 *
kNewSmoothnessThresholdEncode * 1000.0 /
kFramesPerSecond));
// Add an HD encode entry just below the new threshold.
SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
/*p99_processing_time_ms=*/0.99 *
kNewSmoothnessThresholdEncode * 1000.0 /
kFramesPerSecond));
// Verify that Full HD is not smooth and HD is smooth.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kSoftware),
kFramesPerSecond,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsEncode, kKnownProfile, kPixelsHd, kSoftware),
kFramesPerSecond,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
// Verify that the combined smoothness prediction is correct in the case that
// the database contains entries with mixed smoothness predicitions.
TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfoCombinedPrediction) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
// The SmoothDecisionRatioThreshold determines the minimum ratio of smooth
// entries for the combined prediction to be considered smooth.
constexpr int kNumberOfEntries = 10;
const float kSmoothDecisionRatioThreshold = GetSmoothDecisionRatioThreshold();
const int kNotSmoothEntries =
kNumberOfEntries * (1 - kSmoothDecisionRatioThreshold);
const int kSmoothEntries = kNumberOfEntries - kNotSmoothEntries;
// Add `kNotSmoothEntries` that are not smooth at 60 fps.
for (int i = 0; i < kNotSmoothEntries; ++i) {
// Add the entries.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt30Hz));
}
// Verify perf history returns is_smooth = false at 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Add `kSmoothEntries` - 1 that are smooth at 60 fps and verify that
// is_smooth = false still.
for (int i = 0; i < kSmoothEntries - 1; ++i) {
// Add the entries.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
}
// Verify perf history returns is_smooth = false at 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Add one more entry and verify that is_smooth = true now.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
// Verify perf history returns is_smooth = true at 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Add 5 more entries that are smooth at 60 fps and verify that is_smooth =
// true still.
for (int i = 0; i < 5 - 1; ++i) {
// Add the entries.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
}
// Verify perf history returns is_smooth = true at 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
// Test to override smooth decision ratio threshold by setting the corresponding
// field trial parameter.
TEST_P(WebrtcVideoPerfHistoryParamTest,
GetPerfInfoSmoothDecisionRatioThresholdOverride) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
base::test::ScopedFeatureList scoped_feature_list;
std::unique_ptr<base::FieldTrialList> field_trial_list;
// Override the smooth decision ratio threshold through the field trial.
float previousSmoothDecisionRatioThreshold =
GetSmoothDecisionRatioThreshold();
// The ratio of smooth entries must be greater than the threshold for the
// combined stats to be considered smooth.
float kNewSmoothDecisionRatioThreshold = 0.7f;
base::FieldTrialParams field_trial_params;
field_trial_params["smooth_decision_ratio_threshold"] =
base::NumberToString(kNewSmoothDecisionRatioThreshold);
scoped_feature_list.InitAndEnableFeatureWithParameters(
media::kWebrtcMediaCapabilitiesParameters, field_trial_params);
EXPECT_NE(kNewSmoothDecisionRatioThreshold,
previousSmoothDecisionRatioThreshold);
EXPECT_EQ(kNewSmoothDecisionRatioThreshold,
GetSmoothDecisionRatioThreshold());
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
constexpr int kFramesPerSecond = 60;
// Add two smooth Full HD @ 60 fps decode entries.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
// Add one not smooth Full HD @ 30 fps decode entry.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt30Hz));
// Verify that Full HD @ 60 fps is not smooth since the ratio threshold is now
// set to 0.7, but only 2/3 = 0.66 of the entries are smooth.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
kFramesPerSecond,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfoFrameRateBucketing) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// First add 2 records to the history. First record with HD resolution and
// second with Full HD resolution.
constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
constexpr float kP99ProcessingTimeMsSmoothAt20Hz = 44.0f;
// Add the entries.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt20Hz));
// Verify perf history returns is_smooth = true for HD at 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Verify perf history returns is_smooth = true for HD also at 120 fps since
// 120 fps is quantized to 60 fps due to privacy concerns.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
/*frames_per_second=*/120,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Verify perf history returns is_smooth = false for Full HD at both 20 and 30
// fps. Even though the processing time would work at 20 fps the output is
// still expected to be smooth = false since 20 fps is quantized to 30 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/20,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
/*frames_per_second=*/30,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
// Only save valid keys and stats.
TEST_P(WebrtcVideoPerfHistoryParamTest, OnlySaveValidKeysAndStats) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
constexpr float kValidP99ProcessingTimeMs = 12.0f;
// Explicitly state that no save-done callbacks are expected.
EXPECT_CALL(*this, MockSaveDoneCB()).Times(0);
// Add invalid entries and verify that there's no save done callback.
// Unknown profile.
SavePerfRecord(
Features(kIsDecode, VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN,
kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Out of bounds profile.
SavePerfRecord(Features(kIsDecode, static_cast<VideoCodecProfile>(1000),
kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Untracked codec profile.
SavePerfRecord(
Features(kIsDecode, DOLBYVISION_PROFILE5, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Invalid pixels.
SavePerfRecord(
Features(kIsDecode, kKnownProfile, /*video_pixels=*/100, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
SavePerfRecord(
Features(kIsDecode, kKnownProfile, /*video_pixels=*/1e9, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Too few frames processed.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(/*frames_processed=*/10, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Too many frames processed.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(/*frames_processed=*/1e6, kKeyFramesProcessed,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Key frames higher than frames_processed.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed,
/*key_frames_processed=*/kFramesProcessed + 1,
kValidP99ProcessingTimeMs),
/*expect_callback=*/false);
// Negative processing time.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
/*p99_processing_time_ms=*/-1.0f),
/*expect_callback=*/false);
// Too high processing time.
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
/*p99_processing_time_ms=*/60000.0f),
/*expect_callback=*/false);
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, SmoothIsTrueForUntrackedCodecProfiles) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// First add 2 records with untracked codec profiles to the history that are
// not smooth at 60Hz.
constexpr float kP99ProcessingTimeMsNotSmoothAt60Hz = 40.0f;
SavePerfRecord(
Features(kIsDecode, DOLBYVISION_PROFILE4, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsNotSmoothAt60Hz),
/*expect_callback=*/false);
SavePerfRecord(
Features(kIsDecode, DOLBYVISION_PROFILE8, kPixelsHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsNotSmoothAt60Hz),
/*expect_callback=*/false);
// Verify perf history returns is_smooth = true anyway.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, DOLBYVISION_PROFILE4, kPixelsHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, DOLBYVISION_PROFILE8, kPixelsHd, kSoftware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfoFailedInitialize) {
WebrtcPerfHistoryTestParams params = GetParam();
// Fail initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/false);
// When initialization fails, callback should optimistically claim smooth
// performance.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, kPixelsHd, kSoftware),
/*frames_per_second=*/30,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Fail deferred DB initialization (see comment at top of test).
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(false);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, AppendAndDestroyStats) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
// Add the entries.
SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt30Hz));
// Verify its there before we ClearHistory(). Note that perf is NOT smooth at
// 60 fps.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Initiate async clearing of history.
EXPECT_CALL(*this, MockOnClearedHistory());
perf_history_->ClearHistory(
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockOnClearedHistory,
base::Unretained(this)));
// Verify record we added above is no longer present.
// SUBTLE: The PerfHistory will optimistically respond kIsSmooth when no data
// is found. So the signal that the entry was removed is the CB now claims
// "smooth" when it claimed NOT smooth just moments before.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, GetWebrtcVideoStatsDB) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// Request a pointer to WebrtcVideoStatsDB and verify the callback.
EXPECT_CALL(*this, MockGetWebrtcVideoStatsDBCB(_))
.WillOnce([&](const auto* db_ptr) {
// Not able to simply use a matcher because the DB does not exist at the
// time we setup the EXPECT_CALL.
EXPECT_EQ(GetFakeDB(), db_ptr);
});
perf_history_->GetWebrtcVideoStatsDB(
base::BindOnce(&WebrtcVideoPerfHistoryTest::MockGetWebrtcVideoStatsDBCB,
base::Unretained(this)));
task_environment_.RunUntilIdle();
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, GetWebrtcVideoStatsDBFailedInitialize) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/false);
// Request a pointer to WebrtcVideoStatsDB and verify the callback provides
// a nullptr due to failed initialization.
EXPECT_CALL(*this, MockGetWebrtcVideoStatsDBCB(IsNull()));
perf_history_->GetWebrtcVideoStatsDB(
base::BindOnce(&WebrtcVideoPerfHistoryTest::MockGetWebrtcVideoStatsDBCB,
base::Unretained(this)));
task_environment_.RunUntilIdle();
// Complete failed deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(false);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, FailedDatabaseGetForAppend) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// Create a simple record. After we fail to save this record we should find
// smooth = true (the default for no-data-found).
constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
// Fail the "get" step of the save (we always get existing stats so that the
// new stats can be appended to it).
GetFakeDB()->set_fail_next_get(true);
// Attempt (and fail) the save.
SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt30Hz));
// Verify perf history still returns is_smooth = true since
// no data was successfully saved for the given configuration.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, FailedDatabaseAppend) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// Force the DB to fail on the next append.
GetFakeDB()->set_fail_next_append(true);
// Create a simple record. After we fail to save this record we should find
// smooth = true (the default for no-data-found).
constexpr float kP99ProcessingTimeMsSmoothAt30Hz = 24.0f;
// Attempt (and fail) the save.
SavePerfRecord(Features(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt30Hz));
// Verify perf history still returns is_smooth = true since
// no data was successfully saved for the given configuration.
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsEncode, kKnownProfile, kPixelsFullHd, kHardware),
/*frames_per_second=*/60,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest, GetPerfInfo4KSmoothImpliesHdSmooth) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// Add 4K entry that indicates that 4K is smooth at 60 Hz.
constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixels4K, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
// Verify perf history returns is_smooth = true for all resolutions at 30/60
// fps.
constexpr int kPixels[] = {1280 * 720, 1920 * 1080, 3840 * 2160};
constexpr int kFramerates[] = {30, 60};
for (auto pixels : kPixels) {
for (auto framerate : kFramerates) {
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
}
}
// Add an entry indicating that Full HD is not smooth.
constexpr float kP99ProcessingTimeMsNotSmoothAt30Hz = 60.0f;
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsNotSmoothAt30Hz));
// This is an incosistency, but the 4K entry with smooth=true overrides the
// FullHD entry with smooth=false. Verify perf history returns is_smooth =
// true for all resolutions at 30/60 fps.
for (auto pixels : kPixels) {
for (auto framerate : kFramerates) {
EXPECT_CALL(*this, MockGetPerfInfoCB(kIsSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
}
}
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest,
GetPerfInfoFullHdNotSmoothImplies4KNotSmooth) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// Add entry that indicates that FullHD is not smooth at 30 Hz.
constexpr float kP99ProcessingTimeMsNotSmoothAt30Hz = 60.0f;
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsNotSmoothAt30Hz));
// Verify perf history returns is_smooth = true only for resolutions below
// FullHD at 30/60 fps.
constexpr int kPixels[] = {1280 * 720, 1920 * 1080, 3840 * 2160};
constexpr int kFramerates[] = {30, 60};
for (auto pixels : kPixels) {
for (auto framerate : kFramerates) {
EXPECT_CALL(*this, MockGetPerfInfoCB(
pixels < 1920 * 1080 ? kIsSmooth : kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
}
}
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
TEST_P(WebrtcVideoPerfHistoryParamTest,
GetPerfInfoFullHdSmoothEvenIf4KNotSmooth) {
// NOTE: When the DB initialization is deferred, All EXPECT_CALLs are then
// delayed until we db_->CompleteInitialize(). testing::InSequence enforces
// that EXPECT_CALLs arrive in top-to-bottom order.
WebrtcPerfHistoryTestParams params = GetParam();
testing::InSequence dummy;
// Complete initialization in advance of API calls when not asked to defer.
if (!params.defer_initialize)
PreInitializeDB(/*success=*/true);
// Add 4K entry that indicates that 4K is not smooth at 30 Hz.
constexpr float kP99ProcessingTimeMsNotSmoothAt30Hz = 60.0f;
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixels4K, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsNotSmoothAt30Hz));
// Verify perf history returns is_smooth = true for all resolutions below 4K
// at 30/60 fps.
constexpr int kPixels[] = {1280 * 720, 1920 * 1080, 3840 * 2160};
constexpr int kFramerates[] = {30, 60};
for (auto pixels : kPixels) {
for (auto framerate : kFramerates) {
EXPECT_CALL(*this, MockGetPerfInfoCB(
pixels <= 1920 * 1080 ? kIsSmooth : kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
}
}
// Add an entry indicating that Full HD is smooth.
constexpr float kP99ProcessingTimeMsSmoothAt60Hz = 12.0f;
SavePerfRecord(Features(kIsDecode, kKnownProfile, kPixelsFullHd, kSoftware),
VideoStats(kFramesProcessed, kKeyFramesProcessed,
kP99ProcessingTimeMsSmoothAt60Hz));
// Repeat test. The added entry is consistent with the default prediction.
for (auto pixels : kPixels) {
for (auto framerate : kFramerates) {
EXPECT_CALL(*this, MockGetPerfInfoCB(
pixels <= 1920 * 1080 ? kIsSmooth : kIsNotSmooth));
perf_history_->GetPerfInfo(
Features::New(kIsDecode, kKnownProfile, pixels, kSoftware), framerate,
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockGetPerfInfoCB,
base::Unretained(this)));
}
}
// Complete successful deferred DB initialization (see comment at top of test)
if (params.defer_initialize) {
GetFakeDB()->CompleteInitialize(true);
// Allow initialize-deferred API calls to complete.
task_environment_.RunUntilIdle();
}
}
const WebrtcPerfHistoryTestParams kWebrtcPerfHistoryTestParams[] = {
{/*defer_initialize=*/true},
{/*defer_initialize=*/false},
};
INSTANTIATE_TEST_SUITE_P(VaryDBInitTiming,
WebrtcVideoPerfHistoryParamTest,
::testing::ValuesIn(kWebrtcPerfHistoryTestParams));
//
// The following tests are not parameterized. They instead always hard code
// deferred initialization.
//
TEST_F(WebrtcVideoPerfHistoryTest, ClearHistoryTriggersSuccessfulInitialize) {
// Clear the DB. Completion callback shouldn't fire until initialize
// completes.
EXPECT_CALL(*this, MockOnClearedHistory()).Times(0);
perf_history_->ClearHistory(
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockOnClearedHistory,
base::Unretained(this)));
// Give completion callback a chance to fire. Confirm it did not fire.
task_environment_.RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(this);
// Expect completion callback after we successfully initialize.
EXPECT_CALL(*this, MockOnClearedHistory());
GetFakeDB()->CompleteInitialize(true);
// Give deferred callback a chance to fire.
task_environment_.RunUntilIdle();
}
TEST_F(WebrtcVideoPerfHistoryTest, ClearHistoryTriggersFailedInitialize) {
// Clear the DB. Completion callback shouldn't fire until initialize
// completes.
EXPECT_CALL(*this, MockOnClearedHistory()).Times(0);
perf_history_->ClearHistory(
base::BindOnce(&WebrtcVideoPerfHistoryParamTest::MockOnClearedHistory,
base::Unretained(this)));
// Give completion callback a chance to fire. Confirm it did not fire.
task_environment_.RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(this);
// Expect completion callback after completing initialize. "Failure" is
// still a form of completion.
EXPECT_CALL(*this, MockOnClearedHistory());
GetFakeDB()->CompleteInitialize(false);
// Give deferred callback a chance to fire.
task_environment_.RunUntilIdle();
}
} // namespace media