簡化MFC版amcap

一、問題的提出

開始學習並熟悉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);
}

 

五、後續

此例是個練習程序,文檔說明中也有一些知識點需要補充。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章