2025-03-13 23:34:33 +08:00
|
|
|
|
#pragma once
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
#include "CursorInfo.h"
|
|
|
|
|
|
#include "../common/commands.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_GOP 0x7FFFFFFF
|
|
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
#include <thread>
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
#include <condition_variable>
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
#include <future>
|
2025-03-30 18:03:01 +08:00
|
|
|
|
#include "X264Encoder.h"
|
2025-03-13 23:34:33 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
class ThreadPool
|
|
|
|
|
|
{
|
2025-03-13 23:34:33 +08:00
|
|
|
|
public:
|
2025-10-15 04:32:59 +08:00
|
|
|
|
// <20><><EFBFBD>캯<EFBFBD><ECBAAF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̶<EFBFBD><CCB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>
|
|
|
|
|
|
ThreadPool(size_t numThreads) : stop(false)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (size_t i = 0; i < numThreads; ++i) {
|
|
|
|
|
|
workers.emplace_back([this] {
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
std::function<void()> task;
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(this->queueMutex);
|
|
|
|
|
|
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
|
|
|
|
|
|
if (this->stop && this->tasks.empty()) return;
|
|
|
|
|
|
task = std::move(this->tasks.front());
|
|
|
|
|
|
this->tasks.pop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
task();
|
|
|
|
|
|
} catch (...) {
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>쳣
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̳߳<DFB3>
|
|
|
|
|
|
~ThreadPool()
|
|
|
|
|
|
{
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(queueMutex);
|
|
|
|
|
|
stop = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
condition.notify_all();
|
|
|
|
|
|
for (std::thread& worker : workers)
|
|
|
|
|
|
worker.join();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ύ
|
|
|
|
|
|
template<typename F>
|
|
|
|
|
|
auto enqueue(F&& f) -> std::future<decltype(f())>
|
|
|
|
|
|
{
|
|
|
|
|
|
using ReturnType = decltype(f());
|
|
|
|
|
|
auto task = std::make_shared<std::packaged_task<ReturnType()>>(std::forward<F>(f));
|
|
|
|
|
|
std::future<ReturnType> res = task->get_future();
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(queueMutex);
|
|
|
|
|
|
tasks.emplace([task]() {
|
|
|
|
|
|
(*task)();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
condition.notify_one();
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void waitAll()
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(queueMutex);
|
|
|
|
|
|
condition.wait(lock, [this] { return tasks.empty(); });
|
|
|
|
|
|
}
|
2025-03-13 23:34:33 +08:00
|
|
|
|
|
|
|
|
|
|
private:
|
2025-10-15 04:32:59 +08:00
|
|
|
|
std::vector<std::thread> workers;
|
|
|
|
|
|
std::queue<std::function<void()>> tasks;
|
2025-03-13 23:34:33 +08:00
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
std::mutex queueMutex;
|
|
|
|
|
|
std::condition_variable condition;
|
|
|
|
|
|
std::atomic<bool> stop;
|
2025-03-13 23:34:33 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class ScreenCapture
|
|
|
|
|
|
{
|
2025-08-02 23:41:02 +08:00
|
|
|
|
private:
|
2025-10-15 04:32:59 +08:00
|
|
|
|
static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<MONITORINFOEX>* monitors = reinterpret_cast<std::vector<MONITORINFOEX>*>(dwData);
|
|
|
|
|
|
|
|
|
|
|
|
MONITORINFOEX mi;
|
|
|
|
|
|
mi.cbSize = sizeof(MONITORINFOEX);
|
|
|
|
|
|
if (GetMonitorInfo(hMonitor, &mi)) {
|
|
|
|
|
|
monitors->push_back(mi); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>Ϣ
|
|
|
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
}
|
|
|
|
|
|
std::vector<MONITORINFOEX> GetAllMonitors()
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<MONITORINFOEX> monitors;
|
|
|
|
|
|
EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, (LPARAM)&monitors);
|
|
|
|
|
|
return monitors;
|
|
|
|
|
|
}
|
2025-03-13 23:34:33 +08:00
|
|
|
|
public:
|
2025-10-15 04:32:59 +08:00
|
|
|
|
ThreadPool* m_ThreadPool; // <20>̳߳<DFB3>
|
|
|
|
|
|
BYTE* m_FirstBuffer; // <20><>һ֡<D2BB><D6A1><EFBFBD><EFBFBD>
|
|
|
|
|
|
BYTE* m_RectBuffer; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
LPBYTE* m_BlockBuffers; // <20>ֿ黺<D6BF><E9BBBA>
|
|
|
|
|
|
ULONG* m_BlockSizes; // <20>ֿ<EFBFBD><D6BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
int m_BlockNum; // <20>ֿ<EFBFBD><D6BF><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
int m_SendQuality; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
LPBITMAPINFO m_BitmapInfor_Full; // BMP<4D><50>Ϣ
|
|
|
|
|
|
BYTE m_bAlgorithm; // <20><>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD>㷨
|
|
|
|
|
|
|
|
|
|
|
|
int m_iScreenX; // <20><>ʼx<CABC><78><EFBFBD><EFBFBD>
|
|
|
|
|
|
int m_iScreenY; // <20><>ʼy<CABC><79><EFBFBD><EFBFBD>
|
|
|
|
|
|
ULONG m_ulFullWidth; // <20><>Ļ<EFBFBD><C4BB>
|
|
|
|
|
|
ULONG m_ulFullHeight; // <20><>Ļ<EFBFBD><C4BB>
|
|
|
|
|
|
bool m_bZoomed; // <20><>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
double m_wZoom; // <20><>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD>
|
|
|
|
|
|
double m_hZoom; // <20><>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
int m_biBitCount; // ÿ<><C3BF><EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
int m_FrameID; // ֡<><D6A1><EFBFBD><EFBFBD>
|
|
|
|
|
|
int m_GOP; // <20>ؼ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>
|
|
|
|
|
|
bool m_SendKeyFrame; // <20><><EFBFBD>ؼ<CDB9>֡
|
|
|
|
|
|
CX264Encoder *m_encoder; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
ScreenCapture(int n = 32, BYTE algo = ALGORITHM_DIFF, BOOL all = FALSE) :
|
|
|
|
|
|
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),
|
|
|
|
|
|
m_FrameID(0), m_GOP(DEFAULT_GOP), m_iScreenX(0), m_iScreenY(0), m_biBitCount(n),
|
|
|
|
|
|
m_SendKeyFrame(false), m_encoder(nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
m_BlockNum = 8;
|
|
|
|
|
|
m_ThreadPool = new ThreadPool(m_BlockNum);
|
|
|
|
|
|
static auto monitors = GetAllMonitors();
|
|
|
|
|
|
static int index = 0;
|
|
|
|
|
|
if (all && !monitors.empty()) {
|
|
|
|
|
|
int idx = index++ % (monitors.size()+1);
|
|
|
|
|
|
if (idx == 0) {
|
|
|
|
|
|
m_iScreenX = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
|
|
|
|
|
m_iScreenY = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
|
|
|
|
|
m_ulFullWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
|
|
|
|
|
m_ulFullHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
RECT rt = monitors[idx-1].rcMonitor;
|
|
|
|
|
|
m_iScreenX = rt.left;
|
|
|
|
|
|
m_iScreenY = rt.top;
|
|
|
|
|
|
m_ulFullWidth = rt.right - rt.left;
|
|
|
|
|
|
m_ulFullHeight = rt.bottom - rt.top;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
//::GetSystemMetrics(SM_CXSCREEN/SM_CYSCREEN)<29><>ȡ<EFBFBD><C8A1>Ļ<EFBFBD><C4BB>С<EFBFBD><D0A1>
|
|
|
|
|
|
//<2F><><EFBFBD>統<EFBFBD><E7B5B1>Ļ<EFBFBD><C4BB>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>Ϊ125%ʱ<><CAB1><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB>С<EFBFBD><D0A1>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>1.25<EFBFBD>Ŷ<EFBFBD>
|
|
|
|
|
|
DEVMODE devmode;
|
|
|
|
|
|
memset(&devmode, 0, sizeof(devmode));
|
|
|
|
|
|
devmode.dmSize = sizeof(DEVMODE);
|
|
|
|
|
|
devmode.dmDriverExtra = 0;
|
|
|
|
|
|
BOOL Isgetdisplay = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devmode);
|
|
|
|
|
|
m_ulFullWidth = devmode.dmPelsWidth;
|
|
|
|
|
|
m_ulFullHeight = devmode.dmPelsHeight;
|
|
|
|
|
|
int w = GetSystemMetrics(SM_CXSCREEN), h = GetSystemMetrics(SM_CYSCREEN);
|
|
|
|
|
|
m_bZoomed = (w != m_ulFullWidth) || (h != m_ulFullHeight);
|
|
|
|
|
|
m_wZoom = double(m_ulFullWidth) / w, m_hZoom = double(m_ulFullHeight) / h;
|
|
|
|
|
|
Mprintf("=> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD><C5B1><EFBFBD>: %.2f, %.2f\t<EFBFBD>ֱ<EFBFBD><EFBFBD>ʣ<EFBFBD>%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];
|
|
|
|
|
|
for (int blockY = 0; blockY < m_BlockNum; ++blockY) {
|
|
|
|
|
|
m_BlockBuffers[blockY] = new BYTE[m_ulFullWidth * m_ulFullHeight * 4 * 2 / m_BlockNum + 12];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
virtual ~ScreenCapture()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_BitmapInfor_Full != NULL) {
|
|
|
|
|
|
delete[](char*)m_BitmapInfor_Full;
|
|
|
|
|
|
m_BitmapInfor_Full = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
SAFE_DELETE_ARRAY(m_RectBuffer);
|
|
|
|
|
|
|
|
|
|
|
|
for (int blockY = 0; blockY < m_BlockNum; ++blockY) {
|
|
|
|
|
|
SAFE_DELETE_ARRAY(m_BlockBuffers[blockY]);
|
|
|
|
|
|
}
|
|
|
|
|
|
SAFE_DELETE_ARRAY(m_BlockBuffers);
|
|
|
|
|
|
SAFE_DELETE_ARRAY(m_BlockSizes);
|
|
|
|
|
|
|
|
|
|
|
|
SAFE_DELETE(m_ThreadPool);
|
|
|
|
|
|
SAFE_DELETE(m_encoder);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual int SendQuality(int quality)
|
|
|
|
|
|
{
|
|
|
|
|
|
int old = m_SendQuality;
|
|
|
|
|
|
m_SendQuality = quality;
|
|
|
|
|
|
return old;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual RECT GetScreenRect() const
|
|
|
|
|
|
{
|
|
|
|
|
|
RECT rect;
|
|
|
|
|
|
rect.left = m_iScreenX;
|
|
|
|
|
|
rect.top = m_iScreenY;
|
|
|
|
|
|
rect.right = m_ulFullWidth;
|
|
|
|
|
|
rect.bottom = m_ulFullHeight;
|
|
|
|
|
|
return rect;
|
|
|
|
|
|
}
|
2025-05-31 15:49:40 +08:00
|
|
|
|
|
2025-03-13 23:34:33 +08:00
|
|
|
|
public:
|
2025-10-15 04:32:59 +08:00
|
|
|
|
//*************************************** ͼ<><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㷨<EFBFBD><E3B7A8><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD> *************************************
|
|
|
|
|
|
virtual ULONG CompareBitmap(LPBYTE CompareSourData, LPBYTE CompareDestData, LPBYTE szBuffer,
|
|
|
|
|
|
DWORD ulCompareLength, BYTE algo, int startPostion = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// Windows<77>涨һ<E6B6A8><D2BB>ɨ<EFBFBD><C9A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>DWORD<52>Ƚ<EFBFBD>
|
|
|
|
|
|
LPDWORD p1 = (LPDWORD)CompareDestData, p2 = (LPDWORD)CompareSourData;
|
|
|
|
|
|
LPBYTE p = szBuffer;
|
|
|
|
|
|
ULONG channel = algo == ALGORITHM_GRAY ? 1 : 4;
|
|
|
|
|
|
ULONG ratio = algo == ALGORITHM_GRAY ? 4 : 1;
|
|
|
|
|
|
for (ULONG i = 0; i < ulCompareLength; i += 4, ++p1, ++p2) {
|
|
|
|
|
|
if (*p1 == *p2)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
ULONG index = i;
|
|
|
|
|
|
LPDWORD pos1 = p1++, pos2 = p2++;
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ͬ
|
|
|
|
|
|
for (i += 4; i < ulCompareLength && *p1 != *p2; i += 4, ++p1, ++p2);
|
|
|
|
|
|
ULONG ulCount = i - index;
|
|
|
|
|
|
memcpy(pos1, pos2, ulCount); // <20><><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
*(LPDWORD)(p) = index + startPostion;
|
|
|
|
|
|
*(LPDWORD)(p + sizeof(ULONG)) = ulCount / ratio;
|
|
|
|
|
|
p += 2 * sizeof(ULONG);
|
|
|
|
|
|
if (channel != 1) {
|
|
|
|
|
|
memcpy(p, pos2, ulCount);
|
|
|
|
|
|
p += ulCount;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
for (LPBYTE end = p + ulCount / ratio; p < end; p += channel, ++pos2) {
|
|
|
|
|
|
LPBYTE src = (LPBYTE)pos2;
|
|
|
|
|
|
*p = (306 * src[2] + 601 * src[0] + 117 * src[1]) >> 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return p - szBuffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*************************************** ͼ<><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㷨<EFBFBD><E3B7A8><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD> *************************************
|
|
|
|
|
|
ULONG MultiCompareBitmap(LPBYTE srcData, LPBYTE dstData, LPBYTE szBuffer,
|
|
|
|
|
|
DWORD ulCompareLength, BYTE algo)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
int N = m_BlockNum;
|
|
|
|
|
|
ULONG blockLength = ulCompareLength / N; // ÿ<><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>
|
|
|
|
|
|
ULONG remainingLength = ulCompareLength % N; // ʣ<><CAA3><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::future<ULONG>> futures;
|
|
|
|
|
|
for (int blockY = 0; blockY < N; ++blockY) {
|
|
|
|
|
|
// <20><><EFBFBD>㵱ǰ<E3B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD>
|
|
|
|
|
|
ULONG currentBlockLength = blockLength + (blockY == N - 1 ? remainingLength : 0);
|
|
|
|
|
|
// <20><><EFBFBD>㵱ǰ<E3B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ<CABC><CEBB>
|
|
|
|
|
|
ULONG startPosition = blockY * blockLength;
|
|
|
|
|
|
|
|
|
|
|
|
futures.emplace_back(m_ThreadPool->enqueue([=]() -> ULONG {
|
|
|
|
|
|
LPBYTE srcBlock = srcData + startPosition;
|
|
|
|
|
|
LPBYTE dstBlock = dstData + startPosition;
|
|
|
|
|
|
LPBYTE blockBuffer = m_BlockBuffers[blockY];
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><F1B2A2B7>رȶ<D8B1><C8B6><EFBFBD><EFBFBD>ݴ<EFBFBD>С
|
|
|
|
|
|
return m_BlockSizes[blockY] = CompareBitmap(srcBlock, dstBlock, blockBuffer, currentBlockLength, algo, startPosition);
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɲ<EFBFBD><C9B2><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
for (auto& future : futures) {
|
|
|
|
|
|
future.get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD>п<EFBFBD><D0BF>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2> szBuffer
|
|
|
|
|
|
ULONG offset = 0;
|
|
|
|
|
|
for (int blockY = 0; blockY < N; ++blockY) {
|
|
|
|
|
|
memcpy(szBuffer + offset, m_BlockBuffers[blockY], m_BlockSizes[blockY]);
|
|
|
|
|
|
offset += m_BlockSizes[blockY];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return offset; // <20><><EFBFBD>ػ<EFBFBD><D8BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD>С
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual int GetFrameID() const {
|
|
|
|
|
|
return m_FrameID;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual LPBYTE GetFirstBuffer() const {
|
|
|
|
|
|
return m_FirstBuffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual int GetBMPSize() const {
|
|
|
|
|
|
assert(m_BitmapInfor_Full);
|
|
|
|
|
|
return m_BitmapInfor_Full->bmiHeader.biSizeImage;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ToGray(LPBYTE dst, LPBYTE src, int biSizeImage)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (ULONG i = 0; i < biSizeImage; i += 4, dst += 4, src += 4) {
|
|
|
|
|
|
dst[0] = dst[1] = dst[2] = (306 * src[2] + 601 * src[0] + 117 * src[1]) >> 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual LPBITMAPINFO ConstructBitmapInfo(int biBitCount, int biWidth, int biHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
assert(biBitCount == 32);
|
|
|
|
|
|
BITMAPINFO* bmpInfo = (BITMAPINFO*) new BYTE[sizeof(BITMAPINFO)]();
|
|
|
|
|
|
bmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
|
|
bmpInfo->bmiHeader.biWidth = biWidth;
|
|
|
|
|
|
bmpInfo->bmiHeader.biHeight = biHeight;
|
|
|
|
|
|
bmpInfo->bmiHeader.biPlanes = 1;
|
|
|
|
|
|
bmpInfo->bmiHeader.biBitCount = 32;
|
|
|
|
|
|
bmpInfo->bmiHeader.biCompression = BI_RGB;
|
|
|
|
|
|
bmpInfo->bmiHeader.biSizeImage = biWidth * biHeight * 4;
|
|
|
|
|
|
return bmpInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20>㷨+<2B><><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
virtual LPBYTE GetNextScreenData(ULONG* ulNextSendLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
BYTE algo = m_bAlgorithm;
|
|
|
|
|
|
int frameID = m_FrameID + 1;
|
|
|
|
|
|
bool keyFrame = (frameID % m_GOP == 0);
|
|
|
|
|
|
m_RectBuffer[0] = keyFrame ? TOKEN_KEYFRAME : TOKEN_NEXTSCREEN;
|
|
|
|
|
|
LPBYTE data = m_RectBuffer + 1;
|
|
|
|
|
|
// д<><D0B4>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㷨
|
|
|
|
|
|
memcpy(data, (LPBYTE)&algo, sizeof(BYTE));
|
|
|
|
|
|
|
|
|
|
|
|
// д<><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
|
|
|
|
|
|
POINT CursorPos;
|
|
|
|
|
|
GetCursorPos(&CursorPos);
|
|
|
|
|
|
CursorPos.x /= m_wZoom;
|
|
|
|
|
|
CursorPos.y /= m_hZoom;
|
|
|
|
|
|
memcpy(data + sizeof(BYTE), (LPBYTE)&CursorPos, sizeof(POINT));
|
|
|
|
|
|
|
|
|
|
|
|
// д<>뵱ǰ<EBB5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
static CCursorInfo m_CursorInfor;
|
|
|
|
|
|
BYTE bCursorIndex = m_CursorInfor.getCurrentCursorIndex();
|
|
|
|
|
|
memcpy(data + sizeof(BYTE) + sizeof(POINT), &bCursorIndex, sizeof(BYTE));
|
|
|
|
|
|
ULONG offset = sizeof(BYTE) + sizeof(POINT) + sizeof(BYTE);
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ֶ<EFBFBD>ɨ<EFBFBD><C9A8>ȫ<EFBFBD><C8AB>Ļ <20><><EFBFBD>µ<EFBFBD>λͼ<CEBB><CDBC><EFBFBD>뵽m_hDiffMemDC<44><43>
|
|
|
|
|
|
LPBYTE nextData = ScanNextScreen();
|
|
|
|
|
|
if (nullptr == nextData) {
|
|
|
|
|
|
// ɨ<><C9A8><EFBFBD><EFBFBD>һ֡ʧ<D6A1><CAA7>Ҳ<EFBFBD><D2B2>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><CDB9><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>
|
|
|
|
|
|
*ulNextSendLength = 1 + offset;
|
|
|
|
|
|
return m_RectBuffer;
|
|
|
|
|
|
}
|
2025-03-13 23:34:33 +08:00
|
|
|
|
|
|
|
|
|
|
#if SCREENYSPY_IMPROVE
|
2025-10-15 04:32:59 +08:00
|
|
|
|
memcpy(data + offset, &++m_FrameID, sizeof(int));
|
|
|
|
|
|
offset += sizeof(int);
|
2025-03-13 23:34:33 +08:00
|
|
|
|
#if SCREENSPY_WRITE
|
2025-10-15 04:32:59 +08:00
|
|
|
|
WriteBitmap(m_BitmapInfor_Full, nextData, "GHOST", m_FrameID);
|
2025-03-13 23:34:33 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
#else
|
2025-10-15 04:32:59 +08:00
|
|
|
|
m_FrameID++;
|
2025-03-13 23:34:33 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (keyFrame) {
|
|
|
|
|
|
switch (algo) {
|
|
|
|
|
|
case ALGORITHM_DIFF: {
|
|
|
|
|
|
*ulNextSendLength = 1 + offset + m_BitmapInfor_Full->bmiHeader.biSizeImage;
|
|
|
|
|
|
memcpy(data + offset, nextData, m_BitmapInfor_Full->bmiHeader.biSizeImage);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case ALGORITHM_GRAY: {
|
|
|
|
|
|
*ulNextSendLength = 1 + offset + m_BitmapInfor_Full->bmiHeader.biSizeImage;
|
|
|
|
|
|
ToGray(data + offset, nextData, m_BitmapInfor_Full->bmiHeader.biSizeImage);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case ALGORITHM_H264: {
|
|
|
|
|
|
uint8_t* encoded_data = nullptr;
|
|
|
|
|
|
uint32_t encoded_size = 0;
|
|
|
|
|
|
int err = m_encoder->encode(nextData, 32, 4*m_BitmapInfor_Full->bmiHeader.biWidth,
|
|
|
|
|
|
m_ulFullWidth, m_ulFullHeight, &encoded_data, &encoded_size);
|
|
|
|
|
|
if (err) {
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
*ulNextSendLength = 1 + offset + encoded_size;
|
|
|
|
|
|
memcpy(data + offset, encoded_data, encoded_size);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
memcpy(GetFirstBuffer(), nextData, m_BitmapInfor_Full->bmiHeader.biSizeImage);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
switch (algo) {
|
|
|
|
|
|
case ALGORITHM_DIFF:
|
|
|
|
|
|
case ALGORITHM_GRAY: {
|
|
|
|
|
|
*ulNextSendLength = 1 + offset + MultiCompareBitmap(nextData, GetFirstBuffer(), data + offset, GetBMPSize(), algo);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case ALGORITHM_H264: {
|
|
|
|
|
|
uint8_t* encoded_data = nullptr;
|
|
|
|
|
|
uint32_t encoded_size = 0;
|
|
|
|
|
|
int err = m_encoder->encode(nextData, 32, 4 * m_BitmapInfor_Full->bmiHeader.biWidth,
|
|
|
|
|
|
m_ulFullWidth, m_ulFullHeight, &encoded_data, &encoded_size);
|
|
|
|
|
|
if (err) {
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
*ulNextSendLength = 1 + offset + encoded_size;
|
|
|
|
|
|
memcpy(data + offset, encoded_data, encoded_size);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return m_RectBuffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD>㷨
|
|
|
|
|
|
virtual BYTE SetAlgorithm(int algo)
|
|
|
|
|
|
{
|
|
|
|
|
|
BYTE oldAlgo = m_bAlgorithm;
|
|
|
|
|
|
m_bAlgorithm = algo;
|
|
|
|
|
|
return oldAlgo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>ת<EFBFBD><D7AA>
|
|
|
|
|
|
virtual void PointConversion(POINT& pt) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_bZoomed) {
|
|
|
|
|
|
pt.x *= m_wZoom;
|
|
|
|
|
|
pt.y *= m_hZoom;
|
|
|
|
|
|
}
|
|
|
|
|
|
pt.x += m_iScreenX;
|
|
|
|
|
|
pt.y += m_iScreenY;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>ȡλͼ<CEBB>ṹ<EFBFBD><E1B9B9>Ϣ
|
|
|
|
|
|
virtual const LPBITMAPINFO& GetBIData() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_BitmapInfor_Full;
|
|
|
|
|
|
}
|
2025-03-13 23:34:33 +08:00
|
|
|
|
|
|
|
|
|
|
public: // <20><><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
// <20><>ȡ<EFBFBD><C8A1>һ֡<D2BB><D6A1>Ļ
|
|
|
|
|
|
virtual LPBYTE GetFirstScreenData(ULONG* ulFirstScreenLength) = 0;
|
2025-03-13 23:34:33 +08:00
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
// <20><>ȡ<EFBFBD><C8A1>һ֡<D2BB><D6A1>Ļ
|
|
|
|
|
|
virtual LPBYTE ScanNextScreen() = 0;
|
2025-03-13 23:34:33 +08:00
|
|
|
|
};
|