Introduction To Direct Show

3,900 views

Published on

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,900
On SlideShare
0
From Embeds
0
Number of Embeds
32
Actions
Shares
0
Downloads
103
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Introduction To Direct Show

  1. 1. Introduction to DirectShow Qing qing@cs.nthu.edu.tw (Email/MSN) 2007/1/12
  2. 2. 何謂 DirectShow ? <ul><li>DirectShow 是 DirectX 家族中的一支 </li></ul><ul><li>除了 DirectShow 之外, DirectShow 尚包括了 </li></ul><ul><ul><li>DirectPlay </li></ul></ul><ul><ul><li>DirectDraw </li></ul></ul><ul><ul><li>Direct3D </li></ul></ul><ul><ul><li>DirectMusic </li></ul></ul><ul><li>DirectShow 的用途在於多媒體資訊的呈現 </li></ul><ul><ul><li>視訊 </li></ul></ul><ul><ul><li>音訊 </li></ul></ul>
  3. 3. DirectShow 的應用範圍 <ul><li>多媒體訊息的輸入 </li></ul><ul><ul><li>麥克風 </li></ul></ul><ul><ul><li>攝影機 </li></ul></ul><ul><ul><li>檔案 </li></ul></ul><ul><ul><li>網路串流 </li></ul></ul><ul><li>多媒體訊息的剖析 </li></ul><ul><li>多媒體訊息的編碼,解碼 </li></ul><ul><li>多媒體訊息的撥放 </li></ul><ul><ul><li>音訊視訊呈現 </li></ul></ul><ul><li>多媒體訊息的儲存 </li></ul>
  4. 4. 使用 DirectShow 必備 <ul><li>C/C++/VB/C# </li></ul><ul><li>Windows COM 元件的使用 </li></ul>
  5. 5. DirectShow 架構的優點 <ul><li>元件化,可重用性高 </li></ul><ul><ul><li>各種用途的元件,都化身為標準的 Filter ,具備相同的介面,容易搭接各式 Filter </li></ul></ul><ul><li>極具彈性,透過對 Filter 的客製及組裝,可以達成各式的目的 </li></ul>
  6. 6. DirectShow 核心元件 <ul><li>IFilterGraph </li></ul><ul><ul><li>每個撥放結構都是用一個 IFilterGraph 所描述 </li></ul></ul><ul><li>IGraphBuilder </li></ul><ul><ul><li>建立 、 控制 IFilterGraph 的元件 </li></ul></ul><ul><li>IBaseFilter </li></ul><ul><ul><li>DirectShow 中所有的 Filter 都實作的介面 </li></ul></ul><ul><li>IPin </li></ul><ul><ul><li>代表多媒體訊息在 IFilterGraph 中流動的接腳 </li></ul></ul><ul><ul><li>每個 IBaseFilter 都有一個以上的 IPin </li></ul></ul><ul><li>IMediaControl </li></ul><ul><ul><li>控制多媒體訊息撥放行為的元件 </li></ul></ul><ul><li>IMediaEvent </li></ul><ul><ul><li>取得多媒體訊息撥放時的事件 </li></ul></ul>
  7. 7. 一個最簡單的 DirectShow 範例 ( DSFilePlayer.cpp) <ul><li>目的:從檔案執行撥放指定的多媒體檔案 </li></ul><ul><li>步驟: </li></ul><ul><ul><li>初始化 COM </li></ul></ul><ul><ul><li>建立 IFilterGraph 的 instance </li></ul></ul><ul><ul><li>取得 IMediaControl 的介面( IFilterGraph 實作了 IMediaControl 的介面) </li></ul></ul><ul><ul><li>取得 IMediaEvent ( IFilterGraph 實作了 IMediaEvent 的介面) </li></ul></ul><ul><ul><li>透過 IMediaControl 智慧型的建立 Filter Graph 的內容 </li></ul></ul><ul><ul><li>透過 IMediaControl 啟動撥放 </li></ul></ul><ul><ul><li>透過 IMediaEvent 等待撥放結束 </li></ul></ul>
  8. 8. 初始化 COM <ul><li>HRESULT hr; </li></ul><ul><li>hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); </li></ul><ul><li>if( FAILED(hr) ) </li></ul><ul><li>{ </li></ul><ul><li>CoUninitialize(); </li></ul><ul><li>return hr; </li></ul><ul><li>} </li></ul>
  9. 9. 建立 IFilterGraph 的 instance <ul><li>IFilterGraph *pFilterGraph = NULL; </li></ul><ul><li>// </li></ul><ul><li>hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IFilterGraph, (void**) &pFilterGraph); </li></ul>
  10. 10. 取得 IMediaControl/IMediaEvent 的介面 <ul><li>IMediaControl *pMC = NULL; </li></ul><ul><li>IMediaEvent *pME = NULL; </li></ul><ul><li>hr = pFilterGraph->QueryInterface(IID_IMediaControl, (void **) &pMC); </li></ul><ul><li>if( FAILED(hr) ) </li></ul><ul><li>{ </li></ul><ul><li>return hr; </li></ul><ul><li>} </li></ul><ul><li>hr = pFilterGraph->QueryInterface(IID_IMediaEvent, (void **) &pME); </li></ul><ul><li>if( FAILED(hr) ) </li></ul><ul><li>{ </li></ul><ul><li>pFilterGraph->Release(); </li></ul><ul><li>pMC->Release(); </li></ul><ul><li>return hr; </li></ul><ul><li>} </li></ul>
  11. 11. 建立 Filter Graph/ 撥放 / 等待停止 <ul><li>OAEVENT oEvent; </li></ul><ul><li>hr = pME->GetEventHandle(&oEvent); </li></ul><ul><li>if( SUCCEEDED(hr) ) </li></ul><ul><li>{ </li></ul><ul><li>hr = pMC-> RenderFile (fileName); </li></ul><ul><li>if( SUCCEEDED(hr) ) </li></ul><ul><li>{ </li></ul><ul><li>hr = pMC-> Run (); </li></ul><ul><li>if( SUCCEEDED(hr) ) </li></ul><ul><li>{ </li></ul><ul><li>LONG levCode; </li></ul><ul><li>hr = pME-> WaitForCompletion (INFINITE, &levCode); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  12. 12. 何謂 Filter Graph ? *Render WMV9 時會自動建立的 Filter Graph *Render MPEG 時會自動建立的 Filter Graph Output Pin Input Pin 分流 Renderer Source Filter Splitter
  13. 13. 何謂 Filter ? <ul><li>一個 Filter 具備一個以上的 Pin </li></ul><ul><li>Pin 依多媒體訊息流動的方向可分為 Input Pin 或 Output Pin </li></ul><ul><li>Filter 的 Input Pin ,代表對此 Filter 是訊息流入的 Pin </li></ul><ul><li>Filter 的 Outut Pin ,代表對此 Filter 是訊息流出的 Pin </li></ul>
  14. 14. 何謂 Pin <ul><li>Pin 是 DirectShow 中多媒體訊息藉以流經的元件 </li></ul><ul><li>Pin 是 DirectShow 中,兩個 Filter 相接的介面 </li></ul><ul><li>每個 Pin 都有可以接受的 Media Type </li></ul><ul><ul><li>每個 Media Type 都有一個 major type </li></ul></ul><ul><ul><ul><li>例如 MEDIATYPE_Video 或 MEDIATYPE_Audio </li></ul></ul></ul><ul><ul><li>每個 Media Type 都有一個 minor type </li></ul></ul><ul><ul><ul><li>例如 MEDIASUBTYPE_RGB32 </li></ul></ul></ul><ul><li>在 Filter Graph 中要接在一起的兩個 Filter ,其中一個的 Output Pin 可接受的 media type 必須和另一個 Filter 的 Input Pin 可接受的 media type 相符 </li></ul>
  15. 15. Filter Graph 的建立 <ul><li>智慧型連接需要的 Filter </li></ul><ul><li>手動建立 </li></ul><ul><ul><li>自己產生所需的各種 Filter </li></ul></ul><ul><ul><li>依據需求把要連接在一起的兩兩 Filter 接在一起 </li></ul></ul><ul><ul><ul><li>把 Filter A 的 Output Pin 接到 Filter B 的 Input Pin </li></ul></ul></ul>
  16. 16. 如何開始 DirectShow 應用程式的開發 <ul><li>安裝 SDK </li></ul><ul><ul><li>DirectX SDK ,或 </li></ul></ul><ul><ul><li>Platform SDK </li></ul></ul><ul><li>將 SDK 的 include 目錄加至 Visual Studio 的 include 目錄中 </li></ul><ul><li>將 SDK 的 lib 目錄加至 Visual Studio 的 lib 目錄中 </li></ul><ul><li>build DirectX SDK 中附的 DirectShow BaseClasses </li></ul><ul><ul><li>例: DirectX 9.0 </li></ul></ul><ul><ul><li>DXSDKSamplesC++DirectShowBaseClasses </li></ul></ul><ul><li>產生 BaseClassesDebugstrmbasd.lib ( debug mode 用) </li></ul><ul><li>產生 BaseClassesReleasestrmbase.lib ( release mode 用) </li></ul>
  17. 17. 如何設定 DirectShow 應用程式的專案 <ul><li>在專案設定中設定 C/C++ 及 Linker 的選項 </li></ul><ul><li>C/C++ </li></ul><ul><ul><li>General </li></ul></ul><ul><ul><ul><li>Additional Include Directories ,加上: BaseClasses </li></ul></ul></ul><ul><ul><li>Preprocessor </li></ul></ul><ul><ul><ul><li>Preprocessor Definitions ,加上: _WIN32_DCOM </li></ul></ul></ul><ul><li>Linker </li></ul><ul><ul><li>General </li></ul></ul><ul><ul><ul><li>Additional Library Directories ,加上: BaseClassesDebug 或 BaseClassesRelease (視 debug mode 或 release 而定,加上這兩個目錄的原因是要將 Input 中指定的 strmbasd.lib 或 strmbase.lib 加入) </li></ul></ul></ul><ul><ul><li>Input </li></ul></ul><ul><ul><ul><li>Additional Dependencies ,加上: strmbasd.lib (或 strmbase.lib ,視 debug mode 或 release 而定) winmm.lib </li></ul></ul></ul>
  18. 18. BaseClasses 及 DirectShow 範例 <ul><li>雖然 BaseClasses 被放在 DirectShow 的範例程式中,但其實提供了對於 DirectShow COM 介面的高階實作 </li></ul><ul><li>基於 BaseClasses ,繼承其類別,對於實作 DirectShow 中的各式 Filter 有相當大的幫助 </li></ul><ul><li>在撰寫各式 Filter 時,建議參考 DirectShow 中的範例程式 </li></ul><ul><ul><li>例: DirectX 9.0 </li></ul></ul><ul><ul><li>DXSDKSamplesC++DirectShowFilters </li></ul></ul>
  19. 19. 範例程式中示範的基本 Filter 類型 (1/2) <ul><li>Async : Pull mode 的 Source Filter </li></ul><ul><ul><li>Source Filter 是提供多媒體訊息的 Filter (起點) </li></ul></ul><ul><ul><li>Pull Source Filter 是基於另一 Filter 的 Input Pin 的請求,將資料餵至自己的 Output Pin </li></ul></ul><ul><li>Dump : Renderer Filter </li></ul><ul><ul><li>Renderer Filter 是負責呈現多媒體訊息的 Filter (終點) </li></ul></ul><ul><li>EZRGB24 : Image Processing Filter </li></ul><ul><ul><li>針對多媒體訊息進行加工的 Filter </li></ul></ul><ul><li>Grabber : SampleGrabber Filter </li></ul><ul><ul><li>擷錄 Filter Graph 中流動的多媒體訊息用的 Filter </li></ul></ul>
  20. 20. 範例程式中示範的基本 Filter 類型 (2/2) <ul><li>INFTee : Infinite Pin Tee Filter </li></ul><ul><ul><li>Tee Fitler 是分接用的 Filter ,例如一個輸出 Pin 變成兩個輸出 Pin ,將多媒體訊息複製成多份,提供給後續的多個 Filter </li></ul></ul><ul><ul><li>INFTee 可將一個 Input Pin 的內容,複製至不限個數的 Output Pin </li></ul></ul><ul><li>NullInPlace : In-Place Transform Filter </li></ul><ul><ul><li>於原地(不配置額外的記憶體)處理多媒體訊息的 Filter </li></ul></ul><ul><li>NullNull : Minimal Null Filter </li></ul><ul><ul><li>示範最小的 Filter </li></ul></ul><ul><li>PushSource : Push Source Filter </li></ul><ul><ul><li>Push Source Filter 是自己主動將資料餵至自己的 Output Pin 的 Filter </li></ul></ul>
  21. 21. 多媒體呈現應用時常用到的 Push Source Filter <ul><li>QPushSource 是一個通用的範例 </li></ul><ul><li>參考 QPushSource.cpp, QPushSource.h, QPushSourceGuids.h </li></ul><ul><li>繼承後覆寫,或直接改寫 QPushSourceStream 的 </li></ul><ul><ul><li>HRESULT GetMediaType(CMediaType *pMediaType) </li></ul></ul><ul><ul><li>HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest) </li></ul></ul><ul><li>改寫 </li></ul><ul><ul><li>CLSID_QPushSource </li></ul></ul>
  22. 22. HRESULT GetMediaType(CMediaType *pMediaType) <ul><li>當兩個 Pin 之間做連接的動作時,會呼叫 GetMediaType() 判斷兩 Filter 是否能夠相接 </li></ul><ul><ul><li>取決在回傳的 pMediaType 是否相容 </li></ul></ul><ul><li>如何改寫 GetMediaType() ? </li></ul><ul><ul><li>根據你的 Push Source Filter 會回傳的多媒體類型,適時的填入 </li></ul></ul><ul><ul><li>例如產生 RGB32 的 Video 訊息 </li></ul></ul><ul><ul><li>pMediaType->SetType(& MEDIATYPE_Video); </li></ul></ul><ul><ul><li>pMediaType->SetSubtype(& MEDIASUBTYPE_RGB32); </li></ul></ul><ul><ul><li>pvi->bmiHeader.biCompression = BI_RGB; </li></ul></ul><ul><ul><li>pvi->bmiHeader.biBitCount = 32; </li></ul></ul>
  23. 23. HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pRequest) <ul><li>Push Source Filter 的下游 Filter 會呼叫 DecideBufferSize() 來得知究竟應該準備多大的 buffer 空間來接收 Push Source Filter 傳入的資料 </li></ul><ul><li>例如,對 640x480 的 RGB32 資料來說: </li></ul><ul><ul><li>pRequest->cbBuffer = 640*480*4; </li></ul></ul>
  24. 24. 如何使用 QPushSource <ul><li>產生 QPushSource 的 instance </li></ul><ul><ul><li>pPushSource = (QPushSource*) QPushSource::CreateInstance(NULL, &hr); </li></ul></ul><ul><li>由 QPushSource 的 Output Pin 開始 Render FilterGraph </li></ul>
  25. 25. 使用 QPushSource 的步驟 <ul><li>設定或繼承並覆寫 QPushSourceStream::GetMediaType </li></ul><ul><ul><li>指定正確的 Media Type 及 Format </li></ul></ul><ul><li>設定或繼承並覆寫 QPushSourceStream::DecideBufferSize </li></ul><ul><ul><li>指定足夠大的 buffer 大小 </li></ul></ul><ul><li>修改範例 main.cpp 中的 HowToAddANewFrame() ,把多媒體訊息加入至 QPushSource 中的 queue </li></ul>
  26. 26. main.cpp: 示範如何運用 QPushSource <ul><li>// 初始化 COM </li></ul><ul><li>CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); </li></ul><ul><li>// 產生 QPushSource 的 instance </li></ul><ul><li>pPushSource = (QPushSource*) QPushSource::CreateInstance(NULL, &hr); </li></ul><ul><li>// 從 QPushSource 開始 Render 整個 Filter Graph </li></ul><ul><li>hr = RenderSourceFilter(pPushSource, &pFilterGraph); </li></ul><ul><li>// 啟動 Filter Graph 的運作,並等待結束 </li></ul><ul><li>hr = RunGraphAndWaitFormCompletion(pFilterGraph); </li></ul>
  27. 27. Q&A Thanks

×