在directshow中,如果视频没有涉及到编码解码,那么实现即使抓图就比较容易了,最简单的方法就是使用Filter Graph Manager 上的IBasicVideo接口,调用这个接口的GetCurrentImage函数就可以将当前帧抓下来。
BOOL CDXGraph::GetCurrentImage(const char * inFile)
{
//mBasicVideo为Filter Graph Manager上获得IBasicVide接口对象指针
if (!mBasicVideo)
{
return FALSE;
}
long bitmapSize = 0;
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0)))
{
BOOL pass = FALSE;
BYTE * buffer = new BYTE[bitmapSize];
if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer)))
{
BITMAPFILEHEADER hdr;
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)buffer;
int nColors = 1 << lpbi->biBitCount;
if (nColors > 256)
nColors = 0;
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));
CFile bmpFile(inFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary);
bmpFile.Write(&hdr, sizeof(BITMAPFILEHEADER));
bmpFile.Write(buffer, bitmapSize);
bmpFile.Close();
pass = TRUE;
}
delete [] buffer;
return pass;
}
return TRUE;
}
然而GetCurrentImage并不稳定(如果使用VMR则没有问题),所以最好还是自己写一个Treansform Filter,接入到采集设备后面的链路中,则Filter Graph中流过每一个Sample都会经过此filter.我们只需要在Filter上自定义一个接口,用于将当前的Sample数据拷贝出来,也就实现了即时抓图。(自己写的filter可以在这儿下载,抓图filter)