摘要
本文介绍大牛直播SDK(SmartMediaKit)在 Windows 平台 Unity3D 环境下接入 RTSP/RTMP 直播播放 SDK 的工程实践。方案基于 Windows 原生 SmartPlayerSDK,通过 C# P/Invoke 对接底层 Native DLL,并在 Unity 层完成播放器实例管理、播放参数配置、事件回调、YUV 视频帧渲染、多路播放和本地录像等能力封装。本文重点说明 Unity 工程中的集成路径、目录组织、核心调用流程、渲染链路和常见问题处理,帮助开发者在虚拟仿真、安防监控、工业视觉、智慧教室、应急指挥等场景中快速构建稳定、超低延迟(100~200ms)、易维护的 RTSP/RTMP 直播播放能力。
1. 背景介绍
在 Unity3D 项目中接入实时直播播放能力,常见需求包括:在三维场景中叠加实时监控画面、在虚拟仿真系统中接入摄像头或无人机回传视频、在智慧教室或无纸化会议系统中显示多路实时流、在工业视觉或应急指挥平台中统一展示 RTSP/RTMP 直播源。
这类场景与普通点播视频播放不同,核心关注点通常不是播放器 UI 是否复杂,而是:
- 起播是否足够快;
- 延迟是否足够低;
- RTSP/RTMP 协议兼容性是否稳定;
- 多路播放时资源占用是否可控;
- 网络异常、断流、重连、缓冲等状态是否可感知;
- 是否支持录像、快照、静音、音量、旋转、URL 切换等工程能力;
- 是否方便嵌入 Unity 的 RawImage、材质、纹理和场景系统。
大牛直播SDK(SmartMediaKit)Windows 平台 Unity3D RTSP/RTMP 播放方案,整体思路是:底层复用成熟的 Windows Native 播放内核,上层通过 C# 封装适配 Unity 生命周期和渲染体系。这样既能保留原生 SDK 在协议、解码、缓冲、低延迟和录像方面的能力,又能让 Unity 开发者以更自然的方式在场景中使用播放器。
2. 方案定位
SmartU3dWinPlayer 可以理解为大牛直播SDK Windows 播放模块在 Unity3D 环境下的一层工程化封装。它不是重新实现一套播放器内核,而是基于 SmartPlayerSDK.dll 提供的能力,在 Unity 层完成以下工作:
- 通过 C# P/Invoke 调用底层 Native SDK;
- 管理 SDK 初始化、反初始化和播放器句柄;
- 将 RTSP/RTMP 播放参数封装成 Unity 可配置对象;
- 通过视频帧回调获取解码后的 I420/YUV420 数据;
- 将 Y/U/V 三个平面上传到 Unity Texture2D;
- 通过自定义 Shader 在 GPU 中完成 YUV 到 RGB 的转换;
- 使用 RawImage 或材质将视频画面渲染到 Unity UI 或三维对象上;
- 支持多路播放器实例并发管理;
- 支持播放过程中的事件回调、网络状态监控、本地录像等能力。

这种设计方式比较适合 Unity 项目,因为 Unity 本身并不适合直接使用 Windows HWND 方式进行原生窗口渲染。通过"视频帧回调 + Unity 纹理上传 + Shader 渲染"的方式,可以让直播画面自然融入 Unity 的 UI、Canvas、材质球、3D 场景和交互逻辑。
3. 功能特性

Windows 平台 Unity3D RTSP/RTMP 播放 SDK 主要支持以下能力:
| 能力类别 | 功能说明 |
|---|---|
| 协议支持 | 支持 RTSP、RTMP 直播流播放 |
| 编码格式 | 支持常见 H.264/H.265 视频流,具体以授权版本和底层 SDK 能力为准 |
| 低延迟播放 | 支持低缓冲、快速首帧、低延迟播放模式 |
| RTSP 传输 | 支持 RTSP TCP/UDP 传输配置,并支持 TCP/UDP 自动切换策略 |
| 多路播放 | 支持同一 Unity 场景内多路 RTSP/RTMP 流并发播放 |
| Unity 渲染 | 支持 I420 视频帧回调,Unity 侧通过 YUV Shader 渲染到 RawImage |
| 音频控制 | 支持静音、取消静音、音量调节 |
| 解码控制 | 支持软解/硬解策略配置,硬解不可用时可回退到软解 |
| 状态回调 | 支持连接中、连接成功、连接失败、断开、缓冲、下载速度等事件 |
| 本地录像 | 支持播放端录像,支持录像目录、文件大小、文件命名规则配置 |
| 快照扩展 | 可基于 SDK 快照接口或视频帧数据扩展截图能力 |
| 运行时控制 | 支持播放、停止、切换 URL、旋转、缓冲配置等常见操作 |
从工程集成角度看,该方案更适合被封装成 Unity 组件或业务播放器控件,而不是让业务层直接面对大量 Native 接口。推荐在项目中保持"业务 UI 层、播放器实例层、SDK 封装层、Native SDK 层"的清晰分层。
4. 适用场景
该方案可用于以下典型场景:
4.1 安防监控与视频墙
在 Unity 场景中构建多路视频墙,拉取前端 IPC、NVR、无人机、执法记录仪或平台侧转发出来的 RTSP/RTMP 流,实现实时监看、状态展示和业务联动。
4.2 工业视觉与数字孪生
在工业仿真、数字孪生或生产监控系统中,将实时摄像头画面映射到设备模型、监控面板或工艺流程界面中,辅助远程巡检和生产可视化。
4.3 智慧教室与无纸化会议
在 Unity 大屏、交互式教学系统或会议系统中接入教师端、学生端、会议终端或采集设备的视频流,实现多路预览、画面切换和互动展示。
4.4 应急指挥与远程协同
在应急调度、移动执法、无人机巡检、远程专家指导等系统中,Unity 可作为三维指挥界面或综合态势呈现界面,RTSP/RTMP 播放能力则用于接入实时现场画面。
4.5 VR/AR 与虚拟仿真
在 VR 教学、虚拟展厅、仿真实训等场景中,可将实时直播画面作为纹理贴到虚拟屏幕、模型表面或空间 UI 上,实现沉浸式实时视频展示。
5. 工程结构建议
推荐 Unity 工程按以下方式组织 SDK 文件和业务脚本:
这样划分后,业务层只需要关注"创建播放器、绑定画面、开始播放、停止播放、录像控制"等上层动作,不需要直接处理复杂的 Native 回调和底层资源释放。
6. Unity Plugin DLL 配置
将 DLL 放入 Assets/Plugins/x86 和 Assets/Plugins/x86_64 后,需要在 Unity Inspector 中配置对应平台属性。
建议配置如下:
- 选中
Plugins/x86下的 DLL; - 勾选 Standalone Windows;
- CPU 设置为 x86;
- 选中
Plugins/x86_64下的 DLL; - 勾选 Standalone Windows;
- CPU 设置为 x86_64;
- 点击 Apply 保存。
实际项目中推荐优先使用 x86_64 架构。对于多路播放、高清流、硬件解码和复杂 Unity 场景来说,64 位进程在内存空间和稳定性方面更适合生产环境。
需要注意的是,SmartPlayerSDK.dll 可能依赖其他运行库或 FFmpeg 相关 DLL。发布 Standalone Windows 包时,需要确保所有依赖 DLL 都被正确复制到最终可执行程序所在目录或 Unity 打包输出目录中。
7. SDK 初始化流程
SDK 全局初始化建议放在场景根节点的 PlayerManager 中完成。通常一个 Unity 应用只需要初始化一次 SDK。

典型初始化流程包括:
- 创建日志目录;
- 设置 SmartLog 日志路径;
- 调用播放器 SDK 初始化接口;
- 如为商业授权版本,设置授权信息;
- 初始化播放器实例管理容器。
示例流程如下:
cs
private void Awake()
{
string logPath = Path.Combine(Application.persistentDataPath, "DaniuliveLog");
Directory.CreateDirectory(logPath);
NTSmartLog.NT_SL_SetPath(logPath);
NTSmartPlayerSDK.NT_SP_Init(0, IntPtr.Zero);
// 商业授权版本可在此处设置授权信息
// NTSmartPlayerSDK.NT_SP_SetSDKClientKey(clientId, key, 0, IntPtr.Zero);
}
这里建议使用 Application.persistentDataPath 作为日志目录,因为它是 Unity 推荐的可写路径,避免因为程序安装目录无写权限导致日志无法输出。
日志对播放器集成非常重要。RTSP/RTMP 拉流失败、协议握手异常、解码失败、DLL 加载异常、录像路径错误等问题,都可以优先通过 SDK 日志和 Unity Console 双向排查。
8. 播放器实例创建
每一路 RTSP/RTMP 流建议对应一个独立的 PlayerInstance。实例创建时,主要完成以下步骤:
- 调用
NT_SP_Open()获取播放器句柄; - 根据
PlayerConfig配置播放参数; - 注册事件回调;
- 设置播放 URL;
- 将 SDK handle 与 PlayerInstance 建立映射关系。
示例逻辑可以概括为:
cs
uint ret = NTSmartPlayerSDK.NT_SP_Open(out playerHandle, IntPtr.Zero, 0, IntPtr.Zero);
if (ret != NTBaseCodeDefine.NT_ERC_OK)
{
Debug.LogError("Open player failed.");
return;
}
ConfigurePlayer();
NTSmartPlayerSDK.NT_SP_SetEventCallBack(playerHandle, IntPtr.Zero, OnEvent);
NTSmartPlayerSDK.NT_SP_SetURL(playerHandle, url);
Unity 版本的集成与 Windows 原生播放器的一个关键差异在于:原生 Windows Demo 通常可以直接传入窗口句柄,由 SDK 进行 D3D/GDI 渲染;而 Unity 中更推荐通过视频帧回调方式获取解码数据,再交给 Unity 自身的纹理和 Shader 系统渲染。因此在 NT_SP_Open() 时可以不传入渲染窗口句柄,而是后续注册视频帧回调。
9. 播放参数配置
播放参数建议统一封装在 PlayerConfig 中,并通过 Unity Inspector 暴露给业务侧或测试人员配置。常见参数包括:
| 参数 | 建议说明 |
|---|---|
| enableHardwareDecoder | 是否启用硬件解码。多路高清播放建议开启,但需结合显卡和驱动兼容性测试 |
| bufferTimeMs | 播放缓冲时间,单位毫秒。越小延迟越低,网络抗抖动能力越弱 |
| rtspUseTcp | RTSP 是否强制 TCP。公网、弱网、NAT 场景下 TCP 更稳 |
| rtspTimeoutSec | RTSP 连接超时时间 |
| rtspAutoSwitchTcpUdp | RTSP TCP/UDP 自动切换,提高接入成功率 |
| mute | 是否静音 |
| volume | 音量,通常范围 0-100 |
| fastStartup | 是否启用快速首帧 |
| lowLatencyMode | 是否启用低延迟模式 |
| rotateDegrees | 视频旋转角度 |
| recMaxFileSizeKB | 单个录像文件最大大小,超过后自动切片 |
典型参数配置建议:
9.1 超低延迟监控场景
适用于安防监控、无人机回传、工业控制、远程指挥等对实时性要求高的场景。
cs
bufferTimeMs = 0 ~ 200
fastStartup = true
lowLatencyMode = true
rtspAutoSwitch = true
rtspUseTcp = 根据网络环境选择
enableHWDecoder = 多路高清时建议开启
这类场景的目标是尽量降低端到端延迟,因此缓冲不宜设置过大。但需要注意,缓冲越小,对网络抖动越敏感。如果网络质量较差,可能会出现轻微卡顿或丢帧,需要根据现场网络条件进行平衡。
9.2 稳定观看场景
适用于直播展示、会议观看、教学直播等对流畅性要求更高、对毫秒级延迟不极端敏感的场景。
cs
bufferTimeMs = 1000 ~ 3000
fastStartup = true
lowLatencyMode = false
rtspAutoSwitch = true
enableHWDecoder = 按需开启
这类场景可以适当增加缓冲,提高抗抖动能力,让播放更平滑。
10. 开始播放流程

开始播放时,主要执行以下动作:
- 判断当前实例是否已在播放;
- 根据配置开启硬件解码;
- 注册视频帧回调;
- 调用
NT_SP_StartPlay()启动播放; - 播放成功后更新实例状态;
- 在 Unity 主线程中持续执行帧更新。
示例流程如下:
cs
if (config.enableHardwareDecoder)
{
NTSmartPlayerSDK.NT_SP_SetH264HardwareDecoder(playerHandle, 1, 0);
NTSmartPlayerSDK.NT_SP_SetH265HardwareDecoder(playerHandle, 1, 0);
}
NTSmartPlayerSDK.NT_SP_SetVideoFrameCallBack(
playerHandle,
(int)NTSmartPlayerDefine.NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FROMAT_I420,
IntPtr.Zero,
OnVideoFrame);
uint ret = NTSmartPlayerSDK.NT_SP_StartPlay(playerHandle);
这里推荐使用新接口 NT_SP_SetURL() + NT_SP_StartPlay() 的方式,不建议与老接口混用。播放停止时,对应调用 NT_SP_StopPlay()。
11. Unity 视频渲染链路
Unity3D 下的渲染链路建议采用以下方式:

12. 事件回调处理

播放器事件回调用于感知播放状态和网络状态。常见事件包括:
| 事件 | 说明 |
|---|---|
| CONNECTING | 正在连接 |
| CONNECTED | 连接成功 |
| CONNECTION_FAILED | 连接失败 |
| DISCONNECTED | 连接断开 |
| START_BUFFERING | 开始缓冲 |
| BUFFERING | 缓冲中,可获取缓冲百分比 |
| STOP_BUFFERING | 缓冲结束 |
| DOWNLOAD_SPEED | 下载速度上报 |
| RTSP_STATUS_CODE | RTSP 状态码,例如 401 鉴权失败 |
| NEED_KEY / KEY_ERROR | 加密流需要密钥或密钥错误 |
| PLAYBACK_REACH_EOS | 点播流播放结束 |
事件回调的处理原则是:
- 回调线程不直接操作 Unity UI;
- 将状态写入线程安全字段;
- 在主线程中刷新按钮、文本、窗口标题或状态栏;
- 对关键错误进行日志记录;
- 网络断开或连接失败时,由业务层决定是否自动重试。
例如,播放器实例可以维护 connection_status、buffer_percent、download_speed 等字段,再由 PlayerManager.Update() 或 UI 层定时读取并展示。
13. 多路播放设计

多路播放是 Unity3D 场景中非常常见的需求,例如四分屏、九宫格、视频墙、监控矩阵等。
推荐设计如下:
cs
PlayerManager
├── ConcurrentDictionary<IntPtr, PlayerInstance>
├── CreatePlayer(url)
├── ReleasePlayer(handle)
└── Update() -> foreach player.UpdateFrame()
UIController
├── slotPlayers[index]
├── urlInputs[index]
├── renderViews[index]
├── playButtons[index]
└── recordButtons[index]
PlayerInstance
├── player_handle
├── StartPlay()
├── StopPlay()
├── StartRecorder()
├── StopRecorder()
└── UpdateFrame()
这里的关键是以 SDK handle 作为播放器实例的唯一标识。因为 SDK 的视频帧回调和事件回调都会携带 handle,上层可以通过 handle 快速反查对应的 PlayerInstance,从而完成多路回调路由。
14. 本地录像
播放端录像是大牛直播SDK中比较实用的能力。它可以在播放 RTSP/RTMP 流的同时,将拉取到的音视频数据录制为本地文件。

典型录像流程包括:
- 设置是否录制视频;
- 设置是否录制音频;
- 设置录像目录;
- 设置单个文件最大大小;
- 设置录像文件命名规则;
- 设置音频转 AAC 策略;
- 注册录像回调;
- 启动录像;
- 停止录像。
简化流程如下:
cs
NTSmartPlayerSDK.NT_SP_SetRecorderVideo(playerHandle, 1);
NTSmartPlayerSDK.NT_SP_SetRecorderAudio(playerHandle, 1);
NTSmartPlayerSDK.NT_SP_SetRecorderDirectoryW(playerHandle, recDir);
NTSmartPlayerSDK.NT_SP_SetRecorderFileMaxSize(playerHandle, maxFileSizeKB);
NTSmartPlayerSDK.NT_SP_SetRecorderAudioTranscodeAAC(playerHandle, 1);
NTSmartPlayerSDK.NT_SP_SetRecorderCallBack(playerHandle, IntPtr.Zero, OnRecordEvent);
NTSmartPlayerSDK.NT_SP_StartRecorder(playerHandle);
录像目录建议仍然使用 Application.persistentDataPath 下的子目录,避免权限问题。Windows 平台如果路径中存在中文字符,建议使用宽字符版本目录接口。
需要注意的是,播放和录像可以共用同一个播放器句柄。因此在释放资源时,不应简单地在停止播放后立即关闭 handle,而应判断录像是否仍在运行。推荐逻辑是:
cs
如果播放停止,但录像仍在运行:保留 handle
如果录像停止,但播放仍在运行:保留 handle
只有播放和录像都停止:关闭 handle
这样可以避免录像过程中误释放底层资源,导致文件不完整或回调异常。
15. RTSP 传输策略建议
RTSP 播放中,TCP 和 UDP 的选择会直接影响播放稳定性和延迟表现。
15.1 UDP 模式
UDP 模式通常延迟更低,但对网络质量要求更高。局域网、专网、摄像头直连等环境下,如果网络稳定,可以优先尝试 UDP。
15.2 TCP 模式
TCP 模式通常更稳,适用于公网、跨网段、弱网、NAT、防火墙复杂等场景。缺点是网络抖动时可能带来更明显的排队和延迟累积。
15.3 自动切换
工程实践中,建议默认开启 RTSP TCP/UDP 自动切换。这样当一种传输方式连接失败或不适合当前网络时,SDK 可以尝试另一种方式,提高接入成功率。
16. 硬件解码建议
Windows 平台多路高清播放时,硬件解码可以显著降低 CPU 占用。推荐策略是:默认提供开关,让集成方可以在测试阶段对比软解和硬解效果。如果现场机器配置较统一,多路高清播放场景下可以优先考虑开启硬解;如果现场机器型号复杂,则应保留软解回退方案。
17. 退出与资源释放
Unity 应用退出时,资源释放需要格外谨慎。因为底层 Native SDK 存在线程、回调和 C++ Runtime 生命周期,Unity 场景销毁、脚本释放、进程退出之间可能存在顺序问题。
推荐处理原则:
- 先停止所有播放器;
- 停止所有录像;
- 清理播放器实例字典;
- 释放 Unity 纹理和材质;
- 最后再进行 SDK 全局反初始化;
- Standalone 环境下如遇 C++ Runtime 析构竞态,可按项目策略进行进程级退出处理。
在 Editor 模式下不要直接 Kill 进程,否则会关闭整个 Unity Editor。Standalone 包和 Editor 调试环境建议区分处理。
18. 常见问题排查
18.1 播放启动失败
建议检查:
- URL 是否以
rtsp://或rtmp://开头; - 流地址是否可访问;
- 防火墙是否阻断;
- RTSP 是否需要用户名密码;
- RTSP TCP/UDP 配置是否适合当前网络;
- SDK DLL 是否完整;
- x86/x64 架构是否匹配;
- 日志目录是否有写权限。
18.2 录像文件没有生成
建议检查:
- 录像目录是否存在;
- 目录是否有写权限;
- 是否使用了支持中文路径的目录接口;
- 是否设置了录像音频或视频;
- 是否调用了
StartRecorder(); - 是否过早关闭播放器 handle;
- 录像回调是否上报错误。
18.3 RTSP 401 鉴权失败
说明 RTSP 服务端要求认证。需要确认 URL 中是否携带用户名密码,或根据项目需要设置对应鉴权参数。典型格式如下:
cs
rtsp://username:password@ip:port/path
18.4 打包后 DLL 找不到
建议检查:
- DLL 是否放在
Assets/Plugins/x86_64或Assets/Plugins/x86; - Inspector 中平台和 CPU 是否配置正确;
- 依赖 DLL 是否一并复制;
- 目标程序是 32 位还是 64 位;
- 是否缺少 Visual C++ Runtime;
- DLL 文件是否被杀毒软件拦截或隔离。
19. 推荐集成流程
综合来看,建议按照以下顺序完成 Unity3D Windows 播放 SDK 集成:

20. 总结
大牛直播SDK(SmartMediaKit)Windows 平台 Unity3D RTSP/RTMP 直播播放方案,本质上是将成熟的 Windows 原生播放内核与 Unity 的渲染体系进行工程化结合。底层 SDK 负责 RTSP/RTMP 协议接入、音视频解码、低延迟控制、缓冲策略、状态回调和录像能力;Unity 层则负责播放器实例管理、业务 UI、纹理上传、Shader 渲染和场景融合。
通过上述封装方式,开发者可以在 Unity3D Windows 项目中快速构建稳定、低延迟、可扩展的 RTSP/RTMP 直播播放能力,并根据实际业务进一步扩展快照、录像、视频墙、三维场景融合、VR/AR 显示和智能分析等功能。
📎 CSDN官方博客:音视频牛哥-CSDN博客