您的位置:首页 > 其它

广播驱动体系(BDA) 系列讲座:五

2011-12-22 10:38 176 查看
BDA minidriver的职责:调制(tunning)信号,解调(demodulating)信号,获取(capture),分流(demultiplexing)。BDA是在AVStream上的扩展,Bdasup.lib提供了BDA的属性集和方法集。写BDA驱动的主要工作就是把Bdasup.lib中要求的属性集方法集的例程都注册一遍(需要的注册,确实不需要的也可以不管),提供自己的实现。
BDA驱动的入口是DeviceEntry函数,在这个函数里主要做的工作就是注册分发例程,调用KsInitializeDriver
函数,传入一个KSDEVICE_DESCRIPTOR类型的参数,该参数中指定了一个KSDEVICE_DISPATCH参数,用来注册各种例程。一个典型的KSDEVICE_DISPATCH参数如下所示:


extern


const


KSDEVICE_DISPATCH


DeviceDispatch =






{


CDevice::Create, // Add


CDevice::Start, // Start


NULL, // PostStart


NULL, // QueryStop


NULL, // CancelStop


NULL, // Stop


NULL, // QueryRemove


NULL, // CancelRemove


NULL, // Remove


NULL, // QueryCapabilities


NULL, // SurpriseRemoval


NULL, // QueryPower


NULL // SetPower


};





这部分工作实际上是AVStream minidriver要做的,考虑到bda是在AVStream基础上的扩展,我们写bda minidriver时也要做相同的工作。类似的工作在WDM驱动里也要做,不同的是WDM的例程注册都是类似赋值的语句,而AVStream
minidriver的例程注册使用一些模板完成,为我们省掉很多工作。

CDevice::Create
例程中,我们要做的事情主要包括:Download firmware和生成必要Filter实例,如有必要还可以配置DMA等。Download firmware之前要先获得板子的product_id,然后调用Reset8051(0x09),通知下层开始传输fireware,传完后再调用Reset8051(0x08)通知下层传输完毕。生成Filter调用BdaCreateFilterFactory
函数,传入BDA_FILTER_TEMPLATE参数,在该参数中需要指定FilterDispatch,FilterAutomation,PinDescriptors,KSFILTER_CATEGORY(目录位置),NodeDescriptors
和 CONNECTIONS。
FilterDispatch指定了Filter的各个分发例程,FilterAutomation用于提供PropertySet(属性集)和MethodSet(方法集),PinDescriptors用于指定Pin的各个分发例程,KSFILTER_CATEGORY指定生成的的Filter在哪个目录底下(硬件filter用目录索引的方法寻找实例,而不是像软件filter那样用GUID寻找实例),NodeDescriptors
和 CONNECTIONS 共同指定了filter内部的功能拓扑图。

一个典型的FilterDispatch 如下图所示


const


KSFILTER_DISPATCH


FilterDispatch =






{


CFilter::Create, // Create


CFilter::FilterClose, // Close


NULL, // Process


NULL // Reset


};
一个典型的PinDescriptors如下所示


const


KSPIN_DESCRIPTOR_EX


InitialPinDescriptors[] =






{


// Antenna Pin


//






{


&AntennaPinDispatch, 分发例程


&AntennaAutomation, // Pin上的属性集和方法集




//下面是该pin的类型定义






{


0, // Interfaces


NULL,


0, // Mediums


NULL,


SIZEOF_ARRAY(AntennaPinRanges),


AntennaPinRanges,


KSPIN_DATAFLOW_IN,


KSPIN_COMMUNICATION_BOTH,


NULL, // Name


NULL, // Category


0


},




下面指定传输类型和方式


KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT |


KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING |


KSPIN_FLAG_FIXED_FORMAT,


1, // InstancesPossible


0, // InstancesNecessary


NULL, // Allocator Framing


NULL // PinIntersectHandler


}


};





一个典型的AntennaPinDispatch 如下图所示


const


KSPIN_DISPATCH


AntennaPinDispatch =






{


CAntennaPin::PinCreate, // Create


CAntennaPin::PinClose, // Close


NULL, // Process signal data


NULL, // Reset


NULL, // SetDataFormat


CAntennaPin::PinSetDeviceState, // SetDeviceState


NULL, // Connect


NULL, // Disconnect


NULL, // Clock


NULL // Allocator


};
属性集和方法集可以在filter里提供,也可以在Node里提供。Filter上提供的属性集可以被应用层调用,而Node上提供的属性集则只能是BDA架构内的东西可以调用(如第一页所讲,tunner里的两个node都是Network
Provider通过内置的GUID来访问的,node上只需要提供BDA中需要的属性集和方法集即可,比如设置频率等,而这些属性集方法集所绑定的GUID也是BDA内置的。)Filter上提供的属性集可以为上层定制很多特定功能,可以代替DeviceIoControl,实际上在BDA架构下不建议使用DeviceIoControl。

(据观察,我的程序中

Demodulator Node中有一个PropertySetKSPROPSETID_BdaAutodemodulate

Tunner Node中有 KSPROPERTY_BDA_RF_TUNER_FREQUENCY_MULTIPLIER

KSPROPERTY_BDA_RF_TUNER_FREQUENCY

KSPROPERTY_BDA_SIGNAL_STRENGTH

KSPROPERTY_BDA_SIGNAL_QUALITY

KSPROPERTY_BDA_SIGNAL_PRESENT

KSPROPERTY_BDA_SIGNAL_LOCKED

KSPROPERTY_BDA_SAMPLE_TIME

这几个属性,提供对内置frequency和signal的操作的实现。所有BDA内置的属性请参看DDK
à Device Technology à Video Capture Device
à Reference à Broadcast Driver Architecture Drivers
à Broadcast Driver Architecture Property, Event, and Method Sets)。

视频采集驱动中最关键的操作:数据采集,发生在Capture Filter的Output Pin的状态从其他状态变成Start状态时。它会启动一个工作线程,不停的从底层采集数据存放在缓存中,并调用KsPinAttemptProcessing方法以响应Capture
Filter的Process方法把数据往后传。

Stream Pointers是AVStream minidriver中把数据从一个filter传到下一个filter的方法,BDA扩展自AVStream,所以BDA传数据也用Stream
Pointers。AVStream内部管理了一条数据队列,我们要做的事情是往队列里塞数据,把当前指针往后移以及销毁过期数据。Process操作会把Stream Pointer指向的数据复制给下一个与他相连的filter,具体细节被屏蔽,我们要关心的只有Stream
Pointer。要把数据往后移,我们可以调用KsStreamPointerAdvance
函数 , 或者KsStreamPointerUnlock
函数(Eject 参数设置为TRUE),函数中传入要移动数据的Stream Pointer即可。调用完后需要再调用KsStreamPointerSetStatusCode
查看操作是否成功,如果有错误,则调用KsStreamPointerDelete
方法销毁数据(实际上不是真的销毁,只是减少引用计数。当引用计数减少到0的时候,数据才被真正销毁)。

Stream Pointers还提供了一套管理数据队列的方法,KsPinGetLeadingEdgeStreamPointer取得头指针,KsPinGetTrailingEdgeStreamPointer取得尾指针,KsPinGetFirstCloneStreamPointer取得当前正在用的数据的指针,KsStreamPointerGetNextClone则指向当前指针的下一个指针。

如果要传输的只是一个帧里的某一些数据,则调用KsStreamPointerAdvanceOffsets
或者 KsStreamPointerAdvanceOffsetsAndUnlock.函数。

在DeviceAdd例程中,我们还可以在KsDeviceàContext中加入我们需要的数据,这批数据的生命周期就会一直延续到DeviceRemove例程完成为止,在程序中定义一些全局变量是不可取的,最好全放在KsDeviceàContext中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: