效果图如图所示:
1.DirectShow视频的显示
//初始化com
CoInitialize(NULL);
HRESULT hr;
pBuilder = NULL;
pGraph = NULL;
pMediaControl = NULL;
//枚举视频设备
ICreateDevEnum *pDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void**)&pDevEnum);
if (FAILED(hr))
{
return FALSE;
}
IEnumMoniker *pClassEnum = NULL;
//为指定的目录创建枚举器
hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if (hr == S_OK)
{
//使用IEnumMoniker接口枚举所有的设备标识
IMoniker *pMoniker = NULL;
ULONG cFetched;
if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);
pMoniker->Release();
}
}
pClassEnum->Release();
//如何创建FilterGraph
//第一步:创建 ICaptureGraphBuilder2接口
CoCreateInstance(CLSID_CaptureGraphBuilder2, 0,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuilder);
//第二步:创建IGraphBuilder接口
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGraph);
//第三步:调用ICaptureBuilder的SetFilterGraph方法将FilterGraph加入到Builder中
pBuilder->SetFiltergraph(pGraph);
//查询各个接口,得到媒体控制接口,该接口控制整个Graph状态的
pGraph->QueryInterface(IID_IMediaControl, (void**)&pMediaControl);
pGraph->AddFilter(pSrc, L"avi");
pPreview = NULL;
//视频混合渲染器
CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pPreview);
if (pPreview != NULL)
{
pGraph->AddFilter(pPreview, L"preview");
//连接引脚
IPin *pSourceOut;
pSourceOut = FindPin(pSrc, PINDIR_OUTPUT);
IPin *pPreIn = FindPin(pPreview, PINDIR_INPUT);
pGraph->ConnectDirect(pSourceOut, pPreIn, NULL);
//获取预览窗口
pViewWnd = NULL;
pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
pSourceOut, NULL, NULL);
pPreview->QueryInterface(IID_IVideoWindow, (void**)&pViewWnd);
if (pViewWnd)
{
//设置预览窗口的拥有者
//pViewWnd->put_Owner((OAHWND)m_hWnd);
pViewWnd->put_Owner((long)m_hWnd);
pViewWnd->put_Left(1);
pViewWnd->put_Top(1);
//获取预览窗口风格
long style;
pViewWnd->get_WindowStyle(&style);
style = style & ~WS_CAPTION;
style = style & ~WS_DLGFRAME;
style = style & WS_CHILD;
pViewWnd->put_WindowStyle(style);
//设置预览窗口高度和宽度
CRect rc;
GetClientRect(rc);
pViewWnd->put_Height(rc.Height() - 150);
pViewWnd->put_Width(rc.Width() - 2);
//pViewWnd->put_Visible(OATRUE);
}
cmGetCaptureRatio(pSrc, pBuilder);
pMediaControl->Run();
}
2.显示图像参数设置页面
//OleCreatePropertyFrame显示Filter属性页的设置
void CMyDS3Dlg::OnBnClickedButtonPropertypage()
{
// TODO: 在此添加控件通知处理程序代码
if (pSrc != NULL)
{
ISpecifyPropertyPages *pSpec;
CAUUID cauuid;
HRESULT hr;
HWND ghwndApp = 0;
hr = pSrc->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpec);
if (SUCCEEDED(hr))
{
hr = pSpec->GetPages(&cauuid); //显示该页
hr = OleCreatePropertyFrame(ghwndApp, //父窗口
30, 30, //Reserved
NULL, //对话框标题
1, //该滤波器的目标数目
(IUnknown **)&pSrc, //目标指针数组
cauuid.cElems, //属性页数目
(GUID *)cauuid.pElems, //属性页的CLSID数组
0, //本地标识
0, NULL); //Reserved
CoTaskMemFree(cauuid.pElems); //释放内存、资源
pSpec->Release();
}
}
}
3.设置视频属性页
//显示视频属性页
void CMyDS3Dlg::OnBnClickedButtonVideopage()
{
// TODO: 在此添加控件通知处理程序代码
HRESULT hr; //返回值
pSC = NULL;
ISpecifyPropertyPages *pSpec = NULL; //属性页接口
HWND ghwndApp = 0;
//只有停止后,才能进行引脚属性的设置
pMediaControl->Stop();
hr = pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Interleaved, pSrc,
IID_IAMStreamConfig, (void **)&pSC);
if (hr != NOERROR)
hr = pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pSrc,
IID_IAMStreamConfig, (void **)&pSC);
CAUUID cauuid; //所有属性页结构体
hr = pSC->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpec);
if (hr == S_OK)
{
hr = pSpec->GetPages(&cauuid); //获取所有属性页
//显示属性页
hr = OleCreatePropertyFrame(ghwndApp, 30, 30, NULL, 1,
(IUnknown **)&pSC, cauuid.cElems,
(GUID *)cauuid.pElems, 0, 0, NULL);
//释放内存、资源
CoTaskMemFree(cauuid.pElems);
pSpec->Release();
pSC->Release();
}
//回复运行
pMediaControl->Run();
}
4.设置图像的参数
void CMyDS3Dlg::setParameter()
{
HWND hTrackbar = NULL; // Handle to the trackbar control.
// Initialize hTrackbar (not shown).
// Query the capture filter for the IAMVideoProcAmp interface.
IAMVideoProcAmp *pProcAmp = 0;
HRESULT hr = pBuilder->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
if (FAILED(hr))
{
// The device does not support IAMVideoProcAmp, so disable the control.
//hTrackbar->EnableWindow(FALSE);
}
else
{
long Min, Max, Step, Default, Flags, Val;
// Get the range and default value.
hr = m_pProcAmp->GetRange(VideoProcAmp_Brightness, &Min, &Max, &Step,
&Default, &Flags);
if (SUCCEEDED(hr))
{
// Get the current value.
hr = m_pProcAmp->Get(VideoProcAmp_Brightness, &Val, &Flags);
}
if (SUCCEEDED(hr))
{
// Set the trackbar range and position.
::SendMessage(hTrackbar, TBM_SETRANGE, TRUE, MAKELONG(Min, Max));
::SendMessage(hTrackbar, TBM_SETPOS, TRUE, Val);
::EnableWindow(hTrackbar, TRUE);
}
else
{
// This property is not supported, so disable the control.
::EnableWindow(hTrackbar, FALSE);
}
}
}
6.DirectShow抓图
//实现抓取图片
//BMP文件总体上由4部分组成,分别是位图文件头、位图信息头、调色板和图像数据
//typedef struct tagBITMAPFILEHEADER {
// WORD bfType; 2字节
// DWORD bfSize; 4字节
// WORD bfReserved1; 2字节
// WORD bfReserved2; 2字节
// DWORD bfOffBits; 4字节
//} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
bool CMyDS3Dlg::PictureGrab(const char* outFile)
{
//获得IBasicVideo接口
pPreview->QueryInterface(IID_IBasicVideo, (void **)&pBasicVideo);
// TODO: 在此添加控件通知处理程序代码
if (pBasicVideo)
{
long bitmapSize = 0;
HRESULT hr;
//首先获得图像大小
hr = pBasicVideo->GetCurrentImage(&bitmapSize, 0);
if (SUCCEEDED(hr))
{
bool pass = false;
//分配图像帧内存
unsigned char * buffer = new unsigned char[bitmapSize];
//获取图像帧数据
hr = pBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer);
if (SUCCEEDED(hr))
{
BITMAPFILEHEADER hdr; //定义位图变量
LPBITMAPINFOHEADER lpbi; //是个指针,指向BMP头的
lpbi = (LPBITMAPINFOHEADER)buffer;
//int nColor = 1 << lpbi->biBitCount;
//if (nColor > 256)
//nColor = 0;
int nColor = 0;
if (lpbi->biBitCount <= 8)
{
nColor = 1 << lpbi->biBitCount;
}
// Fill in the fields of the file header
hdr.bfType = ((WORD)('M' << 8) | 'B');// 位图类别is always "BM"
hdr.bfSize = bitmapSize + sizeof(hdr); //BMP图像文件的大小
hdr.bfReserved1 = 0; //总为0
hdr.bfReserved2 = 0; //总为0
hdr.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + //BMP图像数据的地址
lpbi->biSize + nColor*sizeof(RGBQUAD));
CFile bitmapFile(outFile, CFile::modeReadWrite |
CFile::modeCreate | CFile::typeBinary);
//写入位图文件头
bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER));
//写入图像帧数据
bitmapFile.Write(buffer, bitmapSize);
bitmapFile.Close();
pass = true;
}
else
{
AfxMessageBox("Failed to capture a frame!");
}
//释放内存
delete[] buffer;
return pass;
}
}
return false;
}
想要源码的同学可以点击下面的链接进行下载: