我使用CDC截取屏幕保存为BMP,发现保存的速度比较慢,保存为avi效果也不理想,我想知道能不能使用directx截取屏幕然后保存为avi或bmp呢?

解决方案 »

  1.   

    我知道用print screen可截取整个屏幕,
    alt+print screen可截取浮动窗口。
    然后直接在画图或绘图软件粘贴。
      

  2.   

    屏幕截取是令人比较感兴趣的事情.虽然现在有不少应用程序如HYPERSNAP等可以用来截取你所喜欢的屏幕画面,但是如果能把这个功能加到自己的程序中,就更能利用它强大的作用. 
    下面用VC来逐步介绍在Windows95下的实现过程.首先我们要确定屏幕截取的区域,用LPRECT结构来定义.可以截取一个窗口,或整个屏幕.以下代码把选定的屏幕区域拷贝到位图中. HBITMAP CopyScreenToBitmap(LPRECT lpRect) //lpRect 代表选定区域{HDC       hScrDC, hMemDC;       // 屏幕和内存设备描述表HBITMAP    hBitmap, hOldBitmap;    // 位图句柄int       nX, nY, nX2, nY2;      // 选定区域坐标int       nWidth, nHeight;      // 位图宽度和高度int       xScrn, yScrn;         // 屏幕分辨率   // 确保选定区域不为空矩形   if (IsRectEmpty(lpRect))     return NULL;   //为屏幕创建设备描述表   hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);   //为屏幕设备描述表创建兼容的内存设备描述表   hMemDC = CreateCompatibleDC(hScrDC);   // 获得选定区域坐标   nX = lpRect- >left;   nY = lpRect- >top;   nX2 = lpRect- >right;   nY2 = lpRect- >bottom;   // 获得屏幕分辨率   xScrn = GetDeviceCaps(hScrDC, HORZRES);   yScrn = GetDeviceCaps(hScrDC, VERTRES);   //确保选定区域是可见的   if (nX < 0)      nX = 0;   if (nY < 0)      nY = 0;   if (nX2 > xScrn)      nX2 = xScrn;   if (nY2 > yScrn)      nY2 = yScrn;   nWidth = nX2 - nX;   nHeight = nY2 - nY;   // 创建一个与屏幕设备描述表兼容的位图hBitmap = CreateCompatibleBitmap (hScrDC, nWidth, nHeight);   // 把新位图选到内存设备描述表中   hOldBitmap = SelectObject(hMemDC, hBitmap);   // 把屏幕设备描述表拷贝到内存设备描述表中BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);   //得到屏幕位图的句柄   hBitmap = SelectObject(hMemDC, hOldBitmap);   //清除    DeleteDC(hScrDC);   DeleteDC(hMemDC);   // 返回位图句柄   return hBitmap;}   得到屏幕位图句柄以后,我们可以把屏幕内容粘贴到剪贴板上.    if (OpenClipboard(hWnd))      //hWnd为程序窗口句柄      {        //清空剪贴板        EmptyClipboard();        //把屏幕内容粘贴到剪贴板上,        hBitmap 为刚才的屏幕位图句柄        SetClipboardData(CF_BITMAP, hBitmap);        //关闭剪贴板        CloseClipboard();      }   我们也可以把屏幕内容以位图格式存到磁盘文件上.      int SaveBitmapToFile(HBITMAP hBitmap ,  LPSTR lpFileName) //hBitmap 为刚才的屏幕位图句柄{      //lpFileName 为位图文件名 HDC            hDC;             //设备描述表      int            iBits;        //当前显示分辨率下每个像素所占字节数 WORD            wBitCount;       //位图中每个像素所占字节数      //定义调色板大小, 位图中像素字节大小 ,      位图文件大小 , 写入文件字节数 DWORD           dwPaletteSize=0, dwBmBitsSize,  dwDIBSize, dwWritten; BITMAP          Bitmap;         //位图属性结构 BITMAPFILEHEADER   bmfHdr;         //位图文件头结构      BITMAPINFOHEADER   bi;             //位图信息头结构  LPBITMAPINFOHEADER lpbi;           //指向位图信息头结构      HANDLE          fh, hDib, hPal,hOldPal=NULL; //定义文件,分配内存句柄,调色板句柄     //计算位图文件每个像素所占字节数   hDC = CreateDC("DISPLAY",NULL,NULL,NULL);iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);   DeleteDC(hDC);   if (iBits < = 1)      wBitCount = 1;   else if (iBits < = 4)      wBitCount = 4;   else if (iBits < = 8)      wBitCount = 8;   else if (iBits < = 24)      wBitCount = 24;   //计算调色板大小   if (wBitCount < = 8)      dwPaletteSize = (1 < <  wBitCount) *      sizeof(RGBQUAD);      //设置位图信息头结构   GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);   bi.biSize            = sizeof(BITMAPINFOHEADER);   bi.biWidth           = Bitmap.bmWidth;   bi.biHeight          = Bitmap.bmHeight;   bi.biPlanes          = 1;   bi.biBitCount         = wBitCount;   bi.biCompression      = BI_RGB;   bi.biSizeImage        = 0;   bi.biXPelsPerMeter     = 0;   bi.biYPelsPerMeter     = 0;   bi.biClrUsed         = 0;   bi.biClrImportant      = 0;   dwBmBitsSize = ((Bitmap.bmWidth *    wBitCount+31)/32)* 4  *Bitmap.bmHeight ;   //为位图内容分配内存   hDib  = GlobalAlloc(GHND,dwBmBitsSize+ dwPaletteSize+sizeof(BITMAPINFOHEADER));   lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);   *lpbi = bi;   // 处理调色板      hPal = GetStockObject(DEFAULT_PALETTE);   if (hPal)   {      hDC  = GetDC(NULL);      hOldPal = SelectPalette(hDC, hPal, FALSE);      RealizePalette(hDC);   }   // 获取该调色板下新的像素值   GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,  (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)    +dwPaletteSize,  (BITMAPINFOHEADER *)    lpbi, DIB_RGB_COLORS);   //恢复调色板      if (hOldPal)   {      SelectPalette(hDC, hOldPal, TRUE);      RealizePalette(hDC);      ReleaseDC(NULL, hDC);   }   //创建位图文件    fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,         FILE_ATTRIBUTE_NORMAL | FILE_         FLAG_SEQUENTIAL_SCAN, NULL);   if (fh == INVALID_HANDLE_VALUE)      return FALSE;   // 设置位图文件头   bmfHdr.bfType = 0x4D42;  // "BM"dwDIBSize    = sizeof(BITMAPFILEHEADER)            + sizeof(BITMAPINFOHEADER)         + dwPaletteSize + dwBmBitsSize;     bmfHdr.bfSize = dwDIBSize;   bmfHdr.bfReserved1 = 0;   bmfHdr.bfReserved2 = 0;   bmfHdr.bfOffBits = (DWORD)sizeof   (BITMAPFILEHEADER)       + (DWORD)sizeof(BITMAPINFOHEADER)     + dwPaletteSize;   // 写入位图文件头WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);   // 写入位图文件其余内容   WriteFile(fh, (LPSTR)lpbi, dwDIBSize,    &dwWritten, NULL);   //清除      GlobalUnlock(hDib);   GlobalFree(hDib);   CloseHandle(fh);}
      

  3.   

    谢谢楼上的兄弟,我现在的程序就是用这个来做的,截取屏幕速度不能很快,而且我的目的主要是在播放vcd或者rm等的时候来截取播放的内容,这样的话就要截取屏幕并且保存为avi文件的速度都要很快,我发现用上面的方法有两个问题:
       第一,会影响播放视频的速度,造成播放的停顿感;
       第二,保存为avi的时候,图像不连续,而且失真比较厉害;
    我知道directx可以直接访问显示设备,而且速度比CDC快,所以我想使用directx来实现,我以前没有用过directx,希望兄弟们多帮忙!
      

  4.   

    你为什么不直接用你的vcd或rm文件转avi文件,那样效果最好,速度也快。
    用你的方法等于时兜了一大圈,效果如何全看你机器的配置了,用p42.6c 512DDR试试
      

  5.   

    不是,我要Record的东西是网上的视频流,而且首先需要用户登陆,找不到一些软件来录取这些视频流,你可以给我推荐一下吗,比如如何截取网上电影!