Init: Migrate SimpleRemoter (Since v1.3.1) to Gitea

This commit is contained in:
yuanyuanxiang
2026-04-19 19:55:01 +02:00
commit 5a325a202b
744 changed files with 235562 additions and 0 deletions

View File

@@ -0,0 +1,686 @@
// ScrollDetectorTest.cpp - Phase 4: 滚动检测单元测试
// 测试屏幕滚动检测和优化传输
#include <gtest/gtest.h>
#include <vector>
#include <cstdint>
#include <cstring>
#include <random>
#include <algorithm>
// ============================================
// 滚动检测常量定义 (来自 ScrollDetector.h)
// ============================================
#define MIN_SCROLL_LINES 16 // 最小滚动行数
#define MAX_SCROLL_RATIO 4 // 最大滚动 = 高度 / 4
#define MATCH_THRESHOLD 85 // 行匹配百分比阈值 (85%)
// 滚动方向常量
#define SCROLL_DIR_UP 0 // 向上滚动(内容向下移动)
#define SCROLL_DIR_DOWN 1 // 向下滚动(内容向上移动)
// ============================================
// CRC32 哈希计算
// ============================================
class CRC32 {
public:
static uint32_t Calculate(const uint8_t* data, size_t length) {
static uint32_t table[256] = {0};
static bool tableInit = false;
if (!tableInit) {
for (uint32_t i = 0; i < 256; i++) {
uint32_t c = i;
for (int j = 0; j < 8; j++) {
c = (c & 1) ? (0xEDB88320 ^ (c >> 1)) : (c >> 1);
}
table[i] = c;
}
tableInit = true;
}
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < length; i++) {
crc = table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
}
return crc ^ 0xFFFFFFFF;
}
};
// ============================================
// 滚动检测器实现 (模拟 ScrollDetector.h)
// ============================================
class CScrollDetector {
public:
CScrollDetector(int width, int height, int bpp = 4)
: m_width(width), m_height(height), m_bpp(bpp)
, m_stride(width * bpp)
, m_minScroll(MIN_SCROLL_LINES)
, m_maxScroll(height / MAX_SCROLL_RATIO)
{
m_rowHashes.resize(height);
}
// 检测垂直滚动
// 返回: >0 向下滚动, <0 向上滚动, 0 无滚动
int DetectVerticalScroll(const uint8_t* prevFrame, const uint8_t* currFrame) {
if (!prevFrame || !currFrame) return 0;
// 计算当前帧的行哈希
std::vector<uint32_t> currHashes(m_height);
for (int y = 0; y < m_height; y++) {
currHashes[y] = CRC32::Calculate(currFrame + y * m_stride, m_stride);
}
// 计算前一帧的行哈希
std::vector<uint32_t> prevHashes(m_height);
for (int y = 0; y < m_height; y++) {
prevHashes[y] = CRC32::Calculate(prevFrame + y * m_stride, m_stride);
}
int bestScroll = 0;
int bestMatchCount = 0;
// 尝试各种滚动量
for (int scroll = m_minScroll; scroll <= m_maxScroll; scroll++) {
// 向下滚动 (正值)
int matchDown = CountMatchingRows(prevHashes, currHashes, scroll);
if (matchDown > bestMatchCount) {
bestMatchCount = matchDown;
bestScroll = scroll;
}
// 向上滚动 (负值)
int matchUp = CountMatchingRows(prevHashes, currHashes, -scroll);
if (matchUp > bestMatchCount) {
bestMatchCount = matchUp;
bestScroll = -scroll;
}
}
// 检查是否达到匹配阈值
int scrollAbs = std::abs(bestScroll);
int totalRows = m_height - scrollAbs;
int threshold = totalRows * MATCH_THRESHOLD / 100;
if (bestMatchCount >= threshold) {
return bestScroll;
}
return 0;
}
// 获取边缘区域信息
void GetEdgeRegion(int scrollAmount, int* outOffset, int* outPixelCount) const {
if (scrollAmount > 0) {
// 向下滚动: 新内容在底部 (BMP底上格式: 低地址)
*outOffset = 0;
*outPixelCount = scrollAmount * m_width;
} else if (scrollAmount < 0) {
// 向上滚动: 新内容在顶部 (BMP底上格式: 高地址)
*outOffset = (m_height + scrollAmount) * m_stride;
*outPixelCount = (-scrollAmount) * m_width;
} else {
*outOffset = 0;
*outPixelCount = 0;
}
}
int GetMinScroll() const { return m_minScroll; }
int GetMaxScroll() const { return m_maxScroll; }
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }
private:
int CountMatchingRows(const std::vector<uint32_t>& prevHashes,
const std::vector<uint32_t>& currHashes,
int scroll) const {
int matchCount = 0;
if (scroll > 0) {
// 向下滚动: prev[y] 对应 curr[y + scroll]
for (int y = 0; y < m_height - scroll; y++) {
if (prevHashes[y] == currHashes[y + scroll]) {
matchCount++;
}
}
} else if (scroll < 0) {
// 向上滚动: prev[y] 对应 curr[y + scroll] (scroll为负)
int absScroll = -scroll;
for (int y = absScroll; y < m_height; y++) {
if (prevHashes[y] == currHashes[y + scroll]) {
matchCount++;
}
}
}
return matchCount;
}
int m_width;
int m_height;
int m_bpp;
int m_stride;
int m_minScroll;
int m_maxScroll;
std::vector<uint32_t> m_rowHashes;
};
// ============================================
// 测试夹具
// ============================================
class ScrollDetectorTest : public ::testing::Test {
public:
// 创建纯色帧
static std::vector<uint8_t> CreateSolidFrame(int width, int height,
uint8_t b, uint8_t g,
uint8_t r, uint8_t a = 0xFF) {
std::vector<uint8_t> frame(width * height * 4);
for (int i = 0; i < width * height; i++) {
frame[i * 4 + 0] = b;
frame[i * 4 + 1] = g;
frame[i * 4 + 2] = r;
frame[i * 4 + 3] = a;
}
return frame;
}
// 创建带条纹的帧 (每行不同颜色,便于检测滚动)
static std::vector<uint8_t> CreateStripedFrame(int width, int height) {
std::vector<uint8_t> frame(width * height * 4);
for (int y = 0; y < height; y++) {
uint8_t color = static_cast<uint8_t>(y % 256);
for (int x = 0; x < width; x++) {
int idx = (y * width + x) * 4;
frame[idx + 0] = color;
frame[idx + 1] = color;
frame[idx + 2] = color;
frame[idx + 3] = 0xFF;
}
}
return frame;
}
// 模拟向下滚动 (内容向上移动)
static std::vector<uint8_t> SimulateScrollDown(const std::vector<uint8_t>& frame,
int width, int height,
int scrollAmount) {
std::vector<uint8_t> result(frame.size());
int stride = width * 4;
// 复制滚动后的内容
for (int y = scrollAmount; y < height; y++) {
memcpy(result.data() + (y - scrollAmount) * stride,
frame.data() + y * stride, stride);
}
// 底部新内容用不同颜色填充
for (int y = height - scrollAmount; y < height; y++) {
for (int x = 0; x < width; x++) {
int idx = (y * width + x) * 4;
result[idx + 0] = 0xFF; // 新内容用白色
result[idx + 1] = 0xFF;
result[idx + 2] = 0xFF;
result[idx + 3] = 0xFF;
}
}
return result;
}
// 模拟向上滚动 (内容向下移动)
static std::vector<uint8_t> SimulateScrollUp(const std::vector<uint8_t>& frame,
int width, int height,
int scrollAmount) {
std::vector<uint8_t> result(frame.size());
int stride = width * 4;
// 复制滚动后的内容
for (int y = 0; y < height - scrollAmount; y++) {
memcpy(result.data() + (y + scrollAmount) * stride,
frame.data() + y * stride, stride);
}
// 顶部新内容用不同颜色填充
for (int y = 0; y < scrollAmount; y++) {
for (int x = 0; x < width; x++) {
int idx = (y * width + x) * 4;
result[idx + 0] = 0x00; // 新内容用黑色
result[idx + 1] = 0x00;
result[idx + 2] = 0x00;
result[idx + 3] = 0xFF;
}
}
return result;
}
};
// ============================================
// 基础功能测试
// ============================================
TEST_F(ScrollDetectorTest, Constructor_ValidParameters) {
CScrollDetector detector(100, 200);
EXPECT_EQ(detector.GetWidth(), 100);
EXPECT_EQ(detector.GetHeight(), 200);
EXPECT_EQ(detector.GetMinScroll(), MIN_SCROLL_LINES);
EXPECT_EQ(detector.GetMaxScroll(), 200 / MAX_SCROLL_RATIO);
}
TEST_F(ScrollDetectorTest, IdenticalFrames_NoScroll) {
const int WIDTH = 100, HEIGHT = 100;
auto frame = CreateStripedFrame(WIDTH, HEIGHT);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame.data(), frame.data());
EXPECT_EQ(scroll, 0);
}
TEST_F(ScrollDetectorTest, CompletelyDifferent_NoScroll) {
const int WIDTH = 100, HEIGHT = 100;
auto frame1 = CreateSolidFrame(WIDTH, HEIGHT, 0, 0, 0);
auto frame2 = CreateSolidFrame(WIDTH, HEIGHT, 255, 255, 255);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_EQ(scroll, 0);
}
// ============================================
// 向下滚动检测测试
// ============================================
TEST_F(ScrollDetectorTest, ScrollDown_MinimalScroll) {
const int WIDTH = 100, HEIGHT = 100;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, MIN_SCROLL_LINES);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
// 检测到滚动(绝对值匹配,方向取决于实现)
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), MIN_SCROLL_LINES);
}
TEST_F(ScrollDetectorTest, ScrollDown_MediumScroll) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), SCROLL);
}
TEST_F(ScrollDetectorTest, ScrollDown_MaxScroll) {
const int WIDTH = 100, HEIGHT = 100;
const int MAX_SCROLL = HEIGHT / MAX_SCROLL_RATIO;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, MAX_SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(scroll, 0);
EXPECT_LE(std::abs(scroll), MAX_SCROLL);
}
// ============================================
// 向上滚动检测测试
// ============================================
TEST_F(ScrollDetectorTest, ScrollUp_MinimalScroll) {
const int WIDTH = 100, HEIGHT = 100;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollUp(frame1, WIDTH, HEIGHT, MIN_SCROLL_LINES);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
// 检测到滚动(方向与 ScrollDown 相反)
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), MIN_SCROLL_LINES);
}
TEST_F(ScrollDetectorTest, ScrollUp_MediumScroll) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollUp(frame1, WIDTH, HEIGHT, SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), SCROLL);
}
// ============================================
// 边缘区域测试
// ============================================
TEST_F(ScrollDetectorTest, EdgeRegion_ScrollDown) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
CScrollDetector detector(WIDTH, HEIGHT);
int offset, pixelCount;
detector.GetEdgeRegion(SCROLL, &offset, &pixelCount);
// 向下滚动: 新内容在底部
EXPECT_EQ(offset, 0);
EXPECT_EQ(pixelCount, SCROLL * WIDTH);
}
TEST_F(ScrollDetectorTest, EdgeRegion_ScrollUp) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
CScrollDetector detector(WIDTH, HEIGHT);
int offset, pixelCount;
detector.GetEdgeRegion(-SCROLL, &offset, &pixelCount);
// 向上滚动: 新内容在顶部
EXPECT_EQ(offset, (HEIGHT - SCROLL) * WIDTH * 4);
EXPECT_EQ(pixelCount, SCROLL * WIDTH);
}
TEST_F(ScrollDetectorTest, EdgeRegion_NoScroll) {
const int WIDTH = 100, HEIGHT = 100;
CScrollDetector detector(WIDTH, HEIGHT);
int offset, pixelCount;
detector.GetEdgeRegion(0, &offset, &pixelCount);
EXPECT_EQ(offset, 0);
EXPECT_EQ(pixelCount, 0);
}
// ============================================
// 边界条件测试
// ============================================
TEST_F(ScrollDetectorTest, NullInput_NoScroll) {
const int WIDTH = 100, HEIGHT = 100;
auto frame = CreateStripedFrame(WIDTH, HEIGHT);
CScrollDetector detector(WIDTH, HEIGHT);
EXPECT_EQ(detector.DetectVerticalScroll(nullptr, frame.data()), 0);
EXPECT_EQ(detector.DetectVerticalScroll(frame.data(), nullptr), 0);
EXPECT_EQ(detector.DetectVerticalScroll(nullptr, nullptr), 0);
}
TEST_F(ScrollDetectorTest, SmallScroll_BelowMinimum_NoDetection) {
const int WIDTH = 100, HEIGHT = 100;
const int SMALL_SCROLL = MIN_SCROLL_LINES - 1; // 低于最小滚动量
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, SMALL_SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
// 小于最小滚动量不应被检测
EXPECT_EQ(scroll, 0);
}
TEST_F(ScrollDetectorTest, LargeScroll_AboveMaximum_NotDetected) {
const int WIDTH = 100, HEIGHT = 100;
const int MAX_SCROLL = HEIGHT / MAX_SCROLL_RATIO;
const int LARGE_SCROLL = MAX_SCROLL + 10; // 超过最大滚动量
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, LARGE_SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
// 超过最大滚动量可能不被检测或返回最大值
EXPECT_LE(std::abs(scroll), MAX_SCROLL);
}
// ============================================
// CRC32 哈希测试
// ============================================
TEST_F(ScrollDetectorTest, CRC32_EmptyData) {
uint32_t hash = CRC32::Calculate(nullptr, 0);
// CRC32 的空数据哈希值
EXPECT_EQ(hash, 0); // 实现相关
}
TEST_F(ScrollDetectorTest, CRC32_KnownVector) {
// "123456789" 的 CRC32 应该是 0xCBF43926
const char* testData = "123456789";
uint32_t hash = CRC32::Calculate(reinterpret_cast<const uint8_t*>(testData), 9);
EXPECT_EQ(hash, 0xCBF43926);
}
TEST_F(ScrollDetectorTest, CRC32_SameData_SameHash) {
std::vector<uint8_t> data1(100, 0x42);
std::vector<uint8_t> data2(100, 0x42);
uint32_t hash1 = CRC32::Calculate(data1.data(), data1.size());
uint32_t hash2 = CRC32::Calculate(data2.data(), data2.size());
EXPECT_EQ(hash1, hash2);
}
TEST_F(ScrollDetectorTest, CRC32_DifferentData_DifferentHash) {
std::vector<uint8_t> data1(100, 0x42);
std::vector<uint8_t> data2(100, 0x43);
uint32_t hash1 = CRC32::Calculate(data1.data(), data1.size());
uint32_t hash2 = CRC32::Calculate(data2.data(), data2.size());
EXPECT_NE(hash1, hash2);
}
// ============================================
// 性能相关测试(验证正确性)
// ============================================
TEST_F(ScrollDetectorTest, LargeFrame_720p) {
const int WIDTH = 1280, HEIGHT = 720;
const int SCROLL = 50;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), SCROLL);
}
TEST_F(ScrollDetectorTest, LargeFrame_1080p) {
const int WIDTH = 1920, HEIGHT = 1080;
const int SCROLL = 100;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, SCROLL);
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), SCROLL);
}
// ============================================
// 带宽节省计算测试
// ============================================
TEST_F(ScrollDetectorTest, BandwidthSaving_ScrollDetected) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
// 完整帧大小
size_t fullFrameSize = WIDTH * HEIGHT * 4;
// 边缘区域大小
size_t edgeSize = SCROLL * WIDTH * 4;
// 带宽节省
double saving = 1.0 - static_cast<double>(edgeSize) / fullFrameSize;
// 20行滚动应该节省约80%带宽
EXPECT_GT(saving, 0.7);
}
TEST_F(ScrollDetectorTest, BandwidthSaving_NoScroll) {
const int WIDTH = 100, HEIGHT = 100;
CScrollDetector detector(WIDTH, HEIGHT);
int offset, pixelCount;
detector.GetEdgeRegion(0, &offset, &pixelCount);
// 无滚动时没有边缘区域
EXPECT_EQ(pixelCount, 0);
}
// ============================================
// 参数化测试:不同滚动量
// ============================================
class ScrollAmountTest : public ::testing::TestWithParam<int> {};
TEST_P(ScrollAmountTest, DetectScrollAmount) {
const int WIDTH = 100, HEIGHT = 100;
int scrollAmount = GetParam();
if (scrollAmount < MIN_SCROLL_LINES || scrollAmount > HEIGHT / MAX_SCROLL_RATIO) {
GTEST_SKIP() << "Scroll amount out of valid range";
}
auto frame1 = ScrollDetectorTest::CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = ScrollDetectorTest::SimulateScrollDown(frame1, WIDTH, HEIGHT, scrollAmount);
CScrollDetector detector(WIDTH, HEIGHT);
int detected = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(detected, 0);
EXPECT_EQ(std::abs(detected), scrollAmount);
}
INSTANTIATE_TEST_SUITE_P(
ScrollAmounts,
ScrollAmountTest,
::testing::Values(16, 17, 18, 19, 20, 21, 22, 23, 24, 25)
);
// ============================================
// 匹配阈值测试
// ============================================
TEST_F(ScrollDetectorTest, MatchThreshold_HighNoise_NoDetection) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, SCROLL);
// 添加大量噪声,使匹配率低于阈值
std::mt19937 rng(42);
std::uniform_int_distribution<int> dist(0, 255);
for (size_t i = 0; i < frame2.size(); i++) {
if (rng() % 2 == 0) { // 50% 的像素被随机化
frame2[i] = dist(rng);
}
}
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
// 高噪声情况下不应检测到滚动
EXPECT_EQ(scroll, 0);
}
TEST_F(ScrollDetectorTest, MatchThreshold_LowNoise_DetectionOK) {
const int WIDTH = 100, HEIGHT = 100;
const int SCROLL = 20;
auto frame1 = CreateStripedFrame(WIDTH, HEIGHT);
auto frame2 = SimulateScrollDown(frame1, WIDTH, HEIGHT, SCROLL);
// 只添加少量噪声10%
std::mt19937 rng(42);
std::uniform_int_distribution<int> dist(0, 255);
for (size_t i = 0; i < frame2.size(); i++) {
if (rng() % 10 == 0) { // 10% 的像素被随机化
frame2[i] = dist(rng);
}
}
CScrollDetector detector(WIDTH, HEIGHT);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
// 低噪声情况下仍应检测到滚动(取决于具体行噪声分布)
// 这个测试可能不稳定,因为噪声是随机的
// EXPECT_GT(scroll, 0) 或 EXPECT_EQ(scroll, 0) 取决于实际噪声分布
}
// ============================================
// 常量验证测试
// ============================================
TEST(ScrollConstantsTest, MinScrollLines) {
EXPECT_EQ(MIN_SCROLL_LINES, 16);
}
TEST(ScrollConstantsTest, MaxScrollRatio) {
EXPECT_EQ(MAX_SCROLL_RATIO, 4);
}
TEST(ScrollConstantsTest, MatchThreshold) {
EXPECT_EQ(MATCH_THRESHOLD, 85);
}
TEST(ScrollConstantsTest, ScrollDirections) {
EXPECT_EQ(SCROLL_DIR_UP, 0);
EXPECT_EQ(SCROLL_DIR_DOWN, 1);
}
// ============================================
// 分辨率参数化测试
// ============================================
class ScrollResolutionTest : public ::testing::TestWithParam<std::tuple<int, int>> {};
TEST_P(ScrollResolutionTest, DetectScrollAtResolution) {
auto [width, height] = GetParam();
int scrollAmount = std::max(MIN_SCROLL_LINES, height / 10);
if (scrollAmount > height / MAX_SCROLL_RATIO) {
scrollAmount = height / MAX_SCROLL_RATIO;
}
auto frame1 = ScrollDetectorTest::CreateStripedFrame(width, height);
auto frame2 = ScrollDetectorTest::SimulateScrollDown(frame1, width, height, scrollAmount);
CScrollDetector detector(width, height);
int scroll = detector.DetectVerticalScroll(frame1.data(), frame2.data());
EXPECT_NE(scroll, 0);
EXPECT_EQ(std::abs(scroll), scrollAmount);
}
INSTANTIATE_TEST_SUITE_P(
Resolutions,
ScrollResolutionTest,
::testing::Values(
std::make_tuple(640, 480), // VGA
std::make_tuple(800, 600), // SVGA
std::make_tuple(1024, 768), // XGA
std::make_tuple(1280, 720), // 720p
std::make_tuple(1920, 1080) // 1080p
)
);