Merge pull request #66 from yuanyuanxiang/dev
Screen image transmission uses H.264 compression #65
This commit is contained in:
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -30,4 +30,6 @@ public:
|
||||
virtual void OnOK();
|
||||
CComboBox m_ComboScreenCapture;
|
||||
CString m_sScreenCapture;
|
||||
CComboBox m_ComboScreenCompress;
|
||||
CString m_sScreenCompress;
|
||||
};
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user