注:该项目使用GitHub Copilot生成式人工智能辅助开发。
最近在做一个小项目:ndi-capture。
它是一个 Windows 平台下的简易 GUI 工具,核心目标很明确:把本地摄像头/采集卡的画面,以 NDI 协议低延迟地推送到局域网中。
写这个的初衷其实很简单——市面上现有的 NDI 发送工具,要么功能冗余,要么配置复杂。而我需要的,只是一个专注、可靠、易于集成的摄像头→NDI 桥接器。特别是我们做校内视频直播的时候,搞OBS+插件就为了这么个小功能实在是有点重了,提高了社团传代培养的成本。于是决定自己动手。
项目定位
- 平台:Windows 10/11(x64)
- 技术栈:C++17 / Qt6 / CMake / DirectShow
- 核心依赖:NDI SDK、libyuv、libjpeg-turbo
- 交付形式:单文件便携版,无需安装
- 开源协议:LGPL Version 3
注意:NDI SDK是NewTek开发的专有软件,使用需符合相关协议。本项目不对该SDK进行分发,请自行前往其官网下载https://ndi.video/for-developers/ndi-sdk/download/
关键技术点
1. 设备枚举与标识
摄像头设备名重复是常见问题。项目中通过解析设备路径生成唯一短 ID,配合友好名称展示,避免用户误选。
// 示例:设备标识生成逻辑(简化)
QString deviceId = generateShortHash(devicePath);
QString displayName = QString("%1 [%2]").arg(friendlyName).arg(deviceId);
2. 像素格式适配
摄像头输出格式多样(YUY2、NV12、MJPEG 等),而 NDI 推荐 UYVY 或 BGRA。项目使用 libyuv 进行高效转换,并针对 MJPEG 启用 libjpeg-turbo 硬解,以优化对部分采集卡的兼容性。
3. 资源独占管理
预览阶段以共享模式打开设备,允许多实例调试;启动推流时切换为独占模式,并通过全局命名互斥量(Global\NDICaptureLock_<hash>)防止进程间冲突。这种「渐进式锁定」策略兼顾了灵活性与稳定性。
4. 日志与可观测性
所有运行日志按时间戳写入 logs/ndi-capture.log,关键路径(设备初始化、格式协商、NDI 连接状态)均有明确记录,便于问题追踪。
编译与使用
项目采用标准 CMake 构建流程,支持按需启用 NDI 功能:
# 仅构建预览功能(无需 NDI SDK)
cmake -S . -B build -DWITH_NDI=OFF
# 完整构建(需指定 NDI SDK 路径)
cmake -S . -B build -DWITH_NDI=ON -DNDI_SDK_DIR="/path/to/ndi/sdk"
依赖管理推荐通过 vcpkg 统一处理:
// vcpkg.json 片段
{
"dependencies": [
"qtbase", "qttools", "libyuv", "libjpeg-turbo"
]
}
构建完成后,使用 windeployqt 收集 Qt 运行时,配合 NDI redistributable 即可打包为独立可执行文件。
一些思考
开发过程中有几个值得记录的细节:
- DirectShow 的兼容性:不同摄像头驱动的引脚枚举行为存在差异,需要做好容错与降级策略。
- NDI 的自适应机制:接收端带宽波动时,NDI 会自动调整码率,但发送端仍需合理设置
max_latency与缓冲区大小,避免累积延迟。
使用注意
- 请自行下载和安装SDK,如果缺失DLL文件,建议手动复制对应的dll到项目根目录。项目Release的二进制文件已经包含了除NDI SDK的所有依赖
- 如果需要推流多个采集卡/摄像头,请启动多个进程实例
开源与协作
项目采用 LGPL-3.0 协议开源,代码托管在:
👉 https://github.com/lqx3089/ndi-capture
如果你也在使用 NDI,或者对视频采集、低延迟传输感兴趣,欢迎交流。Issue 和 PR 都长期开放。
最后想说,技术项目的价值,不在于用了多新的框架,而在于是否解决了真实场景中的问题。
这个工具目前满足了我自己的需求,如果也能帮到你,那就再好不过。
评论