如何使用DirectShow检测PAL/NTSC信号实现采集卡制式自动切换
背景
为录制各类模拟摄像机的复合视频信号,我使用圆刚(AverMedia)生产的基础款USB视频采集设备C039。
我拥有两台模拟摄像机,分别输出两种不同的视频信号:
- PAL B,625线,25 fps
- NTSC M,525线,29.97 fps(即30/1.001)
但遗憾的是,AverMedia C039采集卡的驱动无法根据接入的摄像机自动设置匹配的视频标准。
目标
我希望采集驱动可以根据接入的摄像机,自动配置为对应的PAL或NTSC视频标准。
实现思路
基础方案是先设置某一视频标准(例如PAL),检测是否有对应信号存在,若未检测到则切换为另一制式。
参考DirectShow文档的示例代码拼接开发后,我已经可以通过命令行手动设置正确的视频标准,因此只需要解决切换PAL或NTSC后,如何检测对应信号是否存在的问题。
我知道信号类型自动检测是可实现的,《Video Demystified》一书中也有相关描述,此外商业软件AMCap viewer也已经实现了该功能,但我自己尝试后始终无法完成。
想请教大家如何用C++基于DirectShow检测当前是否存在PAL或NTSC信号?我对Windows/COM/DirectShow编程接触尚浅,非常感谢任何帮助。
已尝试方案
通过IAMAnalogVideoDecoder接口,我可以读取当前制式(get_TVFormat())、设置制式(put_TVFormat())、读取扫描线数等信息。
我采取的步骤可总结为如下代码:
// summary of steps used to set the video standard, given a device moniker // NOTE: declarations, error handling, cleanup, and details of device enumeration are omitted, for brevity InitCaptureGraphBuilder(&pGraph, &pBuild); pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); pGraph->AddFilter(pCap, L"Capture Filter"); pBuild->FindInterface(&PIN_CATEGORY_ANALOGVIDEOIN, &MEDIATYPE_AnalogVideo, pCap, IID_IAMAnalogVideoDecoder, (void**)&pDecoder); pDecoder->put_TVFormat(AnalogVideo_PAL_B); // or AnalogVideo_NTSC_M
上述步骤无需运行graph即可生效。IAMAnalogVideoDecoder接口还提供了get_HorizontalLocked()方法,调用返回成功,但无论是否接入摄像机,输出值都没有变化。我推测可能需要运行graph才能获取水平同步等信息的更新状态,但尝试后没有明显效果,我也不确定我的实现是否正确。
观测结果
下方对话框截图来自AMCap viewer软件(操作路径:选项->视频设备->属性),它和Windows SDK自带的DirectShow示例AmCap sample不是同一软件(不过它可能是基于该示例开发的)。
当我接入或断开与当前设置制式匹配的摄像机时,对话框中的“Signal Detected”值会发生变化(但无论是否接入摄像机,“Lines detected”值都保持不变)。
这个“Signal Detected”的值正是我需要获取的,但我在DirectShow官方文档、模拟视频解码器设备属性集中都没有找到相关说明,它会不会和水平同步有一定关联?
这个对话框和我用ffmpeg打开视频设备时弹出的对话框完全一致,对应ffmpeg命令:
ffmpeg -f dshow -show_video_device_dialog true -i video="..." ...
但这种情况下,接入或断开摄像机时“Signal detected”值不会发生变化。我推测两款软件都是通过filter property pages生成的这个对话框。
AverMedia SDK中定义了AVerGetSignalPresence()函数,不确定它能否实现需求,但如果可以用纯DirectShow实现的话,我更希望不引入额外依赖。
更新
在GraphEdit中调试采集设备后我发现,只有连接了(视频)Renderer,且graph处于运行或暂停状态时,“Signal Detected”的值才会更新。
内容的提问来源于stack exchange,提问作者djvg

