Files
SimpleRemoter/test/unit/screen/DiffAlgorithmTest.cpp
2026-04-19 22:55:21 +02:00

726 lines
25 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// DiffAlgorithmTest.cpp - Phase 4: 差分算法单元测试
// 测试帧间差异计算和编码逻辑
#include <gtest/gtest.h>
#include <vector>
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <random>
// ============================================
// 算法常量定义 (来自 CursorInfo.h)
// ============================================
#define ALGORITHM_GRAY 0 // 灰度算法
#define ALGORITHM_DIFF 1 // 差分算法(默认)
#define ALGORITHM_H264 2 // H264 视频编码
#define ALGORITHM_RGB565 3 // RGB565 压缩
// ============================================
// 差分输出结构
// ============================================
struct DiffRegion {
uint32_t offset; // 字节偏移
uint32_t length; // 长度(含义取决于算法)
std::vector<uint8_t> data; // 差异数据
};
// ============================================
// 测试用差分算法实现
// 模拟 ScreenCapture.h 中的 CompareBitmapDXGI
// ============================================
class DiffAlgorithm {
public:
// 比较两帧,返回差异区域列表
// 输出格式: [offset:4][length:4][data:N]...
static std::vector<DiffRegion> CompareBitmap(
const uint8_t* srcData, // 新帧
const uint8_t* dstData, // 旧帧
size_t dataLength, // 数据长度字节必须是4的倍数
int algorithm // 压缩算法
) {
std::vector<DiffRegion> regions;
if (dataLength == 0 || dataLength % 4 != 0) {
return regions;
}
const uint32_t* src32 = reinterpret_cast<const uint32_t*>(srcData);
const uint32_t* dst32 = reinterpret_cast<const uint32_t*>(dstData);
size_t pixelCount = dataLength / 4;
size_t i = 0;
while (i < pixelCount) {
// 找到差异起始点
while (i < pixelCount && src32[i] == dst32[i]) {
i++;
}
if (i >= pixelCount) break;
// 记录起始位置
size_t startPos = i;
// 找到差异结束点
while (i < pixelCount && src32[i] != dst32[i]) {
i++;
}
// 创建差异区域
DiffRegion region;
region.offset = static_cast<uint32_t>(startPos * 4); // 字节偏移
size_t diffPixels = i - startPos;
const uint8_t* pixelStart = srcData + startPos * 4;
switch (algorithm) {
case ALGORITHM_GRAY: {
// 灰度: 1字节/像素
region.length = static_cast<uint32_t>(diffPixels); // 像素数
region.data.resize(diffPixels);
for (size_t p = 0; p < diffPixels; p++) {
const uint8_t* pixel = pixelStart + p * 4;
// BGRA格式: B=0, G=1, R=2, A=3
// 灰度公式: Y = 0.299*R + 0.587*G + 0.114*B
int gray = (306 * pixel[2] + 601 * pixel[1] + 117 * pixel[0]) >> 10;
region.data[p] = static_cast<uint8_t>(std::min(255, std::max(0, gray)));
}
break;
}
case ALGORITHM_RGB565: {
// RGB565: 2字节/像素
region.length = static_cast<uint32_t>(diffPixels); // 像素数
region.data.resize(diffPixels * 2);
uint16_t* out = reinterpret_cast<uint16_t*>(region.data.data());
for (size_t p = 0; p < diffPixels; p++) {
const uint8_t* pixel = pixelStart + p * 4;
// BGRA -> RGB565
out[p] = ((pixel[2] >> 3) << 11) | // R: 5位
((pixel[1] >> 2) << 5) | // G: 6位
(pixel[0] >> 3); // B: 5位
}
break;
}
case ALGORITHM_DIFF:
case ALGORITHM_H264:
default: {
// DIFF/H264: 4字节/像素原始BGRA
region.length = static_cast<uint32_t>(diffPixels * 4); // 字节数
region.data.resize(diffPixels * 4);
memcpy(region.data.data(), pixelStart, diffPixels * 4);
break;
}
}
regions.push_back(region);
}
return regions;
}
// 序列化差异区域到缓冲区
static size_t SerializeDiffRegions(
const std::vector<DiffRegion>& regions,
uint8_t* buffer,
size_t bufferSize
) {
size_t offset = 0;
for (const auto& region : regions) {
size_t needed = 8 + region.data.size(); // offset(4) + length(4) + data
if (offset + needed > bufferSize) break;
memcpy(buffer + offset, &region.offset, 4);
offset += 4;
memcpy(buffer + offset, &region.length, 4);
offset += 4;
memcpy(buffer + offset, region.data.data(), region.data.size());
offset += region.data.size();
}
return offset;
}
// 应用差异到目标帧
static void ApplyDiff(
uint8_t* dstData,
size_t dstLength,
const std::vector<DiffRegion>& regions,
int algorithm
) {
for (const auto& region : regions) {
if (region.offset >= dstLength) continue;
uint8_t* dst = dstData + region.offset;
switch (algorithm) {
case ALGORITHM_GRAY: {
// 灰度 -> BGRA
for (uint32_t p = 0; p < region.length && region.offset + p * 4 < dstLength; p++) {
uint8_t gray = region.data[p];
dst[p * 4 + 0] = gray; // B
dst[p * 4 + 1] = gray; // G
dst[p * 4 + 2] = gray; // R
dst[p * 4 + 3] = 0xFF; // A
}
break;
}
case ALGORITHM_RGB565: {
// RGB565 -> BGRA
const uint16_t* src = reinterpret_cast<const uint16_t*>(region.data.data());
for (uint32_t p = 0; p < region.length && region.offset + p * 4 < dstLength; p++) {
uint16_t c = src[p];
uint8_t r5 = (c >> 11) & 0x1F;
uint8_t g6 = (c >> 5) & 0x3F;
uint8_t b5 = c & 0x1F;
dst[p * 4 + 0] = (b5 << 3) | (b5 >> 2); // B
dst[p * 4 + 1] = (g6 << 2) | (g6 >> 4); // G
dst[p * 4 + 2] = (r5 << 3) | (r5 >> 2); // R
dst[p * 4 + 3] = 0xFF; // A
}
break;
}
case ALGORITHM_DIFF:
case ALGORITHM_H264:
default: {
// 原始BGRA
size_t copyLen = std::min(static_cast<size_t>(region.length),
dstLength - region.offset);
memcpy(dst, region.data.data(), copyLen);
break;
}
}
}
}
};
// ============================================
// 测试夹具
// ============================================
class DiffAlgorithmTest : public ::testing::Test {
protected:
// 创建纯色帧 (BGRA格式)
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> CreateGradientFrame(int width, int height) {
std::vector<uint8_t> frame(width * height * 4);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int idx = (y * width + x) * 4;
frame[idx + 0] = static_cast<uint8_t>(x * 255 / width); // B
frame[idx + 1] = static_cast<uint8_t>(y * 255 / height); // G
frame[idx + 2] = static_cast<uint8_t>((x + y) * 128 / (width + height)); // R
frame[idx + 3] = 0xFF;
}
}
return frame;
}
// 创建带随机区域变化的帧
static std::vector<uint8_t> CreateFrameWithChanges(
const std::vector<uint8_t>& baseFrame,
int width, int height,
int changeX, int changeY,
int changeW, int changeH,
uint8_t newB, uint8_t newG, uint8_t newR
) {
std::vector<uint8_t> frame = baseFrame;
for (int y = changeY; y < changeY + changeH && y < height; y++) {
for (int x = changeX; x < changeX + changeW && x < width; x++) {
int idx = (y * width + x) * 4;
frame[idx + 0] = newB;
frame[idx + 1] = newG;
frame[idx + 2] = newR;
frame[idx + 3] = 0xFF;
}
}
return frame;
}
};
// ============================================
// 基础功能测试
// ============================================
TEST_F(DiffAlgorithmTest, IdenticalFrames_NoDifference) {
auto frame = CreateSolidFrame(100, 100, 128, 128, 128);
auto regions = DiffAlgorithm::CompareBitmap(
frame.data(), frame.data(), frame.size(), ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 0u);
}
TEST_F(DiffAlgorithmTest, CompletelyDifferent_SingleRegion) {
auto frame1 = CreateSolidFrame(10, 10, 0, 0, 0);
auto frame2 = CreateSolidFrame(10, 10, 255, 255, 255);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].offset, 0u);
EXPECT_EQ(regions[0].length, 100u * 4); // 100像素 * 4字节
}
TEST_F(DiffAlgorithmTest, PartialChange_SingleRegion) {
const int WIDTH = 100, HEIGHT = 100;
auto frame1 = CreateSolidFrame(WIDTH, HEIGHT, 0, 0, 0);
auto frame2 = CreateFrameWithChanges(frame1, WIDTH, HEIGHT,
10, 10, 20, 20, 255, 255, 255);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_DIFF);
// 应该检测到变化区域
EXPECT_GT(regions.size(), 0u);
// 验证总变化像素数
size_t totalChangedPixels = 0;
for (const auto& r : regions) {
totalChangedPixels += r.length / 4; // DIFF算法length是字节数
}
EXPECT_EQ(totalChangedPixels, 20u * 20u); // 20x20区域
}
TEST_F(DiffAlgorithmTest, MultipleRegions_NonContiguous) {
const int WIDTH = 100, HEIGHT = 10;
auto frame1 = CreateSolidFrame(WIDTH, HEIGHT, 128, 128, 128);
auto frame2 = frame1;
// 创建两个不相邻的变化区域
// 区域1: 像素 5-14
for (int i = 5; i < 15; i++) {
frame2[i * 4 + 0] = 0;
frame2[i * 4 + 1] = 0;
frame2[i * 4 + 2] = 255;
}
// 区域2: 像素 50-59 (与区域1不相邻)
for (int i = 50; i < 60; i++) {
frame2[i * 4 + 0] = 255;
frame2[i * 4 + 1] = 0;
frame2[i * 4 + 2] = 0;
}
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 2u);
}
// ============================================
// 算法特定测试
// ============================================
TEST_F(DiffAlgorithmTest, GrayAlgorithm_CorrectOutput) {
auto frame1 = CreateSolidFrame(10, 10, 0, 0, 0); // 黑色
auto frame2 = CreateSolidFrame(10, 10, 255, 255, 255); // 白色
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_GRAY);
ASSERT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].length, 100u); // 100像素
EXPECT_EQ(regions[0].data.size(), 100u); // 1字节/像素
// 白色应该转换为灰度255
EXPECT_EQ(regions[0].data[0], 255);
}
TEST_F(DiffAlgorithmTest, GrayAlgorithm_GrayConversionFormula) {
// 测试灰度转换公式: Y = 0.299*R + 0.587*G + 0.114*B
std::vector<uint8_t> frame1(4, 0); // 1像素黑色
std::vector<uint8_t> frame2(4);
// 测试纯红色 (R=255, G=0, B=0)
frame2[0] = 0; // B
frame2[1] = 0; // G
frame2[2] = 255; // R
frame2[3] = 255; // A
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), 4, ALGORITHM_GRAY);
ASSERT_EQ(regions.size(), 1u);
// 期望: (306 * 255 + 601 * 0 + 117 * 0) >> 10 ≈ 76
uint8_t expectedGray = (306 * 255) >> 10;
EXPECT_NEAR(regions[0].data[0], expectedGray, 1);
}
TEST_F(DiffAlgorithmTest, RGB565Algorithm_CorrectOutput) {
auto frame1 = CreateSolidFrame(10, 10, 0, 0, 0);
auto frame2 = CreateSolidFrame(10, 10, 255, 255, 255);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_RGB565);
ASSERT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].length, 100u); // 100像素
EXPECT_EQ(regions[0].data.size(), 200u); // 2字节/像素
// 白色 RGB565 = 0xFFFF
uint16_t* rgb565 = reinterpret_cast<uint16_t*>(regions[0].data.data());
EXPECT_EQ(rgb565[0], 0xFFFF);
}
TEST_F(DiffAlgorithmTest, RGB565Algorithm_ColorConversion) {
std::vector<uint8_t> frame1(4, 0); // 1像素黑色
std::vector<uint8_t> frame2(4);
// 纯红色 (R=255, G=0, B=0) -> RGB565 = 0xF800
frame2[0] = 0; // B
frame2[1] = 0; // G
frame2[2] = 255; // R
frame2[3] = 255; // A
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), 4, ALGORITHM_RGB565);
ASSERT_EQ(regions.size(), 1u);
uint16_t* rgb565 = reinterpret_cast<uint16_t*>(regions[0].data.data());
EXPECT_EQ(rgb565[0], 0xF800); // 纯红色
}
TEST_F(DiffAlgorithmTest, DiffAlgorithm_PreservesOriginalData) {
std::vector<uint8_t> frame1(8, 0); // 2像素黑色
std::vector<uint8_t> frame2 = {
0x12, 0x34, 0x56, 0x78, // 像素1
0xAB, 0xCD, 0xEF, 0xFF // 像素2
};
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), 8, ALGORITHM_DIFF);
ASSERT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].length, 8u); // 8字节
EXPECT_EQ(regions[0].data, frame2); // 原始数据完整保留
}
// ============================================
// 边界条件测试
// ============================================
TEST_F(DiffAlgorithmTest, EmptyInput_NoRegions) {
auto regions = DiffAlgorithm::CompareBitmap(nullptr, nullptr, 0, ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 0u);
}
TEST_F(DiffAlgorithmTest, SinglePixel_Difference) {
std::vector<uint8_t> frame1 = {0, 0, 0, 255};
std::vector<uint8_t> frame2 = {255, 255, 255, 255};
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), 4, ALGORITHM_DIFF);
ASSERT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].offset, 0u);
EXPECT_EQ(regions[0].length, 4u);
}
TEST_F(DiffAlgorithmTest, SinglePixel_NoDifference) {
std::vector<uint8_t> frame = {100, 150, 200, 255};
auto regions = DiffAlgorithm::CompareBitmap(
frame.data(), frame.data(), 4, ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 0u);
}
TEST_F(DiffAlgorithmTest, NonAlignedLength_Rejected) {
std::vector<uint8_t> data(7); // 不是4的倍数
auto regions = DiffAlgorithm::CompareBitmap(
data.data(), data.data(), data.size(), ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 0u);
}
TEST_F(DiffAlgorithmTest, FirstPixelOnly_Changed) {
std::vector<uint8_t> frame1(40, 128); // 10像素
std::vector<uint8_t> frame2 = frame1;
frame2[0] = 0; // 只改变第一个像素的B通道
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), 40, ALGORITHM_DIFF);
ASSERT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].offset, 0u);
EXPECT_EQ(regions[0].length, 4u); // 只有1个像素
}
TEST_F(DiffAlgorithmTest, LastPixelOnly_Changed) {
std::vector<uint8_t> frame1(40, 128); // 10像素
std::vector<uint8_t> frame2 = frame1;
frame2[36] = 0; // 只改变最后一个像素的B通道
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), 40, ALGORITHM_DIFF);
ASSERT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].offset, 36u); // 第9个像素的偏移
EXPECT_EQ(regions[0].length, 4u);
}
// ============================================
// 序列化测试
// ============================================
TEST_F(DiffAlgorithmTest, Serialize_SingleRegion) {
std::vector<DiffRegion> regions;
DiffRegion r;
r.offset = 100;
r.length = 16;
r.data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
regions.push_back(r);
std::vector<uint8_t> buffer(1024);
size_t written = DiffAlgorithm::SerializeDiffRegions(
regions, buffer.data(), buffer.size());
EXPECT_EQ(written, 8u + 16u); // offset(4) + length(4) + data(16)
// 验证偏移
uint32_t readOffset;
memcpy(&readOffset, buffer.data(), 4);
EXPECT_EQ(readOffset, 100u);
// 验证长度
uint32_t readLength;
memcpy(&readLength, buffer.data() + 4, 4);
EXPECT_EQ(readLength, 16u);
}
TEST_F(DiffAlgorithmTest, Serialize_MultipleRegions) {
std::vector<DiffRegion> regions;
DiffRegion r1;
r1.offset = 0;
r1.length = 4;
r1.data = {1, 2, 3, 4};
regions.push_back(r1);
DiffRegion r2;
r2.offset = 100;
r2.length = 8;
r2.data = {5, 6, 7, 8, 9, 10, 11, 12};
regions.push_back(r2);
std::vector<uint8_t> buffer(1024);
size_t written = DiffAlgorithm::SerializeDiffRegions(
regions, buffer.data(), buffer.size());
EXPECT_EQ(written, (8u + 4u) + (8u + 8u)); // 两个区域
}
TEST_F(DiffAlgorithmTest, Serialize_BufferTooSmall) {
std::vector<DiffRegion> regions;
DiffRegion r;
r.offset = 0;
r.length = 100;
r.data.resize(100, 0xFF);
regions.push_back(r);
std::vector<uint8_t> buffer(10); // 太小
size_t written = DiffAlgorithm::SerializeDiffRegions(
regions, buffer.data(), buffer.size());
EXPECT_EQ(written, 0u); // 无法写入
}
// ============================================
// 应用差异测试
// ============================================
TEST_F(DiffAlgorithmTest, ApplyDiff_DIFF_Reconstructs) {
auto frame1 = CreateGradientFrame(50, 50);
auto frame2 = CreateFrameWithChanges(frame1, 50, 50, 10, 10, 20, 20, 255, 0, 0);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_DIFF);
// 应用差异到frame1的副本
std::vector<uint8_t> reconstructed = frame1;
DiffAlgorithm::ApplyDiff(reconstructed.data(), reconstructed.size(),
regions, ALGORITHM_DIFF);
// 应该完全重建frame2
EXPECT_EQ(reconstructed, frame2);
}
TEST_F(DiffAlgorithmTest, ApplyDiff_GRAY_ApproximateReconstruction) {
auto frame1 = CreateSolidFrame(10, 10, 0, 0, 0);
auto frame2 = CreateSolidFrame(10, 10, 200, 200, 200); // 浅灰色
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_GRAY);
std::vector<uint8_t> reconstructed = frame1;
DiffAlgorithm::ApplyDiff(reconstructed.data(), reconstructed.size(),
regions, ALGORITHM_GRAY);
// 灰度重建R=G=B
for (size_t i = 0; i < reconstructed.size(); i += 4) {
EXPECT_EQ(reconstructed[i], reconstructed[i + 1]); // B == G
EXPECT_EQ(reconstructed[i + 1], reconstructed[i + 2]); // G == R
}
}
TEST_F(DiffAlgorithmTest, ApplyDiff_RGB565_ApproximateReconstruction) {
auto frame1 = CreateSolidFrame(10, 10, 0, 0, 0);
// RGB565有量化误差使用能精确表示的颜色
auto frame2 = CreateSolidFrame(10, 10, 248, 252, 248); // 接近白色
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_RGB565);
std::vector<uint8_t> reconstructed = frame1;
DiffAlgorithm::ApplyDiff(reconstructed.data(), reconstructed.size(),
regions, ALGORITHM_RGB565);
// 验证重建颜色接近原始(允许量化误差)
for (size_t i = 0; i < reconstructed.size(); i += 4) {
EXPECT_NEAR(reconstructed[i], frame2[i], 8); // B
EXPECT_NEAR(reconstructed[i + 1], frame2[i + 1], 4); // G (6位精度)
EXPECT_NEAR(reconstructed[i + 2], frame2[i + 2], 8); // R
}
}
// ============================================
// 性能相关测试(不计时,只验证正确性)
// ============================================
TEST_F(DiffAlgorithmTest, LargeFrame_1080p_Correctness) {
const int WIDTH = 1920, HEIGHT = 1080;
auto frame1 = CreateSolidFrame(WIDTH, HEIGHT, 128, 128, 128);
auto frame2 = CreateFrameWithChanges(frame1, WIDTH, HEIGHT,
100, 100, 200, 200, 255, 0, 0);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_DIFF);
// 应该有变化区域
EXPECT_GT(regions.size(), 0u);
// 重建验证
std::vector<uint8_t> reconstructed = frame1;
DiffAlgorithm::ApplyDiff(reconstructed.data(), reconstructed.size(),
regions, ALGORITHM_DIFF);
EXPECT_EQ(reconstructed, frame2);
}
TEST_F(DiffAlgorithmTest, RandomChanges_AllAlgorithms) {
const int WIDTH = 100, HEIGHT = 100;
std::mt19937 rng(42);
std::uniform_int_distribution<int> dist(0, 255);
auto frame1 = CreateGradientFrame(WIDTH, HEIGHT);
auto frame2 = frame1;
// 随机修改10%的像素
for (int i = 0; i < WIDTH * HEIGHT / 10; i++) {
int idx = (rng() % (WIDTH * HEIGHT)) * 4;
frame2[idx + 0] = dist(rng);
frame2[idx + 1] = dist(rng);
frame2[idx + 2] = dist(rng);
}
// 测试所有算法都能产生输出
for (int algo : {ALGORITHM_GRAY, ALGORITHM_DIFF, ALGORITHM_RGB565}) {
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), algo);
EXPECT_GT(regions.size(), 0u) << "Algorithm " << algo << " failed";
}
}
// ============================================
// 压缩效率测试
// ============================================
TEST_F(DiffAlgorithmTest, CompressionRatio_GRAY) {
auto frame1 = CreateSolidFrame(100, 100, 0, 0, 0);
auto frame2 = CreateSolidFrame(100, 100, 255, 255, 255);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_GRAY);
size_t originalSize = 100 * 100 * 4; // 40000 字节
size_t compressedSize = 8 + regions[0].data.size(); // offset + length + data
// GRAY应该是 100*100*1 = 10000 字节数据
EXPECT_EQ(regions[0].data.size(), 10000u);
// 压缩比约 4:1
EXPECT_LT(compressedSize, originalSize / 3);
}
TEST_F(DiffAlgorithmTest, CompressionRatio_RGB565) {
auto frame1 = CreateSolidFrame(100, 100, 0, 0, 0);
auto frame2 = CreateSolidFrame(100, 100, 255, 255, 255);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_RGB565);
// RGB565应该是 100*100*2 = 20000 字节数据
EXPECT_EQ(regions[0].data.size(), 20000u);
}
TEST_F(DiffAlgorithmTest, NoChange_ZeroOverhead) {
auto frame = CreateGradientFrame(100, 100);
auto regions = DiffAlgorithm::CompareBitmap(
frame.data(), frame.data(), frame.size(), ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 0u);
std::vector<uint8_t> buffer(1024);
size_t written = DiffAlgorithm::SerializeDiffRegions(
regions, buffer.data(), buffer.size());
EXPECT_EQ(written, 0u); // 无变化时零开销
}
// ============================================
// 参数化测试:不同分辨率
// ============================================
class DiffAlgorithmResolutionTest : public ::testing::TestWithParam<std::tuple<int, int>> {};
TEST_P(DiffAlgorithmResolutionTest, Resolution_Correctness) {
auto [width, height] = GetParam();
auto frame1 = std::vector<uint8_t>(width * height * 4, 0);
auto frame2 = std::vector<uint8_t>(width * height * 4, 255);
auto regions = DiffAlgorithm::CompareBitmap(
frame2.data(), frame1.data(), frame1.size(), ALGORITHM_DIFF);
EXPECT_EQ(regions.size(), 1u);
EXPECT_EQ(regions[0].offset, 0u);
EXPECT_EQ(regions[0].length, static_cast<uint32_t>(width * height * 4));
}
INSTANTIATE_TEST_SUITE_P(
Resolutions,
DiffAlgorithmResolutionTest,
::testing::Values(
std::make_tuple(1, 1), // 最小
std::make_tuple(10, 10), // 小
std::make_tuple(100, 100), // 中
std::make_tuple(640, 480), // VGA
std::make_tuple(1280, 720), // 720p
std::make_tuple(1920, 1080) // 1080p
)
);