1. AVStream概覽
AVStream是一款微軟提供的多媒體類驅動程式,它既支援單獨的視頻流媒體,也支援音頻視頻整合的流媒體。微軟把AVStream作為作業系統的一部分,在驅動程式ks.sys中匯出。硬體供應商只需要編寫運行在Ks.sys下層的小驅動程式(minidriver)。
以前的音頻類驅動程式是微軟提供的音頻連接埠驅動程式(audio port class driver)。音頻供應商應該編寫運行在portcls.sys下層的小驅動程式(minidriver)。
微軟僅為已經存在的小驅動程式(minidrivers)提供流媒體類驅動(stream class driver)支援。
AVStream通過以下幾點向供應商提供意義重大的優點:
l 小驅動(minidriver)程式員可以編寫更少的代碼。
l 為音頻和視頻小驅動程式(minidrivers)提供統一的核心流媒體類模型。
l 供應商可以使用COM對象加入新的介面,而不需要對已存在的小驅動程式(minidriver)的二進位檔案做任何修改。
在AVStream驅動模型中,供應商提供小驅動程式(minidriver)與微軟提供的類驅動程式互動,如所示:
2. AVStream小驅動程式(minidriver)樣本
DDK包含兩個AVStream小驅動程式(minidriver)樣本:Avshws和Avssamp。Avshws是一個為模擬硬體如何通過AVStream實現DMA而編寫的pin-centric捕獲驅動程式。Avssamp是一個filter-centric捕獲驅動程式,沒有實現DMA。
這些例子示範了本文檔中描述的許多概念,而且可以被驅動開發人員修改成自己需要的類型。這些例子相關的說明檔案(Readme file)可以在DDK中找到,位於這些樣本相同的路徑中。DDK中未包含這些說明檔案。
3. AVStream標頭檔
所有核心流媒體和AVStream需要引用的材料,包括結構體,函數都在標頭檔Ks.h中生命。為了訪問微軟提供的KS和AVStream類驅動程式支援,小驅動程式必需包含這個標頭檔。
4. AVStream對象層次圖
AVStream小驅動程式(minidriver)可以通過對象層次圖匯出許多不同類型的filter,比如,就是一個。
5. AVStream描述符
AVStream 小驅動程式(minidriver)在調用KsInitializeDriver常式時,通過提供一個嵌套的描述符結構來描述自己和自己支援的filter類型。每個關鍵組件-裝置,filter類廠和pin類廠都有一個相關的描述符。
在裝置描述符中,FilterDescriptors成員指向KSFILTER_DESCRIPTOR結構體數組,這個數組描述了這個裝置可以建立的filter類型。AVStream的客戶可以調用KsCreateFilterFactory常式來動態添加filter類廠。
KSFILTER_DESCRIPTOR表明該filter支援多少類型的pin, filter註冊在哪個分類下面,以及filter的拓撲結構。在每個filter描述符中,小驅動程式(minidriver)提供了一個指向KSPIN_DESCRIPTOR_EX結構體數組的指標。每個這樣的pin描述符描述一類這個filter可以執行個體化的pin。你可以調用KsFilterCreatePinFactory常式建立另外的pin類廠。
典型的AVStream小驅動程式(minidriver)把描述符作為靜態變數布置在源檔案中,然後調用KsInitializeDriver常式完成建立任務。
也存在其他類型的描述符,比如,節點描述符KSNODE_DESCRIPTOR,它描述一個給定節點的拓撲結構。
6. AVStream派遣表
AVStream派遣表,KSDEVICE_DISPATCH, 是一套函數指標,指向派遣常式。小驅動程式(minidriver)可以通過提供回調常式完成驅動指定任務的方式,擴充AVStream提供的功能。
這些小驅動程式(minidriver)提供的常式接收事件的通知訊息,並可以擴充或者修改AVStream提供的預設事件處理。
KSFILTER_DISPATCH和KSPIN_DISPATCH結構體都提供一個叫做Process的派遣常式。使用這個派遣常式區分filter-centric filter和pin-centric filter。要指定一個filter-centric filter,在filtre派遣表中指定一個指向process派遣回調常式的指標。pin-centric filter在每個pin描述符表中,提供一個process派遣常式。
你可以註冊filter,向它發送建立,刪除,資料處理和重啟等通知。你可以註冊pin,向它發送諸如建立,關閉,資料處理,重啟,設定資料格式,以及狀態改變等事件的通知。要註冊通知對象,在相關的派遣結構中指定一個指向供應商提供的派遣常式的指標。
7. 初始化AVStream小驅動程式(minidriver)
AVStream小驅動程式(minidriver)自己不處理裝置的初始化,而是在DriverEntry常式中調用KsInitializeDriver常式完成初始化。KsInitializeDriver常式初始化驅動程式對象,除此以外還負責初始化IRP派遣常式,PnP 添加裝置和卸載裝置事件派遣常式。
在調用KsInitializeDriver時,小驅動程式(minidriver)傳遞一個需要初始化的指向驅動程式對象的指標,一個指向註冊表路徑的指標和一個可選的裝置描述符對象。如果小驅動程式(minidriver)不傳遞裝置描述符對象,AVStream在調用AddDevice常式時建立具有指定特徵的裝置對象。
裝置描述符對象包含一個指向KSDEVICE_DISPATCH結構的指標和一個filter描述符數組。為小驅動程式(minidriver)支援的每一類filter提供一個KSFILTER_DESCRIPTOR。當小驅動程式(minidriver)調用KsInitializeDriver時,AVStream為每一類小驅動程式(minidriver)匯出的filter建立一個filter類廠對象。當接收到相應filter建立的IRP後,由該類filter類廠分別執行個體化該filter。每個filter描述符包含一個指向KSPIN_DECRIPTION_EX對象數組的指標。
當某個filter的給定pin上建立串連時,AVStream pin類廠建立一個pin對象。注意每個filter必需至少匯出一個pin。小驅動程式(minidriver)使用KSPIN_DESCRIPTOR_EX的成員InstanceNecessary來確定建立這種類型pin的數目對於filter的正常運行是否必要。同樣的,小驅動程式(minidriver)也可以使用KSPIN_DESCRIPTOR_EX結構體的成員InstancePossible來確定建立這種類型pin的數目是否超過最大數目。
AVStream支援兩種處理類型:filter-centric processing 和 pin-centric processing. 當布置好描述符後,就要決定使用哪種處理類型了。
安裝AVStream小驅動程式(minidriver)
AVStream小驅動程式(minidriver)必須存在一個inf檔案(系統使用該檔案來安裝驅動程式)。AVStream的inf檔案基於普通inf檔案的格式。牢記以下AVStream驅動程式指南。
如果你為父裝置編寫小驅動程式(minidriver),inf檔案的AddReg一節應該包含:
[ParentName.AddReg]
HKR,"ENUM\[DeviceName]",pnpid,,"[string]"
如果你為子裝置編寫minidriver,inf檔案的AddReg一節應該包含:
[Manufacturer]
...=ChildName
[ChildName]
...=ChildName.Device,AVStream\[string]
注意在流媒體類驅動中,上面的"AVStream"應該替換成"Stream"。
對於所有的AVStream小驅動程式(minidriver), 指定filter應用串必須和KSFILTER_DESCRIPTOR結構中ReferenceGuid成員匹配。
8. Pin-Centric Processing
當編寫AVStream小驅動程式(minidriver)時,你的filter可以使用兩種處理範例的一種:pin-centric processing or filter-centric processing。
pin-centric processing指當新的資料幀到達pin隊列時,AVStream調用小驅動程式(minidriver)的pin process派遣常式。
filter-centric processing指當每個執行個體化的pin上存在有效資料幀時,AVStream調用小驅動程式(minidriver)的filter process派遣常式。注意這種定義指定了預設的行為;小驅動程式(minidriver)可以通過設定KSPIN_DESCRIPTOR_EX結構體中的flags成員來修改這種預設行為。
一般來講,軟體filter使用filter-centric processing,硬體filter使用pin-centric processing。比如,支援變換和呈現資料的硬體可以把資料路由到pin-centric filter。相反的情況很少。
想要得到pin-centric filter,小驅動程式(minidriver)就要在每個KSPIN_DISPATCH結構中提供一個指向AVStrMiniPinProcess回調常式的指標。不要在KSFILTER_DISPATCH結構中指定AVStrMiniPinProcess回調常式的指標。
如果小驅動程式(minidriver)不修改KSPIN_DESCRIPTOR_EX中的flags設定,AVStream將在以下三種情況下調用供應商提供的AVStrMiniPinProcess回調常式:
l 該pin進入最小處理狀態,隊列中必需已經存在資料幀,而且pin必需從欠最小處理狀態至少轉化成最小處理狀態。
l 新資料幀到達。Pin至少處於最小處理狀態,而且在leading edge和之前沒有資料幀。
l 小驅動程式(minidriver)明確調用KsPinAttemptProcessing常式。
預設情況下,暫停就時最小處理狀態。
另外,如果pin的與門是關閉的,AVStream不調用pin的處理派遣常式。例如,如果你使用KsGateXxx常式添加另外的off輸入到該pin的與門,你的處理派遣常式將不被調用。
當AVStream調用AVStrMiniPinProcess常式時,它提供一個指向存在有效資料pin的指標。隨後小驅動程式(minidriver)通過調用KsPinGetLeadingEdgeStreamPointer常式請求leading edge指標。小驅動程式(minidriver)將使用流媒體指標(stream pointer)API管理流媒體資料。
當AVStream調用AVStrMiniPinProcess常式時,通過設定KSPIN_DESCRIPTOR_EX結構中的相關標記(flags),使用pin-centric processing的小驅動程式(minidriver)可以備修改。
如果小驅動程式(minidriver)通過調用KsPinAcquireProcessingMutex常式持有處理互斥量(processing mutex),處理嘗試可能會失敗。如果小驅動程式(minidriver)使用KsGate*調用直接管理門,問題可能同樣會出現。
9. Filter-Centric Processing
10. AVStream中的事件處理
AVStream filter和pin通過在結構體KSFILTER_DESCRIPTOR或者KSPIN_DESCRIPTOR_EX的AutomationTable成員中提供一個KSAUTOMATION_TABLE類型的結構體,描述它們支援的屬性,事件和方法。
要支援事件,AVStream小驅動程式(minidriver)就要在自動動作表中提供一個KSEVENT_SET類型的數組。每個KSEVENT_SET結構包含一個KSEVENT_ITEM數組。每個KSEVENT_ITEM結構描述了小驅動程式(minidriver)如何支援指定的事件。
通過在KSEVENT_ITEM結構中提供AVStrMiniAddEvent和AVStrMiniRemoveEvent處理函數,Minidriver可以自訂事件的行為。
當AVStream接收到一個事件使能請求後,它便產生一個KSEVENT_ENTRY結構。如果小驅動程式(minidriver)已經提供了一個AVStrAddEvent處理函數,AVStream會在調用AVStrAddEvent的時傳遞一個指向KSEVENT_ENTRY結構的指標。
如果沒有提供AVStrAddEvent處理函數,AVStream預設情況下會添加一個事件到對象列表。小驅動程式(minidriver)不會接收到KSEVENT_ENTRY的指標。Minidriver可以調用KsFilterGenerateEvent或者KsPinGenerateEvents觸發一個事件。
11. 使用者模式中方法和事件代碼執行個體
這部分代碼展示了如何在使用者模式的KsProxy外掛程式程式中使用方法和事件。
在你的minidriver中提供了對給定方法支援後,你可以通過調用IksControl::KsMethod方法達到調用底層方法的目的,下面是例子代碼:
PVOID MethodBuffer; // Your method arguments buffer
ULONG MethodBufferSize; // Your method buffer size
KSMETHOD Method;
ULONG BytesReturned;
Method.Set = KSMETHODSETID_MyMethodSet;
Method.Id = KSMETHOD_MyMethodId;
Method.Flags = KSMETHOD_TYPE_SEND;
HRESULT hr =
pIKsControl -> KsMethod (
&Method,
sizeof (Method),
MethodBuffer,
&MethodBufferSize,
&BytesReturned);
在核心模式自動動作表中,你可以是用KSMETHOD_ITEM的Flags成員指定該緩衝區是否是可讀寫的,是否是可映射或者可拷貝的。
要註冊一個minidriver支援的事件,使用一下範例程式碼:
HANDLE EventHandle; // Your event handle.
KSEVENT Event;
KSEVENTDATA EventData;
Event.Set = KSEVENTSETID_MyEventSet;
Event.Id = KSEVENT_MyEventId;
Event.Flags = KSEVENT_TYPE_ENABLE;
EventData.NotificationType = KSEVENTF_EVENT_HANDLE;
EventData.EventHandle.Event = EventHandle;
EventData.EventHandle.Reserved [0] = 0;
EventData.EventHandle.Reserved [1] = 0;
ULONG BytesReturned;
HRESULT hr =
pIKsControl -> KsEvent (
&Event,
sizeof (Event),
&EventData,
sizeof (EventData),
&BytesReturned);
在上面的樣本中,通知將持續除非minidriver讓該事件失效。要讓你的事件失效。調用KsControl::KsEvent。如果你只想在事件第一次發生時被通知,設定Event.Flags為KSEVENT_TYPE_ONESHOT。
12. AVStream子裝置
這部分適用於Microsoft Windows Server 2003和安裝了DirectX 9.0及以後版本的早期作業系統。對於你的裝置,AVStream可以作為一個匯流排列舉程式運行,Enum分支下的鍵,AVStream都為你建立一個子裝置。要這樣做,在註冊表中裝置鍵下放置一個Enum子鍵。
特別是在驅動程式的inf檔案的AddReg部分,供應商為每個Enum下的子項REG_SZ類型的pnpid值。AVStream使用這個串值為每個單獨的裝置構造一個PnP硬體ID。
在DirectX 9.0以前的發行版本中,AVStream建立一個形如"AVStream\<pnpid>"子裝置硬體ID。
例如,供應商在inf檔案的AddReg部分指定一下設定:
[MyTVDevice.AddReg]
HKR,"ENUM\CrossbarDevice",pnpid,,"MyCrossbar"
HKR,"ENUM\TunerDevice",pnpid,,"MyTuner"
因此,AVStream使用下面的裝置ID建立兩個子裝置。
AVStream\MyCrossbar,AVStream\MyTuner
為瞭解決兩個子裝置指定相同的pnpid這種可能的衝突。DirectX 9.0及以後的版本改變了每個子裝置的ID報告機制。對於每個通過父裝置報告的硬體ID,AVStream為每個子裝置建立一個形如下面的ID:
AVStream\<pnpid>#<modified parent hardware ID>
修改過的父硬體ID為父硬體ID中使用 “#”代替所有的反斜線”\”。
如果最終的串太長,AVStream以MAX_DEVICE_ID_LEN終止ID串,包含一個NULL。在Windows Server 2003,這個限制在標頭檔cfgmgr32.h中被設定為200個字元。
例如父裝置報告一下的裝置ID:
PCI\VEN_XXXX&DEV_YYYY&SUBSYS_ZZZZZZZZ&REV_VV
PCI\VEN_XXXX&DEV_YYYY&SUBSYS_ZZZZZZZZ
對於pnpid索引值為MyCrossbar的裝置,AVStream建立一下的子裝置硬體ID:
AVStream\MyCrossbar#PCI#VEN_XXXX&DEV_YYYY&SUBSYS_ZZZZZZZZ&REV_VV
AVStream\MyCrossbar#PCI#VEN_XXXX&DEV_YYYY&SUBSYS_ZZZZZZZZ
對於父裝置報告的相容ID,AVStream使用相同的處理方法。AVStream為子裝置建立相容ID形如下面ID:
AVStream\<pnpid>#<modified parent compatible ID>
相容ID名稱修改機制個長度限制法則與硬體ID是一樣的。
例如,父裝置報告了一下相容ID:
PCI\VEN_XXXX&DEV_YYYY&REV_VV
PCI\VEN_XXXX&DEV_YYYY
PCI\VEN_XXXX&CC_ZZZZZZ
PCI\VEN_XXXX&CC_ZZZZ
PCI\VEN_XXXX
PCI\CC_ZZZZZZ
PCI\CC_ZZZZ
MyCrossbar子裝置將通過AVStream報告如下的相容ID:
AVStream\MyCrossbar#PCI#VEN_XXXX&DEV_YYYY&REV_VV
AVStream\MyCrossbar#PCI#VEN_XXXX&DEV_YYYY
AVStream\MyCrossbar#PCI#VEN_XXXX&CC_ZZZZZZ
AVStream\MyCrossbar#PCI#VEN_XXXX&CC_ZZZZ
AVStream\MyCrossbar#PCI#VEN_XXXX
AVStream\MyCrossbar#PCI#CC_ZZZZZZ
AVStream\MyCrossbar#PCI#CC_ZZZZ
AVStream\MyCrossbar
13. 在AVStream中重啟處理
如果下列任何一種情況為真,AVStream將停止處理。
l 在pin-centric環境中,當前該pin上沒有有效資料。
l 在filter-centric環境中,至少存在一個pin,該pin的KSPIN_DECRIPTOR_EX的flags沒有設定KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING標記,沒有資料等待處理。預設情況下,沒有設定這個標記。
l 不管資料真是否有效,小驅動程式(minidriver)的處理派遣回調常式返回STATUS_PENDING。注意處理派遣常式可以是AVStrMiniFilterProcess也可以是AVStrMiniPinProcess,依賴於小驅動程式(minidriver)實現的pin-centric processing或者filter-centric processing。
當新資料到達空隊列時,AVStream開始處理。因此,如果當相關的隊列裝滿,小驅動程式(minidriver)的處理派遣常式返回為STATUS_PENDING時,小驅動程式(minidriver)將不會被調用重新處理。如果小驅動程式(minidriver)設定STATUS_PENDING,minidriver必需調用KsPinAttemptProcessing或者KsFilterAttemptProcessing重新開始處理。
如果小驅動程式(minidriver)沒有真正的處理資料,不要在處理派遣常式中返回STATUS_PENDING。這會引起AVStream馬上再次調用小驅動程式(minidriver),導致在AVStream和小驅動程式(minidriver)之間的無限迴圈。