Feat: ROI screen capture with remote control support via COMMAND_SCREEN_ROI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -168,6 +168,11 @@ public:
|
||||
int m_nInstructionSet = 0;
|
||||
int m_nBitRate = 0; // H264 编码码率 (kbps), 0=自动
|
||||
|
||||
// 感兴趣区域 (ROI)
|
||||
RECT m_ROI = {0,0,0,0};
|
||||
int m_nScaleSendWidth = 0;
|
||||
int m_nScaleSendHeight = 0;
|
||||
|
||||
// 自定义光标相关
|
||||
DWORD m_dwLastCursorHash = 0; // 上次发送的光标哈希
|
||||
DWORD m_dwLastCursorSendTime = 0; // 上次发送光标的时间
|
||||
@@ -192,7 +197,8 @@ protected:
|
||||
int m_nVScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
|
||||
public:
|
||||
ScreenCapture(int n = 32, BYTE algo = ALGORITHM_DIFF, BOOL all = FALSE, int level = LEVEL_H264_SOFT) :
|
||||
ScreenCapture(int n = 32, BYTE algo = ALGORITHM_DIFF, BOOL all = FALSE, int level = LEVEL_H264_SOFT,
|
||||
RECT rc = {0}, BOOL switchScreen = TRUE) :
|
||||
m_ThreadPool(nullptr), m_FirstBuffer(nullptr), m_RectBuffer(nullptr),
|
||||
m_BitmapInfor_Full(nullptr), m_bAlgorithm(algo), m_SendQuality(100),
|
||||
m_ulFullWidth(0), m_ulFullHeight(0), m_bZoomed(false), m_wZoom(1), m_hZoom(1),
|
||||
@@ -202,6 +208,7 @@ public:
|
||||
m_bLastFrameWasScroll(false), m_nScrollDetectInterval(1), m_EncodeLevel(level)
|
||||
{
|
||||
SetAlgorithm(algo);
|
||||
m_ROI = rc;
|
||||
m_BitmapInfor_Send = nullptr;
|
||||
m_BmpZoomBuffer = nullptr;
|
||||
m_BmpZoomFirst = nullptr;
|
||||
@@ -212,7 +219,7 @@ public:
|
||||
m_nScreenCount = monitors.size();
|
||||
m_bEnableMultiScreen = all;
|
||||
if (all && !monitors.empty()) {
|
||||
int idx = index++ % (monitors.size()+1);
|
||||
int idx = (switchScreen ? index++ : index) % (monitors.size()+1);
|
||||
if (idx == 0) {
|
||||
m_iScreenX = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
m_iScreenY = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
@@ -899,7 +906,8 @@ public:
|
||||
bool shouldDetectScroll = !keyFrame && algo != ALGORITHM_H264 &&
|
||||
m_bEnableScrollDetect && m_bServerSupportsScroll && m_pScrollDetector &&
|
||||
!m_bLastFrameWasScroll && m_nScrollDetectInterval > 0 &&
|
||||
(m_FrameID % m_nScrollDetectInterval == 0);
|
||||
(m_FrameID % m_nScrollDetectInterval == 0) &&
|
||||
!m_nScaleSendWidth;
|
||||
|
||||
if (shouldDetectScroll) {
|
||||
int scrollAmount = m_pScrollDetector->DetectVerticalScroll(GetFirstBuffer(), nextData);
|
||||
@@ -1045,9 +1053,14 @@ public:
|
||||
// 鼠标位置转换:将服务端坐标(基于发送分辨率)转换为客户端坐标(原始分辨率)
|
||||
virtual void PointConversion(POINT& pt) const
|
||||
{
|
||||
// 0. ROI 偏移:ROI 坐标系 → scale 坐标系
|
||||
if (m_nScaleSendWidth) {
|
||||
pt.x += m_ROI.left;
|
||||
pt.y += m_ROI.top;
|
||||
}
|
||||
// 1. 处理图像缩小传输的坐标缩放(maxWidth 限制)
|
||||
int sendWidth = m_BitmapInfor_Send->bmiHeader.biWidth;
|
||||
int sendHeight = m_BitmapInfor_Send->bmiHeader.biHeight;
|
||||
int sendWidth = m_nScaleSendWidth ? m_nScaleSendWidth : (int)m_BitmapInfor_Send->bmiHeader.biWidth;
|
||||
int sendHeight = m_nScaleSendHeight ? m_nScaleSendHeight : (int)m_BitmapInfor_Send->bmiHeader.biHeight;
|
||||
if (sendWidth != m_ulFullWidth || sendHeight != m_ulFullHeight) {
|
||||
pt.x = (LONG)(pt.x * (double)m_ulFullWidth / sendWidth + 0.5);
|
||||
pt.y = (LONG)(pt.y * (double)m_ulFullHeight / sendHeight + 0.5);
|
||||
@@ -1074,12 +1087,17 @@ public:
|
||||
pt.y = (LONG)(pt.y / m_hZoom);
|
||||
}
|
||||
// 1'. full → send 缩放(位图下采样传输时)
|
||||
int sendWidth = m_BitmapInfor_Send->bmiHeader.biWidth;
|
||||
int sendHeight = m_BitmapInfor_Send->bmiHeader.biHeight;
|
||||
int sendWidth = m_nScaleSendWidth ? m_nScaleSendWidth : (int)m_BitmapInfor_Send->bmiHeader.biWidth;
|
||||
int sendHeight = m_nScaleSendHeight ? m_nScaleSendHeight : (int)m_BitmapInfor_Send->bmiHeader.biHeight;
|
||||
if (sendWidth != (int)m_ulFullWidth || sendHeight != (int)m_ulFullHeight) {
|
||||
pt.x = (LONG)((double)pt.x * sendWidth / m_ulFullWidth + 0.5);
|
||||
pt.y = (LONG)((double)pt.y * sendHeight / m_ulFullHeight + 0.5);
|
||||
}
|
||||
// 0'. scale 坐标系 → ROI 坐标系
|
||||
if (m_nScaleSendWidth) {
|
||||
pt.x -= m_ROI.left;
|
||||
pt.y -= m_ROI.top;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取位图结构信息
|
||||
@@ -1164,11 +1182,25 @@ public: // 纯虚接口
|
||||
// 获取下一帧屏幕
|
||||
virtual LPBYTE ScanNextScreen() = 0;
|
||||
|
||||
// ROI crop:从 src(scale 后缓冲)裁剪到 target;src==target 时 in-place 安全
|
||||
LPBYTE applyROICrop(LPBYTE target, LPBYTE src, int scaledW, int scaledH)
|
||||
{
|
||||
int rw = m_BitmapInfor_Send->bmiHeader.biWidth, rh = m_BitmapInfor_Send->bmiHeader.biHeight;
|
||||
for (int row = 0; row < rh; row++)
|
||||
memmove(target + row * rw * 4, src + ((scaledH - m_ROI.bottom + row) * scaledW + m_ROI.left) * 4, rw * 4);
|
||||
return target;
|
||||
}
|
||||
|
||||
virtual LPBYTE scaleBitmap(LPBYTE target, LPBYTE bitmap)
|
||||
{
|
||||
if (m_ulFullWidth == m_BitmapInfor_Send->bmiHeader.biWidth && m_ulFullHeight == m_BitmapInfor_Send->bmiHeader.biHeight)
|
||||
return bitmap;
|
||||
return ScaleBitmap(target, (uint8_t*)bitmap, m_ulFullWidth, m_ulFullHeight, m_BitmapInfor_Send->bmiHeader.biWidth,
|
||||
m_BitmapInfor_Send->bmiHeader.biHeight, m_nInstructionSet);
|
||||
int scaledW = m_nScaleSendWidth ? m_nScaleSendWidth : (int)m_BitmapInfor_Send->bmiHeader.biWidth;
|
||||
int scaledH = m_nScaleSendHeight ? m_nScaleSendHeight : (int)m_BitmapInfor_Send->bmiHeader.biHeight;
|
||||
LPBYTE src = bitmap;
|
||||
if ((ULONG)scaledW != m_ulFullWidth || (ULONG)scaledH != m_ulFullHeight)
|
||||
src = ScaleBitmap(target, (uint8_t*)bitmap, m_ulFullWidth, m_ulFullHeight, scaledW, scaledH, m_nInstructionSet);
|
||||
if (m_nScaleSendWidth) {
|
||||
src = applyROICrop(target, src, scaledW, scaledH);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user