当前位置: 首页 > news >正文

大牛直播SDK(SmartMediaKit)Android Unity3D 播放器集成文档

目标平台:Android(API 21+)
支持协议:RTSP、RTMP


目录

  1. 概述
  2. 环境要求
  3. 工程文件说明
  4. 快速集成步骤
  5. PlayerConfig 配置说明
  6. 核心 API 说明
  7. 事件回调说明
  8. 录像功能
  9. 视频渲染原理

1. 概述

本文档描述如何在 Android Unity3D 工程中集成大牛直播 SDK,实现 RTSP / RTMP 直播流的拉取、渲染与本地录像功能。

架构总览

帧渲染模型(PULL)

SDK 不主动推送帧数据,而是由 Unity 主线程每帧主动调用GetVideoFrame()拉取,避免跨线程写纹理的问题:

2. 环境要求

项目要求
Unity2019.4.13f1 或更高
Android API最低 21(Android 5.0),推荐 26+
构建工具IL2CPP 或 Mono 均可
权限INTERNETWRITE_EXTERNAL_STORAGE(录像)、READ_EXTERNAL_STORAGE

AndroidManifest.xml 权限

<uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28"/><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"android:maxSdkVersion="32"/>

Android 10+ 录像路径建议使用Application.persistentDataPath,无需存储权限。


3. 工程文件说明

各文件职责

文件职责是否需要修改
NTSmartPlayerAPI.csJNI 接口定义,1:1 对应 Java 层❌ 通常不改
NTPlayerEvent.cs事件 ID 常量,对应NTSmartEventID.java❌ 不改
NTPlayerWrapper.cs句柄管理、状态机、配置下发⚠️ 如需扩展参数可改
PlayerConfig.cs序列化配置字段,Inspector 可调✅ 按需扩展
PlayerInstance.cs事件处理、YUV 渲染、状态文本✅ 按需扩展
PlayerManager.cs场景入口,SDK 初始化⚠️ 一般不改
UIController.cs业务 UI 逻辑✅ 按需修改

4. 快速集成步骤

Step 1 — 拷贝 SDK 文件

将大牛直播提供的以下文件放入工程对应目录:

Step 2 — 拷贝 C# 脚本

将本工程Assets/目录下的所有.cs文件拷贝到目标工程。

Step 3 — 配置 Player Settings

Edit → Project Settings → Player → Android:

设置项推荐值
Minimum API LevelAndroid 5.0 (API 21)
Scripting BackendIL2CPP(发布)/ Mono(调试)
Target ArchitectureARM64(必选)、ARMv7(可选)
Internet AccessRequired
Write PermissionExternal (SDCard)(如需 sdcard 录像)

Step 4 — 搭建场景 | 接线 Inspector

Step 5 — 授权 SDK

PlayerManager.Awake()初始化后调用:

NTSmartPlayerAPI.NT_U3D_SetSDKClientKey("your_cid","your_key",0);

或在PlayerConfig扩展字段统一管理。


Step 6. PlayerConfig 配置说明

PlayerManagerGameObject 上通过 Inspector 配置,也可在代码中访问PlayerManager.Instance.config

[Serializable]publicclassPlayerConfig{// ── 解码 ──────────────────────────────────────────────────────────────publicboolenableHardwareDecoder=false;// false = 软解(兼容性好);true = 硬解(性能好,需设备支持)// 运行中不可切换,需停止播放后修改再重新开始// ── 缓冲 ──────────────────────────────────────────────────────────────[Range(0,8000)]publicintbufferTimeMs=0;// 0 = 最低延迟模式;建议直播设 0,点播/不稳定网络设 500~2000// ── RTSP 传输 ──────────────────────────────────────────────────────────publicboolrtspUseTcp=false;// false = 优先 UDP,丢包时考虑改 true[Range(1,30)]publicintrtspTimeoutSec=10;// 连接超时(秒)publicboolrtspAutoSwitchTcpUdp=true;// UDP 失败自动切 TCP// ── 音频 ──────────────────────────────────────────────────────────────publicboolmute=false;[Range(0,100)]publicintvolume=100;publicbooluseAudioTrack=true;// true = AudioTrack 模式(推荐)// ── 播放行为 ──────────────────────────────────────────────────────────publicboolfastStartup=true;// 减少起播黑屏时间publicboollowLatencyMode=false;// 超低延迟,会增加丢帧概率[Range(0,270)]publicintrotateDegrees=0;// 顺时针旋转:0/90/180/270// ── 录像 ──────────────────────────────────────────────────────────────publicintrecMaxFileSizeMB=500;// 单个录像文件最大体积(MB),超过后自动切片}

6. 核心 API 说明

6.1 播放控制(通过 UIController 或直接调用)

// 创建播放器实例(内部调用 NT_U3D_Open + ApplyConfig)PlayerInstanceplayer=PlayerManager.Instance.CreatePlayer("rtsp://...");// 绑定渲染目标(必须在 StartPlay 前调用)player.SetRenderTarget(rawImage,matI420,matNV21,matNV12);// 开始播放player.StartPlay();// 停止播放player.StopPlay();// 销毁播放器(Close 句柄 + 释放纹理)PlayerManager.Instance.DestroyPlayer();

6.2 实时控制(播放中随时可调)

// 静音 / 取消静音player.SetMuteRealtime(true);// 调节音量(0–100)player.SetVolumeRealtime(80);

6.3 录像控制

// 开始录像(目录路径,SDK 自动创建)player.StartRecorder("/sdcard/daniulive/Record");// 或使用 persistentDataPath(Android 10+ 推荐,无需权限)player.StartRecorder(Application.persistentDataPath+"/Record");// 停止录像player.StopRecorder();// 查询状态boolisRecording=player.is_recording;

6.4 状态查询

boolisPlaying=player.is_playing;boolisRecording=player.is_recording;longhandle=player.handle;// 0 = 未初始化intwidth=player.VideoWidth;intheight=player.VideoHeight;stringstatus=player.StatusText;// 格式化状态文本,直接显示给用户

7. 事件回调说明

事件由 SDK 通过UnitySendMessage发到PlayerManager.onNTSmartEvent,再分发到PlayerInstance.HandleEvent()

消息格式(逗号分隔):

handle,code,param1,param2,param3,param4

所有事件 ID 定义在NTPlayerEvent.cs,与 Android SDK 的NTSmartEventID.java完全对应。

事件列表

常量说明参数
STARTED0x1000001SDK 内部状态机已启动
CONNECTING0x1000002连接中
CONNECTION_FAILED0x1000003连接失败
CONNECTED0x1000004已连接,即将收到视频
DISCONNECTED0x1000005连接断开
STOP0x1000006SDK 内部停止(如断流)
RESOLUTION_INFO0x1000007视频分辨率p1=width, p2=height
NO_MEDIADATA0x1000008长时间收不到媒体数据
SWITCH_URL0x1000009正在切换 URL
CAPTURE_IMAGE0x100000A快照结果p1=0 成功,非0 失败
RTSP_STATUS_CODE0x100000BRTSP 状态码上报p1=状态码(如 401)
RECORDER_NEW_FILE0x1000021录像开始写入新文件p3=完整文件路径
RECORDER_FILE_DONE0x1000022一个录像文件写完p3=完整文件路径
START_BUFFERING0x1000081开始缓冲
BUFFERING0x1000082缓冲中p1=进度百分比(0–100)
STOP_BUFFERING0x1000083缓冲结束,恢复播放
DOWNLOAD_SPEED0x1000091下载速度上报见下方说明

DOWNLOAD_SPEED 参数解析

p1 = 下载速度(Byte/s) p2 = 丢包率编码(long): bit31=1 → 高 15 位为前向丢包率 FLR(Q8.8 定点,÷256 得比例) bit15=1 → 低 15 位为综合丢包率 LR(Q8.8 定点,÷256 得比例)

示例解析(已在PlayerInstance.HandleEvent中实现):

// 转换为百分比floatflr=((loss>>16)&0x7FFF)/256.0f*100f;// 前向丢包率 %floatlr=(loss&0x7FFF)/256.0f*100f;// 综合丢包率 %

8. 录像功能

录像流程

StartRecorder(dir) ├─ NT_U3D_CreateFileDirectory(dir) ← 创建目录 ├─ NT_U3D_SetRecorderDirectory(handle, dir) ├─ NT_U3D_SetRecorderFileMaxSize(handle, MB) ├─ NT_U3D_SetRecorderAudioTranscodeAAC(handle, 1) ← 音频转 AAC(重要) └─ NT_U3D_StartRecorder(handle) └─ 触发 RECORDER_NEW_FILE 事件(p3 = 文件路径)

录像与播放的关系

  • 录像和播放共享同一个 SDK 句柄,可以同时进行
  • 单独录像(不播放):理论上支持,但建议同时启动播放保证视频数据正常拉取
  • 停止播放时,若录像仍在进行,录像不会中断

文件切片

recMaxFileSizeMB(默认 500MB)达到后 SDK 自动切片:

  • 触发RECORDER_FILE_DONE(旧文件写完)
  • 触发RECORDER_NEW_FILE(新文件开始)

录像路径建议

// Android 10+ 推荐,无需存储权限stringdir=Path.Combine(Application.persistentDataPath,"Record");// 对应路径:/data/data/<包名>/files/Record 或// /sdcard/Android/data/<包名>/files/Record(外部存储)// 旧版 Android(≤9)可用 sdcard 路径,需权限stringdir="/sdcard/daniulive/Record";

9. 视频渲染原理

帧格式

常量格式使用场景
FORMAT_I4203YUV 4:2:0 Planar软解默认输出
FORMAT_NV214YUV 4:2:0 Semi-Planar(VU 交错)硬解常见
FORMAT_NV125YUV 4:2:0 Semi-Planar(UV 交错)硬解常见

纹理结构

I420(三平面):

yTex_: Texture2D(stride0, height, Alpha8) ← Y 分量 uTex_: Texture2D(stride1, height/2, Alpha8) ← U 分量 vTex_: Texture2D(stride2, height/2, Alpha8) ← V 分量

NV21 / NV12(双平面):

yTex_: Texture2D(stride0, height, Alpha8) ← Y 分量 uTex_: Texture2D(width/2, height/2, RG16) ← UV 交错分量

Shader 属性

Shader 通过以下属性名接收纹理:

_NT_SDK_Y ← Y 纹理 _NT_SDK_U ← U(或 UV)纹理 _NT_SDK_V ← V 纹理(仅 I420 格式使用)

注意:Shader 和 Material 由大牛直播 SDK 提供,不要修改。


附录 A:事件回调格式参考

SDK 通过UnitySendMessage发出的原始消息格式:

"handle,code,param1,param2,param3,param4"

PlayerManager.onNTSmartEvent()中解析:

string[]parts=msg.Split(',');// parts[0] = handle(long,多播放器时用于路由)// parts[1] = code(int,事件 ID)// parts[2] = param1// parts[3] = param2// parts[4] = param3(录像事件中为文件路径)// parts[5] = param4(目前未使用)

附录 B:调用时序图

播放时序

UIController.OnPlayClicked() → PlayerManager.CreatePlayer(url) → PlayerInstance.Open(url, config, goName) → NTPlayerWrapper.Open() → NT_U3D_Open() ← 获取句柄 → NT_U3D_Set_Game_Object() ← 注册事件接收对象 → ApplyConfig() ← 一次性下发所有参数 → PlayerInstance.SetRenderTarget(...) ← 绑定渲染目标 → PlayerInstance.StartPlay() → NTPlayerWrapper.StartPlay() → NT_U3D_StartPlay() ← 开始拉流 每帧: PlayerManager.Update() → PlayerInstance.UpdateFrame() → NT_U3D_GetVideoFrame() ← 拉帧 → UploadTextures() ← 上传 YUV 纹理 事件: SDK → UnitySendMessage("PlayerManager", "onNTSmartEvent", msg) → PlayerInstance.HandleEvent(code, p1, p2, p3)

停止时序

UIController.OnPlayClicked()(再次点击) → PlayerInstance.StopPlay() → NTPlayerWrapper.StopPlay() → NT_U3D_StopPlay() → UIController.ClearRenderView() → 若 !is_recording → PlayerManager.DestroyPlayer() → PlayerInstance.Close() → NTPlayerWrapper.Close() → NT_U3D_StopPlay() (幂等,已停则跳过) → NT_U3D_StopRecorder() (幂等) → NT_U3D_Close() → DisposeTextures()

📎 CSDN官方博客:音视频牛哥-CSDN博客

http://www.jsqmd.com/news/860585/

相关文章:

  • Redis常用命令
  • 华为云云容器引擎CCE 2026-Q1优化升级,全面进化您的云原生体验!
  • ElevenLabs丹麦文语音合规性警报:GDPR+丹麦数据保护局2024新规下,语音缓存、日志与语音指纹处理的7项强制操作
  • 亲测新加坡家具物流优质公司分享
  • 编写跨部门沟通协作效率监测程序,统计沟通频次耗时,优化职场协作工作流程。
  • 如何学习Three.js
  • 【Qt】界面优化(三)盒子模型的介绍和使用,给按钮,复选框,单行输入框设置样式
  • [深度洞察]2026年制造业竞争情报智能化监控的核心发展趋势是什么?详解企业级全链路自动化闭环方案
  • 从“卖算力”到“卖Token”:换的不是“秤”,是“货”!
  • 论文降重卡关?Paperxie 用「双 buff 叠加」,把查重和 AIGC 率一起打通关
  • 2026年企业整合营销预算10-100万,哪五家整合营销公司值得选型? - GEO优化
  • 【ElevenLabs粤语语音实战指南】:20年AI语音工程师亲测的5大落地陷阱与3步合规接入法
  • Access to system table ‘mysql.innodb_index_stats‘ is rejected.
  • 终极指南:3分钟掌握HTML到Word完美转换,html-to-docx让你的文档格式零损失
  • OpenClaw.NET 兼容性目录指南(Compatibility Catalog)
  • AI 智能体开发平台及特点
  • Linux 文件 IO:缓冲区、重定向与一切皆文件
  • 小红书营销不止于种草!2026年五大小红书营销公司综合能力白皮书暨推荐榜单 - GEO优化
  • 安全IP哪家强|2026 五大主流厂商深度测评与选型指南
  • wingetAn unexpected error occurred while executing the command: 0x8a15005e解决方法
  • 观察不同时段调用taotoken聚合接口的响应速度差异
  • 洛谷-【图论2-3】最小生成树1
  • 山东大学软件学院项目实训个人进展6
  • 2026 年海南进出口公司注册代办哪家强?全岛服务商排行榜权威发布 - GrowthUME
  • * LangChain4j中的流式调用
  • 《2026浦东5家初高中学科辅导机构横向测评:我帮你把坑踩完了》 - GrowthUME
  • AI编程工具 Codex 入门教程,带你7分钟上手 Codex !
  • Cert-Manager 安装与配置文档
  • 2026年福州汽车贴膜合规资质权威测评:4家主流门店横向对比,附避坑指南与选型推荐 - GrowthUME
  • 巨亏47亿,市值5000亿:拆解智谱AI的定价逻辑