Merge pull request #66 from yuanyuanxiang/dev

Screen image transmission uses H.264 compression #65
This commit is contained in:
yuanyuanxiang
2025-03-30 19:52:10 +08:00
committed by GitHub
152 changed files with 44123 additions and 62 deletions

Binary file not shown.

View File

@@ -781,7 +781,8 @@ VOID CMy2015RemoteDlg::OnOnlineWindowManager()
VOID CMy2015RemoteDlg::OnOnlineDesktopManager()
{
int n = ((CMy2015RemoteApp*)AfxGetApp())->m_iniFile.GetInt("settings", "DXGI");
BYTE bToken[2] = { COMMAND_SCREEN_SPY, n };
CString algo = ((CMy2015RemoteApp*)AfxGetApp())->m_iniFile.GetStr("settings", "ScreenCompress", "");
BYTE bToken[32] = { COMMAND_SCREEN_SPY, n, algo.IsEmpty() ? ALGORITHM_DIFF : atoi(algo.GetString())};
SendSelectedCommand(bToken, sizeof(bToken));
}
@@ -854,7 +855,8 @@ VOID CMy2015RemoteDlg::SendSelectedCommand(PBYTE szBuffer, ULONG ulLength)
//<2F><><EFBFBD><EFBFBD>Bar
VOID CMy2015RemoteDlg::OnAbout()
{
MessageBox("Copyleft (c) FTU 2025", "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
MessageBox("Copyleft (c) FTU 2025" + CString("\n<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: ") + __DATE__ +
CString(sizeof(void*)==8 ? " (x64)" : " (x86)"), "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
}
//<2F><><EFBFBD><EFBFBD>Menu

View File

@@ -30,6 +30,22 @@ IMPLEMENT_DYNAMIC(CScreenSpyDlg, CDialog)
CScreenSpyDlg::CScreenSpyDlg(CWnd* Parent, IOCPServer* IOCPServer, CONTEXT_OBJECT* ContextObject)
: CDialog(CScreenSpyDlg::IDD, Parent)
{
#ifndef _WIN64
m_pCodec = nullptr;
m_pCodecContext = nullptr;
memset(&m_AVPacket, 0, sizeof(AVPacket));
memset(&m_AVFrame, 0, sizeof(AVFrame));
//创建解码器.
bool succeed = false;
m_pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (m_pCodec) {
m_pCodecContext = avcodec_alloc_context3(m_pCodec);
if (m_pCodecContext) {
succeed = (0 == avcodec_open2(m_pCodecContext, m_pCodec, 0));
}
}
#endif
m_FrameID = 0;
ImmDisableIME(0);// 禁用输入法
m_bFullScreen = FALSE;
@@ -86,6 +102,17 @@ CScreenSpyDlg::~CScreenSpyDlg()
{
m_BitmapData_Full = NULL;
}
#ifndef _WIN64
if (m_pCodecContext)
{
avcodec_free_context(&m_pCodecContext);
m_pCodecContext = 0;
}
m_pCodec = 0;
// AVFrame需要清除
av_frame_unref(&m_AVFrame);
#endif
}
void CScreenSpyDlg::DoDataExchange(CDataExchange* pDX)
@@ -187,10 +214,7 @@ VOID CScreenSpyDlg::OnReceiveComplete()
}
case TOKEN_NEXTSCREEN:
{
if (m_ContextObject->InDeCompressedBuffer.GetBYTE(1)==ALGORITHM_DIFF)
{
DrawNextScreenDiff(false);
}
DrawNextScreenDiff(false);
break;
}
case TOKEN_KEYFRAME: {
@@ -277,15 +301,52 @@ VOID CScreenSpyDlg::DrawNextScreenDiff(bool keyFrame)
LPBYTE dst = (LPBYTE)FirstScreenData, p = (LPBYTE)NextScreenData;
if (keyFrame)
{
if (m_BitmapInfor_Full->bmiHeader.biSizeImage == NextScreenLength)
memcpy(dst, p, m_BitmapInfor_Full->bmiHeader.biSizeImage);
switch (algorithm)
{
case ALGORITHM_DIFF: case ALGORITHM_GRAY: {
if (m_BitmapInfor_Full->bmiHeader.biSizeImage == NextScreenLength)
memcpy(dst, p, m_BitmapInfor_Full->bmiHeader.biSizeImage);
break;
}
case ALGORITHM_H264: {
break;
}
default:
break;
}
}
else if (0 != NextScreenLength) {
for (LPBYTE end = p + NextScreenLength; p < end; ) {
ULONG ulCount = *(LPDWORD(p + sizeof(ULONG)));
memcpy(dst + *(LPDWORD)p, p + 2 * sizeof(ULONG), ulCount);
switch (algorithm)
{
case ALGORITHM_DIFF: {
for (LPBYTE end = p + NextScreenLength; p < end; ) {
ULONG ulCount = *(LPDWORD(p + sizeof(ULONG)));
memcpy(dst + *(LPDWORD)p, p + 2 * sizeof(ULONG), ulCount);
p += 2 * sizeof(ULONG) + ulCount;
p += 2 * sizeof(ULONG) + ulCount;
}
break;
}
case ALGORITHM_GRAY: {
for (LPBYTE end = p + NextScreenLength; p < end; ) {
ULONG ulCount = *(LPDWORD(p + sizeof(ULONG)));
LPBYTE p1 = dst + *(LPDWORD)p, p2 = p + 2 * sizeof(ULONG);
for (int i = 0; i < ulCount; ++i, p1 += 4)
memset(p1, *p2++, sizeof(DWORD));
p += 2 * sizeof(ULONG) + ulCount;
}
break;
}
case ALGORITHM_H264: {
if (Decode((LPBYTE)NextScreenData, NextScreenLength))
{
bChange = TRUE;
}
break;
}
default:
break;
}
}
@@ -302,6 +363,51 @@ VOID CScreenSpyDlg::DrawNextScreenDiff(bool keyFrame)
}
bool CScreenSpyDlg::Decode(LPBYTE Buffer, int size) {
#ifndef _WIN64
// 解码数据.
av_init_packet(&m_AVPacket);
m_AVPacket.data = (uint8_t*)Buffer;
m_AVPacket.size = size;
int err = avcodec_send_packet(m_pCodecContext, &m_AVPacket);
if (!err)
{
err = avcodec_receive_frame(m_pCodecContext, &m_AVFrame);
if (err == AVERROR(EAGAIN)) {
Mprintf("avcodec_receive_frame error: EAGAIN\n");
return false;
}
// 解码数据前会清除m_AVFrame的内容.
if (!err)
{
LPVOID Image[2] = { 0 };
LPVOID CursorInfo[2] = { 0 };
//成功.
//I420 ---> ARGB.
//WaitForSingleObject(m_hMutex,INFINITE);
libyuv::I420ToARGB(
m_AVFrame.data[0], m_AVFrame.linesize[0],
m_AVFrame.data[1], m_AVFrame.linesize[1],
m_AVFrame.data[2], m_AVFrame.linesize[2],
(uint8_t*)m_BitmapData_Full,
m_BitmapInfor_Full->bmiHeader.biWidth*4,
m_BitmapInfor_Full->bmiHeader.biWidth,
m_BitmapInfor_Full->bmiHeader.biHeight);
return true;
}
Mprintf("avcodec_receive_frame failed with error: %d\n", err);
}
else {
Mprintf("avcodec_send_packet failed with error: %d\n", err);
}
#endif
return false;
}
void CScreenSpyDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
@@ -622,31 +728,25 @@ void CScreenSpyDlg::EnterFullScreen()
{
if (!m_bFullScreen)
{
//get current system resolution
int g_iCurScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int g_iCurScreenHeight = GetSystemMetrics(SM_CYSCREEN);
// 1. 获取屏幕分辨率
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
//for full screen while backplay
// 2. 记录当前窗口状态
GetWindowPlacement(&m_struOldWndpl);
CRect rectWholeDlg;//entire client(including title bar)
CRect rectClient;//client area(not including title bar)
CRect rectFullScreen;
GetWindowRect(&rectWholeDlg);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &rectClient);
ClientToScreen(&rectClient);
// 3. 修改窗口样式,移除标题栏、边框
LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_BORDER);
SetWindowLong(m_hWnd, GWL_STYLE, lStyle);
rectFullScreen.left = rectWholeDlg.left-rectClient.left;
rectFullScreen.top = rectWholeDlg.top-rectClient.top;
rectFullScreen.right = rectWholeDlg.right+g_iCurScreenWidth - rectClient.right;
rectFullScreen.bottom = rectWholeDlg.bottom+g_iCurScreenHeight - rectClient.bottom;
//enter into full screen;
WINDOWPLACEMENT struWndpl;
struWndpl.length = sizeof(WINDOWPLACEMENT);
struWndpl.flags = 0;
struWndpl.showCmd = SW_SHOWNORMAL;
struWndpl.rcNormalPosition = rectFullScreen;
SetWindowPlacement(&struWndpl);
// 4. 隐藏滚动条
ShowScrollBar(SB_BOTH, FALSE); // 隐藏水平和垂直滚动条
// 5. 重新调整窗口大小并更新
SetWindowPos(&CWnd::wndTop, 0, 0, screenWidth, screenHeight, SWP_NOZORDER | SWP_FRAMECHANGED);
// 6. 标记全屏模式
m_bFullScreen = true;
}
}
@@ -656,10 +756,24 @@ bool CScreenSpyDlg::LeaveFullScreen()
{
if (m_bFullScreen)
{
// 1. 恢复窗口样式
LONG lStyle = GetWindowLong(m_hWnd, GWL_STYLE);
lStyle |= (WS_CAPTION | WS_THICKFRAME | WS_BORDER);
SetWindowLong(m_hWnd, GWL_STYLE, lStyle);
// 2. 恢复窗口大小
SetWindowPlacement(&m_struOldWndpl);
CMenu *SysMenu = GetSystemMenu(FALSE);
SysMenu->CheckMenuItem(IDM_FULLSCREEN, MF_UNCHECKED); //菜单样式
SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
// 3. 显示滚动条
ShowScrollBar(SB_BOTH, TRUE); // 显示水平和垂直滚动条
// 4. 标记退出全屏
m_bFullScreen = false;
CMenu* SysMenu = GetSystemMenu(FALSE);
SysMenu->CheckMenuItem(IDM_FULLSCREEN, MF_UNCHECKED); //菜单样式
return true;
}
return false;

View File

@@ -2,6 +2,29 @@
#include "IOCPServer.h"
#include "..\..\client\CursorInfo.h"
extern "C"
{
#include "libavcodec\avcodec.h"
#include "libavutil\avutil.h"
#include "libyuv\libyuv.h"
}
#ifndef _WIN64
// https://github.com/Terodee/FFMpeg-windows-static-build/releases
#pragma comment(lib,"libavcodec.lib")
#pragma comment(lib,"libavutil.lib")
#pragma comment(lib,"libswresample.lib")
#pragma comment(lib,"libyuv/libyuv.lib")
#else
// ȱ<><C8B1>`FFMPEG`<60><>̬<EFBFBD><EFBFBD><E2A3AC>ʱ<EFBFBD>޷<EFBFBD><DEB7><EFBFBD><EFBFBD><EFBFBD>64λ<34><CEBB><EFBFBD><EFBFBD>!
#endif
#pragma comment(lib, "Mfplat.lib")
#pragma comment(lib, "Mfuuid.lib")
#pragma comment(lib, "Bcrypt.lib")
#pragma comment(lib, "Strmiids.lib")
// CScreenSpyDlg <20>Ի<EFBFBD><D4BB><EFBFBD>
class CScreenSpyDlg : public CDialog
@@ -55,6 +78,14 @@ public:
WINDOWPLACEMENT m_struOldWndpl;
#ifndef _WIN64
AVCodec* m_pCodec;
AVCodecContext* m_pCodecContext;
AVPacket m_AVPacket;
AVFrame m_AVFrame;
#endif
bool Decode(LPBYTE Buffer, int size);
void EnterFullScreen();
bool LeaveFullScreen();

View File

@@ -5,6 +5,7 @@
#include "2015Remote.h"
#include "SettingDlg.h"
#include "afxdialogex.h"
#include "client/CursorInfo.h"
// CSettingDlg <20>Ի<EFBFBD><D4BB><EFBFBD>
@@ -16,6 +17,7 @@ CSettingDlg::CSettingDlg(CWnd* pParent)
, m_nListenPort(0)
, m_nMax_Connect(0)
, m_sScreenCapture(_T("GDI"))
, m_sScreenCompress(_T("<EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"))
{
}
@@ -32,6 +34,8 @@ void CSettingDlg::DoDataExchange(CDataExchange* pDX)
DDX_Control(pDX, IDC_COMBO_SCREEN_CAPTURE, m_ComboScreenCapture);
DDX_CBString(pDX, IDC_COMBO_SCREEN_CAPTURE, m_sScreenCapture);
DDV_MaxChars(pDX, m_sScreenCapture, 32);
DDX_Control(pDX, IDC_COMBO_SCREEN_COMPRESS, m_ComboScreenCompress);
DDX_CBString(pDX, IDC_COMBO_SCREEN_COMPRESS, m_sScreenCompress);
}
BEGIN_MESSAGE_MAP(CSettingDlg, CDialog)
@@ -54,9 +58,30 @@ BOOL CSettingDlg::OnInitDialog()
int DXGI = ((CMy2015RemoteApp*)AfxGetApp())->m_iniFile.GetInt("settings", "DXGI");
CString algo = ((CMy2015RemoteApp*)AfxGetApp())->m_iniFile.GetStr("settings", "ScreenCompress", "");
m_nListenPort = (nPort<=0 || nPort>65535) ? 6543 : nPort;
m_nMax_Connect = nMaxConnection<=0 ? 10000 : nMaxConnection;
int n = algo.IsEmpty() ? ALGORITHM_DIFF : atoi(algo.GetString());
switch (n)
{
case ALGORITHM_GRAY:
m_sScreenCompress = "<EFBFBD>Ҷ<EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
break;
case ALGORITHM_DIFF:
m_sScreenCompress = "<EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
break;
case ALGORITHM_H264:
m_sScreenCompress = "H264ѹ<EFBFBD><EFBFBD><EFBFBD>";
break;
default:
break;
}
m_ComboScreenCompress.InsertString(ALGORITHM_GRAY, "<EFBFBD>Ҷ<EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
m_ComboScreenCompress.InsertString(ALGORITHM_DIFF, "<EFBFBD><EFBFBD>Ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
m_ComboScreenCompress.InsertString(ALGORITHM_H264, "H264ѹ<EFBFBD><EFBFBD><EFBFBD>");
m_ComboScreenCapture.InsertString(0, "GDI");
m_ComboScreenCapture.InsertString(1, "DXGI");
m_sScreenCapture = DXGI ? "DXGI" : "GDI";
@@ -77,6 +102,9 @@ void CSettingDlg::OnBnClickedButtonSettingapply()
int n = m_ComboScreenCapture.GetCurSel();
((CMy2015RemoteApp*)AfxGetApp())->m_iniFile.SetInt("settings", "DXGI", n);
n = m_ComboScreenCompress.GetCurSel();
((CMy2015RemoteApp*)AfxGetApp())->m_iniFile.SetInt("settings", "ScreenCompress", n);
m_ApplyButton.EnableWindow(FALSE);
m_ApplyButton.ShowWindow(SW_HIDE);
}

View File

@@ -30,4 +30,6 @@ public:
virtual void OnOK();
CComboBox m_ComboScreenCapture;
CString m_sScreenCapture;
CComboBox m_ComboScreenCompress;
CString m_sScreenCompress;
};

Binary file not shown.