VS2010基于DirectShows实现视频预览控件

来源:互联网 发布:网络机顶盒看电视软件 编辑:程序博客网 时间:2024/05/22 12:37

     之前用VFW实现视频预览控件,使用的时候经常会弹出视频源选择窗口,为了解决这个问题,采用最新的DirectShow来实现视频预览,而且VFW目前基本上已经不使用了,DirectX的功能比较强大。因需求比较单一,还是只实现简单的视频预览功能,并没有实时存储视频。实现过程完全参照MSDN实现。要使用DirectShow的功能首先需要包含头文件

#include<dshow.h>,并引入库   #pragma comment(lib,"strmiids.lib")

一、控件界面

        界面还是和上篇VFW实现方法一样。

视频预览大致流程是“枚举视频设备 -> 初始化并绑定视频采集过滤器 -> 将视频导入特定的流中”   ,具体实现方法参考MSDN上的DirectShow部分。

为显示界面添加CPreviewWindow类,下面是PreviewWindow.h的实现。

#pragma once#include "afxwin.h"#include <atlbase.h>#include <windows.h>#include <dshow.h>#include <vector>using namespace std;#ifndef SAFE_RELEASE#define SAFE_RELEASE( x ) if ( NULL != x ) { x->Release( ); x = NULL; }#endif#pragma comment(lib,"strmiids.lib")typedef struct Device{CString Description;CString FrindlyName;int WaveInID;CString DevicePath;}Device,*PDevice;// CPreviewWindow 对话框class CPreviewWindow : public CDialogEx{DECLARE_DYNAMIC(CPreviewWindow)public:CPreviewWindow(CWnd* pParent = NULL);   // 标准构造函数virtual ~CPreviewWindow();HWND GetHwnd();//返回对话框类句柄// 对话框数据enum { IDD = IDD_VIDEOVIEW };protected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持DECLARE_MESSAGE_MAP()public:CStatic m_video;public://CVideoCapture(void);//~CVideoCapture(void);HRESULT EnumDevices(REFGUID category);//枚举设备HRESULT InitCaptureGraphBuilder();<span style="white-space:pre"></span>//初始化视频采集过滤器BOOL InitPreview();void StartPreview();void StopPreview();void CancelPreview();void PausePreview();public:IEnumMoniker *pEnum;IMoniker *pMoniker;vector<Device> m_device;IBaseFilter *pCap;//视频采集过滤器//IBaseFilter *SmartTee;//Smart Tee Filter//IBaseFilter *pRender;//Video Render FilterICaptureGraphBuilder2 *pBuilder;//视频采集过滤器图表IGraphBuilder *pGraph;//过滤器图表管理器IVideoWindow *pVideoWindow;IMediaControl *pControl;//用户命令接口,用来控制过滤器图表IMediaEvent *pEvent;//过滤器图表事件接口//HWND hWnd;afx_msg void OnSizing(UINT fwSide, LPRECT pRect);};
枚举视频设备实现如下:

HRESULT CPreviewWindow::EnumDevices(REFGUID category){// Create the System Device Enumerator.ICreateDevEnum *pDevEnum;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pDevEnum));if(SUCCEEDED(hr)){// Create an enumerator for the category.hr = pDevEnum->CreateClassEnumerator(category,&pEnum,0);if(hr == S_FALSE){pDevEnum->Release();return VFW_E_NOT_FOUND;// The category is empty. Treat as an error.}//show device listDevice dev;CString str;while(pEnum->Next(1,&pMoniker,NULL) == S_OK){IPropertyBag *pPropBag;HRESULT hr = pMoniker->BindToStorage(0,0,IID_PPV_ARGS(&pPropBag));if(FAILED(hr)){pMoniker->Release();continue;}VARIANT var;VariantInit(&var);// Get description or friendly name.hr = pPropBag->Read(L"Description",&var,0);if(SUCCEEDED(hr)){dev.Description = var.bstrVal;VariantClear(&var);}hr = pPropBag->Read(L"FriendlyName",&var,0);if(SUCCEEDED(hr)){dev.FrindlyName = var.bstrVal;//MessageBox(dev.FrindlyName);OutputDebugString(var.bstrVal);VariantClear(&var);}hr = pPropBag->Write(L"FrindlyName",&var);hr = pPropBag->Read(L"WaveInID",&var,0);if(SUCCEEDED(hr)){dev.WaveInID = var.lVal;VariantClear(&var);}hr = pPropBag->Read(L"DevicePath",&var,0);if(SUCCEEDED(hr)){dev.DevicePath = var.bstrVal;VariantClear(&var);}m_device.push_back(dev);//增加设备pPropBag->Release();pMoniker->Release();}pDevEnum->Release();}return hr;}
初始化视频采集过滤器:

HRESULT CPreviewWindow::InitCaptureGraphBuilder(){// Create the Capture Graph BuilderHRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,CLSCTX_INPROC_SERVER,IID_ICaptureGraphBuilder2,(void**)&pBuilder);if(SUCCEEDED(hr)){// Create the Filter Graph Manager.hr = CoCreateInstance(CLSID_FilterGraph,0,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&pGraph);if(SUCCEEDED(hr)){pBuilder->SetFiltergraph(pGraph);return S_OK;}else{pBuilder->Release();}}return hr;}
初始化好视频采集过滤器之后就可以将其绑定到视频源上采集数据,那么采集到的数据如何显示到界面上呢?这是最关键的问题。

首先定义一个IVideoWindow类型的对象,该对象用于连接视频图像数据与MFC窗口界面。下面就实现这个功能:

BOOL CPreviewWindow::InitPreview(){if(pMoniker == NULL)EnumDevices(CLSID_VideoInputDeviceCategory);//枚举设备HRESULT hr = pMoniker->BindToObject(0,0,IID_IBaseFilter,(void**)&pCap);if(SUCCEEDED(hr)){hr = pGraph->AddFilter(pCap,L"Capture Filter");}hr = pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pCap,NULL,NULL);hr = pGraph->QueryInterface(IID_IVideoWindow,(void**)&pVideoWindow);if(SUCCEEDED(hr)){pVideoWindow->put_Owner((OAHWND)this->m_hWnd);//设定视频窗口为主窗口的一个子窗口pVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);//设定窗口模式CRect rectClient;::GetClientRect(this->m_hWnd,rectClient);pVideoWindow->SetWindowPosition(0,0,rectClient.right,rectClient.bottom);//设定窗口大小}else{return FALSE;}hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl);if(FAILED(hr)){return FALSE;}return TRUE;}

到目前已经可以显示视频预览了,那么如何控制视频预览呢?

定义一个IMediaControl pControl对象来控制视频的预览,下面就具体实现视频预览的控制方法:

void CPreviewWindow::PausePreview(){if(pControl)pControl->Pause();//暂停}void CPreviewWindow::StopPreview(){if(pControl)pControl->Stop();//停止pVideoWindow->put_Visible(FALSE);}void CPreviewWindow::StartPreview(){pVideoWindow->put_Visible(OATRUE);//设定可视pControl->Run();//开始预览}

调用方法:

在控件CVideoPreviewCtrl类中添加如下代码:

public:
CPreviewWindow m_PreviewWin;
BOOL InitFlag;
void EnumDevices(void);
void StartPreview(void);
void PausePreview(void);
void StopPreview(void);

重写OnCreate方法:

int CVideoPreviewCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO:  在此添加您专用的创建代码
if(!m_PreviewWin.Create(IDD_VIDEOVIEW,this))
MessageBox(L"创建对话框失败");
m_PreviewWin.InitCaptureGraphBuilder();
InitFlag = m_PreviewWin.InitPreview();
return 0;
}


添加接口供外部调用:

void CVideoPreviewCtrl::StartPreview(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

// TODO: 在此添加调度处理程序代码
//MessageBox(L"开始预览");
//m_PreviewWin.EnumDevices(CLSID_VideoInputDeviceCategory);
if(InitFlag)
m_PreviewWin.StartPreview();
}

void CVideoPreviewCtrl::PausePreview(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加调度处理程序代码
m_PreviewWin.PausePreview();


void CVideoPreviewCtrl::StopPreview(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: 在此添加调度处理程序代码
m_PreviewWin.StopPreview();
}

测试方法参见VFW实现。



CVideoWindow.cpp



0 0
原创粉丝点击