◆◆◆◆◆如何抓取视频画面和游戏画面?跟DirectDraw和DirectX有关!有点难度的问题!欢迎讨论!

UC80862056 2005-11-06 11:35:09
如何抓取视频画面和游戏画面?跟DirectDraw和DirectX有关!有点难度的问题!欢迎讨论!
请给出详细点的代码!
我想你也很关心这个问题吧?不会也请帮忙顶一下,增加点人气,谢谢!
...全文
3021 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
UC80862056 2006-02-17
  • 打赏
  • 举报
回复
Alizee艾莉婕 la isla bonita
http://www.wair.cn/other/file/laislabonita.wmv

http://alizeefans.photo.163.com

相关评论

作者: qin5172 发布日期: 2005-1-08
说实话,我向来以为外国女人没好看的,可是这个这个。。。我看呆了。。。。。。
作者: 阿城℃ 发布日期: 2005-1-08
同感啊......
强烈支持.
作者: jinling889 发布日期: 2005-1-08
看不到 只听到
作者: qin5172 发布日期: 2005-1-15
大家 来看啊,很美的人哦
作者: jimmy 发布日期: 2005-1-15
唱歌可以唱得这么吸引人,这么媚态横生……

真是惊为天人啊!!!
作者: jinling889 发布日期: 2005-1-15
不过她真的好靓~~~~~
作者: 米老鼠 发布日期: 2005-1-16
啊哈哈,真漂亮啊 !歌也不错啊
作者: tachie 发布日期: 2005-1-17
确实很漂亮~~~~
应该说比麦当娜还要漂亮!!!!
作者: anjisheng 发布日期: 2005-10-07
确实很漂亮~~~~ 应该说比麦当娜还要漂亮!!!!
作者: zhangliuzhen 发布日期: 2005-10-08
是啊。在个外国人好例外啊.

UC80862056 2006-02-17
  • 打赏
  • 举报
回复
Alizee艾莉婕 la isla bonita
http://www.wair.cn/other/file/laislabonita.wmv

http://alizeefans.photo.163.com
ly_liuyang 2006-02-15
  • 打赏
  • 举报
回复
D3D截图代码也包括在http://lysoft.lz169.com/projects/DXCapture.rar

是时候揭帖啦~~
ly_liuyang 2006-02-15
  • 打赏
  • 举报
回复
可以截取layered窗口(包括透明窗口)的代码:

procedure CaptureScreen(AFileName: string);
const
CAPTUREBLT = $40000000;
var
hdcScreen: HDC;
hdcCompatible: HDC;
bmp: TBitmap;
hbmScreen: HBITMAP;
begin
hdcScreen := CreateDC('DISPLAY', nil, nil, nil);
hdcCompatible := CreateCompatibleDC(hdcScreen);
hbmScreen := CreateCompatibleBitmap(hdcScreen,
GetDeviceCaps(hdcScreen, HORZRES),
GetDeviceCaps(hdcScreen, VERTRES));
SelectObject(hdcCompatible, hbmScreen);
bmp := TBitmap.Create;
bmp.Handle := hbmScreen;
BitBlt(hdcCompatible,
0, 0,
bmp.Width, bmp.Height,
hdcScreen,
0, 0,
SRCCOPY or CAPTUREBLT);

bmp.SaveToFile(AFileName);
bmp.Free;
DeleteDC(hdcScreen);
DeleteDC(hdcCompatible);
end;

顺便升级了http://lysoft.lz169.com/projects/DXCapture.rar
现在支持YV12,NV12,YUY2,UUVY 4个格式,并解决了点Bug

并无偿开放DX Primary Surface截图代码!包含DX8与DX9两个版本

...
interface

{$DEFINE D3D9}

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons,
{$IFDEF D3D9}
// D3DX9, // use D3D to save surface
Direct3D9
{$ELSE}
// D3DX8, // use D3D to save surface
Direct3D8
{$ENDIF};
...
procedure TForm1.BitBtn1Click(Sender: TObject);
// Capture screen through D3D.
var
BitsPerPixel: Byte;
{$IFDEF D3D9}
pD3D: IDirect3D9;
pSurface: IDirect3DSurface9;
g_pD3DDevice: IDirect3DDevice9;
{$ELSE}
pD3D: IDirect3D8;
pSurface: IDirect3DSurface8;
g_pD3DDevice: IDirect3DDevice8;
{$ENDIF}
D3DPP: TD3DPresentParameters;
ARect: TRect;
LockedRect: TD3DLockedRect;
BMP: TBitmap;
i, p: Integer;
begin
BitsPerPixel := GetDeviceCaps(Canvas.Handle, BITSPIXEL);
FillChar(d3dpp, SizeOf(d3dpp), 0);
D3DPP.Windowed := True;
D3DPP.Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
D3DPP.SwapEffect := D3DSWAPEFFECT_DISCARD;
D3DPP.BackBufferWidth := Screen.Width;
D3DPP.BackBufferHeight := Screen.Height;
D3DPP.BackBufferFormat := D3DFMT_X8R8G8B8;
{$IFDEF D3D9}
pD3D := Direct3DCreate9(D3D_SDK_VERSION);
pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, @D3DPP, g_pD3DDevice);
g_pD3DDevice.CreateOffscreenPlainSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, pSurface, nil);
g_pD3DDevice.GetFrontBufferData(0, pSurface);
{$ELSE}
pD3D := Direct3DCreate8(D3D_SDK_VERSION);
pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GetDesktopWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DPP, g_pD3DDevice);
g_pD3DDevice.CreateImageSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, pSurface);
g_pD3DDevice.GetFrontBuffer(pSurface);
{$ENDIF}
// use D3D to save surface. Notes: D3DX%ab.dll is required!
// D3DXSaveSurfaceToFile('Desktop.bmp', D3DXIFF_BMP, pSurface, nil, nil);
// use Bitmap to save surface
ARect := Screen.DesktopRect;
pSurface.LockRect(LockedRect, @ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);
BMP := TBitmap.Create;
BMP.Width := Screen.Width;
BMP.Height := Screen.Height;
case BitsPerPixel of
8: BMP.PixelFormat := pf8bit;
16: BMP.PixelFormat := pf16bit;
24: BMP.PixelFormat := pf24bit;
32: BMP.PixelFormat := pf32bit;
end;
p := Cardinal(LockedRect.pBits);
for i := 0 to Screen.Height - 1 do
begin
CopyMemory(BMP.ScanLine[i], Ptr(p), Screen.Width * BitsPerPixel div 8);
p := p + LockedRect.Pitch;
end;
BMP.SaveToFile('Desktop.bmp');
BMP.Free;
pSurface.UnlockRect;
end;

以上DX截图代码,不需要额外的DLL支持,有DirectX 9.0即可

希望各位能支持一下LYSoft,常来LYSoft上看看

BTW: 这个问题揭帖后,请提交到FAQ吧
UC80862056 2006-02-15
  • 打赏
  • 举报
回复
先结贴了。
欢迎讨论 bcfans@163.com
jilu_sun 2006-02-15
  • 打赏
  • 举报
回复
收藏
ly_liuyang 2006-02-14
  • 打赏
  • 举报
回复
情人节快乐~

提供效果程序下载
http://lysoft.lz169.com/projects/DXCapture.rar

支持WMP10,RealOne2,WinDVD6的Overlay Surface覆盖表面截图

目前仅能转换YV12格式,截图后生成VRAM文件(包括描述文件和显存数据),要支持其他格式,就得另外做的

还有primary Surface主表明截图,也包括的

暂没开放代码,仅作为技术可行性研究成果,其中的截图库可自由使用.

该贴,也是应该结的了:)
UC80862056 2006-02-14
  • 打赏
  • 举报
回复
DXCapture运行出错!
Access violation at address 00451341 in module 'DXCapture.exe'. Read of address 00000000.
==============================================================
主表面截图,这个方法还是无法抓取半透明的窗体,抓取时半透明的窗体会出现短暂时间的隐藏然后又显示出来(GetFrontBuffer执行时出现这种情况),在抓取的图像上没有这个半透明窗体的图像。怎没办?如何解决?

给你写信了。
程序的源文件和DX8.1的头文件在附件中。

再次感谢你的帮助!



UC80862056 2006-02-05
  • 打赏
  • 举报
回复
to:ly_liuyang
还用COM钩子替换过程地址吗?还是自己建立主表面来抓屏幕?
能具体点吗?谢谢。
另:祝大家新年快乐!
ly_liuyang 2006-02-03
  • 打赏
  • 举报
回复
用DX的PRIMARYSURFACE方法就能处理
不要使用普通的GETDC
reborter 2006-02-03
  • 打赏
  • 举报
回复
学习一下,顶一下
UC80862056 2006-02-01
  • 打赏
  • 举报
回复
如何抓取半透明或指定色透明的窗体?如flashget悬浮窗!

本来打算开始写抓取视频画面的代码的,可是偶然发现用getdc(0),bitblt的方法无法抓取桌面上的半透明和指定色透明的窗体的图像,可是用PrintScreen键却能抓到!真是郁闷死了,不知道为什么?难道这种窗体也是使用了类似覆盖的方式来显示?但是我想这种效果应该是使用了GDI函数将他们与后面的图像合成而成的。不知道PrintScreen键是怎么实现抓取他们的,难道是遍历桌面上的所用窗体,检查他们的属性,找到有半透明和指定色透明属性的窗体然后再用特殊的画法将他们画到截取的桌面图像上?但是这样会不会太慢,而且还要判断窗体的排列顺序等等。总之,我没什么思路!郁闷!真是一步一个坎!

抓取视频和游戏画面的代码我还没开始写,但是我想应该是会遇到一些麻烦的,如:如何知道播放器使用的是什么图像格式?游戏使用的那个版本的DirectX对象等等。以后写的时候遇到具体问题再问其它的吧!

(要求不使用模拟PrintScreen键的方法,因为我已经实现了,但是感觉这种方法是投机取巧。并且模拟PrintScreen键后原来剪贴板中的内容会被覆盖掉,所以这是一种不好的方法。)
UC80862056 2006-01-22
  • 打赏
  • 举报
回复
MV: la isla bonita[Alizee(艾莉婕)]
http://www.mtvup.com/LIST/200553144641469.htm

图像格式转换是很折磨人。

等我仔细看看再问。谢谢了。

wealsh 2006-01-21
  • 打赏
  • 举报
回复
抓视频可以用这个
DSPack 2.33
http://www.2ccc.com/article.asp?articleid=2843

里面带有Demo

ly_liuyang 2006-01-21
  • 打赏
  • 举报
回复
楼上的,方法是不行的
截取别的程序的Overlay Surface,不是一件容易的事情

现在YV12格式处理,已经做了,能满足普通的需要

视频连续看,觉得还行,但是截图下来的图片,质量就不那么好了

Overlay Surface截图技术研究,算是告一段落了,成功解决了:)
ly_liuyang 2006-01-19
  • 打赏
  • 举报
回复
最新研究,有了新的发现!!!!!

通过Hook DDraw的DirectDrawCreate(RealOne用)同DirectDrawCreateEx(WMP用)
获得IDirectDraw(7)
再COM Hook CreateSurface,注意RealOne使用的是通过QueryInterface获得IDirectDraw2
WMP则是IDirectDraw7

Hook了CreateSurface后,就能获得OverlaySurface

所以必须在软件使用前,启动全局Hook,才有效


在需要截图的时候
Lock Overlay Surface,读取数据,马上Unlock,以免损失性能

解码读出来的数据,即可,但是由于获得的数据是显卡硬件VRAM的数据,一般是YUY2,YV12等格式,需要转换为RGB格式

现在原数据能获取了,就差格式转换,有空再弄,不同的显卡,支持的格式不一样,不同的工具所使用的格式也不一样的,所以这个是比较麻烦的

例如,在我的GF6600上,RealOne(RMVB)用的是YUY2,而WMP(AVI)用的是YV12,还与当前播放的文件格式有关

最简单的方法是,Hook CreateSurface后,禁止创建Overlay那就普通的方法都能截图,呵呵
柯本 2006-01-13
  • 打赏
  • 举报
回复
首先声明:那个说"Delphi的人水平都很低.."的人不是我(因为回贴中只有我回过一个VC的参考,所以要澄清一下)
为了证明delphi能同样完成VC的功能,我用了2小时将我原来的VC程序改成了delphi的,真累不过很高兴完成了,虽然程序写的不咋样(毕竟是改写的),不过还是基本能达到原VC的效果(只是效率很低.截一图要10几秒),供大家参考一下吧!(我的暂只能截DX的窗口,因为程序本身有窗口,把它改成后台应该能截全屏了)
首先,下载
http://kuga.51.net/download/files/directx7.rar
(我没有找到更高版本的SDK,不过我原来VC也是用DX7写的,在DX9下应该可用)
全部程序如下:

unit dxcapu;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DirectDraw, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
g_pDD : IDirectDraw7;
g_ddcaps: TDDCaps_DX7 ;
g_pDDSPrimary:IDIRECTDRAWSURFACE7;
hRet : HRESULT;
ddsd,ddsdl:TDDSurfaceDesc2;
procedure ErrorOut(hRet : HRESULT; FuncName : string);
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
const
Is555:boolean=false;
function GetRed(color:WORD ):byte;
begin
if( Is555 ) then
result:= (color shr 7) and $ff
else
result:= (color shr 8) and $ff;
end;

function GetGreen(color:WORD ):byte;
begin
if( Is555 ) then
result:= (color shr 2) and $ff
else
result:= (color shr 3) and $ff;
end;

function GetBlue(color:WORD):byte;
begin
result:= (color and $1f) shl 3;
end ;



procedure TForm1.ErrorOut(hRet : HRESULT; FuncName : string);
var
OutString : string;
begin
OutString := FuncName + ': ' + #13 + DDErrorString(hRet);
MessageBox(0, PChar(OutString), PChar(Caption), MB_OK or MB_ICONSTOP);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
fp:tfilestream;
lpBuffer:pword;
nPitch:integer; // 表面跨距
nWidth, nHeight:integer; // 表面宽高
FileHeader: BITMAPFILEHEADER ;
Header:BITMAPINFOHEADER ;
wd: WORD;
i,j:integer;
bt:byte;
begin
hRet := DirectDrawCreateEx(nil, g_pDD, IDirectDraw7, nil);
if hRet <> DD_OK then
begin
ErrorOut(hRet, 'DirectDrawCreateEx');
Exit;
end;
// Setting the cooperate level
hRet := g_pDD.SetCooperativeLevel(Handle, DDSCL_NORMAL);
if hRet <> DD_OK then
begin
ErrorOut(hRet, 'SetCooperativeLevel');
Exit;
end;
ZeroMemory(@g_ddcaps,sizeof(g_ddcaps));
g_ddcaps.dwSize := sizeof(g_ddcaps);
hRet := g_pDD.GetCaps(@g_ddcaps,nil);
if hRet <> DD_OK then
begin
ErrorOut(hRet, 'GetCaps');
Exit;
end;
ZeroMemory(@ddsd,sizeof(ddsd));
ddsd.dwSize := sizeof(ddsd);
ddsd.dwFlags := DDSD_CAPS;
ddsd.ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;
hRet :=g_pDD.CreateSurface(ddsd, g_pDDSPrimary,nil);
if hRet <> DD_OK then
begin
ErrorOut(hRet, 'CreateSurface');
Exit;
end;
fp:=tfilestream.create('e:\temp\t.bmp',fmOpenReadWrite or fmCreate );
fp.Seek(0,0);
ZeroMemory(@ddsdl,sizeof(ddsdl));
ddsdl.dwSize := sizeof(ddsdl);
hRet := g_pDDSPrimary.Lock( nil, ddsd, DDLOCK_WAIT, 0 );
if hRet <> DD_OK then
begin
ErrorOut(hRet, 'Lock');
Exit;
end;
lpBuffer := ddsd.lpSurface;
nWidth := ddsd.dwWidth;
nHeight := ddsd.dwHeight;
nPitch := ddsd.lPitch shr 1; //lPitch以Byte为单位,GraphPitch以WORD为单位。所以GraphPitch = lPitch / 2;
ShowMessage(Format('%d %d %d',[nWidth, nHeight , nPitch ]));

FileHeader.bfType := $4D42;
FileHeader.bfSize := nWidth * nHeight * 3 + $36;
FileHeader.bfReserved1 := 0;
FileHeader.bfReserved2 := 0;
FileHeader.bfOffBits := $36;
fp.Write(FileHeader, sizeof(BITMAPFILEHEADER));

// 保存文件信息
Header.biSize := sizeof(BITMAPINFOHEADER); // 结构的大小
Header.biWidth := nWidth; // 宽
Header.biHeight := nHeight; // 高
Header.biPlanes := 1; // 固定
Header.biBitCount := 24; // 颜色数
Header.biCompression := BI_RGB; // 是否压缩
Header.biSizeImage := nWidth * nHeight * 3; // 图片的大小
Header.biXPelsPerMeter := 0;
Header.biYPelsPerMeter := 0;
Header.biClrUsed := 0;
Header.biClrImportant := 0;
fp.write(Header, Header.biSize);
fp.Seek($36,0);

lpBuffer := pword(pchar(lpBuffer)+ 2*( nPitch* (nHeight - 1)));
for i:=0 to nHeight-1 do
begin
for j:=0 to nWidth-1 do
begin
wd := lpBuffer^;
bt:= GetBlue( wd ); // 蓝
fp.write( bt, 1);
bt:= GetGreen( wd ); // 绿
fp.write( bt, 1);
bt:= GetRed( wd ); // 红
fp.write( bt, 1);
inc(lpBuffer);
end;
lpBuffer := pword(pchar(lpBuffer)-2*(nWidth+nPitch)); // 指针转到上一行的开始
end;
fp.Free;
// 解锁表面
hRet:= g_pDDSPrimary.Unlock( nil );
ShowMessage('ok');

end;

end.



UC80862056 2006-01-13
  • 打赏
  • 举报
回复
老大你果然强!佩服佩服!
这个问题在大富翁论坛挂了很长时间了都没答案,不知道大富翁论坛怎么了。看来还是csdn的人强。Hook技术我接触过但是COM Hook技术没接触过,没有概念。

HypeeSnapDX使用了键盘钩子这个我之前猜到了。但是用COM Hook我是没想到的。

另外你说挂钩DDraw的DirectDrawCreate,监控FDD.CreateSurface,但是如果主表面在挂钩之前已经创建完了那还能监控到吗?这里我不太明白...

另外就是不知道具体如何实现,请老大写完后能给我具体的指导...我非常想将艾莉婕alizee2004演唱会的图像抓下来,所以非常着急。

另外有一个用VC++实现了这个功能的人说用Delphi的人水平都很低等我改学VC++了再告诉我如何实现,这让我很气愤,此人真是井底之蛙!

老大你太厉害了。真不知道有什么技术问题能难倒你。真给delphiers争脸。

我给你发短信了,请查收。谢谢了。
ly_liuyang 2006-01-11
  • 打赏
  • 举报
回复
普通DX的方法不能截取通过Overlay硬件加速的视频图像的
这是没办法的
除非:关闭显卡的硬件加速功能
或者使用COM Hook技术实现!

思路是:采用独立DLL,做成全局热键Hook
挂钩DDraw的DirectDrawCreate,监控FDD.CreateSurface(ddsd, FDDSPrimary, nil)(需要COM Hook技术)
获得主表面,这个时候就可以通过主表面实现截图处理:
创建OffSurface离屏表面,用IDirectDrawSurface的BltFast从PrimarySurface复制数据到OffSurface,然后Lock离屏表面,这个时候就可以保存图像数据了

HypeeSnapDX,SnagIt等都是这样实现的

要弄Overlay截图,只能用Hook的方法

要有时间偶再实现它,COM Hook的方法是修改COM接口的VMT,比起API Hook来说,简单不少的
UC80862056 2006-01-10
  • 打赏
  • 举报
回复
to:ly_liuyang老大
我早知道你很厉害!
我不奢求原代码,但是给个程序看看使用效果好吗?
真的能在Windows XP sp2 DX9.0c的环境下截取视频画面吗?
我用DX的方式截图但是截不到!

bcfans@163.com
加载更多回复(18)

1,183

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧