如何抓取视频画面和游戏画面?跟DirectDraw和DirectX有关!有点难度的问题!欢迎讨论!
请给出详细点的代码!
我想你也很关心这个问题吧?不会也请帮忙顶一下,增加点人气,谢谢!

解决方案 »

  1.   

    http://www.codeproject.com/directx/LiveVideo.asp
      

  2.   

    给段示例代码:pD3D := Direct3DCreate8(D3D_SDK_VERSION);
    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;
    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);
    ARect := Screen.DesktopRect;
    pSurface.LockRect(lockedRect, @ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);
    PBits := lockedRect.pBits;
    //将数据从PBits中Copy出来,格式为RGBA。不过行顺序和默认的DIB相反。
    pSurface.UnlockRect;
      

  3.   

    太谢谢楼上的老大s了!
    不过……是不是需要引用什么单元啊?能不能给全一点啊??我感觉用delphi写这样的程序有些障碍!没有资料也没有Pascal的SDK,郁闷中!!
      

  4.   

    有现成第三方封装好的DX SDK for Delphi,google搜索一下
      

  5.   

    我在VC版回过的,供参考
    http://community.csdn.net/Expert/topic/3960/3960312.xml?temp=.8360254
      

  6.   

    楼上的老大太谢谢你了。
    问个问题:Direct3D和DirectDraw抓屏是一回事吗?是不是要分别处理?能不能给出Delphi的代码?毕竟用delphi写DX程序跟用VC很不同。详细一点的,包括引用的单元什么的。
    为了使用delphi的人们,将这个问题作一个完美的了结。贤分少的话我再开贴子给你分。先谢谢了。
      

  7.   

    no. DirectDraw is being replaced by Direct3D, but they are different.
      

  8.   

    谢谢楼上的老大。谢谢你多次回我的帖子。那么就是说在现在的Direct9.0c中DirectDraw已经被Direct3D替代了。那么现在只须用Direct3D中的函数处理这种情况了就行了,是吗?
      

  9.   

    不是的DDraw在DX7以后就停止更新了,但是你在以后的版本里仍然可以使用,版本是7.0所谓的替代其实是指D3D8.0以后提供了一些新的功能,可以实现DDraw的效果具体用哪个,看个人习惯和具体情况了新手的话,建议直接放弃DDraw,完全使用D3D
      

  10.   

    我感觉用delphi写这样的程序有些障碍!
    ==========================================语言上没有障碍的其实
    关键是技术支持上,没办法,谁叫Delphi不是微软的呢没有资料也没有Pascal的SDK,郁闷中!!
    ========================================
    这个是有的,jedi比较不错的,你可以尝试一下
      

  11.   

    没什么难度的事情
    弄个DX8/9的SDK就行的这里可以下载
    http://www.clootie.ru/articles/HowToCompile_ObjectPascal.html#run上面代码中的 lockedRect.pBits 可以直接用TBitMap.ScanLine来处理
    然后SaveToFile搞定呵呵:)
      

  12.   

    to: ly_liuyang
    给个全点的代码好吗?
      

  13.   

    N日了,又看见这个贴的,呵呵
    偶的有完整的DX截图代码出售,嘻嘻:)
      

  14.   

    to:ly_liuyang老大
    我早知道你很厉害!
    我不奢求原代码,但是给个程序看看使用效果好吗?
    真的能在Windows XP sp2 DX9.0c的环境下截取视频画面吗?
    我用DX的方式截图但是截不到![email protected]
      

  15.   

    普通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来说,简单不少的
      

  16.   

    老大你果然强!佩服佩服!
    这个问题在大富翁论坛挂了很长时间了都没答案,不知道大富翁论坛怎么了。看来还是csdn的人强。Hook技术我接触过但是COM Hook技术没接触过,没有概念。HypeeSnapDX使用了键盘钩子这个我之前猜到了。但是用COM Hook我是没想到的。另外你说挂钩DDraw的DirectDrawCreate,监控FDD.CreateSurface,但是如果主表面在挂钩之前已经创建完了那还能监控到吗?这里我不太明白...另外就是不知道具体如何实现,请老大写完后能给我具体的指导...我非常想将艾莉婕alizee2004演唱会的图像抓下来,所以非常着急。另外有一个用VC++实现了这个功能的人说用Delphi的人水平都很低等我改学VC++了再告诉我如何实现,这让我很气愤,此人真是井底之蛙!老大你太厉害了。真不知道有什么技术问题能难倒你。真给delphiers争脸。我给你发短信了,请查收。谢谢了。
      

  17.   

    首先声明:那个说"Delphi的人水平都很低.."的人不是我(因为回贴中只有我回过一个VC的参考,所以要澄清一下)
    为了证明delphi能同样完成VC的功能,我用了2小时将我原来的VC程序改成了delphi的,真累不过很高兴完成了,虽然程序写的不咋样(毕竟是改写的),不过还是基本能达到原VC的效果(只是效率很低.截一图要10几秒),供大家参考一下吧!(我的暂只能截DX的窗口,因为程序本身有窗口,把它改成后台应该能截全屏了)
    首先,下载
    http://kuga.51.net/download/files/directx7.rar
    (我没有找到更高版本的SDK,不过我原来VC也是用DX7写的,在DX9下应该可用)
    全部程序如下:unit dxcapu;interfaceuses
      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.
      

  18.   

    最新研究,有了新的发现!!!!!通过Hook DDraw的DirectDrawCreate(RealOne用)同DirectDrawCreateEx(WMP用)
    获得IDirectDraw(7)
    再COM Hook CreateSurface,注意RealOne使用的是通过QueryInterface获得IDirectDraw2
    WMP则是IDirectDraw7Hook了CreateSurface后,就能获得OverlaySurface所以必须在软件使用前,启动全局Hook,才有效
    在需要截图的时候
    Lock Overlay Surface,读取数据,马上Unlock,以免损失性能解码读出来的数据,即可,但是由于获得的数据是显卡硬件VRAM的数据,一般是YUY2,YV12等格式,需要转换为RGB格式现在原数据能获取了,就差格式转换,有空再弄,不同的显卡,支持的格式不一样,不同的工具所使用的格式也不一样的,所以这个是比较麻烦的例如,在我的GF6600上,RealOne(RMVB)用的是YUY2,而WMP(AVI)用的是YV12,还与当前播放的文件格式有关最简单的方法是,Hook CreateSurface后,禁止创建Overlay那就普通的方法都能截图,呵呵
      

  19.   

    抓视频可以用这个
    DSPack 2.33
    http://www.2ccc.com/article.asp?articleid=2843里面带有Demo
      

  20.   

    楼上的,方法是不行的
    截取别的程序的Overlay Surface,不是一件容易的事情现在YV12格式处理,已经做了,能满足普通的需要视频连续看,觉得还行,但是截图下来的图片,质量就不那么好了Overlay Surface截图技术研究,算是告一段落了,成功解决了:)
      

  21.   

    MV: la isla bonita[Alizee(艾莉婕)]
    http://www.mtvup.com/LIST/200553144641469.htm图像格式转换是很折磨人。等我仔细看看再问。谢谢了。
      

  22.   

    如何抓取半透明或指定色透明的窗体?如flashget悬浮窗!本来打算开始写抓取视频画面的代码的,可是偶然发现用getdc(0),bitblt的方法无法抓取桌面上的半透明和指定色透明的窗体的图像,可是用PrintScreen键却能抓到!真是郁闷死了,不知道为什么?难道这种窗体也是使用了类似覆盖的方式来显示?但是我想这种效果应该是使用了GDI函数将他们与后面的图像合成而成的。不知道PrintScreen键是怎么实现抓取他们的,难道是遍历桌面上的所用窗体,检查他们的属性,找到有半透明和指定色透明属性的窗体然后再用特殊的画法将他们画到截取的桌面图像上?但是这样会不会太慢,而且还要判断窗体的排列顺序等等。总之,我没什么思路!郁闷!真是一步一个坎!抓取视频和游戏画面的代码我还没开始写,但是我想应该是会遇到一些麻烦的,如:如何知道播放器使用的是什么图像格式?游戏使用的那个版本的DirectX对象等等。以后写的时候遇到具体问题再问其它的吧!(要求不使用模拟PrintScreen键的方法,因为我已经实现了,但是感觉这种方法是投机取巧。并且模拟PrintScreen键后原来剪贴板中的内容会被覆盖掉,所以这是一种不好的方法。)
      

  23.   

    用DX的PRIMARYSURFACE方法就能处理
    不要使用普通的GETDC
      

  24.   

    to:ly_liuyang
    还用COM钩子替换过程地址吗?还是自己建立主表面来抓屏幕?
    能具体点吗?谢谢。
    另:祝大家新年快乐!
      

  25.   

    情人节快乐~提供效果程序下载
    http://lysoft.lz169.com/projects/DXCapture.rar支持WMP10,RealOne2,WinDVD6的Overlay Surface覆盖表面截图目前仅能转换YV12格式,截图后生成VRAM文件(包括描述文件和显存数据),要支持其他格式,就得另外做的还有primary Surface主表明截图,也包括的暂没开放代码,仅作为技术可行性研究成果,其中的截图库可自由使用.该贴,也是应该结的了:)
      

  26.   

    DXCapture运行出错!
    Access violation at address 00451341 in module 'DXCapture.exe'. Read of address 00000000.
    ==============================================================
    主表面截图,这个方法还是无法抓取半透明的窗体,抓取时半透明的窗体会出现短暂时间的隐藏然后又显示出来(GetFrontBuffer执行时出现这种情况),在抓取的图像上没有这个半透明窗体的图像。怎没办?如何解决?给你写信了。
    程序的源文件和DX8.1的头文件在附件中。再次感谢你的帮助!
      

  27.   

    可以截取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吧
      

  28.   

    D3D截图代码也包括在http://lysoft.lz169.com/projects/DXCapture.rar是时候揭帖啦~~
      

  29.   

    先结贴了。
    欢迎讨论 [email protected]
      

  30.   

    Alizee艾莉婕 la isla bonita
    http://www.wair.cn/other/file/laislabonita.wmvhttp://alizeefans.photo.163.com
      

  31.   

    Alizee艾莉婕 la isla bonita
    http://www.wair.cn/other/file/laislabonita.wmvhttp://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 
    是啊。在个外国人好例外啊.