摘要
本文介绍大牛直播SDK(SmartMediaKit)在 Android 平台 Unity3D 工程中的 RTSP/RTMP 播放器集成方式,适用于安防监控、工业可视化、无人机回传、智慧教室、数字孪生、远程巡检、车载视频、AR/VR 可视化等需要在 Unity 场景中嵌入实时视频画面的应用场景。
通过大牛直播SDK提供的 Android Unity3D 播放器能力,开发者可以在 Unity3D 工程中快速接入 RTSP/RTMP 实时流播放,实现低延迟播放、播放状态回调、视频画面显示、本地录像、软硬解码配置、RTSP 传输策略配置、下载速度提示等能力。Unity 侧主要完成场景搭建、UI 控制、播放参数配置和视频承载,SDK 侧负责实时流媒体播放、解码、事件回调和录像等核心能力。
关键词: 大牛直播SDK、SmartMediaKit、Unity3D、Android、RTSP播放器、RTMP播放器、低延迟播放、Unity播放器集成、实时音视频SDK
1. 方案概述
在 Unity3D 项目中接入 RTSP/RTMP 实时流播放,与普通本地视频文件播放不同。RTSP/RTMP 播放涉及实时网络连接、流媒体拉取、解码、缓冲控制、状态回调、画面显示和异常处理等多个环节。如果业务侧从零实现完整播放链路,不仅开发周期长,还需要持续处理不同视频源、不同 Android 设备、不同网络环境下的兼容性问题。
大牛直播SDK Android Unity3D 播放器方案,面向 Unity3D 实时视频集成场景提供标准化播放器能力。SDK 侧负责 RTSP/RTMP 拉流、播放控制、解码适配、状态事件、下载速度统计和录像等能力;Unity 侧负责 UI 交互、播放地址输入、状态展示、显示区域承载和业务逻辑组织。

当前示例工程已将 SDK 接口、播放器封装、播放实例、播放器管理器和 UI 控制进行了分层。NTSmartPlayerAPI 负责 Android SDK JNI 包装,业务层无需直接持有 AndroidJavaObject;NTPlayerWrapper 负责句柄生命周期、播放/录像状态和配置下发;PlayerInstance 负责单路播放器实例、画面显示适配和事件处理;PlayerManager 负责 SDK 初始化、实例创建销毁和事件分发;UIController 负责界面按钮、输入框、状态文本和 RawImage 适配。
2. 适用场景
大牛直播SDK Android Unity3D RTSP/RTMP 播放器适用于需要在 Unity3D 中显示实时视频画面的 Android 应用。典型场景包括工业数字孪生系统中的现场视频叠加、无人机或车载系统中的实时回传画面显示、安防监控系统中的 RTSP 预览、智慧教室和无纸化会议中的实时同屏、远程巡检中的现场视频查看,以及 AR/VR、仿真训练和应急指挥中的实时视频融合。
这类项目通常更关注以下能力:视频画面能否稳定播放、延迟是否可控、播放状态是否可感知、是否支持 RTSP/RTMP 常见视频源、是否便于接入 Unity UI 或场景对象、是否可以在播放过程中进行录像留痕。大牛直播SDK通过播放器模块和 Unity3D 示例工程,将这些能力封装为相对清晰的集成流程,便于开发者快速完成工程验证和业务集成。
3. 集成前准备
开始集成前,建议准备以下内容:
| 项目 | 说明 |
|---|---|
| Unity3D 工程 | Android 目标平台工程 |
| Android Native 插件 | 大牛直播SDK提供的 .so 及相关依赖 |
| C# 脚本文件 | 播放器接口层、管理层、实例层和 UI 控制层 |
| Material 与 Shader | 用于 Unity 侧视频画面显示 |
| 测试流地址 | RTSP 或 RTMP 播放地址 |
| Android 真机 | 建议使用真实设备验证播放、录像和性能 |
Android 工程至少需要网络访问权限:
<uses-permission android:name="android.permission.INTERNET" />
如果项目需要录像,推荐优先使用应用私有目录保存录像文件。示例工程中提供了录像目录配置项,当未指定录像目录时,可使用 Application.persistentDataPath/Record 作为默认录像路径。
4. 工程目录说明

建议将播放器相关文件按职责放入 Unity 工程目录,便于后续维护和复用。推荐目录结构如下:
Assets/
├── NTSmartPlayerAPI.cs
├── NTPlayerEvent.cs
├── NTPlayerWrapper.cs
├── PlayerConfig.cs
├── PlayerInstance.cs
├── PlayerManager.cs
├── UIController.cs
├── Plugins/
│ └── Android/
│ ├── libSmartPlayer.so
│ └── 其他依赖 .jar
├── Materials/
│ ├── MaterialYuv420.mat
│ ├── MaterialNV21.mat
│ └── MaterialNV12.mat
└── Shaders/
├── Unlit_YUV420.shader
├── Unlit_NV21.shader
└── Unlit_NV12.shader
各文件职责建议理解如下:
| 文件 | 说明 |
|---|---|
NTSmartPlayerAPI.cs |
Android SDK JNI 静态包装层,统一封装播放器底层接口 |
NTPlayerEvent.cs |
播放器事件 ID 常量定义 |
NTPlayerWrapper.cs |
播放器句柄生命周期、播放控制、录像控制和参数下发封装 |
PlayerConfig.cs |
播放配置数据结构,可在 Inspector 中调整 |
PlayerInstance.cs |
单路播放器实例,负责播放状态、事件处理和视频显示适配 |
PlayerManager.cs |
单例管理器,负责 SDK 初始化、播放器创建销毁和事件分发 |
UIController.cs |
UI 控制器,负责按钮、输入框、状态文本和 RawImage 显示适配 |
其中,NTSmartPlayerAPI 是 SDK 接口层,内部负责初始化 Android 侧播放器对象并提供统一的 NT_U3D_* 接口;NTPlayerWrapper 进一步封装播放器句柄、播放状态、录像状态和配置下发;PlayerManager 是场景中的单例管理器;UIController 负责用户交互和显示区域适配。
5. 插件、Material 与 Shader 放置

Android Native 插件应放入:
Assets/Plugins/Android/
├── libSmartPlayer.so
└── 其他依赖 .jar
Unity 在构建 Android APK 时,会自动将该目录下的 .so 和 .jar 依赖打入应用包。请确保 SDK 库文件与目标 CPU 架构匹配,例如 arm64-v8a 或 armeabi-v7a。
视频显示相关 Material 和 Shader 建议放入:
Assets/Materials/
├── MaterialYuv420.mat
├── MaterialNV21.mat
└── MaterialNV12.mat
Assets/Shaders/
├── Unlit_YUV420.shader
├── Unlit_NV21.shader
└── Unlit_NV12.shader
SDK 已对不同视频格式的显示链路进行适配,开发者通常只需在 Inspector 中正确配置对应 Material,即可完成 Unity 侧视频画面显示。示例工程中,UIController 会实例化 I420、NV21、NV12 三类 Material,播放实例会根据实际视频格式选择对应显示材质。
6. Unity 场景搭建
推荐使用以下场景层级:
Canvas
├── PlayerManager 挂载 PlayerManager.cs
└── Panel 挂载 UIController.cs
├── VideoArea
│ └── RawImage
└── ControlsArea
├── StatusText
├── InputField_Url
└── ButtonRow
├── BtnDecoder
├── BtnMute
├── BtnStartStopPlayback
└── BtnRecord
PlayerManager 用于 SDK 初始化、播放器实例管理和事件接收,场景中通常只需要一个。Panel 作为播放器 UI 面板,挂载 UIController,用于控制播放、停止、录像、静音、软硬解码切换和状态显示。

VideoArea 用于承载视频显示区域,建议设置黑色背景。其子节点 RawImage 用于显示视频画面。示例工程中,UIController 会根据视频分辨率和显示区域大小自动调整 RawImage 尺寸,使画面按比例显示,避免拉伸变形。
PlayerManager 在 Awake() 中完成 SDK 初始化,并在 Update() 中驱动播放器刷新;UIController 在 Start() 中完成 Material 实例化、按钮事件绑定、默认 URL 设置和显示区域初始化。
7. Inspector 接线说明
完成场景搭建后,需要在 UIController 的 Inspector 中配置以下字段:
| 字段 | 赋值对象 |
|---|---|
| Render View | 场景中的 RawImage |
| Video Area RT | VideoArea 的 RectTransform |
| Status Text | StatusText 的 Text 组件 |
| Url Input | InputField_Url |
| Btn Decoder | 软硬解码切换按钮 |
| Btn Mute | 静音/取消静音按钮 |
| Btn Play | 开始/停止播放按钮 |
| Btn Record | 开始/停止录像按钮 |
| Mat I420 | I420 对应 Material |
| Mat NV21 | NV21 对应 Material |
| Mat NV12 | NV12 对应 Material |
| Default Url | 默认 RTSP/RTMP 播放地址 |
| Record Directory | 录像目录,留空则使用默认目录 |
PlayerManager 上的 PlayerConfig 可直接在 Inspector 中调整播放参数,包括解码模式、缓冲时长、RTSP 传输策略、音频设置、低延迟模式、旋转角度和录像文件大小等。PlayerConfig 已将常用配置项通过可视化字段暴露,便于调试和项目集成。
8. 播放参数配置
PlayerConfig 是播放器参数配置入口,建议开发者优先通过 Inspector 调整。主要参数如下:
| 参数 | 说明 |
|---|---|
enableHardwareDecoder |
是否启用硬件解码 |
bufferTimeMs |
播放缓冲时长,0 表示最低延迟 |
rtspUseTcp |
是否强制 RTSP TCP 模式 |
rtspTimeoutSec |
RTSP 连接超时时间 |
rtspAutoSwitchTcpUdp |
UDP 连接失败后是否自动切换 TCP |
mute |
默认是否静音 |
volume |
默认音量,范围 0--100 |
useAudioTrack |
是否使用 AudioTrack 输出 |
fastStartup |
是否启用快速首帧 |
lowLatencyMode |
是否启用低延迟模式 |
rotateDegrees |
视频旋转角度 |
recMaxFileSizeMB |
单个录像文件最大体积 |
对于低延迟场景,可以将 bufferTimeMs 设置得较低,并结合 fastStartup、lowLatencyMode、RTSP TCP/UDP 策略进行测试。需要注意的是,低延迟和抗网络抖动之间通常存在平衡关系。缓冲越低,延迟越小,但在网络波动较大的情况下,卡顿或丢帧概率可能增加。因此,建议结合实际视频源、码率、网络环境和目标设备进行综合调优。
cs
using System;
using UnityEngine;
[Serializable]
public class PlayerConfig
{
[Header("解码")]
[Tooltip("启用硬件解码(H264/H265);不支持时 SDK 自动回退到软解")]
public bool enableHardwareDecoder = false;
[Header("缓冲")]
[Tooltip("播放缓冲时长(毫秒);0 = 不缓冲(最低延迟)")]
[Range(0, 8000)]
public int bufferTimeMs = 0;
[Header("RTSP 传输")]
[Tooltip("true = 强制 TCP;false = 优先 UDP")]
public bool rtspUseTcp = false;
[Tooltip("连接超时(秒)")]
[Range(1, 30)]
public int rtspTimeoutSec = 10;
[Tooltip("UDP 连接失败后自动切换为 TCP")]
public bool rtspAutoSwitchTcpUdp = true;
[Header("音频")]
public bool mute = false;
[Range(0, 100)]
public int volume = 100;
[Tooltip("true = AudioTrack 模式;false = 自动选择")]
public bool useAudioTrack = true;
[Header("播放行为")]
[Tooltip("快速首帧(减少起播黑屏)")]
public bool fastStartup = true;
[Tooltip("超低延迟模式(会增加丢帧概率)")]
public bool lowLatencyMode = false;
[Tooltip("画面顺时针旋转角度:0 / 90 / 180 / 270")]
[Range(0, 270)]
public int rotateDegrees = 0;
[Header("录像")]
[Tooltip("单个录像文件最大体积(MB)")]
public int recMaxFileSizeMB = 500;
}
9. RTSP/RTMP 播放流程
在示例工程中,播放流程已经封装到 UI 和播放器管理逻辑中。开发者在输入框中填入 RTSP 或 RTMP 地址后,点击播放按钮即可启动播放。

业务流程如下:
输入 RTSP/RTMP 地址
→ 点击开始播放
→ 创建播放器实例
→ 应用播放配置
→ 绑定 RawImage 显示目标
→ 启动播放
→ Unity 主线程刷新视频画面
当前工程中,UIController.OnPlayClicked() 会根据当前状态决定开始播放或停止播放。开始播放时,会获取或创建播放器实例,绑定 RawImage 和 Material,然后启动播放;停止播放时,会停止播放并清理画面,如果当前没有录像任务,则释放播放器实例。
cs
public void StartPlay()
{
if (!wrapper_.StartPlay()) return;
need_get_frame_ = true;
need_init_texture_ = true;
StatusText = "连接中...";
}
public void StopPlay()
{
if (!is_playing) return;
wrapper_.StopPlay();
need_get_frame_ = false;
need_init_texture_ = false;
VideoWidth = 0;
VideoHeight = 0;
downloadSpeedBps_ = -1;
flrHundredths_ = -1;
lrHundredths_ = -1;
bufferStatus_ = 0;
bufferPercent_ = 0;
connectionStatus_ = 0;
StatusText = "";
}
播放前需要确保 RawImage 和 Material 已正确配置。示例工程通过 SetRenderTarget() 将 RawImage 和三类 Material 绑定到播放器实例中,保证播放器启动后可以将视频画面显示到 Unity UI 中。
10. 视频画面显示说明
播放器采用 Unity 主线程刷新画面的方式。SDK 负责准备解码后的视频帧,Unity 侧在主线程中刷新并显示到 RawImage。该方式符合 Unity 的渲染机制,便于与 Unity UI 和场景显示逻辑结合。
开发者在集成时主要关注以下几点:
- RawImage 是最终视频显示控件;
- Material 和 Shader 用于不同视频格式的显示适配;
- 播放器会根据实际视频格式选择对应显示材质;
- 分辨率变化后,UI 层会自动调整 RawImage 尺寸;
- 建议直接使用 SDK 示例工程提供的 Material 和 Shader。
示例工程中,播放器实例负责视频画面刷新,UI 层负责根据显示区域和视频分辨率做等比适配。收到分辨率信息后,UIController 会记录视频宽高,并在后续显示刷新中调整 RawImage 的尺寸。
11. 事件回调与状态显示
SDK 会向 Unity 层回调播放状态、连接状态、分辨率信息、缓冲状态、下载速度、录像文件生成等事件。业务层可根据这些事件更新 UI 状态、提示网络质量、展示当前分辨率或处理录像文件路径。

常见事件类型包括:
连接中 / 已连接 / 连接失败 / 断开
分辨率变化
长时间无媒体数据
RTSP 状态码提示
缓冲开始 / 缓冲中 / 缓冲结束
下载速度
快照结果
录像文件生成 / 录像文件完成
事件由 SDK 发送到 PlayerManager,再由播放器实例进行处理。示例工程中,PlayerManager.onNTSmartEvent() 是事件入口,播放器实例会根据事件更新连接状态、缓冲状态、下载速度、录像状态和分辨率信息,最终形成状态文本供 UI 展示。
12. 下载速度与网络状态提示
播放器支持下载速度上报,可用于辅助判断网络质量。示例工程会在状态文本中展示当前速度信息,并结合缓冲状态反馈播放体验。
cs
public static class NTPlayerEvent
{
private const int PLAYER_SDK = 0x01000000; // EVENT_DANIULIVE_PLAYER_SDK
// ── 连接 / 播放状态 ───────────────────────────────────────────────────
/// <summary>开始播放(SDK 内部状态机已启动)</summary>
public const int STARTED = PLAYER_SDK | 0x1;
/// <summary>连接中</summary>
public const int CONNECTING = PLAYER_SDK | 0x2;
/// <summary>连接失败</summary>
public const int CONNECTION_FAILED = PLAYER_SDK | 0x3;
/// <summary>已连接</summary>
public const int CONNECTED = PLAYER_SDK | 0x4;
/// <summary>断开连接</summary>
public const int DISCONNECTED = PLAYER_SDK | 0x5;
/// <summary>停止播放</summary>
public const int STOP = PLAYER_SDK | 0x6;
// ── 媒体信息 ──────────────────────────────────────────────────────────
/// <summary>视频解码分辨率。p1=width, p2=height</summary>
public const int RESOLUTION_INFO = PLAYER_SDK | 0x7;
/// <summary>收不到媒体数据(检查 URL 或网络)</summary>
public const int NO_MEDIADATA = PLAYER_SDK | 0x8;
/// <summary>切换 URL 中</summary>
public const int SWITCH_URL = PLAYER_SDK | 0x9;
/// <summary>截取快照结果。p1=0 成功,非 0 失败</summary>
public const int CAPTURE_IMAGE = PLAYER_SDK | 0xA;
/// <summary>RTSP 状态码上报(目前只上报 401)。p1=status code</summary>
public const int RTSP_STATUS_CODE = PLAYER_SDK | 0xB;
// ── 录像 ──────────────────────────────────────────────────────────────
/// <summary>录像写入新文件。p3=新文件完整路径</summary>
public const int RECORDER_NEW_FILE = PLAYER_SDK | 0x21;
/// <summary>一个录像文件写入完成。p3=已完成文件完整路径</summary>
public const int RECORDER_FILE_DONE = PLAYER_SDK | 0x22;
// ── 缓冲 ──────────────────────────────────────────────────────────────
/// <summary>开始缓冲</summary>
public const int START_BUFFERING = PLAYER_SDK | 0x81;
/// <summary>缓冲中。p1=百分比进度(0--100)</summary>
public const int BUFFERING = PLAYER_SDK | 0x82;
/// <summary>缓冲结束,恢复正常播放</summary>
public const int STOP_BUFFERING = PLAYER_SDK | 0x83;
// ── 下载速度 ──────────────────────────────────────────────────────────
/// <summary>
/// 下载速度上报。p1=速度(Byte/s)。
/// p2 bit 编码:
/// bit31=1 → 高 15 位为前向丢包率 FLR(Q8.8 定点,÷256 得实际比例)
/// bit15=1 → 低 15 位为综合丢包率 LR (Q8.8 定点,÷256 得实际比例)
/// </summary>
public const int DOWNLOAD_SPEED = PLAYER_SDK | 0x91;
}
当用户反馈"播放卡顿""延迟高""画面不连续"时,可优先检查以下内容:
- 当前是否已连接;
- 是否频繁进入缓冲;
- 下载速度是否低于视频实际码率;
- 视频分辨率和码率是否过高;
- RTSP 使用 TCP 还是 UDP;
- 当前网络是否存在明显抖动;
- 目标设备解码性能是否满足要求。
示例工程中已经包含下载速度事件和缓冲事件的状态处理逻辑,业务侧可根据项目需要决定是否在 UI 中展示。
13. 录像能力说明
播放器支持播放过程中启动本地录像,适用于安防留痕、巡检归档、远程会诊记录、问题复盘等场景。录像目录可在 Inspector 中配置;如果未配置,可使用应用私有目录下的默认路径。

业务流程如下:
点击开始录像
→ 确定录像目录
→ 启动录像
→ SDK 写入录像文件
→ 回调新文件路径或文件完成事件
→ 业务侧展示、上传或归档
当前工程中,录像和播放可以共享同一个播放器实例。点击录像按钮时,如果播放器实例不存在,会先创建播放器实例再启动录像;停止录像时,如果当前没有播放任务,可以释放播放器资源。
cs
// ── 录像控制 ──────────────────────────────────────────────────────────────
public void StartRecorder(string directory)
{
int maxMB = PlayerManager.Instance?.config?.recMaxFileSizeMB ?? 500;
if (!wrapper_.StartRecorder(directory, maxMB))
Debug.LogError("[PlayerInstance] StartRecorder failed");
}
public void StopRecorder()
{
wrapper_.StopRecorder();
}
录像过程中,SDK 会通过事件回调通知新文件生成和文件完成,业务侧可以根据回调路径进行文件展示、上传、归档或后续处理。
14. 软硬解码与低延迟建议
示例工程提供软硬解码切换能力。硬解码通常 CPU 占用更低,适合分辨率较高或设备性能有限的场景;软解码兼容性相对更稳,适合调试阶段或设备差异较大的项目。首次集成时,建议先使用软解码验证播放链路,确认播放地址、网络连通性和场景接线均正常后,再切换硬解码进行性能测试。
示例工程中,软硬解码按钮用于切换当前解码模式,并在播放或录像运行中禁用,避免运行过程中切换关键解码参数。静音按钮则支持播放中实时切换。
低延迟调优可重点关注以下参数:
| 调优项 | 建议 |
|---|---|
bufferTimeMs |
越低延迟越小,但抗抖动能力下降 |
fastStartup |
可用于减少起播等待 |
lowLatencyMode |
适合强实时场景 |
rtspUseTcp |
网络复杂时 TCP 更稳 |
rtspAutoSwitchTcpUdp |
建议保留自动切换能力 |
enableHardwareDecoder |
需结合目标设备测试兼容性 |
低延迟播放效果受视频源、编码参数、网络质量、缓冲策略、解码方式和设备性能共同影响。建议在目标场景中进行端到端测试,以获得更符合业务需求的参数组合。
15. Android 打包注意事项
打包 Android 前,建议重点检查以下内容:
Assets/Plugins/Android/下的.so和.jar依赖是否完整;- AndroidManifest 是否包含网络权限;
- 目标 CPU 架构是否与 SDK 库匹配;
- Material 和 Shader 是否正确放入工程并参与打包;
- Scene 中是否存在
PlayerManager对象; UIController的 Inspector 字段是否全部接好;- 默认播放地址是否可访问;
- Android 真机是否与播放源处于可连通网络中;
- 录像目录是否可写;
- 目标设备是否满足播放分辨率和解码性能要求。
建议优先使用真机进行测试。编辑器环境可用于 UI 布局和业务逻辑预览,Android Native SDK 相关能力应以真机测试结果为准。
16. 常见问题
16.1 点击播放后没有画面
建议按以下顺序排查:
- 确认 RTSP/RTMP 地址是否可用;
- 确认 Android 设备与播放源网络是否互通;
- 确认 AndroidManifest 已配置网络权限;
- 确认 RawImage、Material、Shader 已正确接线;
- 查看是否收到连接、分辨率或错误状态事件;
- 尝试切换软解码或 RTSP TCP 模式。
16.2 连接失败
可以先使用 VLC 或其他播放器验证播放地址。如果是 RTSP 流,可尝试启用 TCP 模式,或开启 UDP 失败后自动切 TCP。若播放源需要鉴权,请确认 URL 中的用户名、密码和端口配置正确。
16.3 画面比例异常
示例工程会根据视频分辨率和显示区域自动调整 RawImage 尺寸。请确认 VideoArea 的 RectTransform 设置合理,RawImage 不要额外添加会影响尺寸计算的布局组件。收到分辨率信息后,UI 层会按视频宽高比进行显示适配。
16.4 播放卡顿或延迟较高
可结合缓冲时长、低延迟模式、RTSP TCP/UDP 策略、下载速度和视频码率综合调整。低延迟场景建议减少缓冲,但在网络波动明显时可适当增加缓冲以提升流畅性。
16.5 录像文件找不到
请检查 Inspector 中的录像目录配置。如果留空,通常使用应用私有目录下的默认 Record 路径。可通过录像文件事件查看实际文件路径。
16.6 是否支持播放中切换软硬解码
不建议在播放过程中切换软硬解码。软硬解码属于播放前关键配置,示例工程中播放或录像运行时会禁用解码模式切换按钮。
17. 总结
大牛直播SDK(SmartMediaKit)Android Unity3D RTSP/RTMP 播放器方案,面向需要在 Unity3D 场景中接入实时音视频画面的 Android 应用,提供了低延迟播放、播放状态回调、视频画面适配、本地录像、软硬解码配置、RTSP/RTMP 地址接入等能力。通过示例工程提供的分层封装,开发者可以快速完成 SDK 插件放置、场景搭建、Inspector 接线、播放参数配置和真机运行验证。
在实际项目中,开发者可根据业务需求灵活调整 UI 布局、播放地址、缓冲策略、软硬解码模式、录像目录和状态展示方式。对于安防监控、工业可视化、无人机回传、智慧教室、数字孪生、远程巡检、车载视频、AR/VR 可视化等场景,该方案能够帮助开发者在 Unity3D 中快速构建稳定、低延迟、易集成的 RTSP/RTMP 实时视频播放能力。
大牛直播SDK将持续围绕跨平台低延迟播放、实时音视频采集、推流、录像、轻量级服务、GB28181 接入等方向完善产品能力,为企业级实时音视频应用提供稳定可靠的底层技术支撑。
📎 CSDN官方博客:音视频牛哥-CSDN博客