天天看点

AVStream ddk 翻译

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;

hresult hr =

pikscontrol -> ksevent (

    &event,

        sizeof (event),

    &eventdata,

        sizeof (eventdata),

在上面的示例中,通知将持续除非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)之间的无限循环