简化MFC版amcap

来源:互联网 发布:淘宝的类目都有哪些 编辑:程序博客网 时间:2024/06/10 14:49

一、问题的提出

开始学习并熟悉DirectShow,最好的范例就是AMCap,因为它提供了两套Dshow最基本的代码模型:预览与捕获,并实现了显示设备属性页和流控等一系列技术,并且很多硬件捕获把它附加为软件,以便可以察看自己硬件的预览效果。

AMCapDirectX安装包内,安装后的路径为:XXX:/DXSDK/Samples/C++/DirectShow/Capture/AMCap

AMCap是基于Win32的,很多代码实现与MFC不同,并且测试实例是基于对话框,所以需要对代码做一些改动。

 

二、效果图

三、示例实现与实现功能

实现:

1.    预览

2.    捕获为位图

3.    捕获为AVI

4.    视频源

5.    视频格式

6.    根据视频格式同步视频尺寸

7.    热插拔

8.    多视频设备切换

 

未实现

1.    音频

2.    视频源

3.    视频尺寸设置不到视频格式中

4.    不支持vfw

5.    不支持流控

6.    不支持DV

7.    不支持crossbars

8.    ……

 

四、具体代码实现

虽然AMCap是由Win32实现,但代码直接复制到MFC的对话框程序内,修改一下就可以使用。这里主要讲几点amcapsimp的新增代码点。

1) 捕获一帧并保存为位图

此功能的实现原理和代码是从DirectX C++文档中的DirectShowCapturing an Image From a Still Image Pin修改而来。它在生成预览graph时创建ISampleGrabber的实例对象,转换成IBaseFilter对象后加入filter graph。其它流程和文档中一致。

把位图缓存并写到文件中是由一个回调函数来处理:SampleGrabberCallback,具体代码为文档提供。

 

2) 热插拔的通知处理

首先在OnInitDialog中注册设备通知

BOOL CamcapsimpDlg::DeviceNotifyRegister()
{
    DeviceNotifyUnregister();

    DEV_BROADCAST_DEVICEINTERFACE   broadcastInterface;
    
    
// Register to receive notification when device is plugged in.
    broadcastInterface.dbcc_size        = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    broadcastInterface.dbcc_devicetype    
= DBT_DEVTYP_DEVICEINTERFACE;
    broadcastInterface.dbcc_classguid    
= AM_KSCATEGORY_CAPTURE;
    
    m_hDeviceNotify 
= RegisterDeviceNotification(m_hWnd,
        
&broadcastInterface, DEVICE_NOTIFY_WINDOW_HANDLE);

    
if( m_hDeviceNotify ) {
        
return TRUE;
    }


    
return FALSE;
}

 

然后声明并实现一个虚函数,在设备改变时重新枚举一遍设备

virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

LRESULT CamcapsimpDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
    
switch(message)
    
{
     
case WM_DEVICECHANGE:
            
// We are interested in only device arrival & removal events
            if(DBT_DEVICEARRIVAL != wParam && DBT_DEVICEREMOVECOMPLETE != wParam)
                
break;

            PDEV_BROADCAST_HDR pdbh 
= (PDEV_BROADCAST_HDR) lParam;
            
if(pdbh->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
            
{
                
break;
            }


            PDEV_BROADCAST_DEVICEINTERFACE pdbi 
= (PDEV_BROADCAST_DEVICEINTERFACE) lParam;
            
// Check for capture devices.
            if(pdbi->dbcc_classguid != AM_KSCATEGORY_CAPTURE)
            
{
                
break;
            }


            
// Check for device arrival/removal.
            if(DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam)
            
{
                m_bDeviceChanged 
= FALSE;
                AddDevicesToCombox();
            }

            
break;
    }

    
    
return CDialog::WindowProc(message, wParam, lParam);
}

 

五、后续

此例是个练习程序,文档说明中也有一些知识点需要补充。