學習DirectShow有一段時間了,把這段學習過程中翻譯出來的SDK與大家分享,同時也希望專家們指出我理解上的錯誤,萬分感謝。
1. DirectShow介紹
DirectShow是一個windows平台上的流媒體架構,提供了高品質的多媒體流採集和回放功能。它支援多種多樣的媒體檔案格式,包括ASF、MPEG、AVI、MP3和WAV檔案,同時支援使用WDM驅動或早期的VFW驅動來進行多媒體流的採集。DirectShow整合了其它的DirectX技術,能自動地偵測並使用可利用的音視頻硬體加速,也能支援沒有硬體加速的系統。
DirectShow大大簡化了媒體回放、格式轉換和採集工作。但與此同時,它也為使用者自訂的解決方案提供了底層流量控制架構,從而使使用者可以自行建立支援新的檔案格式或其它用途的DirectShow組件。
以下是幾個使用DirectShow編寫的典型應用:DVD播放器、視頻編輯應用、AVI到ASF轉換器、MP3播放器和數位視訊採集應用。
DirectShow是建立在元件物件模型(COM)上的,因此當你編寫DirectShow應用時,你必須具備COM用戶端程式編寫的知識。對於大部分的應用,你不需要實現自己的COM對象,DirectShow提供了大部分你需要的DirectShow組件,但是假如你需要編寫自己的DirectShow組件,你還需要具備編寫COM組件的知識。
1.1. DirectShow支援的格式
DirectShow是一個開放的架構,因此只要有合適的filter來分析和解碼,它可以支援任何格式。DirectShow預設支援以下的檔案類型和壓縮格式:
註:打*號的需要Windows Media Format SDK支援
檔案類型:
Windows Media? Audio (WMA)*
Windows Media? Video (WMV)*
Advanced Systems Format (ASF)*
Motion Picture Experts Group (MPEG)
Audio-Video Interleaved (AVI)
QuickTime (version 2 and lower)
WAV
AIFF
AU
SND
MIDI
壓縮格式:
Windows Media Video*
ISO MPEG-4 video version 1.0*
Microsoft MPEG-4 version 3*
Sipro Labs ACELP*
Windows Media Audio*
MPEG Audio Layer-3 (MP3) (decompression only)
Digital Video (DV)
MPEG-1 (decompression only)
MJPEG
Cinepak
微軟自己沒有提供MPEG2解碼器,一些可用的DirectShow MPEG2硬體或軟體解碼器是由第三方提供的。
1.2. 常見問題集(摘錄)
1.2.1. 一般問題
*DirectShow支援哪些作業系統?
DirectShow支援Windows9X、Windows2000、Windows Me和Windows XP。
*使用DirectShow需要多少COM知識?
應用程式開發人員只需要基本的COM組件知識:執行個體化COM組件、調用介面、管理介面的引用計數。Filter開發人員則需要更多。
*有與DirectShow相容的硬體列表(HCL)嗎?
沒有。如果硬體相容DirectShow,DirectShow會使用它們,如果沒有相容的硬體,DirectShow使用GDI繪製視頻,以及使用WaveOut系列多媒體API來播放音頻。
*可以使用哪些語言來編寫DirectShow應用?
DirectShow主要為C/C++開發設計。Visual Basic只能使用其中的很小一部分。可以通過MS JScript或VB Script來支援基於指令碼的DVD和TV應用。也可能用Delphi來編寫,但SDK文檔不提供這方面的內容。
*DirectShow會通過Managed 程式碼實現嗎?
目前還沒有這個計劃。DirectX SDK提供了有限的使用音視頻回放類的託管回放功能,你可以使用COM interop建立Managed 程式碼的DirectShow用戶端應用,但是因為效能上的原因,不推薦建立運行在CLR上的filter。
*DirectShow開發需要什麼樣的編譯器?
任何能夠產生COM對象的編譯器都可以。
*DirectShow和DirectX的其它組件的關係
DirectShow和DirectX的其它組件在內部進行聯絡。DirectShow在硬體的支援下使用DirectSound和DirectDraw。Video Renderer和Overlay Mixer使用DirectDraw 3和DirectDraw5表面(surfaces)。Video Mixing Renderer 7(只支援WINXP)使用DirectDraw7表面。Video Mixing Renderer 9使用最新的(目前是Directx9)Direct3D API函數。即便是某個應用程式套件組合含了DirectX其它組件,你也不必使用其它組件的API去編寫它。參考SDK的例子:Texture3D Sample。
*DirectShow與ActiveMovie的關係?
ActiveMovie是DirectShow原來的名稱,現已不再使用,但是一部分API仍保留了"AM"的首碼,比如AM_MEDIA_TYPE和IAMVideoAccelerator。
*DirectShow是限於多媒體應用嗎?
DirectShow預設包含的組件主要是為音視頻流設計的,但是,DirectShow架構已經成功地用於其它資料流的解決方案中。
*GraphEdit工具有源碼嗎?GraphEdit.exe是否可再發布?
沒有源碼,不可再發布。
*DMO可以代替DirectShow filter嗎?
在編寫編碼器、解碼器、效果器應用時,鼓勵用DMO代替DirectShow filter。在其它的應用中,使用DirectShow filter可能會比較合適。
1.2.2. 程式編寫問題
*如何設定編譯環境,需要哪些標頭檔和庫?
參考"設定編譯環境"章節
*GraphEdit列示了很多沒有文檔支援的filter,它們都是些什嗎?
GraphEdit枚舉了所有作為filter類型註冊在系統中的filter,包括由第三方應用程式安裝的filter,以及其它微軟技術如Windows Media或NetMeeting安裝的,另外,一些DirectShow filter被用來做寫入程式碼或硬解碼驅動的外殼。Microsoft H.263 Video Codec用於NetMeeting,不再被DirectShow支援。
*如何知道DirectShow已經被安裝?
調用CoCreateInstance建立一個Filter Graph Manager執行個體,如果成功,表示DirectShow已經被安裝,下面是一個例子:
| IGraphBuilder *pGraph; HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) &pGraph);
|
*如果不通過屬性設定頁來更改filter的設定?
當然是通過filter提供的介面羅。如果沒有提供,就沒有辦法啦
*DirectShow能通知應用程式當前回放位置嗎?
不提供回調來通知位置,需要使用一個計時器定時調用IMediaSeeking::GetCurrentPosition方法來得到當前回放位置。
*filter運行在哪個特權層級下?
運行在Ring 3特權層級下,某些流量控制驅動(如音視頻採集驅動)運行在Ring 0特權層級下。
*需要一個Kernel調試器嗎?
這依據具體的項目。安裝DirectX調試執行階段程式庫(DirectX debug runtime library)意味著安裝調試驅動(Debug driver)和其它核心組件(kernel mode component),因此如果你的應用程式在其中的某個組件中產生了一個調試斷言(debug assert),你的機器就會自動重啟除非你擁有一個kernal調試器。
*DEFINE_GUID宏是怎麼工作的?
使用DEFINE_GUID宏可以讓你通過包含同一個標頭檔來定義GUID值而不必使用extern關鍵詞。比如,你的工程中有三個源檔案:src1.cpp,src2.cpp,src3.cpp,它們都使用一個相同的GUID值,而為了保證一致性,這個GUID只能在你的工程中定義一次,這時,其它的源檔案必須定義外部參考來使用它。用了DEFINE_GUID,你可以使用在所有源檔案中包含同一個標頭檔,在標頭檔中這樣定義GUID:
DEFINE_GUID(CLSID_MyObject, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
這個例子中GUID為0,實際編程中請用Guidgen工具來產生一個GUID,在其中的一個源檔案中,在你的標頭檔前包含initguid.h,如:
// Src1.cpp #include #include "MyGuids.h" // Src2.cpp #include "MyGuids.h" // Src3.cpp #include "MyGuids.h"
|
在沒有包含Initguid.h的地方,DEFINE_GUID宏建立外部參考來使用GUID值,在包含Initguid.h的地方,DEFINE_GUID重定義DEFINE_GUID宏以產生GUID的定義。
如是沒有在任何地方添加Initguid.h,你會得到一個連結錯誤:"unresolved external symbol." ,如果同樣的GUID包含Initguid.h兩次,會得到編譯錯誤"redefinition; multiple initialization."要解決這些問題,請確認Initguid.h只包含一次。同樣的,不要包含Initguid.h到先行編譯標頭檔中去,因為先行編譯標頭檔會被每個源檔案包含。