DirectShow的截图方案简述

 

DirectShow的截图方案简述

用directshow可以有多种实现的方案,下面介绍三种

 

第一种采用IMediaDet接口的GetBitmaps方法,速度很快,但是Video的类型有限制,对于WMF类型、RMVB等都无法正常截图,下面是例子代码:
BOOL Grabber1()
{
if(!m_pMediaDet) // IMediaDet接口,它除了用于截图还可以用于判断媒体类型
   return FALSE;
BOOL bResult = FALSE;
HRESULT thr;
long width = 0, height = 0; 
AM_MEDIA_TYPE mt;
m_pMediaDet->put_Filename(m_strMediaFile.AllocSysString());
thr = m_pMediaDet->get_StreamMediaType(&mt);

 

if (1/*mt.formattype != FORMAT_VideoInfo*/) //在此有类型限制
{
   VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);
   width = pVih->bmiHeader.biWidth;
   height = pVih->bmiHeader.biHeight;
   if (height < 0)
    height *= -1;
}
else 
{
   return VFW_E_INVALIDMEDIATYPE;      
     }
FreeMediaType(mt);

 

long size;
char * pBuffer;
int gt; // grabber time
gt = m_curpos * m_Duration / m_filelength;
thr = m_pMediaDet->GetBitmapBits(gt,&size,NULL,width,height);
if(SUCCEEDED(thr))
{
   pBuffer = new char[size];
   if(!pBuffer)
    return E_OUTOFMEMORY;
}
try
{
   thr = m_pMediaDet->GetBitmapBits(gt,0,pBuffer,width,height);
}
catch(...)
{
   delete [] pBuffer;
   throw;
}
if(SUCCEEDED(thr))
{
   BITMAPINFOHEADER * bmih = (BITMAPINFOHEADER*)pBuffer;
   HDC hdcDest = ::GetDC(0);
   void * pData = pBuffer + sizeof(BITMAPINFOHEADER);
   // Note: In general a BITMAPINFOHEADER can include extra color 
   // information at the end, so calculating the offset to the image 
   // data is not generally correct. However, the IMediaDet interface 
   // always returns an RGB-24 image with no extra color information 
   BITMAPINFO bmi;
   ZeroMemory(&bmi, sizeof(BITMAPINFO));
   CopyMemory(&(bmi.bmiHeader),bmih,sizeof(BITMAPINFOHEADER));
   HBITMAP hB = CreateDIBitmap(hdcDest,
    bmih,
    CBM_INIT,
    pData,
    &bmi,
    DIB_RGB_COLORS);
   // write to bitmap
    BITMAPFILEHEADER   hdr;     //Bitmap的头信息 
    LPBITMAPINFOHEADER    lpbi; // Bitmap的文件信息(包括数据) 
    lpbi = (LPBITMAPINFOHEADER)pBuffer; 
    int nColors = 1 << lpbi->biBitCount; 
    if (nColors > 256) 
     nColors = 0; 
    hdr.bfType     = ((WORD) ('M' << 8) | 'B');     //always is "BM" 
    hdr.bfSize     = size + sizeof( hdr ); 
    hdr.bfReserved1    = 0; 
    hdr.bfReserved2    = 0; 
    hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize);

 

// 保存图  
CString bmpPath(m_grbDirectory);
    bmpPath += "//temp.bmp";
    CFile bitmapFile(bmpPath, CFile::modeNoTruncate|
    CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary); 
    bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER)); 
    bitmapFile.Write(pBuffer, size); 
    bitmapFile.Close();
    bResult = TRUE;
}
bResult = FALSE;
delete [] pBuffer;
return bResult;
}

 

 

 

第二种方案采用的是IBasicVideo中的GetCurrentImage方法,这种方案几乎可以处理所有的视频类型,但是每一次截图都有一个短暂的暂停,也是就停顿,下面是例子:

 

BOOL Grabber2()
{
if(m_pGraph == NULL)
    return FALSE;
else 
    m_pGraph->QueryInterface(IID_IBasicVideo,(void **)&m_pBasicVideo);

 

if(m_pBasicVideo == NULL)
    return FALSE;
long bitmapSize = 0; 
BOOL bResult = FALSE;
if (SUCCEEDED(m_pBasicVideo->GetCurrentImage(&bitmapSize, 0))) 

    unsigned char * buffer = new unsigned char[bitmapSize]; 
    if (SUCCEEDED(m_pBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer))) 
    { 
     BITMAPFILEHEADER hdr; 
     LPBITMAPINFOHEADER lpbi; 
     lpbi = (LPBITMAPINFOHEADER)buffer; 
     int nColors = 0; 
     if( lpbi->biBitCount <=8) 
     nColors = 1 << lpbi->biBitCount; 
     hdr.bfType = ((WORD) ('M' << 8) | 'B'); //always is "BM" 
     hdr.bfSize = bitmapSize + sizeof( hdr ); 
     hdr.bfReserved1 = 0; 
     hdr.bfReserved2 = 0; 
     hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize + 
     nColors * sizeof(RGBQUAD)); 
  
     // write to file  
     CString bmpPath(m_grbDirectory);
     bmpPath += "//";// to save something
     bmpPath += RandString(16);
     bmpPath += ".bmp";
     CFile bitmapFile(bmpPath, CFile::modeNoTruncate|
     CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary); 
     bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER)); 
     bitmapFile.Write(buffer,bitmapSize); 
     bitmapFile.Close();
     bResult = TRUE; 
    // MessageBox(bmpPath,"成功保存提示");
     CRect rcTmp;
     GetWindowRect(&rcTmp);
     m_windowmove = -m_windowmove;
     rcTmp.OffsetRect(CPoint(0,m_windowmove));
     MoveWindow(rcTmp);
    }
    delete [] buffer;
    bResult = FALSE;
}
if(m_pBasicVideo != NULL)
{
    m_pBasicVideo->Release();
    m_pBasicVideo = NULL;
}

 

return bResult;
}

 

为了寻求既快而且能处理所有类型的方案,找到了IVMRWindowlessControl9接口。它是VRM9中才有的,所以必须引入d3d9.h和vrm9.h头文件。

但是在之前用的IMediaDet接口中包含了Qedit.h,而这个文件和上述两个头文件是不相容的。所以如果同在一个.h中#include他们会出现类似这样的报错:
syntax      error      :      identifier      'IDirect3DSurface9'   
所以,我尝试着把qedit.h放置到.cpp中去,错误虽然少了,但变成了这些:
error C2061: syntax error : identifier 'LPDIRECT3D'
error C2061: syntax error : identifier 'LPDIRECT3DDEVICE'
error C2061: syntax error : identifier 'LPDIRECT3DDEVICE2'

为了解决问题,可以把qedit.h去掉,但是那样就没法用IMediaDet接口了。所以,必须建立一个点的头文件,把包含ImediaDet那部分copy进去,然后使用它就可以了,我把用到的置于了mediadet.h中,主要包含了SampleGrabberCB和IMediaDet以及CLSID的定义。这样问题就解决了。

例子代码如下:

      if(m_pVMRWC && m_fStyle == VIDEO_STYLE) 
      {
          BYTE* lpCurrImage = NULL;

          // Read the current video frame into a byte buffer.    The information
          // will be returned in a packed Windows DIB and will be allocated
          // by the VMR.
          if(m_pVMRWC->GetCurrentImage(&lpCurrImage) == S_OK)
          {
              BITMAPFILEHEADER      hdr;
              DWORD                 dwSize, dwWritten;
              LPBITMAPINFOHEADER    pdib = (LPBITMAPINFOHEADER) lpCurrImage;

              // Create a new file to store the bitmap data  
     CString bmpPath(m_grbDirectory);
     bmpPath += "//";// to save something
     bmpPath += RandString(16);
     bmpPath += ".bmp";
              HANDLE hFile = CreateFile(TEXT(bmpPath), GENERIC_WRITE, FILE_SHARE_READ, NULL,
                                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

              if (hFile == INVALID_HANDLE_VALUE)
                  return FALSE;

              // Initialize the bitmap header
              dwSize = DibSize(pdib);
              hdr.bfType            = BFT_BITMAP;
              hdr.bfSize            = dwSize + sizeof(BITMAPFILEHEADER);
              hdr.bfReserved1       = 0;
              hdr.bfReserved2       = 0;
              hdr.bfOffBits         = (DWORD)sizeof(BITMAPFILEHEADER) + pdib->biSize +
                  DibPaletteSize(pdib);

              // Write the bitmap header and bitmap bits to the file
              WriteFile(hFile, (LPCVOID) &hdr, sizeof(BITMAPFILEHEADER), &dwWritten, 0);
              WriteFile(hFile, (LPCVOID) pdib, dwSize, &dwWritten, 0);

              // Close the file
              CloseHandle(hFile);

              // The app must free the image data returned from GetCurrentImage()
              CoTaskMemFree(lpCurrImage);

              // Give user feedback that the write has completed
              // MessageBox(bmpPath);
              return TRUE;
          }
      }
      return FALSE;

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值