knowledge-work-plugins 之 Zoom Video SDK for Windows 官方示例应用完全指南:20 个 Sample 选型、代码模式与构建实战
【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins
本篇技术指南以 knowledge-work-plugins 仓库中 partner-built/zoom-plugin/skills/video-sdk/windows 技能库的官方示例参考文档为核心,系统讲解 Zoom Video SDK Windows 端(C++)官方示例工程的完整清单、推荐学习路径、关键代码模式与构建配置。读完本文,你将能够:根据业务需求(原始音视频采集、自定义音视频注入、云录制、信令、转写等)快速选定对应示例工程作为起点,理解贯穿所有示例的"单例获取 → 委托实现 → 订阅使用"通用架构,并掌握在 Visual Studio 中编译运行这些示例所需的全部前提与配置细节。
一、示例总览:20 个官方 Sample 一览
Zoom Video SDK Windows 官方示例仓库(videosdk-windows-rawdata-sample)提供了覆盖 SDK 主要能力的示例工程。下表汇总了全部示例的名称、功能定位与核心特性,是选型时的首要参考:
| 示例 | 描述 | 关键特性 |
|---|---|---|
| VSDK_SkeletonDemo | 最小化会话加入 | 最简单的入门起点 |
| VSDK_getRawVideo | 采集原始视频 | YUV420 帧提取 |
| VSDK_getRawAudio | 采集原始音频 | PCM 音频提取 |
| VSDK_getRawShare | 采集屏幕共享 | 共享内容捕获 |
| VSDK_sendRawVideo | 发送自定义视频 | 虚拟摄像头注入 |
| VSDK_sendRawAudio | 发送自定义音频 | 虚拟麦克风注入 |
| VSDK_sendRawShare | 发送自定义共享 | 自定义屏幕共享源 |
| VSDK_CloudRecording | 云录制 | 启停云端录制 |
| VSDK_CommandChannel | 自定义消息 | 收发自定义命令 |
| VSDK_CallIn | PSTN 呼入 | 电话拨入支持 |
| VSDK_Callout | PSTN 呼出 | 电话拨出支持 |
| VSDK_ServiceQuality | 网络统计 | 质量监控 |
| VSDK_TranscriptionAndTranslation | 实时转写 | 实时字幕 |
| VSDK_MultiStreamVideo | 多路视频流 | 多摄像头支持 |
| VSDK_PreviewCameraAndMicrophone | 设备预览 | 入会前设备测试 |
| VSDK_Share2ndCameraAsMultiCam | 第二摄像头 | 多摄像头共享 |
| VSDK_Share2ndCameraAsShareScreenDemo | 摄像头作为共享 | 摄像头内容共享 |
| VSDK_ShareScreenPreprocessorDemo | 共享预处理 | 自定义共享处理 |
| VSDK_RTMSDemo | 实时消息 | RTMS 集成 |
| VSDK_DuilibDemo2 | 完整 UI 演示 | 完整 GUI 应用 |
官方示例仓库与文档的链接信息可在技能库的 SKILL.md 与 windows.md 中查阅,本文聚焦于这些示例的本地化解读与代码模式。
从示例清单可以看出,官方示例覆盖了 SDK 的四大能力域:原始数据采集(Raw Data Capture)、原始数据注入(Raw Data Injection)、通信(Communication)与录制/流媒体/高级特性,下文第三节将按类别展开。
二、推荐学习路径:五个阶段吃透核心示例
官方建议的学习路径遵循"先跑通最小闭环,再逐项深入"的原则,与技能库中 concepts/sdk-architecture-pattern.md 所总结的"单例 → 委托 → 订阅"三段式架构一脉相承。
阶段 1:从 VSDK_SkeletonDemo 起步
这是代码量最小、最纯粹的会话加入示例,演示了以下 SDK 基础能力:
- SDK 初始化(
CreateZoomVideoSDKObj+initialize) - JWT 鉴权(
token字段) - 会话加入/离开(
joinSession/leaveSession) - Windows 消息循环(回调驱动的关键前提)
- 基础委托实现(
IZoomVideoSDKDelegate)
需要掌握的核心模式:
// 1. 创建 SDK IZoomVideoSDK* sdk = CreateZoomVideoSDKObj(); // 2. 初始化 ZoomVideoSDKInitParams params; params.domain = L"https://zoom.us"; sdk->initialize(params); // 3. 添加委托 sdk->addListener(myDelegate); // 4. 加入会话 ZoomVideoSDKSessionContext ctx; ctx.sessionName = L"session"; ctx.token = L"jwt"; ctx.audioOption.connect = false; sdk->joinSession(ctx); // 5. 消息循环(关键!) while (running) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } Sleep(10); }为什么消息循环"关键"?技能库中的 troubleshooting/windows-message-loop.md 明确指出:Zoom Video SDK 依赖 Windows 消息机制派发回调。事件发生时,SDK 将消息投递到调用joinSession()所在线程的消息队列;若没有PeekMessage/GetMessage驱动的消息循环,onSessionJoin()、onError()等回调永远不会触发——表现为"joinSession()返回成功但无任何回调"。因此:
- 消息循环必须与调用 SDK 方法的线程同一线程;
- 回调内禁止阻塞(不要
sleep或忙等); - GUI 应用(WinMain 标准消息循环)天然满足,控制台/自定义主循环必须显式补充。
阶段 2:视频采集 VSDK_getRawVideo
该示例演示如何捕获远端用户的原始 YUV420 视频帧,包含:
IZoomVideoSDKRawDataPipeDelegate接口实现onRawDataFrameReceived()回调- YUV 缓冲区提取(Y、U、V 三平面)
- 分辨率与旋转角处理
核心模式:
class VideoCapture : public IZoomVideoSDKRawDataPipeDelegate { void onRawDataFrameReceived(YUVRawDataI420* data) override { int width =>void onMixedAudioRawDataReceived(AudioRawData* data) override { char* buffer =>// 初始化 SDK IZoomVideoSDK* sdk = CreateZoomVideoSDKObj(); ZoomVideoSDKInitParams params; params.domain = L"https://zoom.us"; params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap; sdk->initialize(params);内存模式注意事项:技能库 SKILL.md 特别强调,原始数据的内存模式应始终使用堆模式(ZoomVideoSDKRawDataMemoryModeHeap),并同时为视频、共享、音频三路分别设置:
params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap; params.shareRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap; params.audioRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;堆模式(而非栈模式)可避免大尺寸视频帧导致的内存问题;此外还可通过params.enableLog = true与params.logFilePrefix开启日志以辅助排查。
2. 委托注册
必须始终在加入会话之前注册委托:
sdk->addListener(new MyDelegate()); sdk->joinSession(context);若在joinSession()之后才调用addListener(),将错过早期事件(examples/session-join-pattern.md 中明确标注此为错误用法)。同时注意:IZoomVideoSDKDelegate拥有 70~80+ 个纯虚方法,全部必须实现(哪怕为空实现),否则会产生抽象类编译错误。
3. 音频连接策略
官方推荐"先入会、后连音频"的两段式:入会时设置audioOption.connect = false,在onSessionJoin()回调中再调用startAudio():
context.audioOption.connect = false; // 入会配置 void onSessionJoin() override { sdk->getAudioHelper()->startAudio(); // 在此连接 }该策略分离了会话加入与音频初始化,可提高可靠性并便于错误处理。同理,自己的摄像头应在onSessionJoin中通过videoHelper->startVideo()开启。
4. 消息循环
所有示例都包含消息循环,这是回调触发的必要前提(前文已详述):
while (!g_exit) { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } Sleep(10); }五、构建与配置
前置条件
- Visual Studio 2019 或 2022(安装"使用 C++ 的桌面开发"工作负载,含 MSVC v142/v143 编译器与 Windows 10/11 SDK)
- Windows SDK 10.0.19041.0 及以上
- Zoom Video SDK(从 Zoom Marketplace 下载)
构建步骤
- 打开解决方案文件(
.sln) - 将平台设置为x64
- 将配置设置为Release
- 生成解决方案(Ctrl+Shift+B)
- 将 SDK DLL 拷贝到输出目录
技能库 SKILL.md 补充了运行时环境的基线:Windows 10(1903 或更高)或 Windows 11,支持 x64(推荐)、x86 与 ARM64 架构;若使用 C#/.NET 应用,还需 .NET Framework 4.8 及以上与 C++/CLI 支持。
配置文件
每个示例通过config.json提供运行参数:
{ "jwt": "your-jwt-token", "session_name": "test-session", "password": "", "user_name": "Bot" }在 examples/session-join-pattern.md 的完整实现中,LoadConfig()会读取该 JSON(使用 jsoncpp),将jwt、session_name、password、user_name(默认"Bot")映射为全局宽字符串,再填入ZoomVideoSDKSessionContext完成入会。若文件无法打开或 SDK 初始化失败,程序会立即退出并返回错误码。
六、进阶深化:示例背后的 SDK 实现细节
理解示例代码后,可进一步结合技能库参考文档深入底层实现。
6.1 五层 API 层级与"导航式"访问
references/windows-reference.md 将 SDK 建模为五层深的单例对象树,所有功能都通过"导航"而非"构造"获取:
- Level 1 入口:
CreateZoomVideoSDKObj() → IZoomVideoSDK*,提供initialize、joinSession、addListener、getVideoHelper、getAudioHelper、getShareHelper、getChatHelper、getCmdChannel、getRecordingHelper等入口; - Level 2 核心 Helper 与会话:
IZoomVideoSDKSession(getMyself、getRemoteUsers)、IZoomVideoSDKVideoHelper(仅控制自己的摄像头)、IZoomVideoSDKAudioHelper、IZoomVideoSDKShareHelper; - Level 3 用户与渲染对象:
IZoomVideoSDKUser(GetVideoCanvas、GetVideoPipe、getVideoStatus)、IZoomVideoSDKCanvas(SDK 渲染)、IZoomVideoSDKRawDataPipe(原始 YUV)、IZoomVideoSDKShareAction(共享控制); - Level 4 设备/聊天/回调:
IZoomVideoSDKCameraDevice、IZoomVideoSDKChatHelper、IZoomVideoSDKRawDataPipeDelegate; - Level 5 原始数据与工具:
YUVRawDataI420、AudioRawData、IZoomVideoSDKUserHelper、IZoomVideoSDKCmdChannel等。
关键区分:VideoHelper/AudioHelper只控制自己的音视频流(startVideo()开启自己的摄像头);观看远端参会人的视频,必须通过其user->GetVideoCanvas()->subscribeWithView(hwnd, aspect, resolution)或user->GetVideoPipe()->subscribe(resolution, delegate)订阅。屏幕共享则更特殊:远端共享必须使用onUserShareStatusChanged回调中的IZoomVideoSDKShareAction(而非user->GetShareCanvas()),因为一个用户可能同时存在多个共享流。
6.2 两种渲染/处理路线:Canvas API 与 Raw Data Pipe
| 路线 | 接口 | 适用场景 |
|---|---|---|
| Canvas API | IZoomVideoSDKCanvas::subscribeWithView(HWND) | 标准应用、画质最佳、实现最简单 |
| Raw Data Pipe | IZoomVideoSDKRawDataPipe::subscribe(delegate) | 自定义处理、特效、录制、计算机视觉 |
Canvas API 由 SDK 直接渲染到窗口句柄,无需 YUV 转换,支持ZoomVideoSDKVideoAspect_Original / FullFilled / PanAndScan / LetterBox等纵横比与ZoomVideoSDKResolution_90P / 180P / 360P / 720P / 1080P / Auto等分辨率选项;Raw Data Pipe 则向委托回调交付YUVRawDataI420帧,交由应用自行转换渲染(GDI/DirectX/OpenGL 均可)。
6.3 原始视频处理的进阶要点(对应 VSDK_getRawVideo)
examples/raw-video-capture.md 给出了 YUV420(I420 平面)的内存布局:Y 平面为全分辨率(width × height字节),U/V 平面各为四分之一分辨率((width/2) × (height/2)字节),单帧总大小为width × height × 1.5字节:
| 分辨率 | Y 缓冲区 | U 缓冲区 | V 缓冲区 | 总计 |
|---|---|---|---|---|
| 720p(1280×720) | 921,600 | 230,400 | 230,400 | 1,382,400 |
| 1080p(1920×1080) | 2,073,600 | 518,400 | 518,400 | 3,110,400 |
| 360p(640×360) | 230,400 | 57,600 | 57,600 | 345,600 |
YUVRawDataI420的主要方法包括GetYBuffer/GetUBuffer/GetVBuffer(三平面指针)、GetStreamWidth/GetStreamHeight(帧尺寸)、GetRotation(0/90/180/270)、GetTimeStamp(时间戳)以及CanAddRef/AddRef/Release(引用计数,用于跨回调异步处理)。采集到的.yuv文件可用 FFplay 回放或 FFmpeg 转码:
ffplay -video_size 1280x720 -pixel_format yuv420p -f rawvideo video.yuv ffmpeg -video_size 1280x720 -pixel_format yuv420p -framerate 30 -f rawvideo -i video.yuv -c:v libx264 output.mp4性能优化建议:预分配 RGB 缓冲区(仅尺寸变化时重分配);回调内使用AddRef()将帧投递到独立处理线程,处理完Release();AI 处理订阅低分辨率(ZoomVideoSDKResolution_360P),显示则用高分辨率 Canvas。
6.4 原始音频采集格式(对应 VSDK_getRawAudio)
examples/raw-audio-capture.md 明确音频格式为:PCM 未压缩、32000 Hz、16-bit 有符号、单声道或双声道、小端序,每次回调约 640~1280 字节(20~40ms 音频)。三种回调分别对应:
onMixedAudioRawDataReceived:全体参会人混合音频,适合整场录制;onOneWayAudioRawDataReceived:逐用户音频(需特殊配置),适合按发言人转写;onSharedAudioRawDataReceived:屏幕共享内容音频,与参会人音频分离。
AudioRawData提供GetBuffer()(PCM 缓冲区)、GetBufferLen()(字节数)、GetSampleRate()(通常 32000)与GetChannelNum()(1=单声道,2=双声道)。采集到的.pcm可用 FFplay 回放或转为 WAV:
ffplay -f s16le -ar 32000 -ac 1 audio.pcm ffmpeg -f s16le -ar 32000 -ac 1 -i audio.pcm output.wav常见坑位:音频回调不触发(未在onSessionJoin连接音频)、FFmpeg 中错误使用 44100 Hz、静音(无人发言或全员静音,需检查onUserAudioStatusChanged)。
6.5 订阅时机与错误码(调试示例的关键依据)
references/windows-reference.md 强调两条时序铁律:
- 不要在
onUserJoin中订阅视频——此时视频可能尚未就绪,会触发 Error 2(Internal_Error)。正确做法是在onUserVideoStatusChanged中检查pipe->getVideoStatus().isOn为真后再订阅,并跳过自己(if (user == myself) continue;); - 订阅过快会触发
ZoomVideoSDKSubscribeFailReason_TooFrequentCall(=6),处理方式是在相邻订阅调用之间插入Sleep(200)。
常用错误码速查:0 Success、1 Wrong_Usage(错误状态调用)、2 Internal_Error(视频未就绪/过早订阅)、7 Invalid_Parameter(NULL 指针、非法 HWND)、8 Call_Too_Frequently(调用过于频繁)。
6.6 线程安全与生命周期
SDK 回调运行在 SDK 线程而非主线程:不要在回调中执行重操作、不要在回调中调用cleanup()、跨线程传递数据使用线程安全队列(如YUVRawDataI420的引用计数配合生产者-消费者队列)并加锁保护共享状态。退会时统一在onUserLeave/onSessionLeave中解除订阅并清理,最后按leaveSession(false)→cleanup()→DestroyZoomVideoSDKObj()的顺序释放。
七、相关文档导航
本文对应的示例参考文档位于 references/samples.md,技能库中与之配套的深度资料还包括:
- SDK 架构模式:贯穿所有功能的"单例 → 委托 → 订阅"万能三段式
- 会话加入模式:完整的 JWT 鉴权 + 入会代码(含
main.cpp与config.json) - 原始视频采集:YUV 捕获完整实现与 FFmpeg 处理
- 原始音频采集:PCM 捕获完整实现与 FFplay 处理
- 发送原始视频 / 发送原始音频:虚拟摄像头/虚拟麦克风注入实现
- API 参考:五层 API 层级、方法签名、错误码与时序规则
- 委托方法:全部回调方法
- Windows 消息循环:回调不触发的第一排查项
- 常见问题:快速诊断清单
行动建议:以VSDK_SkeletonDemo打通"初始化 → 委托 → 入会 → 消息循环"的最小闭环,再根据业务诉求选择VSDK_getRawVideo或VSDK_getRawAudio切入原始数据采集;若需要向会话注入内容,则对应研读VSDK_sendRawVideo(虚拟摄像头)与VSDK_sendRawAudio(虚拟麦克风)。任何示例运行异常,优先检查消息循环是否存在、委托是否在入会前注册、订阅是否发生在视频就绪之后。
【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考