Improve: Adjust quality level definitions and add disable option

This commit is contained in:
yuanyuanxiang
2026-02-13 12:04:37 +01:00
parent b0d0dbb560
commit afa43c6e80
9 changed files with 233 additions and 85 deletions

View File

@@ -156,6 +156,7 @@ public:
bool m_bLastFrameWasScroll; // 上一帧是否是滚动帧(用于强制同步)
int m_nScrollDetectInterval; // 滚动检测间隔0=禁用, 1=每帧, 2=每2帧, ...
int m_nInstructionSet = 0;
int m_nBitRate = 0; // H264 编码码率 (kbps), 0=自动
protected:
int m_nVScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN);
@@ -212,12 +213,6 @@ public:
Mprintf("=> 桌面缩放比例: %.2f, %.2f\t分辨率:%d x %d\n", m_wZoom, m_hZoom, m_ulFullWidth, m_ulFullHeight);
m_wZoom = 1.0 / m_wZoom, m_hZoom = 1.0 / m_hZoom;
}
if (ALGORITHM_H264 == m_bAlgorithm) {
m_encoder = new CX264Encoder();
if (!m_encoder->open(m_ulFullWidth, m_ulFullHeight, 20, m_ulFullWidth * m_ulFullHeight / 1266)) {
Mprintf("Open x264encoder failed!!!\n");
}
}
m_BlockBuffers = new LPBYTE[m_BlockNum];
m_BlockSizes = new ULONG[m_BlockNum];
@@ -911,8 +906,13 @@ public:
case ALGORITHM_H264: {
uint8_t* encoded_data = nullptr;
uint32_t encoded_size = 0;
int err = m_encoder->encode(nextData, 32, 4* m_BitmapInfor_Send->bmiHeader.biWidth,
m_BitmapInfor_Send->bmiHeader.biWidth, m_BitmapInfor_Send->bmiHeader.biHeight, &encoded_data, &encoded_size);
int width = m_BitmapInfor_Send->bmiHeader.biWidth, height = m_BitmapInfor_Send->bmiHeader.biHeight;
if (m_encoder == nullptr) {
m_encoder = new CX264Encoder();
int bitrate = (m_nBitRate > 0) ? m_nBitRate : (width * height / 1266);
m_encoder->open(width, height, 20, bitrate);
}
int err = m_encoder->encode(nextData, 32, 4 * width, width, height, &encoded_data, &encoded_size);
if (err) {
return nullptr;
}
@@ -936,8 +936,13 @@ public:
case ALGORITHM_H264: {
uint8_t* encoded_data = nullptr;
uint32_t encoded_size = 0;
int err = m_encoder->encode(nextData, 32, 4 * m_BitmapInfor_Send->bmiHeader.biWidth,
m_BitmapInfor_Send->bmiHeader.biWidth, m_BitmapInfor_Send->bmiHeader.biHeight, &encoded_data, &encoded_size);
int width = m_BitmapInfor_Send->bmiHeader.biWidth, height = m_BitmapInfor_Send->bmiHeader.biHeight;
if (m_encoder == nullptr) {
m_encoder = new CX264Encoder();
int bitrate = (m_nBitRate > 0) ? m_nBitRate : (width * height / 1266);
m_encoder->open(width, height, 20, bitrate);
}
int err = m_encoder->encode(nextData, 32, 4 * width, width, height, &encoded_data, &encoded_size);
if (err) {
return nullptr;
}
@@ -967,6 +972,21 @@ public:
return oldAlgo;
}
// 设置 H264 编码码率 (kbps), 0=自动计算
// 返回码率是否变化,调用者需要在变化时 RestartScreen
virtual bool SetBitRate(int bitrate)
{
if (m_nBitRate == bitrate)
return false;
m_nBitRate = bitrate;
return true;
}
virtual int GetBitRate() const
{
return m_nBitRate;
}
// 鼠标位置转换
virtual void PointConversion(POINT& pt) const
{

View File

@@ -115,9 +115,7 @@ public:
m_BitmapInfor_Send = new BITMAPINFO(*m_BitmapInfor_Full);
m_nInstructionSet = cfg.GetInt("settings", "CpuSpeedup", 0);
bool canScale = (m_bAlgorithm != ALGORITHM_H264);
if (strategy == 1 || !canScale) {
if (strategy == 1) {
// strategy=1 或不支持缩放: 原始分辨率
} else if (maxWidth > 0 && maxWidth < m_BitmapInfor_Send->bmiHeader.biWidth) {
// maxWidth>0: 自定义 maxWidth等比缩放自适应质量使用

View File

@@ -105,6 +105,8 @@ CScreenManager::CScreenManager(IOCPClient* ClientObject, int n, void* user):CMan
m_ScreenSettings.QualityLevel = cfg.GetInt("settings", "QualityLevel", QUALITY_ADAPTIVE); // 默认自适应
m_ScreenSettings.CpuSpeedup = cfg.GetInt("settings", "CpuSpeedup", 0);
LoadQualityProfiles(); // 加载质量配置
m_hWorkThread = __CreateThread(NULL,0, WorkThreadProc,this,0,NULL);
}
@@ -263,7 +265,7 @@ void CScreenManager::InitScreenSpy()
// 如果已设置质量等级,使用对应的算法(优先于启动参数)
int level = m_ScreenSettings.QualityLevel;
if (level >= 0 && level < QUALITY_COUNT) {
algo = GetQualityProfile(level).algorithm;
algo = m_QualityProfiles[level].algorithm;
}
Mprintf("CScreenManager: Type %d Algorithm: %d (QualityLevel=%d)\n", DXGI, int(algo), level);
if (DXGI == USING_VIRTUAL) {
@@ -575,7 +577,7 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
iniFile cfg(CLIENT_PATH);
// strategy=2 是自适应质量使用的临时策略,不覆盖用户的原始策略
// strategy=2 是自适应质量使用的临时策略,不覆盖用户的原始 ScreenStrategy
if (strategy == 2) {
if (maxWidth == 0) {
// maxWidth=0 表示"使用默认策略",读取用户原来的设置
@@ -587,7 +589,7 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
}
Mprintf("maxWidth=0, 回退到默认策略: strategy=%d\n", strategy);
}
// strategy=2 只写入 ScreenWidth不覆盖用户的 ScreenStrategy
// 保存自适应的 ScreenWidth下次启动时作为初始值
cfg.SetInt("settings", "ScreenWidth", maxWidth);
Mprintf("写入配置: ScreenWidth=%d (保留原 ScreenStrategy)\n", maxWidth);
} else {
@@ -616,11 +618,9 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
needRestart = !m_ScreenSpyObject->IsOriginalSize();
Mprintf("strategy=1 (原始), needRestart=%d\n", needRestart);
break;
case 2: // 自定义 maxWidth (maxWidth > 0)
if (maxWidth > 0 && maxWidth != currentWidth) {
needRestart = true;
}
Mprintf("strategy=2 (自定义), maxWidth=%d, currentWidth=%d, needRestart=%d\n",
case 2: // 自适应质量调整 (maxWidth > 0maxWidth=0 时已回退到 case 0/1)
needRestart = (maxWidth != currentWidth);
Mprintf("strategy=2 (自适应), maxWidth=%d, currentWidth=%d, needRestart=%d\n",
maxWidth, currentWidth, needRestart);
break;
}
@@ -663,8 +663,8 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
break;
}
case CMD_QUALITY_LEVEL: {
// 质量等级调整 (level: -1=自适应, 0-4=具体等级)
int8_t level = (int8_t)szBuffer[1]; // 有符号,支持 -1
// 质量等级调整 (level: -2=关闭, -1=自适应, 0-5=具体等级)
int8_t level = (int8_t)szBuffer[1]; // 有符号,支持负值
int persist = ulLength >= 3 ? szBuffer[2] : 0; // 是否保存到配置
m_ScreenSettings.QualityLevel = level;
// 保存到配置
@@ -672,15 +672,32 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
iniFile cfg(CLIENT_PATH);
cfg.SetInt("settings", "QualityLevel", level);
}
// 应用具体等级的配置 (自适应模式由服务端动态调整)
if (level >= 0 && level < QUALITY_COUNT) {
const QualityProfile& profile = GetQualityProfile(level);
// 应用具体等级的配置
if (level == QUALITY_DISABLED) {
// 关闭模式:不修改任何设置,使用原有的算法和帧率配置
Mprintf("质量等级: 关闭 (使用原有设置)\n");
} else if (level >= 0 && level < QUALITY_COUNT) {
// 具体等级:应用本地配置
const QualityProfile& profile = m_QualityProfiles[level];
m_ScreenSettings.MaxFPS = profile.maxFPS;
bool needRestart = false;
if (m_ScreenSpyObject) {
// 如果当前是 H264 且码率变化,需要重启以重新创建编码器
bool isH264 = (m_ScreenSpyObject->GetAlgorithm() == ALGORITHM_H264);
bool bitRateChanged = m_ScreenSpyObject->SetBitRate(profile.bitRate);
if (isH264 && bitRateChanged) {
needRestart = true;
}
m_ScreenSpyObject->SetAlgorithm(profile.algorithm);
}
Mprintf("质量等级: Level=%d, FPS=%d, Algo=%d\n", level, profile.maxFPS, profile.algorithm);
Mprintf("质量等级: Level=%d, FPS=%d, Algo=%d, BitRate=%d\n", level,
profile.maxFPS, profile.algorithm, profile.bitRate);
if (needRestart) {
Mprintf("H264 码率变化,重启截屏...\n");
RestartScreen();
}
} else {
// 自适应模式:由服务端动态调整
Mprintf("质量等级: 自适应模式\n");
}
break;
@@ -695,6 +712,15 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
Mprintf("使用的CPU加速指令集: %d\n", set);
break;
}
case CMD_QUALITY_PROFILES: {
// 接收服务端下发的质量配置
if (ulLength >= 1 + sizeof(QualityProfile) * QUALITY_COUNT) {
memcpy(m_QualityProfiles, szBuffer + 1, sizeof(QualityProfile) * QUALITY_COUNT);
SaveQualityProfiles();
Mprintf("收到质量配置更新\n");
}
break;
}
case COMMAND_NEXT: {
m_DlgID = ulLength >= 9 ? *((uint64_t*)(szBuffer + 1)) : 0;
// 解析服务端能力标志(如果有)
@@ -1294,3 +1320,38 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength)
}
}
}
void CScreenManager::LoadQualityProfiles()
{
iniFile cfg(CLIENT_PATH);
for (int i = 0; i < QUALITY_COUNT; i++) {
char section[32];
sprintf(section, "profile%d", i);
// 读取配置,没有则用默认值
const QualityProfile& def = GetQualityProfile(i);
m_QualityProfiles[i].maxFPS = cfg.GetInt(section, "maxFPS", def.maxFPS);
m_QualityProfiles[i].maxWidth = cfg.GetInt(section, "maxWidth", def.maxWidth);
m_QualityProfiles[i].algorithm = cfg.GetInt(section, "algorithm", def.algorithm);
m_QualityProfiles[i].bitRate = cfg.GetInt(section, "bitRate", def.bitRate);
}
}
void CScreenManager::SaveQualityProfiles()
{
iniFile cfg(CLIENT_PATH);
for (int i = 0; i < QUALITY_COUNT; i++) {
const QualityProfile& def = GetQualityProfile(i);
const QualityProfile& cur = m_QualityProfiles[i];
// 只有与默认值不同时才保存
if (cur.maxFPS == def.maxFPS && cur.maxWidth == def.maxWidth &&
cur.algorithm == def.algorithm && cur.bitRate == def.bitRate) {
continue;
}
char section[32];
sprintf(section, "profile%d", i);
cfg.SetInt(section, "maxFPS", cur.maxFPS);
cfg.SetInt(section, "maxWidth", cur.maxWidth);
cfg.SetInt(section, "algorithm", cur.algorithm);
cfg.SetInt(section, "bitRate", cur.bitRate);
}
}

View File

@@ -30,8 +30,11 @@ public:
virtual ~CScreenManager();
HANDLE m_hWorkThread;
ScreenSettings m_ScreenSettings = { 20 };
QualityProfile m_QualityProfiles[QUALITY_COUNT]; // 本地质量配置(可被服务端覆盖)
void InitScreenSpy();
void LoadQualityProfiles(); // 从配置文件加载质量配置
void SaveQualityProfiles(); // 保存质量配置到配置文件
static DWORD WINAPI WorkThreadProc(LPVOID lParam);
VOID SendBitMapInfo();
VOID OnReceive(PBYTE szBuffer, ULONG ulLength);

View File

@@ -25,12 +25,11 @@ CScreenSpy::CScreenSpy(ULONG ulbiBitCount, BYTE algo, BOOL vDesk, int gop, BOOL
m_BitmapInfor_Send = new BITMAPINFO(*m_BitmapInfor_Full);
m_nInstructionSet = cfg.GetInt("settings", "CpuSpeedup", 0);
bool canScale = (m_bAlgorithm != ALGORITHM_H264);
Mprintf("CScreenSpy: strategy=%d, maxWidth=%d, fullWidth=%d\n",
strategy, maxWidth, m_BitmapInfor_Send->bmiHeader.biWidth);
Mprintf("CScreenSpy: strategy=%d, maxWidth=%d, fullWidth=%d, algo=%d\n",
strategy, maxWidth, m_BitmapInfor_Send->bmiHeader.biWidth, m_bAlgorithm);
if (strategy == 1 || !canScale) {
// strategy=1 或不支持缩放: 原始分辨率
if (strategy == 1) {
// strategy=1: 用户明确选择原始分辨率
Mprintf("CScreenSpy: 使用原始分辨率\n");
} else if (maxWidth > 0 && maxWidth < m_BitmapInfor_Send->bmiHeader.biWidth) {
// maxWidth>0: 自定义 maxWidth等比缩放自适应质量使用

View File

@@ -213,6 +213,7 @@ enum {
CMD_SCROLL_INTERVAL = 77, // 滚动检测间隔
CMD_QUALITY_LEVEL = 78, // 质量等级 (-1=自适应, 0-4=具体等级)
CMD_INSTRUCTION_SET = 79,
CMD_QUALITY_PROFILES = 80, // 下发质量配置表 (1 + QUALITY_COUNT * sizeof(QualityProfile))
TOKEN_SCROLL_FRAME = 99, // 滚动优化帧
// 服务端发出的标识
@@ -942,42 +943,57 @@ typedef struct MasterSettings {
// 自适应质量等级
enum QualityLevel {
QUALITY_DISABLED = -2, // 关闭质量控制(使用原有算法设置)
QUALITY_ADAPTIVE = -1, // 自适应模式
QUALITY_ULTRA = 0, // 极佳 (局域网)
QUALITY_HIGH = 1, // 良好
QUALITY_MEDIUM = 2, // 一般
QUALITY_LOW = 3, // 较差
QUALITY_MINIMAL = 4, // 最低
QUALITY_COUNT = 5,
QUALITY_ULTRA = 0, // 极佳 (局域网, DIFF)
QUALITY_HIGH = 1, // 优秀 (RGB565)
QUALITY_GOOD = 2, // 良好 (H264, 1080P)
QUALITY_MEDIUM = 3, // 一般 (H264, 900P)
QUALITY_LOW = 4, // 较差 (H264, 720P)
QUALITY_MINIMAL = 5, // 最低 (H264, 540P)
QUALITY_COUNT = 6,
};
// 质量配置 (与 QualityLevel 对应)
/* 质量配置(与 QualityLevel 对应)
- strategy = 01080p 限制
- strategy = 1原始分辨率
- strategy = 2 + maxWidth > 0自定义宽度
- strategy = 2 + maxWidth = 0回退到用户保存的 strategy0 或 1
*/
struct QualityProfile {
int maxFPS; // 最大帧率
int maxWidth; // 最大宽度 (0=不限)
int algorithm; // 压缩算法: 0=GRAY, 1=DIFF, 3=RGB565
int algorithm; // 压缩算法: 0=GRAY, 1=DIFF, 2=H264, 3=RGB565
int bitRate; // kbps - H264
};
// 控制端使用,客户端优先从配置中读取
inline const QualityProfile& GetQualityProfile(int level) {
// 预定义质量配置: algorithm: 0=GRAY, 1=DIFF, 3=RGB565
// 预定义质量配置: algorithm: 0=GRAY, 1=DIFF, 2=H264, 3=RGB565
// 注意: level 必须在 [0, QUALITY_COUNT) 范围内
static const QualityProfile g_QualityProfiles[QUALITY_COUNT] = {
{30, 0, 1}, // Ultra: 30FPS, 原始, DIFF
{20, 0, 3}, // High: 20FPS, 原始, RGB565
{15, 1920, 3}, // Medium: 15FPS, 1080P,RGB565
{10, 1920, 0}, // Low: 10FPS, 1080P,GRAY
{5, 1280, 0}, // Minimal: 5FPS, 720P, GRAY
{25, 0, 1, 0 }, // Ultra: 25FPS, 原始, DIFF (局域网办公)
{20, 0, 3, 0 }, // High: 20FPS, 原始, RGB565 (一般办公)
{20, 1920, 2, 3000}, // Good: 20FPS, 1080P, H264 (跨网/偶尔视频)
{15, 1600, 2, 2000}, // Medium: 15FPS, 900P, H264
{12, 1280, 2, 1200}, // Low: 12FPS, 720P, H264
{8, 1024, 2, 800 }, // Minimal: 8FPS, 540P, H264 (极差网络)
};
if (level < 0 || level >= QUALITY_COUNT) {
static const QualityProfile disabled = {0, 0, -1, 0}; // 关闭模式返回空配置
return disabled;
}
return g_QualityProfiles[level];
}
// 根据RTT获取目标质量等级
// 根据RTT获取目标质量等级 (控制端使用)
inline int GetTargetQualityLevel(int rtt, int usingFRP) {
// 根据模式应用不同 RTT阈值 (毫秒)
static const int g_RttThresholds[2][QUALITY_COUNT] = {
// 直连: ULTRA, HIGH, MEDIUM, LOW, MINIMAL
/* DIRECT */ { 30, 100, 200, 400, INT_MAX },
// 直连: ULTRA, HIGH, GOOD, MEDIUM, LOW, MINIMAL
/* DIRECT */ { 30, 80, 150, 250, 400, INT_MAX },
// FRP:
/* PROXY */ { 60, 200, 400, 800, INT_MAX },
/* PROXY */ { 60, 160, 300, 500, 800, INT_MAX },
};
for (int i = 0; i < QUALITY_COUNT; i++) {
if (rtt < g_RttThresholds[usingFRP][i])

View File

@@ -43,9 +43,11 @@ enum {
IDM_SCROLL_DETECT_2, // 滚动检测:跨网推荐
IDM_SCROLL_DETECT_4, // 滚动检测:标准模式
IDM_SCROLL_DETECT_8, // 滚动检测省CPU模式
IDM_QUALITY_OFF, // 关闭质量控制(使用原有算法)
IDM_ADAPTIVE_QUALITY, // 自适应质量
IDM_QUALITY_ULTRA, // 手动质量Ultra
IDM_QUALITY_HIGH, // 手动质量High
IDM_QUALITY_GOOD, // 手动质量Good
IDM_QUALITY_MEDIUM, // 手动质量Medium
IDM_QUALITY_LOW, // 手动质量Low
IDM_QUALITY_MINIMAL, // 手动质量Minimal
@@ -154,16 +156,23 @@ CScreenSpyDlg::CScreenSpyDlg(CMy2015RemoteDlg* Parent, Server* IOCPServer, CONTE
m_ContextObject->InDeCompressedBuffer.CopyBuffer(m_BitmapInfor_Full, ulBitmapInforLength, 1);
m_ContextObject->InDeCompressedBuffer.CopyBuffer(&m_Settings, sizeof(ScreenSettings), 57);
// 从客户端配置初始化自适应质量状态 (QualityLevel: -1=自适应, 0-4=具体等级)
if (m_Settings.QualityLevel == QUALITY_ADAPTIVE) {
// 从客户端配置初始化自适应质量状态 (QualityLevel: -2=关闭, -1=自适应, 0-5=具体等级)
if (m_Settings.QualityLevel == QUALITY_DISABLED) {
m_AdaptiveQuality.enabled = false;
m_AdaptiveQuality.currentLevel = QUALITY_HIGH; // 关闭模式时不使用等级
} else if (m_Settings.QualityLevel == QUALITY_ADAPTIVE) {
m_AdaptiveQuality.enabled = true;
m_AdaptiveQuality.currentLevel = QUALITY_HIGH; // 自适应默认从 High 开始
} else if (m_Settings.QualityLevel >= 0 && m_Settings.QualityLevel < QUALITY_COUNT) {
m_AdaptiveQuality.enabled = false;
m_AdaptiveQuality.currentLevel = m_Settings.QualityLevel;
}
// 初始化当前分辨率限制
m_AdaptiveQuality.currentMaxWidth = GetQualityProfile(m_AdaptiveQuality.currentLevel).maxWidth;
// 初始化当前分辨率限制关闭模式时为0不限制
if (m_Settings.QualityLevel != QUALITY_DISABLED) {
m_AdaptiveQuality.currentMaxWidth = GetQualityProfile(m_AdaptiveQuality.currentLevel).maxWidth;
} else {
m_AdaptiveQuality.currentMaxWidth = 0;
}
m_bIsCtrl = FALSE;
m_bIsTraceCursor = FALSE;
@@ -348,13 +357,15 @@ BOOL CScreenSpyDlg::OnInitDialog()
// 屏幕质量子菜单
CMenu qualityMenu;
if (qualityMenu.CreatePopupMenu()) {
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_OFF, "关闭(&O)");
qualityMenu.AppendMenuL(MF_STRING, IDM_ADAPTIVE_QUALITY, "自适应(&A)");
qualityMenu.AppendMenuSeparator(MF_SEPARATOR);
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_ULTRA, "Ultra (30FPS, DIFF)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_ULTRA, "Ultra (25FPS, DIFF)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_HIGH, "High (20FPS, RGB565)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_MEDIUM, "Medium (15FPS, RGB565)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_LOW, "Low (10FPS, RGB565)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_MINIMAL, "Minimal (5FPS, GRAY)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_GOOD, "Good (20FPS, H264)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_MEDIUM, "Medium (15FPS, H264)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_LOW, "Low (12FPS, H264)");
qualityMenu.AppendMenuL(MF_STRING, IDM_QUALITY_MINIMAL, "Minimal (8FPS, H264)");
SysMenu->AppendMenuL(MF_STRING | MF_POPUP, (UINT_PTR)qualityMenu.Detach(), _T("屏幕质量(&Q)"));
}
// 初始化勾选状态
@@ -427,17 +438,30 @@ BOOL CScreenSpyDlg::OnInitDialog()
// 启动传输速率更新定时器 (1秒)
SetTimer(4, 1000, NULL);
// 如果非自适应模式,发送保存的质量等级给客户端应用
if (!m_AdaptiveQuality.enabled) {
// 下发质量配置表(让客户端可以持久化保存)
{
BYTE profileCmd[1 + sizeof(QualityProfile) * QUALITY_COUNT];
profileCmd[0] = CMD_QUALITY_PROFILES;
for (int i = 0; i < QUALITY_COUNT; i++) {
memcpy(profileCmd + 1 + i * sizeof(QualityProfile),
&GetQualityProfile(i), sizeof(QualityProfile));
}
m_ContextObject->Send2Client(profileCmd, sizeof(profileCmd));
}
// 发送初始质量配置给客户端
if (m_Settings.QualityLevel == QUALITY_DISABLED) {
// 关闭模式:不发送任何质量命令,保持客户端原有设置
} else {
// 自适应或固定等级模式:发送质量等级和分辨率
BYTE cmd[4] = { CMD_QUALITY_LEVEL, (BYTE)m_AdaptiveQuality.currentLevel, 0 };
m_ContextObject->Send2Client(cmd, sizeof(cmd));
// 如果有分辨率限制,也发送
if (m_AdaptiveQuality.currentMaxWidth > 0) {
BYTE sizeCmd[16] = { CMD_SCREEN_SIZE, 2 }; // strategy=2 表示自定义maxWidth
memcpy(sizeCmd + 2, &m_AdaptiveQuality.currentMaxWidth, sizeof(int));
m_ContextObject->Send2Client(sizeCmd, 10);
}
// 始终发送 CMD_SCREEN_SIZE让客户端同步分辨率策略
// maxWidth=0 表示使用默认分辨率1080p 限制)
BYTE sizeCmd[16] = { CMD_SCREEN_SIZE, 2 }; // strategy=2 表示自适应质量
memcpy(sizeCmd + 2, &m_AdaptiveQuality.currentMaxWidth, sizeof(int));
m_ContextObject->Send2Client(sizeCmd, 10);
}
SendNext();
@@ -1102,23 +1126,34 @@ void CScreenSpyDlg::OnSysCommand(UINT nID, LPARAM lParam)
break;
}
case IDM_QUALITY_OFF: { // 关闭质量控制
m_AdaptiveQuality.enabled = false;
m_Settings.QualityLevel = QUALITY_DISABLED;
UpdateQualityMenuCheck(SysMenu);
// 发送给客户端保存 (QualityLevel=-2 表示关闭)
BYTE cmd[4] = { CMD_QUALITY_LEVEL, (BYTE)QUALITY_DISABLED, 1 }; // persist=1
m_ContextObject->Send2Client(cmd, sizeof(cmd));
UpdateWindowTitle();
Mprintf("关闭质量控制,使用原有算法设置\n");
break;
}
case IDM_ADAPTIVE_QUALITY: { // 自适应质量开关
m_AdaptiveQuality.enabled = !m_AdaptiveQuality.enabled;
m_AdaptiveQuality.enabled = true;
m_Settings.QualityLevel = QUALITY_ADAPTIVE;
UpdateQualityMenuCheck(SysMenu);
// 发送给客户端保存 (QualityLevel=-1 表示自适应)
int8_t level = m_AdaptiveQuality.enabled ? QUALITY_ADAPTIVE : m_AdaptiveQuality.currentLevel;
BYTE cmd[4] = { CMD_QUALITY_LEVEL, (BYTE)level, 1 }; // persist=1
BYTE cmd[4] = { CMD_QUALITY_LEVEL, (BYTE)QUALITY_ADAPTIVE, 1 }; // persist=1
m_ContextObject->Send2Client(cmd, sizeof(cmd));
if (m_AdaptiveQuality.enabled) {
// 启用时立即评估一次
EvaluateQuality();
}
// 启用时立即评估一次
EvaluateQuality();
UpdateWindowTitle();
break;
}
case IDM_QUALITY_ULTRA:
case IDM_QUALITY_HIGH:
case IDM_QUALITY_GOOD:
case IDM_QUALITY_MEDIUM:
case IDM_QUALITY_LOW:
case IDM_QUALITY_MINIMAL: {
@@ -1126,6 +1161,7 @@ void CScreenSpyDlg::OnSysCommand(UINT nID, LPARAM lParam)
int level = nID - IDM_QUALITY_ULTRA;
// 关闭自适应模式
m_AdaptiveQuality.enabled = false;
m_Settings.QualityLevel = level;
// 应用选择的等级 (persist=true 保存到客户端)
ApplyQualityLevel(level, true);
UpdateQualityMenuCheck(SysMenu);
@@ -1228,16 +1264,19 @@ void CScreenSpyDlg::UpdateWindowTitle()
int width = m_BitmapInfor_Full->bmiHeader.biWidth;
int height = m_BitmapInfor_Full->bmiHeader.biHeight;
const char* qualityName = GetQualityName(m_AdaptiveQuality.currentLevel);
// 构建质量名称:关闭显示 "Off",自适应和手动都会显示 "当前等级"
CString qualityName = m_Settings.QualityLevel == QUALITY_DISABLED ? "" :
CString(" | ") + GetQualityName(m_AdaptiveQuality.currentLevel);
CString strTitle;
UINT fps = (UINT)(m_dFrameRate + 0.5); // 四舍五入显示
if (m_dTransferRate >= 1024) {
strTitle.FormatL("%s - 远程桌面控制 %d×%d | %u FPS | %.1f MB/s | %s",
m_IPAddress, width, height, fps, m_dTransferRate / 1024, qualityName);
strTitle.FormatL("%s - 远程桌面控制 %d×%d | %u FPS | %.1f MB/s%s",
m_IPAddress, width, height, fps, m_dTransferRate / 1024, qualityName.GetString());
} else {
strTitle.FormatL("%s - 远程桌面控制 %d×%d | %u FPS | %.0f KB/s | %s",
m_IPAddress, width, height, fps, m_dTransferRate, qualityName);
strTitle.FormatL("%s - 远程桌面控制 %d×%d | %u FPS | %.0f KB/s%s",
m_IPAddress, width, height, fps, m_dTransferRate, qualityName.GetString());
}
SetWindowText(strTitle);
}
@@ -1245,8 +1284,12 @@ void CScreenSpyDlg::UpdateWindowTitle()
const char* CScreenSpyDlg::GetQualityName(int level)
{
static const char* names[] = {
"Ultra", "High", "Medium", "Low", "Minimal"
"Ultra", "High", "Good", "Medium", "Low", "Minimal"
};
if (level == QUALITY_DISABLED)
return "Off";
if (level == QUALITY_ADAPTIVE)
return "Auto";
if (level >= 0 && level < QUALITY_COUNT)
return names[level];
return "Unknown";
@@ -1256,16 +1299,20 @@ void CScreenSpyDlg::UpdateQualityMenuCheck(CMenu* SysMenu)
{
if (!SysMenu) SysMenu = GetSystemMenu(FALSE);
// 先全部取消勾选
SysMenu->CheckMenuItem(IDM_QUALITY_OFF, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_ADAPTIVE_QUALITY, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_QUALITY_ULTRA, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_QUALITY_HIGH, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_QUALITY_GOOD, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_QUALITY_MEDIUM, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_QUALITY_LOW, MF_UNCHECKED);
SysMenu->CheckMenuItem(IDM_QUALITY_MINIMAL, MF_UNCHECKED);
// 勾选当前项
if (m_AdaptiveQuality.enabled) {
if (m_Settings.QualityLevel == QUALITY_DISABLED) {
SysMenu->CheckMenuItem(IDM_QUALITY_OFF, MF_CHECKED);
} else if (m_AdaptiveQuality.enabled) {
SysMenu->CheckMenuItem(IDM_ADAPTIVE_QUALITY, MF_CHECKED);
} else {
} else if (m_AdaptiveQuality.currentLevel >= 0 && m_AdaptiveQuality.currentLevel < QUALITY_COUNT) {
SysMenu->CheckMenuItem(IDM_QUALITY_ULTRA + m_AdaptiveQuality.currentLevel, MF_CHECKED);
}
}

View File

@@ -915,8 +915,8 @@ NtCreateThreadEx(shellcodeע
%s - <20><><EFBFBD>̼<EFBFBD>¼=%s - Keylogger
%s - ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=%s - Registry Manager
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d=%s - Remote Desktop %d<><64>%d
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f MB/s | %s=%s - Remote Desktop %d<><64>%d | %u FPS | %.1f MB/s | %s
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.0f KB/s | %s=%s - Remote Desktop %d<><64>%d | %u FPS | %.1f KB/s | %s
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f MB/s%s=%s - Remote Desktop %d<><64>%d | %u FPS | %.1f MB/s%s
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.0f KB/s%s=%s - Remote Desktop %d<><64>%d | %u FPS | %.0f KB/s%s
%s - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=%s - Proxy Service
%s - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=%s - Service Manager
%s - Զ<><D4B6><EFBFBD>ն<EFBFBD>=%s - Terminal
@@ -1212,3 +1212,5 @@ PE
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѶϿ<EFBFBD>=Connection lost
- Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѶϿ<D1B6>= - Remote desktop disconnected
λͼ<EFBFBD>ļ<EFBFBD>(*.bmp)|*.bmp|=Bitmap Files(*.bmp)|*.bmp|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>SSE2ָ<EFBFBD>(&5)=Enable Client SSE2(&5)
<EFBFBD>ر<EFBFBD>(&O)=Disbale(&O)

View File

@@ -912,8 +912,8 @@ NtCreateThreadEx(shellcodeע
%s - <20><><EFBFBD>̼<EFBFBD>¼=%s - <20>I<EFBFBD><50><D39B>
%s - ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=%s - <20><><EFBFBD>݋<EFBFBD><DD8B>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD>
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d=%s - <20>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f MB/s | %s=%s - <20>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f MB/s | %s
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.0f KB/s | %s=%s - <20>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f KB/s | %s
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f MB/s%s=%s - <20>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.1f MB/s%s
%s - Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.0f KB/s%s=%s - <20>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d<><64>%d | %u FPS | %.0f KB/s%s
%s - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=%s - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
%s - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=%s - <20><><EFBFBD>չ<EFBFBD><D5B9><EFBFBD>
%s - Զ<><D4B6><EFBFBD>ն<EFBFBD>=%s - <20>h<EFBFBD>˽K<CBBD>˙C
@@ -1209,3 +1209,5 @@ PE
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѶϿ<EFBFBD>=<EFBFBD>B<EFBFBD><EFBFBD><EFBFBD>є<EFBFBD><EFBFBD>_
- Զ<><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѶϿ<D1B6>= - <20>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD>є<EFBFBD><D194>_
λͼ<EFBFBD>ļ<EFBFBD>(*.bmp)|*.bmp|=<EFBFBD>cꇈD<EFBFBD>n(*.bmp)|*.bmp|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>SSE2ָ<EFBFBD>(&5)=<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ñ<EFBFBD><EFBFBD><EFBFBD> SSE2(&5)
<EFBFBD>ر<EFBFBD>(&O)=<EFBFBD>P<EFBFBD>](&O)