视频截图也不是一个什么新概念,早期的播放器如金山影霸就支持视频截图。视频截图有其应用的需求,影片播放过程中有些精彩的画面,用户可能想保留下来。普通的print screen按钮不一定有用,因为启用DX加速,使用printf screen捕捉不到屏幕信息。
DShow里头有三种类型的filter:source filter | trasform filter | render filter。三种filter贯穿了整个播放过程。多个filter连接在一起,构成一个filter graph。创建graph,然后通过graph来查询一些接口,获取到视频流每一帧数据,保存成一帧帧图片。借助于DShow,实现视频截图应该说非常容易,而且DShow可以截获视频的方法还不少呢。下面就简单介绍一两个方法。
方法一:利用IBasicVideo接口获取视频帧数据
IBasicVideo接口提供了一个方法GetCurrentImage()获取视频帧的数据。使用此方法不是特别可靠。在Render是Video Render的时候,如果采取的DirectDraw,就会失败。另外,使用GetCurrentImage()方法获取视频帧数据,需要确定媒体类型,不同的媒体类型,获取的数据结构和内容都不尽相同,这也是保存图片的一个麻烦所在。下面说说如何使用IBasicVideo来获取视频帧。
(1) 创建FilterGraph [CoCreateInstance]
(2) 调用IGraphBuilder::RenderFile()打开文件
(3) 通过IGraphBuilder查询出接口IBasicVideo
(4) 通过调用IBasicVideo::GetCurrentImage()获取图片信息捕获图片
方法二:利用IMediaDet接口获取视频帧数据
优点:相对于IBasicVideo接口捕获视频图像而言,使用IMediaDet更加专业也更加方便。举个例子:调用IBasicVideo获取视频数据的时机?如果我想捕获某一时刻的某一帧图像,用IBasicVideo能做得到吗?用IMediaDet就不一样了,调用GetBitmapBits可以获取指定时间的帧数据。而且,用IMediaDet获取数据的格式是固定的RGB24。这样一来,获取到的数据,保存到图像就方便多了,不用担心不同的杂乱格式带来的烦恼。
使用IMediaDet接口获取视频数据方法如下:
(1) 创建MediaDet对象 [CoCreateInstance(CLSID_MediaDet...)]
(2) 调用IMediaDet::put_Filename() 指定要打开的源文件的名称
(3) 调用IMediaDet::GetBitmapBits获取视频帧数据
/////////////////////////////////////////////////////////////
// Sample Code:
long size;
hr = pDet->GetBitmapBits(0, &size, 0, width, height);
if (SUCCEEDED(hr))
{
char *pBuffer = new char[size];
if (!pBuffer)
return E_OUTOFMEMORY;
try {
hr = pDet->GetBitmapBits(0, 0, pBuffer, width, height);
}
catch (...) {
delete [] pBuffer;
throw;
}
if (SUCCEEDED(hr))
{
BITMAPINFOHEADER *bmih = (BITMAPINFOHEADER*)pBuffer;
HDC hdcDest = GetDC(0);
// Find the address of the start of the image data.
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 hBitmap = CreateDIBitmap(hdcDest, bmih, CBM_INIT,
pData, &bmi, DIB_RGB_COLORS);
}
delete[] pBuffer;
}
////////////////////////////////////////