DirectShow实现视频的实时显示并抓图,可以设置视频参数

效果图如图所示:

DirectShow实现视频的实时显示并抓图,可以设置视频参数_第1张图片

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;
}

想要源码的同学可以点击下面的链接进行下载:

https://download.csdn.net/download/jacken123456/10438781

你可能感兴趣的:(C++,DirectShow,图像处理)