通常,数据仅通过触发事件、微型驱动程序的处理和缓冲区完成向下游移动。 若要查明挂起或停止的原因,请使用以下命令:
检查是否存在不匹配 的 KsGateXxx 调用。
检查是否省略了 KsXxxAttemptProcessing 调用。
查找与触发事件相关的代码中的问题,包括引用问题流的 pin 标志或调用 KsPinAttemptProcessing 的代码。
在与处理调度相关的代码中查找问题,尤其是在它排队到硬件以及创建克隆指针的位置。
在代码中查找与驱动程序的延迟过程调用相关的问题, (DPC) ,尤其是在缓冲区已完成或对 KsStreamPointerDelete 进行任何调用时。
在流的启动代码中查找问题。
收集此信息的最有效方法是记录受影响区域中的所有内容,包括处理、缓冲区获取 ((例如克隆和编程硬件) 、缓冲区释放 ((如删除克隆) )以及任何门操作。 此信息大多高度依赖于计时,需要基于内存的日志记录或 ETW。
若要维护基于内存的滚动日志,请使用以下代码:
typedef struct _LOGENTRY {
ULONG Tag;
ULONG Arg[3];
} LOGENTRY, *PLOGENTRY;
#define LOGSIZE 2048
LONG g_LogCount;
LOGENTRY g_Log [LOGSIZE];
#define LOG(tag,arg1,arg2,arg3) do { \
LONG i = InterlockedIncrement (&g_LogCount) % LOGSIZE; \
g_Log [i].Tag = tag; \
g_Log [i].Arg [0] = (ULONG)(arg1); \
g_Log [i].Arg [1] = (ULONG)(arg2); \
g_Log [i].Arg [2] = (ULONG)(arg3); \
} while (0)
然后,使用简单的“dc g_Log”在调试器中查看 g_Log 数组的内容。
以下示例使用上述基于内存的方案来确定处理停止的原因。 输出来自 graphedt 中的 AVStream 流式处理方案。 记录了以下微型驱动程序事件:
缩写 | 说明 |
---|---|
Strt |
当微型驱动程序首先从微型驱动程序的 “开始”调度 中排队设备缓冲区时,会发生此事件。 |
中国< |
此事件在微型驱动程序 的进程调度开始时 发生。 |
AddB |
当微型驱动程序从其 进程 调度中将缓冲区排队到设备时,会发生此事件。 |
DPC< |
此事件发生在微型驱动程序的 CallOnDPC 的开头。 它指示缓冲区完成。 |
Atmp |
当微型驱动程序从 DPC 内部调用 KsPinAttemptProcessing 时,会发生此事件。 |
Dele |
当微型驱动程序从 DPC 内部调用 以删除克隆流指针时,会发生此事件。 |
日志摘录如下:
f9494b80 3c435044 816e2c90 00000000 00000000 DPC<.,n.........
f9494b90 656c6544 816e2c90 81750260 00000000 Dele.,n.`.u.....
f9494ba0 706d7441 816e2c90 ffa4d418 00000000 Atmp.,n.........
f9494bb0 3c637250 819c1f00 00000000 00000000 Prc<............
f9494bc0 42646441 819c1f00 ffa2eb08 00000000 AddB............
f9494bd0 3c435044 816e2c90 00000000 00000000 DPC<.,n.........
f9494be0 656c6544 816e2c90 ffa80348 00000000 Dele.,n.H.......
f9494bf0 706d7441 816e2c90 ffa4d418 00000000 Atmp.,n.........
f9494c00 3c637250 819c1f00 00000000 00000000 Prc<............
f9494c10 42646441 819c1f00 ffa3d9b8 00000000 AddB............
第一个日志摘录代表正常的流式处理状态。 在第一行中,调用微型驱动程序的 CallOnDPC 以完成缓冲区 (DPC<) 。 (Dele) 中删除缓冲区,如果队列中有任何未处理的缓冲区 (Atmp) ,则调用 KsPinAttemptProcessing 向前移动前边缘。 在这种情况下,通过调用 中国<) 的进程调度 (可以看出。 (AddB) 将更多缓冲区添加到队列中,整个方案将重复执行。
下一个摘录包括停止发生前日志中的最后一个条目。
f949b430 3c435044 816e2c90 00000000 00000000 DPC<.,n.........
f949b440 656c6544 816e2c90 ffac4de8 00000000 Dele.,n..M......
f949b450 706d7441 816e2c90 ffa4d418 00000000 Atmp.,n.........
f949b460 3c435044 816e2c90 00000000 00000000 DPC<.,n.........
f949b470 656c6544 816e2c90 816ffc80 00000000 Dele.,n...o.....
f949b480 706d7441 816e2c90 ffa4d418 00000000 Atmp.,n.........
f949b490 3c435044 816e2c90 00000000 00000000 DPC<.,n.........
f949b4a0 656c6544 816e2c90 ffa80348 00000000 Dele.,n.H.......
f949b4b0 706d7441 816e2c90 ffa4d418 00000000 Atmp.,n.........
f949b4c0 3c435044 816e2c90 00000000 00000000 DPC<.,n.........
f949b4d0 656c6544 816e2c90 8174e1c0 00000000 Dele.,n...t.....
f949b4e0 706d7441 816e2c90 ffa4d418 00000000 Atmp.,n.........
在此示例中, (DPC<) 的重复实例指示多个缓冲区正在完成,但队列中没有未处理的缓冲区,因此不会调用进程调度, (没有 Prc<) 表示。 事实上,队列中所有已处理的缓冲区都已完成,这显然是在可以添加任何新的未处理的缓冲区之前完成的。 由于应用程序已在 (运行,因此不会) 调用 Start ,并且不会调用 CallOnDPC (因为没有准备好) 完成的已处理缓冲区,因此任何新缓冲区显然在前缘之前累积,等待处理,且没有任何启动处理。
问题是已设置KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING标志。 设置此标志后,只能通过调用 Start 或 CallOnDPC 进行处理。 如果未设置此标志,则每当将新缓冲区添加到队列时,都会启动处理。