摘要:利用微軟公司提供的DirectShow接口技術,Windows系統下的流媒體編程變得簡單。文章對DirectShow技術作了概括介紹,并給出了視頻捕獲程序的實現過程。
關鍵詞:DirectShow;流媒體;visual c++
中圖分類號:TP37文獻標識碼:A文章編號:1009-3044(2008)32-1202-02
The Stream Media Development Technology Based on Directshow
FAN Yi-hong, ZHANG Gui-rong
(Electronic Information Engineering College, Henan University of Science and Technology, Luoyang 471003, China)
Abstract: Make use of the DirectShow interface technique provided by the Microsoft Corporation, stream media programming under windows system is becoming simple. This paper introduces DirectShow and presents software implementation of a video capture.
Key words: directShow; stream media; visual c++
1 引言
伴隨著計算機和網絡技術的快速發展,流媒體技術在視頻會議,視頻點播,遠程教育,在線影院,網上演示等許多領域都得到了十分廣泛的應用。怎樣使流媒體的處理變得簡單和高效已經成為當今人們十分關心的問題。DirectShow是Microsoft提供的一套在Windows平臺上進行流媒體處理的SDK,它給出了一種全新的流媒體數據處理模型,并封裝了采集、壓縮和解壓縮等一系列算法,為視頻監控、視頻會議等流媒體應用系統的開發提供了良好的平臺。本文介紹了vc環境下基于DirectShow的視頻捕獲程序實現過程。
2 DirectShow的體系結構
DirectShow本質上是基于COM組建模型且規定了一組接口的流媒體應用框架。在DirectShow中最基本的概念是過濾器。一個過濾器(Filter)就是一個COM對象,具有特定的功能,過濾器對象通過其輸入針和輸出針之間的有序連接構成過濾器圖表,過濾器圖表(Filter Graph)由過濾器圖表管理器(Filter Graph Manager)對象管理,用戶通過過濾器圖表管理器提供的接口就可以實現流媒體的回放、采集等功能。
DirectShow中的過濾器按實現的功能可分為三種基本類型,源過濾器(Source Filter)、變換過濾器(Transform Filter)及渲染過濾器(Rendering Filter)。Source Filter主要負責獲取數據,數據源可以是文件、因特網計算機里的采集卡(WDM驅動的或VFW驅動的)、數字攝像機等。Transform Filter主要負責數據格式的轉換。Rendering Filter主要負責數據的最終去向,將數據送給顯卡、聲卡進行流媒體的演示,或者輸出到文件進行存儲。Filter一般有一個或多個Pin組成,Filter之間通過Pin相互連接,構成一條順序的鏈路。Source Filter只有輸出Pin沒有輸入Pin,Transform Filter既有輸出Pin也有輸入Pin,Rendering Filter只有輸入Pin沒有輸出Pin。
開發DirectShow應用程序,一般有3個階段。第一個階段,創建一個Filter Graph Manager組件。第二階段,根據實際的應用,創建一條完整的Filter鏈路,該過程可以調用Filter Graph的接口方法手工編程實現、也可以調用Filter Graph Manager的接口方法實現智能連接。第三個階段,調用Filter Graph Manager上的各個接口方法進行控制,并完成Filter Graph Manager與應用程序的事件交互。
3 視頻捕獲程序的實現
3.1 系統設置
首先下載DirectX SDK并安裝(假如安裝在D:\\DXSDK目錄下)。然后對VC開發環境配置。
編譯基類源代碼,生成靜態連接庫文件,用VC打開 D:\\DXSDK\\Sample\\C++\\Directshow\\BaseClasses\\baseclass.dsw并編譯,Debug版本生成strmbasd.lib。
配置VC的編譯環境:執行VC的菜單命令Tools|Options,在隨后彈出的對話框中單擊Directories標簽,在Show directories for下拉列表中選擇Include files,配置如下:(注意,務必將DirectX SDK的目錄放在標準的VC目錄之前。)
D:\\DXSDK\\Include
D:\\DXSDK\\SAMPLES\\C++\\DIRECTSHOW\\BASECLASSES
D:\\DXSDK\\SAMPLES\\C++\\COMMON\\INCLUDE
D:\\Program Files\\Microsoft Visual Studio\\VC98\\INCLUDE
D:\\Program Files\\Microsoft Visual Studio\\VC98\\MFC\\INCLUDE
D:\\Program Files\\Microsoft Visual Studio\\VC98\\ATL\\INCLUDE
再在Show directories for 下拉列表中選擇Library files,配置如下:
D:\\DXSDK\\Lib
D:\\DXSDK\\SAMPLES\\C++\\DIRECTSHOW\\BASECLASSES\\DEBUG
D:\\Program Files\\Microsoft Visual Studio\\VC98\\LIB
D:\\Program Files\\Microsoft Visual Studio\\VC98\\MFC\\LIB
執行VC的菜單命令Project|Settings,在隨后彈出的對話框中單擊Link標簽,在Object/library modules文本框中,添加strmbasd.lib Winmm.lib。
3.2 系統設計
在動手寫程序之前,應首先明確系統的功能,確定需要用到那些Filter,然后在GraphEdit(D:\\DXSDK\\Bin\\DXUtils)中把這些Filter連接起來,觀看效果。視頻捕獲程序需要用到:Video Device、AVI Decompressor、Video Renderer3種Filter。
3.3 代碼實現
1) 創建一個基于基本對話框的工程capture,制作對話框如圖2所示。
在建立類向導中為picture控件添加CStatic 類型變量m_videowindows,用作視頻圖像的播放窗口。
2) 系統初始化。
在CCaptureDlg::OnInitDialog()中添加代碼:
CoInitialize(NULL);//初始化com組件
在captureDlg.h中加入:
#include \"streams.h\"
#include \"qedit.h\"
3) 在void CCaptureDlg::OnButton1()(button1為監控按鈕)中添加代碼,實現視頻監控。
① 創建Filter Graph Builder。
IGraphBuilder *mGraph=NULL;
ICaptureGraphBuilder2 * pBuilder=NULL;
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)mGraph);
CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2, (void **)pBuilder);
pBuilder->SetFiltergraph(mGraph);
①在Filter Graph加入視頻源過濾器
//創建一個系統枚舉組件
ICreateDevEnum *pSysDevEnum=NULL;
CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER,IID_ICreateDevEnum,(void**)pSysDevEnum);
//指定枚舉的類型目錄,獲得IEnumMoniker接口
IEnumMoniker *pEnumCat=NULL;
pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,pEnumCat,0);
//使用IEnumMoniker接口枚舉所有的設備標識,因系統只有一個視頻設備,因沒用循環
IMoniker *pMoniker=NULL;
IBaseFilter * m_pFilter=NULL;
ULONG cFetched;
if(pEnumCat->Next(1,pMoniker,cFetched)==S_OK)
{//創建Filter實例
pMoniker->BindToObject(NULL,NULL,IID_IBaseFilter,(void**)m_pFilter);
mGraph->AddFilter(m_pFilter, L\"Video Device\");}
pMoniker->Release();
pEnumCat->Release();
pSysDevEnum->Release();
③ 在Filter Graph加入AVI Decompressor Filter
IBaseFilter *pAviDecompressorF=NULL;
CoCreateInstance(CLSID_AVIDec, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void **)pAviDecompressorF);
mGraph->AddFilter(pAviDecompressorF, L\"AVI Decompressor\");
pAviDecompressorF->Release();
④ 連接各Filter。
pBuilder->RenderStream(PIN_CATEGORY_CAPTURE,MEDIATYPE_Video,m_pFilter,pAviDecompressorF,NULL);
pBuilder->Release();
⑤ 定義各個接口,用于對Filter Graph控制。可以根據需要增減。
IMediaControl *mMediaControl;
IVideoWindow*mVideoWindow;
mGraph->QueryInterface(IID_IMediaControl, (void **)mMediaControl);
mGraph->QueryInterface(IID_IVideoWindow, (void **)mVideoWindow);
⑥ 設置視頻窗口
if (mVideoWindow)
{mVideoWindow->put_Visible(OAFALSE);
mVideoWindow->put_Owner((OAHWND)m_videowindows.GetSafeHwnd());
RECT windowRect;
::GetClientRect(m_videowindows.GetSafeHwnd(), windowRect);
mVideoWindow->put_Left(0);
mVideoWindow->put_Top(0);
mVideoWindow->put_Width(windowRect.right - windowRect.left);
mVideoWindow->put_Height(windowRect.bottom - windowRect.top);
mVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);
mVideoWindow->put_MessageDrain((OAHWND) m_videowindows.GetSafeHwnd());
if (m_videowindows.GetSafeHwnd() != NULL)
mVideoWindow->put_Visible(OATRUE);
else
mVideoWindow->put_Visible(OAFALSE);}
⑦ 運行
mMediaControl->Run();
以上程序在VC6.0環境下運行通過,其他代碼略。
4 結束語
實驗證明,利用DirectShow的流媒體開發具有代碼量少、通用性強、實時性好的特點。
參考文獻:
[1] 陸其明.DirectShow開發指南[M].北京:清華大學出版社,2003.
[2] 陸其明.DirectShow務實精選[M].北京:科學出版社,2004.