KS相机驱动
+ -

AVStream数据流处理

2025-02-27 8 0

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

0 篇笔记 写笔记

作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!