AVStream数据流处理
AVStream类驱动程序使用分配器为以帧为单位的数据流分配缓冲区。
帧是一块连续的内存块,其默认大小是通过KSPIN_DESCRIPTOR_EX的 AllocatorFraming 成员。
typedef struct {
ULONG CountItems;
ULONG PinFlags;
KS_COMPRESSION OutputCompression;
ULONG PinWeight;
KS_FRAMING_ITEM FramingItem[1]; //CountItems
} KSALLOCATOR_FRAMING_EX, *PKSALLOCATOR_FRAMING_EX;
由于这个结构体初始化比比较复杂,故一般使用宏DECLARE_SIMPLE_FRAMING_EX来初始化
DECLARE_SIMPLE_FRAMING_EX (
CapturePinAllocatorFraming, //Name
STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED),//mem type
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY, //flags
2, //frames
0, //alignment
2 * PAGE_SIZE,//minFrameSize
2 * PAGE_SIZE //MaxFrameSize
);
帧大小的修改
以上是对默认的数据流帧分配,实际对于音视频数据流,其帧的大小会随着不同的格式或者分辨率而帧的大小不同,故在CreatePin时,可以修改其参数。
NTSTATUS CCapturePin::DispatchCreate(IN PKSPIN Pin,IN PIRP Irp)
{
...
do
{
//判断对应的属性是否可以修改
Status = KsEdit(Pin, &Pin->Descriptor, AVSHWS_POOLTAG);
if (!NT_SUCCESS(Status))
{
break;
}
Status = KsEdit(Pin, &Pin->Descriptor->AllocatorFraming, AVSHWS_POOLTAG);
if (!NT_SUCCESS(Status))
{
break;
}
PKSALLOCATOR_FRAMING_EX Framing = const_cast <PKSALLOCATOR_FRAMING_EX>(Pin->Descriptor->AllocatorFraming);
Framing->FramingItem[0].Frames = 2;
Framing->FramingItem[0].PhysicalRange.MinFrameSize =
Framing->FramingItem[0].PhysicalRange.MaxFrameSize =
Framing->FramingItem[0].FramingRange.Range.MinFrameSize =
Framing->FramingItem[0].FramingRange.Range.MaxFrameSize = CapPin->m_VideoInfoHeader->bmiHeader.biSizeImage;
Framing->FramingItem[0].PhysicalRange.Stepping = Framing->FramingItem[0].FramingRange.Range.Stepping = 0;
} while (0);
return Status;
}
引脚为中心
对于以引脚为中心的驱动程序,每个引脚都有一个独立的缓冲区队列。当数据包到达引脚(读写)时,AVStream将数据包添加到队列,并调用引脚对应的处理进程CPin::Process。
在引脚对应的处理进程中,通过调用KsPinGetLeadingEdgeStreamPointer获取其前导流指针。
可以使用KsStreamPointerClone来克隆当前的流指针,生成的克隆最初引用与原始流指针相同的数据帧,并且处于相同的状态(锁定或解锁)。添加引用数据帧的克隆流指针会递增该特定帧的引用计数。 请注意,在引用计数降至零之前,不会完成有问题的帧(因此帧所属的 IRP)
只能将流指针向一个方向移动:移动到较新的帧。 这称为推进流指针。推进流指针时,可将其移动到较新的帧,或在其当前帧内向前推进一些字节数。 例如,微型驱动程序可以将流指针从第一帧到达推进到第二帧到达。
若要推进流指针,以引脚为中心的筛选器可以调用 KsStreamPointerAdvance 或 KsStreamPointerUnlock , 并将弹出 参数设置为 TRUE。
参考:https://learn.microsoft.com/zh-cn/windows-hardware/drivers/stream/introduction-to-stream-pointers
筛选器为中心
以筛选器为中心的处理的微型驱动程序不应直接使用流指针。
如果筛选器使用以筛选器为中心的处理,则默认情况下,当每个引脚实例上都有可用的数据帧时,AVStream 会调用微型驱动程序提供的 AVStrMiniFilterProcess 回调例程。
以筛选器为中心的处理的微型驱动程序使用KSPROCESSPIN来处理数据。
NTSTATUS
CCaptureFilter::
Process (
IN PKSPROCESSPIN_INDEXENTRY ProcessPinsIndex
)
{
...
PKSPROCESSPIN ProcessPin = ProcessPinsIndex [VIDEO_PIN_ID].Pins [0];
RtlCopyMemory ( ProcessPin -> Data,
m_SynthesisBuffer,
m_VideoInfoHeader -> bmiHeader.biSizeImage
);
ProcessPin -> BytesUsed = m_VideoInfoHeader -> bmiHeader.biSizeImage;
ProcessPin -> Terminate = TRUE;
...
}
微型驱动程序还可以访问对应于当前流指针和引脚的流标头结构:
PKSSTREAM_HEADER StreamHeader = ProcessPin -> StreamPointer -> StreamHeader;
参考:https://learn.microsoft.com/zh-cn/windows-hardware/drivers/stream/filter-centric-processing