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)之间的无限循环

AVStream ddk 翻译的更多相关文章

  1. HarmonyOS USB DDK助你轻松实现USB驱动开发

    HDF(Hardware Driver Foundation)驱动框架是HarmonyOS硬件生态开放的基础,为开发者提供了驱动加载.驱动服务管理和驱动消息机制等驱动能力,让开发者能精准且高效地开发驱 ...

  2. 《Django By Example》第五章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者@ucag注:大家好,我是新来的翻译, ...

  3. 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...

  4. [翻译]开发文档:android Bitmap的高效使用

    内容概述 本文内容来自开发文档"Traning > Displaying Bitmaps Efficiently",包括大尺寸Bitmap的高效加载,图片的异步加载和数据缓存 ...

  5. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  6. 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...

  7. 《Django By Example》第二章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...

  8. 《Django By Example》第一章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:本人目前在杭州某家互联网公司工作, ...

  9. 【翻译】Awesome R资源大全中文版来了,全球最火的R工具包一网打尽,超过300+工具,还在等什么?

    0.前言 虽然很早就知道R被微软收购,也很早知道R在统计分析处理方面很强大,开始一直没有行动过...直到 直到12月初在微软技术大会,看到我软的工程师演示R的使用,我就震惊了,然后最近在网上到处了解和 ...

随机推荐

  1. iOS-OC、Swift 混编之桥接文件

    新建一个OC语言的项目,然后添加一个基于NSObject的Swift文件SwiftFileModel类 .swift import UIKit class SwiftFileModel: NSObje ...

  2. 修改Java程序的进程名

    1.修改tomcat进程名字: 当同一个服务器上启动多个tomcat后,我们会在任务管理器中看见多个java.exe,当我们需要对某个tomcat进行监控时,却无法区分出该tomcat的进程,那么如何 ...

  3. HDU 6181 Two Paths

    这是一道次短路的题 但是本题有两个坑 注意边权的范围,一定要在所有与距离有关的地方开 long long 本题所求的并不是次短路,而是与最短路不同的最短的路径,如果最短路不止一条,那么就输出最短路的长 ...

  4. Mac系统下XAMPP的简单使用

    XAMPP简单使用的方法使用方法 XAMPP的简介即应用在博客园也有 1.安装完成后打开manager-osx.app 把Manager Servers下的三个server打开(使之变绿如下) 第一个 ...

  5. Python自动化--语言基础3--字典、函数、全局/局部变量

    字典 dict1 = {'name':'han','age':18,'class':'first'} print(dict1.keys()) #打印所有的key值 print(dict1.values ...

  6. 让网站通过Https访问

    Prerequisites Before you begin, you should have some configuration already taken care of. We will be ...

  7. Windows下使用Sublime text3快速编辑Linux文件,写Shell

    所需要配合的工具是WinSCP 添加完毕之后直接在目录下双击要编辑的shell脚本文件,即可弹出Sublime Text的编辑器 然后咱通过Putty看看Linux虚拟机上的文件有没有发生变化

  8. POJ - 2912 Rochambeau 种类并查集

    题意:有三组小朋友在玩石头剪刀布,同一组的小朋友出的手势是一样的.这些小朋友中有一个是裁判,他可以随便出手势.现在给定一些小朋友的关系,问能否判断出裁判,如果能最早什么时候能够找到裁判. 思路:枚举每 ...

  9. jsp去除空行的web.xml配置

    在jsp中我们引入的标签,例如jstl的标签,循环遍历等等,可能会产生很多空行,其实也没什么,不会影响展示,但是空行多多少少会影响性能,这是我们只需要在web.xml中配置一下我们就可以很简单的去掉, ...

  10. SSRF漏洞总结

    SSRF漏洞:(服务端请求伪造)是一种由攻击者构造形成由服务端发起请求的一个安全漏洞.一般情况下,SSRF攻击的目标是从外网无法访问的内部系统.(正是因为它是由服务端发起的,所以它能够请求到与它相连而 ...