终于完成了一个有点难度的东东了。远端屏幕传输。就是效率不高 ( 积分: 5 )

1、服务端CPU占用差不多,客户端你的比我多了一倍;
-------------------------------------------------
这个我想主要我的协议太过于复杂了。用了一套比较严格的格式,每个包还有一个 CRC16 的数据校验。但服务器发送也是计算了 CRC 的呀,也许问题在别的地方。再看看


2、操作了10来分钟,测试了一下播放动画,感觉分块冗余数据太大,我的传了7M多点,你的传了差不多35M,将近5倍,需要改进,建议你用API写BMP,只取数据,不要头;
---------------------
我已经用 API 来自己了自己的 BMP 类了。你没发现我的服务端比你小很多吧,我的服务端才 120K, UPX 压了后60K 不到。分块冗余数据太大是因为我是用固定分块。把屏幕划成 8 X 8 的格子。 这里需要改进。


3、部分块检测不准确,画面不对;
------------------------
的确有这个问题,比较画面变化时,分块之间的地方有没检测到的时候。

3、界面挺漂亮的,有远控的样子。
---------------------
多谢,已经完成了一些功能,如文件上传/下载,远程DOS,
但也还有很多没完成。还有很多BUG。比如有时 serv 会出现非法操作。
 
//来动点真格的,我贴个我写的256色的 DIB 类
//没什么功能,就一个,简单

unit DIBLite;
{*******************************************************************************
一个简化的 DIB 类,!!!!只能处理 256色BMP!!!!

BMP 文件格式
[BMP 文件头]
[BMP 消息头]
[BMP Data]

Version: V1.0
Author: Redfox
CreateDate :2007-04-28

********************************************************************************}

interface

uses
Windows;

type
TDIBLite = class
public
m_fhi: BITMAPFILEHEADER;
m_bmi: PBitmapInfo; // 指向一个 BitmapInfo ,后面有调色板数据
m_lpBits:pointer; // 指向 DIBits
m_hDc:HDC;
m_hBmp:HBITMAP;
m_Width:Integer;
m_Height:Integer;
m_LineSize:Integer; // 每一行的字节数
m_DataSize:Integer; // Bits 数据大小
m_hPal:HPALETTE; // 调色板
m_BmpInfoLen :Integer; // 信息头+调色板长度

constructor Create(w,h:Integer);
destructor Destroy;override;

procedure SaveToFile(fname:string);
end;

implementation

{ TDIBLite }

constructor TDIBLite.Create(w, h: Integer);
var
hDeskDc:HDC;
w1:Integer; // 调整后的宽度,必须能被 4 整除
begin
inherited Create;
m_BmpInfoLen := SizeOf(TBitmapInfo) + 256 * SizeOf(TRGBQuad)-4;
m_bmi := SysGetMem(m_BmpInfoLen);
m_Width := w;
m_Height := h;

w1 := w;
if (w1 mod 4) <> 0 then w1 := ((w1 shr 2) + 1) shl 2; // w1 :=( w1 div 4 +1) * 4;
m_LineSize := w1;
m_DataSize := m_LineSize * h;

m_fhi.bfType := $4D42; // BM
m_fhi.bfSize := SizeOf(BitmapFileHeader) + m_BmpInfoLen + m_DataSize; // 文件大小
m_fhi.bfReserved1 := 0;
m_fhi.bfReserved2 := 0;
m_fhi.bfOffBits := SizeOf(TBitmapfileHeader) + m_BmpInfoLen;

m_bmi^.bmiHeader.biSize := SizeOf(TBitmapInfo) -4; // 由于 Delphi 的问题,最后一个0长度的数组被加了进去
m_bmi^.bmiHeader.biWidth := w;
m_bmi^.bmiHeader.biHeight := h;
m_bmi^.bmiHeader.biPlanes := 1; // 必须等于 1
m_bmi^.bmiHeader.biBitCount := 8; // BitsPerPixel = 8;
m_bmi^.bmiHeader.biCompression := BI_RGB; // 压缩方式,不压缩

m_bmi^.bmiHeader.biSizeImage := m_DataSize; // 位图数据大小, biWidth 必须 4 字节对齐
m_bmi^.bmiHeader.biXPelsPerMeter := 0;
m_bmi^.bmiHeader.biYPelsPerMeter := 0;
m_bmi^.bmiHeader.biClrUsed := 256; // 0 2^8
m_bmi^.bmiHeader.biClrImportant := 0;

hDeskDc := GetDC(0);
m_hDc := CreateCompatibleDC(hDeskDc);
ReleaseDC(0,hDeskDc);

{ 调色板 }
m_hPal := CreateHalftonePalette(hDeskDc);
GetPaletteEntries(m_hPal,0,256,Pointer(@m_bmi.bmiColors[0])^);

DeleteObject( SelectPalette(m_hDc,m_hPal,False));
RealizePalette(m_hDc);

m_hBmp := CreateDIBSection(m_hDc,m_bmi^,DIB_PAL_COLORS, m_lpBits, 0,0);
SelectObject(m_hDc,m_hBmp);
SetDIBColorTable(m_hDc,0,256,Pointer(@m_bmi.bmiColors[0])^);
end;

destructor TDIBLite.Destroy;
begin
SysFreeMem(m_bmi);
DeleteObject(m_hBmp);
DeleteDC(m_hDc);
inherited;
end;

procedure TDIBLite.SaveToFile(fname: string);
var
hFile: THandle;
i:DWORD;
begin
hFile:=CreateFile(PChar(fname),GENERIC_WRITE,0,nil,CREATE_ALWAYS,0,0);
WriteFile(hFile,m_fhi,SizeOf(BitmapFileHeader),i,nil);
WriteFile(hFile,m_bmi^,m_BmpInfoLen,i,nil);
WriteFile(hFile,m_lpBits^,m_DataSize,i,nil);
CloseHandle(hFile);
end;

end.
 
//再帖一个 系出同门

unit BMPLite;
{*******************************************************************************
一个简化的 BMP DDB 类,!!!!只能处理 32位色BMP!!!!

BMP 文件格式
[BMP 文件头]
[BMP 消息头]
[BMP Data]

Version: V1.0
Author: Redfox
CreateDate :2007-04-28

********************************************************************************}

interface

uses
Windows;

type
TBMPLite = class
private
m_lpLineBits:pointer;
function getScanLine(i: Integer): Pointer; // 指向一行的 DIBits 数据
public
m_fhi: BITMAPFILEHEADER;
m_bmi: PBitmapInfo; // 指向一个 BitmapInfo ,后面有调色板数据
m_hDc:HDC;
m_hBmp:HBITMAP;
m_Width:Integer;
m_Height:Integer;
m_LineSize:Integer; // 每一行的字节数
m_DataSize:Integer; // Bits 数据大小
m_hPal:HPALETTE; // 调色板
m_BmpInfoLen :Integer; // 信息头+调色板长度

constructor Create(w,h:Integer);
destructor Destroy;override;

procedure SaveToFile(fname:string);
property ScanLine[i:Integer]:pointer read getScanLine;
end;

implementation

{ TBMPLite }

constructor TBMPLite.Create(w, h: Integer);
var
hDeskDc:HDC;
w1:Integer; // 调整后的宽度,必须能被 4 整除
begin
inherited Create;
//m_BmpInfoLen := SizeOf(TBitmapInfo) + 256 * SizeOf(TRGBQuad)-4;
m_BmpInfoLen := SizeOf(TBitmapInfo) -4;
m_bmi := SysGetMem(m_BmpInfoLen);
m_Width := w;
m_Height := h;

w1 := w;
if (w1 mod 4) <> 0 then w1 := ((w1 shr 2) + 1) shl 2; // w1 :=( w1 div 4 +1) * 4;
m_LineSize := w1 *4;
m_DataSize := m_LineSize * h;

m_fhi.bfType := $4D42; // BM
m_fhi.bfSize := SizeOf(BitmapFileHeader) + m_BmpInfoLen + m_DataSize; // 文件大小
m_fhi.bfReserved1 := 0;
m_fhi.bfReserved2 := 0;
m_fhi.bfOffBits := SizeOf(TBitmapfileHeader) + m_BmpInfoLen;

m_bmi^.bmiHeader.biSize := SizeOf(TBitmapInfo) -4; // 由于 Delphi 的问题,最后一个0长度的数组被加了进去
m_bmi^.bmiHeader.biWidth := w;
m_bmi^.bmiHeader.biHeight := h;
m_bmi^.bmiHeader.biPlanes := 1; // 必须等于 1
m_bmi^.bmiHeader.biBitCount := 32; // BitsPerPixel = 8;
m_bmi^.bmiHeader.biCompression := BI_RGB; // 压缩方式,不压缩

m_bmi^.bmiHeader.biSizeImage := m_DataSize; // 位图数据大小, biWidth 必须 4 字节对齐
m_bmi^.bmiHeader.biXPelsPerMeter := 0;
m_bmi^.bmiHeader.biYPelsPerMeter := 0;
m_bmi^.bmiHeader.biClrUsed := 0; // 0 2^8
m_bmi^.bmiHeader.biClrImportant := 0;

hDeskDc := GetDC(0);
m_hDc := CreateCompatibleDC(hDeskDc);


{ 调色板 }
{
m_hPal := CreateHalftonePalette(hDeskDc);
GetPaletteEntries(m_hPal,0,256,Pointer(@m_bmi.bmiColors[0])^);

DeleteObject( SelectPalette(m_hDc,m_hPal,False));
RealizePalette(m_hDc);
}
//m_hBmp := CreateDIBSection(m_hDc,m_bmi^,DIB_PAL_COLORS, m_lpBits, 0,0);
m_hBmp := CreateCompatibleBitmap(hDeskDc,w, h);
SelectObject(m_hDc,m_hBmp);
//SetDIBColorTable(m_hDc,0,256,Pointer(@m_bmi.bmiColors[0])^);
ReleaseDC(0,hDeskDc);
m_lpLineBits := SysGetMem(m_LineSize);
end;

destructor TBMPLite.Destroy;
begin
SysFreeMem(m_bmi);
if m_lpLineBits <> nil then
SysFreeMem(m_lpLineBits);
DeleteObject(m_hBmp);
DeleteDC(m_hDc);
inherited;
end;

function TBMPLite.getScanLine(i: Integer): Pointer;
begin
Result := nil;

if GetDIBits(m_hDc, m_hBmp, m_Height- i-1,1,m_lpLineBits,m_bmi^,DIB_RGB_COLORS) <> 0 then
Result := m_lpLineBits;
end;

procedure TBMPLite.SaveToFile(fname: string);
var
hFile: THandle;
lpData:pointer;
i:DWORD;
n:DWORD;
begin
//lpData := SysGetMem(m_DataSize);
//i := GetDIBits(m_hDc, m_hBmp, 0,m_Height,lpData,m_bmi^,DIB_RGB_COLORS);
//i := GetLastError;
hFile:=CreateFile(PChar(fname),GENERIC_WRITE,0,nil,CREATE_ALWAYS,0,0);
WriteFile(hFile,m_fhi,SizeOf(BitmapFileHeader),i,nil);
WriteFile(hFile,m_bmi^,m_BmpInfoLen,i,nil);
for i := m_Height-1 downto 0 do
begin
lpData := Self.ScanLine;
WriteFile(hFile,lpData^,m_LineSize,n,nil);
end;

//WriteFile(hFile,lpData^,m_DataSize,i,nil);
CloseHandle(hFile);
//SysFreeMem(lpData);
end;

end.
 
好阿,做得很好.你们两人的程序我都测试了.
客户端CPU消耗如guanyueguan所说,QSmile兄的占到5%左右,guanyueguan兄的2%左右.但这不是问题.
服务端,guanyueguan兄的表现出优势,屏幕无变化的只有3-4%,QSmile兄的一直维持在40%以上,但是在服务端屏幕内窗口移动时,QSmile兄的效果较好,控制端变化较平滑.总之是各有优点,预祝QSmile兄做出一个完美的远控来.你的远端控制好象还没有加进操作代码.建议你们两个互通有无,互相取长补短.
to guanyueguan兄:我很欣赏你的抓屏技巧,请问你的隔行扫描是怎么实现的,能不能给点提示.
 
客户端CPU消耗如guanyueguan所说,QSmile兄的占到5%左右,guanyueguan兄的2%左右
----------------------------------
喔,这个CPU 消耗应该是我在做 CRC 时产生的。

我现在在综合 guanyueguan 的方法,希望能做出更高效的抓屏分析。
 
我想 QSmile 已經明白我寫出的算法,其實就是隔行取樣,再分析出最小矩形,代碼我早就貼在了盒子上:http://www.2ccc.com/article.asp?articleid=4081,我發給你的是修改了點的錯誤,但算法沒變,我這個還有錯誤,暫時就不發了,修改的差不多了的時候再發一次。
 
用QQ群討論吧,xxagri也加進來:16973143。
 
我上班时不能上QQ。要晚上了
 
MSN 呢?
 
都不能。-_-!
 
to guanyueguan:我加群.
 
基本上完成屏幕傳輸的第一個版本了,比紅蜻蜓還是差點,還要繼續攻克矩形計算算法了,多矩形計算還是沒那麼好算,冗余處理要再改進一點了。

算法原理:隔行取樣,分析出變化矩形,可能會有多個變化矩形,看你如何去分析了。目前我用的還是一個變化矩形,所以冗余數據還是比較多。
 
to guanyueguan,
说实话,我明白了你的意思,但对你在2ccc.com 上留的那段代码,我真的没看懂。
如果是一行只生成一个变化矩形,我想有更简单的方法
你可以从左到右搜第一个变化点,然后从右到左搜第二个变化点。这样也许更简单吧。

如果我说错了,不要笑话。
 
當然可以,只是程序沒有從左至右簡單,而且不適合改為多矩形計算。
 
QSmile 有沒有在做隔行掃描版本?我差不多快完成了,現在感覺就比紅蜻蜓差一點了,再優化矩形計算算法就差不多,但要超過它是真的很難。
沒想到當初的猜想是真的,居然能寫到這個程度,看來只要努力,還是能有收獲的。算法仍然是盒子上發布的,修改點錯誤,再優化該優化的地方,就能達到不錯的效果了。希望你不要對算法有疑問,多多調試就會發現問題效能所在。
你寫的 TBMPLite 效能不行,要改改,自己想想吧。
 
寫錯了,是 TDIBLite 。
 
TDIBLite 的用途是不一样的。我只在小分块时使用它。
只是这样可以很方便读出所有数据。
它的效率不好这我是知道的,但想了很久没想到更快的方法,还望给点提示,Thanks
 
第一:參考TBitmap的代碼;
第二:GetDC,CreateCompatibleDC,CreateCompatibleBitmap,SelectObject,BitBlt,GetDIBits,比你這個絕對要快點。
 
QSmile 有沒有在做隔行掃描版本?

-----------
现在做的就是隔行扫描的。

我现在的方法很简单,也还没有摆脱老的思维模式,
我是用固定分块,把屏幕分成 m * n 个块。
然后用隔行扫描,看哪些块是发生了变化了的。
然后发送变化的部分。

我现在的瓶颈与问题主要有几个。
1. 就是你说的 DIB 类效率不高,但是我想了很久也没想到更好的方法来得到BMP数据。一是我用的 CreateDIBSection, 一是用 GetDIBits 但两者在本质上而言是没多大区别的。还希望给你给我提示点

2. 那个 BMP 类在不同的机上,差别也很大,特别是杂牌主板集成显卡那种。关键也是那个 ScanLine 得到数据的过程。

3. 有些地方被分到了两个区时,这时有可能会显示不同步,特别是文字性的变化很多区域。

我也在思考着更好的方法,想要冗余数据不多,这样在检查时就要更花点时间;
如果想检查快点,而数据冗余度就比较大。
除非能找到一个更好的算法,让检查速度快,冗余度又小,否则只能找个折衷的方法。
 
用 GetDC,CreateCompatibleDC,CreateCompatibleBitmap,SelectObject,BitBlt,GetDIBits,比你這個絕對要快點。
---------------
根据我的测试是一样的。过几天再试试
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
961
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
892
DelphiTeacher的专栏
D
顶部