产品
热门产品
存储与大数据
人工智能
SaaS集成
基础PaaS
研发运维
企业应用
专有部署
热门产品
图像技术 IA
面向图片场景提供的多种人工智能技术
视频直播 LIVE
大规模实时转码、低延时的直播服务
存储与大数据
存储服务
对象存储 OBS
稳定、安全、可靠的云存储服务
人工智能
AI开发平台
AI零代码平台
AI能力定制平台
视觉分析
视图计算 VEC
云边融合 AI赋能的智能视图计算
内容审核
内容审核 CM
图片审核|文本审核|音频审核|视频审核
人脸与人体识别
人脸人体识别 FHR
人脸识别|人体识别|人脸比对|摔倒检测
OCR识别
OCR识别 OCR
卡证识别|通用文本识别|车牌识别
图像技术
图像技术 IA
面向图片场景提供的多种人工智能技术
AI市场
模型市场 MaaS
图片、音频、视频等多场景的算法模型
SaaS集成
基础组件
APIcloud
API文档、调试、MOCK一体化协作平台
统一身份认证平台
统一的身份认证、授权管理
基础PaaS
视频应用
视频直播 LIVE
大规模实时转码、低延时的直播服务
视频点播 VOD
视频流畅播放服务
音视频通话 RTC
便捷的跨平台实时音视频互动直播服务
媒体处理 MPC
简洁的云媒体转码及内容合成处理服务
视频工具
视频工具 SDK
视频剪辑SDK | 播放SDK
物联网平台
帝视物联网视频 SDK
低延时、海量存储的物联网视频监控服务
企业物联网平台
设备管理|设备接入|规则引擎|应用开发
生活物联网平台
针对消费级智能设备的物联网平台
边缘计算
边云协同操作系统
网络与CDN
内容分发网络 CDN
安全、稳定、低延时的分发加速服务
P2P内容分发网络 PCDN
利用闲置资源而构建的低成本高品质CDN
应用开发
云短信 SMS
融合三网,安全可信的短信服务
支付 360PAY
一站式支付解决方案
消息推送 360PUSH
高效、精确、实时的消息推送
研发运维
研发效能
兼容性测试
提供数百款TOP机型的云测服务
真机租用
远程真机租用,流畅体验如手机在手
ios预审
智能扫描、分析、筛查ios审核的被拒风险点
企业应用
视频应用
幕印企业学堂
企业培训|内容付费|知识营销
易讲教室直播
视频技术与传统教室融合
企业工具
亿方云企业网盘
在线编辑、文件管理、知识管理
电子签章
无纸办公,远程签署各种电子合同
安全应用
SSL证书
一站式的 HTTPS 解决方案
三六零天御加固保
提供安全可靠的加固防护产品及服务
专有部署
云计算
360Stack云计算管理平台
规划、建设、运维一体的云计算解决方案
大数据
奇麟大数据
企业级一站式大数据平台
容器服务
360容器管理平台
可对外私有化的容器云平台
AI开发平台
360AI开发平台 专有版
全流程机器学习开发平台
更多产品,敬请期待
解决方案
产品解决方案
行业解决方案
产品解决方案
视频
通用直播解决方案
短视频解决方案
公共语音房聊天室解决方案
物联网
儿童手表音视频通话
云端NVR解决方案
数据上云
通用存储解决方案
IoT设备
AI+IPC解决方案
智能门锁解决方案
安防传感解决方案
智能网关解决方案
个护健康解决方案
账号体系
360用户帐号体系解决方案
行业解决方案
智慧城市
智慧社区解决方案
智慧交通解决方案
电商视频解决方案
电商视频解决方案
电商平台收款解决方案
教育
在线教育解决方案
互动课堂解决方案
全屋智能
智慧公寓解决方案
智慧酒店解决方案
家庭智能解决方案
智慧安防解决方案
医疗
健康看护解决方案
智能制造
工业物联网解决方案
游戏
游戏音视频解决方案
更多解决方案,敬请期待
帮助支持
技术社区
关于我们
控制台
登录
注册
SDK管理
云直播
产品文档
常见问题
API文档
云点播
产品文档
快速入门
API文档
CDN
产品文档
API文档
云存储
产品文档
SDK手册
API文档
互动直播
产品文档
API文档
操作指南
SDK管理
播放SDK
上传SDK
剪辑SDK
媒体处理
产品文档
API文档
帝视
产品文档
API文档
操作指南
支付平台
产品列表
产品文档
渠道接入解析
内容审核
产品文档
API文档
OCR识别
产品文档
API文档
人脸与人体识别
产品文档
API文档
SSL证书
产品说明
购买指南
电子签章
产品介绍
接入流程
云短信
接口文档
物联网平台
产品简介
快速入门
幕印企业学堂
产品介绍
生活物联网平台
产品简介
快速入门
图片处理
产品介绍
接口文档
视图计算
产品介绍
快速入门
常见问题
易讲-教室直播
产品介绍
帮助说明
Android互动直播
版本说明
Windows互动直播
开发文档
版本说明
iOS互动直播
Android推流
开发文档
版本说明
iOS推流
iOS推流SDK开发文档
Android上传SDK
Android上传SDK接入文档
Android上传SDK版本说明
IOS上传SDK
iOS上传sdk开发文档
IOS上传SDK版本说明
Net SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
IoT SDK
iOS
开发文档
版本说明
VCloudPlayer
Android
开发文档
版本说明
Web
开发文档
版本说明
固件端
开发文档
WEB播放SDK
WEB播放器介绍
跨域请求媒体源失败
QHWW-Player
拍摄SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
剪辑SDK
iOS
版本说明
开发文档
Android
开发文档
版本说明
投屏SDK
iOS
开发文档
Android
开发文档
播放SDK
iOS
开发文档
版本说明
Android
开发文档
版本说明
Web 上传SDK
首页
>
开发者中心
>
SDK管理
>
IoT SDK
>
iOS
>
开发文档
# 帝视SDK(iOS)接入文档 本文介绍如何使用帝视SDK快速实现安防监控功能。 帝视SDK提供了观看实时音视频、观看回放、实时通话、上传云存、数据加密等功能,用户通过网络可以远程观看摄像头的流并进行相关操作。 ##### 版本号:2.7.0.20060901 ## Demo体验 360智汇云云平台提供帝视SDK接入Demo源码,下载地址:https://zyun.360.cn/ ## 前提条件 - Xcode 11.0或以上版本 - 支持iOS 10.0或以上版本的iOS设备 - 有效的智汇云账户([免费注册](https://zyun.360.cn/)) ## 准备开发环境 本节介绍如何创建项目,并将帝视相关SDK集成至你的项目中。 #### 创建iOS项目 - 打开 Xcode 并点击 Create a new Xcode project。 - 选择项目类型为 Single View App,并点击 Next。 - 输入项目信息,如项目名称、开发团队信息、组织名称和语言,并点击 Next。 > Note:如果你没有添加过开发团队信息,会看到 Add account… 按钮。点击该按钮并按照屏幕提示登入 Apple ID,完成后即可选择你的账户作为开发团队。 - 选择项目存储路径,并点击 Create。 - 将你的 iOS 设备连接至电脑。 - 进入 TARGETS > Project Name > General > Signing 菜单,选择 Automatically manage signing,并在弹出菜单中点击 Enable Automatic。  #### 集成 SDK - 用户可以前往 [SDK下载](https://zyun.360.cn/developer)页面,获取最新版的SDK,然后解压。也可以使用Demo中libs文件夹中的SDK拷贝到用户的工程目录下。需要拷贝的文件清单如下: - QHVCCommonKit.framework - QHVCNetKit.framework - QHVCPlayerKit.framework - QHVCRTCKit.framework - webRTC.framework - QSLMQTTSDK.framework - 打开 Xcode,进入 TARGETS > Project Name > Build Phases > Link Binary with Libraries 菜单,点击 + ,在弹出菜单点击“Add Other...”添加如下库。 - QHVCCommonKit.framework - QHVCNetKit.framework - QHVCPlayerKit.framework - QHVCRTCKit.framework - webRTC.framework - QSLMQTTSDK.framework - libc++.tbd - libz.tbd - libsqlite3.0.tbd ###### 添加前:  ###### 添加后:  需要把如下几个库设置为动态库:  ## 实现监控项目 本节介绍如何实现监控项目。 > ==注意:文档中的代码示例是基于Demo编写,具体代码实现请参考相关代码。== ### 1.初始化启动函数 - 导入头文件 ``` #import <QHVCCommonKit/QHVCCommonKit.h> ``` - 在初始化启动函数后的两分钟内调用视频云鉴权服务,视频云会鉴定客户使用SDK的合法性,如果不调用,中途SDK将会停止服务;鉴权算法见代码,签名密钥建议保存在业务服务器,签名由业务服务器下发来保证密钥的安全性。 ``` - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self notifyAppStart]; return YES; } - (void)notifyAppStart { QHVCGlobalConfig* globalConfig = [QHVCGlobalConfig sharedInstance]; [QHVCCommonCoreEntry coreOnAppStart:globalConfig.appId appVer:globalConfig.appVersion deviceId:globalConfig.deviceId model:globalConfig.model optionalParams:nil]; } ``` ### 2.用户系统 用户属于业务方,SDK不管理用户关系,业务方需要管理用户关系以及用户的设备列表。帝视服务端在给用户提供服务时,需要业务提供鉴别该用户身份合法性的token;如果需要加密传输,业务还需要提供相关的密钥,具体密钥算法后面部分详细介绍。 ### 3. 函数调用流程 #### 3.1 SDK接口调用函数主要流程  图中黄色背景部分是SDK注册实现的函数回调,包括错误回调、Token验证结果回调、回放时间结果回调、更新当前回放播放时间进度回调、回放暂停回调、回放恢复回调、回放播放完毕回调、回放seek完毕回调、回放倍速播放回调、日志信息监控回调、callback模式回调数据给播放器、信令消息收发回调。 功能模块简单解释如下: - 观看直播:拉取固件端实时音视频数据通过网络传输在本地进行播放。 - 观看回放:从固件端拉取指定时间点开始的音视频数据通过网络传输到本地进行播放,支持seek操作、倍速播放等。 - 实时RTC通话:可与固件端进行实时通话,支持一对一RTC通话,如果硬件设备支持,也可支持多人音视频通话,两种通话的技术接入方案不一样。 - 观看云存:用户如果选择把回放数据存放在云端,可以从云端拉取回放数据到本地播放。 - 文件下载:支持从指定设备上下载已经存在的图片、短视频资源。 - 信令通道:SDK在工作的过程中,与固件端需要频繁的交互信息,SDK提供两种信令通道的选择,即:外部业务长连或者SDK内部长连,默认值为SDK内部长连,如果需要使用业务自己的信令通道,需要在启动服务时显示设置。 - 数据加密:为了保证数据传输的过程中安全,SDK支持对音视频数据进行加密传输。 #### 3.2 观看直播 - 观看带token校验直播流程  固件端的流,需要业务用户身份合法才能观看,因此SDK设计了业务Token验证流程,其验证逻辑是在播放器初始化的同时,添加了异步Token验证流程,Token由业务提供,帝视SDK会将Token传输到固件端,固件端验证成功后把结果返回并通过帝视验证Token回调函数通知结果,如果成功就开始推流,失败就拒绝推流。 - 观看加密直播流程  视频在网络传输的过程中需要保证视频内容的绝对安全,因此固件端会对每帧视频数据进行加密传输,客户端接收数据后对应的进行解密,解密后再把数据传给播放器播放。视频密钥由业务提供,业务自己保证密钥的安全性。 - 观看带token校验加密直播流程  首先验证业务Token,Token验证成功后开始推流,固件端对视频数据加密传输,客户端接收数据后,业务把密钥传递给SDK,SDK解密后给播放器进行播放。 #### 3.3 观看回放 - 观看回放流程  初始化播放器的同时,调用帝视获取卡录时间轴,待时间轴数据返回后,选择一个时间点执行seek操作,固件将会从指定时间点之后进行推送音视频数据。 - 观看带token校验回放流程  在观看回放的基础上,需要先验证用户身份,待身份验证成功后再发起观看回放流程。 - 观看加密回放流程  在观看回放的基础上,把当前视频的密钥给SDK,SDK解密后传递给播放器进行播放,业务需要保证密钥的正确性和安全性。 - 观看带token校验加密回放流程  #### 3.4 观看云存 - 观看云存流程  一段回放视频数据被上传到云端,回放生成完毕后,帝视服务器会把云存地址通知给业务服务器,业务服务器把地址下发给观看端,观看端直接使用云存地址初始化播放器进行拉流观看。 - 观看加密云存流程  播放器在接收到原始视频数据包后,监听相关回调接口,在回调接口用事先拿到的密钥调用帝视提供的解密接口进行数据解密。 #### 3.5 实时RTC通话  在观看直播的过程中,可以进行发起RTC通话,根据硬件性能提供两种RTC通话模式,如果硬件配置较低,请使用一对一RTC通话,如果硬件配置较高,使用多家融合连麦方案。 #### 3.6 获取视频流附加数据流程  视频数据在传输或者展示等各个环节有缓存,业务需要根据画面实际时间展示各种AI信息等,需要在每一帧上携带准确的信息,这个信息通过在SEI中携带,SDK支持在视频数据帧中携带用户自定义的各种信息。播放器在接收到每帧数据中解析出来并通过用户自定义信息回调给业务进行处理。 #### 3.7 文件下载流程  如果要观看固件上存储的小视频或者图片,可以调用帝视getDeviceFileDownloadUrlWithFileKey接口获取文件的完整下载地址,业务拿到这个下载地址即可进行自行下载。 #### 3.8 数据加密 帝视提供数据解密方法,业务需把密钥及时更新给SDK。 ### 4. SDK使用实例 > 以下实例举例中使用的API参数说明,具体解释见附件API。 #### 4.1 枚举定义 ``` /** SDK错误码 */ typedef NS_ENUM(NSInteger, QHVCNetErrorCode) { QHVCNetErrorCodeNoError = 0,//无错误 QHVCNetErrorCodeFailed = 1,//一般错误,原因未分类 QHVCNetErrorCodeInvalidArgument = 2,//无效的参数 QHVCNetErrorCodeSignallingModelError = 3,//信令通道模式使用错误 QHVCNetErrorCodeUninitOnAppStart = 100, QHVCNetErrorCodeRepeatInitAppStart, QHVCNetErrorCodeUninit, QHVCNetErrorCodeRepeatInit, QHVCNetErrorCodeEventCallbackIsEmpty, QHVCNetErrorCodeLongConnectCallbackIsEmpty, QHVCNetErrorCodeInputBufferSizeTooSmaller, QHVCNetErrorCodeLocalSercerListenAddressInvalid, QHVCNetErrorCodeSessionIsEmpty, QHVCNetErrorCodeSessionIsUsed, QHVCNetErrorCodeSessionInvalid = 110, QHVCNetErrorCodeTokenTooLong, QHVCNetErrorCodeFileKeyIsEmpty, QHVCNetErrorCodeFileDownloadRangeNoLegal, QHVCNetErrorCodeDownloadFileOpenFileFailed, QHVCNetErrorCodeDownloadFileGetAbsFilePathFailed, QHVCNetErrorCodeDownloadFileRepeatDownloadSameFileKey, QHVCNetErrorCodeRecordRangeNoLegal, QHVCNetErrorCodeRecordPlaySpeedNoLegal, QHVCNetErrorCodeP2PPunchHoleFailed, QHVCNetErrorCodeDirectIPConnectFailed = 120, QHVCNetErrorCodeDisableAllConnectType, QHVCNetErrorCodeNoFoundDecryptKey, QHVCNetErrorCodeNoSupportedDecryptAlgo, QHVCNetErrorCodeVerifyTokenFailed, QHVCNetErrorCodeWaitTokenTimeoutInP2P, QHVCNetErrorCodeWaitTimelineResTimeoutInP2P, QHVCNetErrorCodeWaitStreamConnectTimeoutInP2P, QHVCNetErrorCodeStreamConnectFailedInP2P, QHVCNetErrorCodeHeartBeatTimeoutInP2P, QHVCNetErrorCodeTooLongTimeNoReceivePeerDataInP2P = 130, QHVCNetErrorCodeStreamDisconnectInP2P, QHVCNetErrorCodeWaitLongConnnectConnectSucessTimeoutInRelay, QHVCNetErrorCodeWaitTokenTimeoutInRelay, QHVCNetErrorCodeWaitTimelineResTimeoutInRelay, QHVCNetErrorCodeHeartbeatTimeoutInRelay, QHVCNetErrorCodeWaitStreamConnectTimeoutInRelay, QHVCNetErrorCodeCallScheuleFailedInRelay, QHVCNetErrorCodeScheduleCallbackFailedInRelay, QHVCNetErrorCodeStreamConnectFailedInRelay, QHVCNetErrorCodeTooLongTimeNoReceivePeerDataInRelay = 140, QHVCNetErrorCodeStreamDisConnectInRelay, QHVCNetErrorCodeWaitTokenTimeoutInDirectIP, QHVCNetErrorCodeWaitTimelineResTimeoutInDirectIP, QHVCNetErrorCodeWaitStreamConnenctTimeoutInDirectIP, QHVCNetErrorCodeStreamConnectFailedInDirectIP, QHVCNetErrorCodeHeartbeatTimeoutInDirectIP, QHVCNetErrorCodeTooLongtimeNoReceivePeerDataInDirectIP, QHVCNetErrorCodeStreamDisconnectInDirectIP, QHVCNetErrorCodeRepeatCallGetRecordTimeline, //comm QHVCNetErrorCodeDeviceSerialNumberIsEmpty = 1000, QHVCNetErrorCodeClientIdIsEmpty, QHVCNetErrorCodeAppIdIsEmpty, QHVCNetErrorCodePlatformIdIsEmptyOnAppStart, QHVCNetErrorCodeVersionIsEmptyOnAppStart, QHVCNetErrorCodeOperatingSystemIsEmptyOnAppStart, QHVCNetErrorCodeMIDIsEmptyOnAppStart, QHVCNetErrorCodeModelIsEmptyOnAppStart, QHVCNetErrorCodeDeviceChannelNumNoLegal, QHVCNetErrorCodeNoSupportedBitrateType, QHVCNetErrorCodeNoSupportedPlayType = 1010, QHVCNetErrorCodeNoSupportedPlayMode, QHVCNetErrorCodeUserIdIsEmpty, QHVCNetErrorCodeChannelIdIsEmpty, QHVCNetErrorCodeUserSignIsEmpty, QHVCNetErrorCodeSecretKeyNumNoLegal, QHVCNetErrorCodeLongConnectTopicIsEmpty, QHVCNetErrorCodeLongConnectDataIsEmpty, QHVCNetErrorCodeLongConnectDataParseFailed, QHVCNetErrorCodeLongConnectDataUnknownModel, QHVCNetErrorCodeLongConnectDataNoFoundModel = 1020, QHVCNetErrorCodeLongConnectDataNoFoundData, QHVCNetErrorCodeNetSDKParseFailed, QHVCNetErrorCodeNetSDKUnknownType, QHVCNetErrorCodeNetSDKNoFoundContext, QHVCNetErrorCodeLongConnectNetSDKNoFoundResValueOfREQRelayRes, QHVCNetErrorCodeLongConnectNetSDKNoFoundTokenResOfREQRelayRes, QHVCNetErrorCodeLongConnectNetSDKUnknownFailed, QHVCNetErrorCodeNoSupportedLogLevel, QHVCNetErrorCodeLogPathIsEmpty, QHVCNetErrorCodeMediaDeviceHandleInvalid = 1030, //license鉴权 QHVCNetErrorCodeAuthParamNonExistent = 100000,//认证串不存在 QHVCNetErrorCodeAuthFormatError = 100001,//认证格式不正确 QHVCNetErrorCodeAuthTimeNonExistent = 100002,//请求时间戳不存在 QHVCNetErrorCodeAuthTimeFormatError = 100003,//请求时间戳格式不正确 QHVCNetErrorCodeAuthRandomNonExistent = 100004,//随机数不存在 QHVCNetErrorCodeAuthRandomFormatError = 100005,//随机数格式不正确 QHVCNetErrorCodeAuthFailed = 100006,//认证失败 QHVCNetErrorCodeAuthTimestampExpired = 110005,//请求时间戳过期或过大 QHVCNetErrorCodeProductInvalid = 200002,//产品不存在 QHVCNetErrorCodeProductStatusException = 200003,//产品状态异常 QHVCNetErrorCodeDeviceInvalid = 400002,//设备不存在 QHVCNetErrorCodeDeviceUnactivated = 400004,//设备未激活 QHVCNetErrorCodeDeviceLicenseOverdue = 400005,//设备license已过期 QHVCNetErrorCodeDeviceServiceOverdue = 400006,//设备云服务已过期 QHVCNetErrorCodeDeviceServiceInvalid = 400008,//设备云服务不存在 QHVCNetErrorCodeDeviceNotbound = 400009,//设备未绑定 QHVCNetErrorCodeDeviceTokenFailed = 500000,//设备获取token失败 }; /** * 日志等级 */ typedef NS_ENUM(NSInteger, QHVCNetLogLevel) { QHVCNetLogLevelTrace = 0,//trace QHVCNetLogLevelDebug = 1,//debug QHVCNetLogLevelInfo = 2,//info QHVCNetLogLevelWarn = 3,//warn QHVCNetLogLevelError = 4,//error QHVCNetLogLevelAlarm = 5,//alarm QHVCNetLogLevelFatal = 6,//fatal QHVCNetLogLevelNone = 7,//none }; /** * 网络状态 */ typedef NS_ENUM(NSInteger, QHVCNetNetworkStatus) { QHVCNetNetworkNotReachable = 0, QHVCNetNetworkReachableViaWiFi, QHVCNetNetworkReachableViaWWAN }; /** * QHVCNetKit提供的服务类型 */ typedef NS_OPTIONS(NSInteger, QHVCNetServiceType) { QHVCNetServicePrecache = 1 << 0, // 预缓存服务 QHVCNetServiceGodSees = 1 << 1 // 帝视服务 }; /** 长连服务 */ typedef NS_ENUM(NSInteger, QHVCNetLongConnectService) { QHVCNetLongConnectServiceSDK = 0,//SDK自带长连 QHVCNetLongConnectServiceExternal,//外部长连 }; /** 网络连接类型 */ typedef NS_ENUM(NSInteger, QHVCNetGodSeesNetworkConnectType) { QHVC_NET_GODSEES_NETWORK_CONNECT_TYPE_P2P = 1,//p2p QHVC_NET_GODSEES_NETWORK_CONNECT_TYPE_RELAY = (1<<1),//云端 QHVC_NET_GODSEES_NETWORK_CONNECT_TYPE_DIRECT_IP = (1<<2),//IP直连 }; /** 会话类型 */ typedef NS_ENUM(NSInteger, QHVCNetGodSeesSessionType) { QHVC_NET_GODSEES_SESSION_TYPE_LIVE = 1, //直播 QHVC_NET_GODSEES_SESSION_TYPE_RECORD, //回放 QHVC_NET_GODSEES_SESSION_TYPE_FILE_DOWNLOAD, //文件下载 }; /** 码流类型 码流大小根据硬件设备性能自定义 */ typedef NS_ENUM(NSInteger, QHVCNetGodSeesStreamType) { QHVC_NET_GODSEES_STREAM_TYPE_MAIN = 1, // 主码流 QHVC_NET_GODSEES_STREAM_TYPE_SUB, // 子码流 QHVC_NET_GODSEES_STREAM_TYPE_THIRD, // 第三码流 }; /** 数据帧类型 */ typedef NS_ENUM(NSInteger, QHVCNetGodSeesFrameDataType) { QHVC_NET_GODSEES_FRAME_DATA_TYPE_NONE = 0, QHVC_NET_GODSEES_FRAME_DATA_TYPE_H264, QHVC_NET_GODSEES_FRAME_DATA_TYPE_H265, QHVC_NET_GODSEES_FRAME_DATA_TYPE_AAC, QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_S16LE, QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_MULAW, QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_ALAW, }; /** 解密规则 */ typedef NS_ENUM(NSInteger, QHVCNetGodSeesDecryptionRules) { QHVC_NET_GODSEES_DECRYPTION_RULES_NONE = 0, //无密 QHVC_NET_GODSEES_DECRYPTION_RULES_XOR = 1, //XOR方式 QHVC_NET_GODSEES_DECRYPTION_RULES_RC4, //RC4方式 }; /** rtc session状态 */ typedef NS_ENUM(NSInteger, QHVCNetGodSeesRTCSessionStatus) { QHVC_NET_GODSEES_RTC_SESSION_SUCCESS = 1, //成功建立rtc session QHVC_NET_GODSEES_RTC_SESSION_BE_USED, //固件rtc session已经被其它APP占用 QHVC_NET_GODSEES_RTC_SESSION_REJECT, //固件拒绝rtc session QHVC_NET_GODSEES_RTC_SESSION_TIMEOUT, //rtc session timeout QHVC_NET_GODSEES_RTC_SESSION_NO_SUPPORT_SPY_RTC, //不支持自研rtc QHVC_NET_GODSEES_RTC_SESSION_UNKNOWN_RES = 50, //未知的响应 }; ``` #### 4.2 数据结构定义 ``` /** 以天为单位卡录时间轴数据结构 */ @interface QHVCNetGodSeesRecordTimelineDay : NSObject @property(nonatomic, assign) uint32_t timeS;//时间。单位:秒 @property(nonatomic, assign) uint32_t recordDataType;//数据录制类型。0:SDK内部保留,代表所有类型,其它值由业务自定义。 @end /** 卡录时间轴数据结构 */ @interface QHVCNetGodSeesRecordTimeline : NSObject @property(nonatomic, assign) uint64_t startMS;//开始时间。单位:毫秒 @property(nonatomic, assign) uint32_t durationMS;//持续时间。单位:毫秒 @property(nonatomic, assign) uint32_t recordDataType;//数据录制类型。0:SDK内部保留,代表所有类型,其它值由业务自定义。 @end /** 音频流格式 */ @interface QHVCNetGodSeesAudioStreamFormat : NSObject @property (nonatomic, assign) int sampleRate;//采样率 @property (nonatomic, assign) int sampleBits;//采样深度 @property (nonatomic, assign) int channelNumbers;//声道数 @end ``` #### 4.3 NetSDK相关服务 以上SDK提供的这些功能中,都需要事先启动NetSDK的本地服务,建议在用户登录成功进行调用,启动本地服务方法是一个异步回调,建议业务在回调中处理下一步流程,否则可能会导致底层服务未启动完毕而不能正常提供服务的问题。 - 启动本地服务 ``` - (void)startLocalServer { QHVCNet* netkit = [QHVCNet sharedInstance]; [netkit setLogLevel:(QHVCNetLogLevel)[QHVCLogger getLoggerLevel] detailInfo:0 callback:^(const char *buf, size_t buf_size) { NSLog(@"NetSDK netLog:%@", [NSString stringWithUTF8String:buf]); }]; NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; path = [path stringByAppendingPathComponent:@"videoCache"]; NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:path]) { [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; } QHVCHUDManager *hudManager = [QHVCHUDManager new]; [hudManager showLoadingProgressOnView:self.view message:@"Loading..."]; QHVCGVConfig* config = [QHVCGVConfig sharedInstance]; [netkit startLocalServer:path cacheSize:500 options:@{kQHVCNetOptionsServicesKey:@(QHVCNetServiceGodSees | QHVCNetServicePrecache), kQHVCNetGodSeesOptionsUseLongConnectKey:@(config.longConnectService) } completion:^(BOOL result, NSError * _Nonnull error) { if (result) { [hudManager hideHud]; [self refreshDeviceListData]; } else { [hudManager showTextOnlyAlertViewOnView:self.view message:error.domain hideFlag:YES]; } }]; } ``` - 停止本地服务代码如下: ``` [[QHVCNet sharedInstance] stopLocalServer]; ``` #### 4.4 观看直播实例代码 创建帝视会话实例: ``` - (void) prepareLive { QHVCGlobalConfig* globalConfig = [QHVCGlobalConfig sharedInstance]; QHVCGVConfig * config = [QHVCGVConfig sharedInstance]; [[QHVCNet sharedInstance] setGodSeesDelegate:self]; _sessionId = [NSString stringWithFormat:@"%@_%@_%lld", globalConfig.appId, config.userName, [QHVCToolUtils getCurrentDateByMilliscond]]; [[QHVCNet sharedInstance] enableGodSeesMonitorVideoState:config.shouldShowPerformanceInfo]; [[QHVCNet sharedInstance] setGodSeesNetworkConnectType:config.networkConnectType]; QHVCGVUserSystem* userSystem = [QHVCGVUserSystem sharedInstance]; //测试数据,此部分数据需要正式放在业务服务器去计算 NSInteger randNum = arc4random()%1000000 +1; NSUInteger authTime = [QHVCToolUtils getCurrentDateBySecond]; NSString *AK = @"视频云官网后台申请"; NSString *SK = @"视频云官网后台申请"; NSString *productId = @"视频云官网后台申请"; NSString *paramsStr = [NSString stringWithFormat:@"product_id=%@sn=%@", productId,_deviceModel.bindedSN]; NSString *paramsSign = [QHVCToolUtils getMD5String:[NSString stringWithFormat:@"%@%ld", [QHVCToolUtils getMD5String:paramsStr], (long)randNum]]; NSString *authString = [NSString stringWithFormat:@"%@\n%lu\n%ld\n%@", AK, authTime, randNum, paramsSign]; NSString *sign = [QHVCToolUtils hmacSha1:SK data:authString]; NSString *token = [NSString stringWithFormat:@"%@:%@", AK, sign]; //end QHVC_WEAK_SELF [[QHVCNet sharedInstance] createGodSeesSessionByProductId:productId authTime:authTime randomNum:randNum productSign:token sessionId:_sessionId userId:[userSystem userInfo].userId serialNumber:_deviceModel.bindedSN deviceChannelNumber:1 sessionType:QHVC_NET_GODSEES_SESSION_TYPE_LIVE options:@{kQHVCNetGodSeesOptionsStreamTypeKey:@([config streamType]),kQHVCNetGodSeesOptionsUseLongConnectKey:@([config longConnectService])} completion:^(QHVCNetErrorCode result) { QHVC_STRONG_SELF _playerUrl = [[QHVCNet sharedInstance] getGodSeesPlayUrl:_sessionId]; [[QHVCNet sharedInstance] pullRemoteDeviceDataStream:_sessionId userToken:[QHVCGVUserSystem sharedInstance].userInfo.token]; [self initPlayer]; }]; } - (void)initPlayer { [QHVCPlayer setLogLevel:(QHVCPlayerLogLevel)[QHVCLogger getLoggerLevel]]; QHVCGlobalConfig* globalConfig = [QHVCGlobalConfig sharedInstance]; QHVCGVConfig* config = [QHVCGVConfig sharedInstance]; _player = [[QHVCPlayer alloc] initWithURL:_playerUrl channelId:globalConfig.appId userId:config.userName playType:QHVCPlayTypeLive options:@{@"hardDecode":@([config isHardDecode]), @"playMode":@(QHVCPlayModeLowLatency | QHVCPlayModeLive_IOT), @"inputStream":@(YES), @"streamType":@(config.playerStreamType), @"enableAnalyzeSei":@(config.enableAnalyzeSei)}]; _player.playerDelegate = self; _player.playerAdvanceDelegate = self; [_player createPlayerView:_playerView]; [_player setSystemVolumeCallback:YES]; [_player setSystemVolumeViewHidden:NO]; [_player prepare]; [[QHVCNet sharedInstance] notifyServerReceiveMediaData:_sessionId enable:YES]; if ([[QHVCGVConfig sharedInstance] shouldShowPerformanceInfo]) { [_player openNetStats:5]; } } ``` 播放器真实开始播放 ``` /** 播放器首次加载缓冲准备完毕,在此回调中调用play开始播放 */ - (void)onPlayerPrepared:(QHVCPlayer *_Nonnull)player { [_player play]; } ``` 播放器首屏渲染,可以隐藏掉遮罩图 ``` /** 播放器首屏渲染,可以显示第一帧画面 */ - (void)onPlayerFirstFrameRender:(NSDictionary *_Nullable)mediaInfo player:(QHVCPlayer *_Nonnull)player { [QHVCLogger printLogger:QHVC_LOG_LEVEL_DEBUG content:[NSString stringWithFormat:@"onPlayerFirstFrameRender mediaInfo:%@",mediaInfo]]; self.ivPlaceHolder.hidden = YES; } ``` 播放器接收外部输入数据 ``` /** NetSDK将帧数据抛出,业务端可以将相关数据直接吐给播放器播放。 注意:此代理只会在开启QHVC_NET_GODSEES_PLAYER_RECEIVE_DATA_MODEL_CALLBACK时才会触发该回调,此时需要业务把该回调数据直接传递给播放器使用。(开启方法:在createGodSeesSession方法的参数中,设置播放器接收数据模式QHVCNetGodSeesPlayerReceiveDataModel为QHVC_NET_GODSEES_PLAYER_RECEIVE_DATA_MODEL_CALLBACK) @param sessionId 会话ID @param frameDataType 数据帧类型 @param frameData 帧数据 @param length 帧数据长度 @param pts 显示时间戳 @param dts 解码时间戳 @param isKeyFrame 是否是关键帧 @param audioStreamFormat 音频格式 */ - (void)onGodSees:(NSString *)sessionId didReceiveFrameDataType:(QHVCNetGodSeesFrameDataType)frameDataType frameData:(const uint8_t *)frameData frameDataLen:(int)length pts:(uint64_t)pts dts:(uint64_t)dts isKeyFrame:(BOOL)isKeyFrame audioStreamFormat:(QHVCNetGodSeesAudioStreamFormat *)audioStreamFormat { if ([QHVCToolUtils isNullString:sessionId]) { return; } QHVCMonitorSessionModel* model = _sessionDict[sessionId]; QHVCPlayer* player = model.player; if (player == nil) { return; } QHVC_PACKET_TYPE type = QHVC_PACKET_TYPE_NONE; if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_H264) { type = QHVC_PACKET_TYPE_H264; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_H265) { type = QHVC_PACKET_TYPE_H265; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_AAC) { type = QHVC_PACKET_TYPE_AAC; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_S16LE) { type = QHVC_PACKET_TYPE_PCM_S16LE; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_ALAW) { type = QHVC_PACKET_TYPE_PCM_ALAW; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_MULAW) { type = QHVC_PACKET_TYPE_PCM_MULAW; } if (model.isCalling && type == QHVC_PACKET_TYPE_AAC) { [[QHVCRTCClient sharedInstance] inputAudioSource:frameData frame_size:length timestamp:pts]; return; } QHVCStreamCodecContext tmp_audioStreamCodecContext; QHVCStreamCodecContext* audioStreamCodecContext = &tmp_audioStreamCodecContext; if (audioStreamFormat) { audioStreamCodecContext->sample_rate = audioStreamFormat.sampleRate; audioStreamCodecContext->sample_bits = audioStreamFormat.sampleBits; audioStreamCodecContext->nb_channels = audioStreamFormat.channelNumbers; } else { audioStreamCodecContext = NULL; } [player inputStream:type data:frameData size:length pts:pts dts:dts isKey:isKeyFrame streamCodecContext:audioStreamCodecContext]; } ``` - 结束观看直播 ``` - (void) stopPlayer { [_player stop]; _player = nil; [[QHVCNet sharedInstance] setGodSeesDelegate:nil]; [[QHVCNet sharedInstance] destroyGodSeesSession:_sessionId serialNumber:_deviceModel.bindedSN]; } ``` #### 4.5 观看回放实例代码 准备卡录播放,进行身份认证 ``` - (void) prepareCardRecord { QHVCGlobalConfig* globalConfig = [QHVCGlobalConfig sharedInstance]; QHVCGVConfig * config = [QHVCGVConfig sharedInstance]; [[QHVCNet sharedInstance] setGodSeesDelegate:self]; _sessionId = [NSString stringWithFormat:@"%@_%@_%lld",globalConfig.appId, config.userName, [QHVCToolUtils getCurrentDateByMilliscond]]; [[QHVCNet sharedInstance] enableGodSeesMonitorVideoState:config.shouldShowPerformanceInfo]; [[QHVCNet sharedInstance] setGodSeesNetworkConnectType:config.networkConnectType]; QHVCGVUserSystem* userSystem = [QHVCGVUserSystem sharedInstance]; //测试数据,此部分数据需要正式放在业务服务器去计算 NSInteger randNum = arc4random()%1000000 +1; NSUInteger authTime = [QHVCToolUtils getCurrentDateBySecond]; NSString *AK = @"视频云官网申请"; NSString *SK = @"视频云官网申请"; NSString *productId = @"视频云官网申请"; NSString *paramsStr = [NSString stringWithFormat:@"product_id=%@sn=%@", productId,_deviceModel.bindedSN]; NSString *paramsSign = [QHVCToolUtils getMD5String:[NSString stringWithFormat:@"%@%ld", [QHVCToolUtils getMD5String:paramsStr], (long)randNum]]; NSString *authString = [NSString stringWithFormat:@"%@\n%lu\n%ld\n%@", AK, authTime, randNum, paramsSign]; NSString *sign = [QHVCToolUtils hmacSha1:SK data:authString]; NSString *token = [NSString stringWithFormat:@"%@:%@", AK, sign]; //end [[QHVCNet sharedInstance] createGodSeesSessionByProductId:productId authTime:authTime randomNum:randNum productSign:token sessionId:_sessionId userId:[userSystem userInfo].userId serialNumber:_deviceModel.bindedSN deviceChannelNumber:1 sessionType:QHVC_NET_GODSEES_SESSION_TYPE_RECORD options:@{kQHVCNetGodSeesOptionsStreamTypeKey:@([config streamType]),kQHVCNetGodSeesOptionsUseLongConnectKey:@([config longConnectService])} completion:^(QHVCNetErrorCode result) { _playerUrl = [[QHVCNet sharedInstance] getGodSeesPlayUrl:_sessionId]; [[QHVCNet sharedInstance] pullRemoteDeviceDataStream:_sessionId userToken:userSystem.userInfo.token]; }]; [self initPlayer]; } - (void)initPlayer { if (_player != nil) { [_player stop]; _player = nil; } [QHVCPlayer setLogLevel:(QHVCPlayerLogLevel)[QHVCLogger getLoggerLevel]]; QHVCGVConfig * config = [QHVCGVConfig sharedInstance]; QHVCGlobalConfig * globalConfig = [QHVCGlobalConfig sharedInstance]; _player = [[QHVCPlayer alloc] initWithURL:_playerUrl channelId:globalConfig.appId userId:config.userName playType:QHVCPlayTypeLive options:@{@"hardDecode":@([config isHardDecode]), @"playMode":@(QHVCPlayModeFluency|QHVCPlayModeLive_IOT), @"inputStream":@(YES), @"streamType":@(config.playerStreamType), @"enableAnalyzeSei":@(config.enableAnalyzeSei)}]; _player.playerDelegate = self; _player.playerAdvanceDelegate = self; [_player createPlayerView:_playerView]; [_player setSystemVolumeCallback:YES]; [_player setSystemVolumeViewHidden:NO]; [_player prepare]; [[QHVCNet sharedInstance] notifyServerReceiveMediaData:_sessionId enable:YES]; if ([[QHVCGVConfig sharedInstance] shouldShowPerformanceInfo]) { [_player openNetStats:5]; } } ``` 监听播放器开始播放 ``` /** 播放器首次加载缓冲准备完毕,在此回调中调用play开始播放 */ - (void)onPlayerPrepared:(QHVCPlayer *_Nonnull)player { [_player play]; } /** 播放器首屏渲染,可以显示第一帧画面 */ - (void)onPlayerFirstFrameRender:(NSDictionary *_Nullable)mediaInfo player:(QHVCPlayer *_Nonnull)player { } ``` 监听拉流回调函数,身份验证成功请求时间轴,失败就直接结束 ``` - (void) onGodSees:(NSString *)sessionId didPullStreamSucceed:(NSInteger)status info:(NSString *)info { [QHVCLogger printLogger:QHVC_LOG_LEVEL_TRACE content:[NSString stringWithFormat:@"didPullStreamSucceed: sessionId = %@, status = %zd, info = %@",sessionId,status,info]]; if ([_sessionId isEqual:sessionId]) { if (status == QHVCNetErrorCodeNoError) {//请求时间轴 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[QHVCNet sharedInstance] getGodSeesRecordTimeline:_sessionId startTime:0 endTime:-1]; }); return; } NSString *errMsg = @""; if (status == QHVC_NET_GODSEES_TOKEN_ERROR_TokenVerifyFail) { errMsg = kQHVC_NET_GODSEES_TOKEN_ERROR_TokenVerifyFail_TEXT; } else if (status == QHVC_NET_GODSEES_TOKEN_ERROR_RelayConnectionOverLimit) { errMsg = kQHVC_NET_GODSEES_TOKEN_ERROR_RelayConnectionOverLimit_TEXT; } else if (status == QHVC_NET_GODSEES_TOKEN_ERROR_RecordConnectionOverLimit) { errMsg = kQHVC_NET_GODSEES_TOKEN_ERROR_RecordConnectionOverLimit_TEXT; } else if (status == QHVC_NET_GODSEES_TOKEN_ERROR_TotalConnectionOverLimit) { errMsg = kQHVC_NET_GODSEES_TOKEN_ERROR_TotalConnectionOverLimit_TEXT; } errMsg = [errMsg stringByAppendingFormat:@" 错误码:%zd",status]; runOnMainQueueWithoutDeadlocking(^{ [QHVCToast makeToast:errMsg]; }); } } ``` 监听时间轴请求成功返回,解析时间轴并做相关UI展示 ``` - (void)onGodSees:(NSString *)sessionId didRecordTimeline:(NSArray<QHVCNetGodSeesRecordTimeline *> *)data recordType:(uint32_t)recordType { if ([_sessionId isEqual:sessionId]) { [self analysisCardRecordTimeline:data]; } } ``` 选择一个时间点进行播放 ``` [[QHVCNet sharedInstance] setGodSeesRecordSeek:_sessionId timeStamp:self.currentSeekTime]; ``` 监听seek完成 ``` /** * 拖动操作缓冲完成 */ - (void)onPlayerSeekComplete:(QHVCPlayer *_Nonnull)player { } ``` 监听更新当前播放进度值 ``` - (void) onGodSees:(NSString *)sessionId didRecordUpdateCurrentTimeStamp:(NSUInteger)timeStampByMS { } ``` 监听NetSDK数据回调吐给播放器 ``` /** NetSDK将帧数据抛出,业务端可以将相关数据直接吐给播放器播放。 注意:此代理只会在开启QHVC_NET_GODSEES_PLAYER_RECEIVE_DATA_MODEL_CALLBACK时才会触发该回调,此时需要业务把该回调数据直接传递给播放器使用。(开启方法:在createGodSeesSession方法的参数中,设置播放器接收数据模式QHVCNetGodSeesPlayerReceiveDataModel为QHVC_NET_GODSEES_PLAYER_RECEIVE_DATA_MODEL_CALLBACK) @param sessionId 会话ID @param frameDataType 数据帧类型 @param frameData 帧数据 @param length 帧数据长度 @param pts 显示时间戳 @param dts 解码时间戳 @param isKeyFrame 是否是关键帧 @param audioStreamFormat 音频格式 */ - (void)onGodSees:(NSString *)sessionId didReceiveFrameDataType:(QHVCNetGodSeesFrameDataType)frameDataType frameData:(const uint8_t *)frameData frameDataLen:(int)length pts:(uint64_t)pts dts:(uint64_t)dts isKeyFrame:(BOOL)isKeyFrame audioStreamFormat:(QHVCNetGodSeesAudioStreamFormat *)audioStreamFormat { if ([QHVCToolUtils isNullString:sessionId]) { return; } QHVCMonitorSessionModel* model = _sessionDict[sessionId]; QHVCPlayer* player = model.player; if (player == nil) { return; } QHVC_PACKET_TYPE type = QHVC_PACKET_TYPE_NONE; if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_H264) { type = QHVC_PACKET_TYPE_H264; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_H265) { type = QHVC_PACKET_TYPE_H265; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_AAC) { type = QHVC_PACKET_TYPE_AAC; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_S16LE) { type = QHVC_PACKET_TYPE_PCM_S16LE; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_ALAW) { type = QHVC_PACKET_TYPE_PCM_ALAW; } else if (frameDataType == QHVC_NET_GODSEES_FRAME_DATA_TYPE_PCM_MULAW) { type = QHVC_PACKET_TYPE_PCM_MULAW; } if (model.isCalling && type == QHVC_PACKET_TYPE_AAC) { [[QHVCRTCClient sharedInstance] inputAudioSource:frameData frame_size:length timestamp:pts]; return; } QHVCStreamCodecContext tmp_audioStreamCodecContext; QHVCStreamCodecContext* audioStreamCodecContext = &tmp_audioStreamCodecContext; if (audioStreamFormat) { audioStreamCodecContext->sample_rate = audioStreamFormat.sampleRate; audioStreamCodecContext->sample_bits = audioStreamFormat.sampleBits; audioStreamCodecContext->nb_channels = audioStreamFormat.channelNumbers; } else { audioStreamCodecContext = NULL; } [player inputStream:type data:frameData size:length pts:pts dts:dts isKey:isKeyFrame streamCodecContext:audioStreamCodecContext]; } ``` 结束播放 ``` - (void) stopPlayer { [_player stop]; _player = nil; [[QHVCNet sharedInstance] setGodSeesDelegate:nil]; [[QHVCNet sharedInstance] destroyGodSeesSession:_sessionId serialNumber:_deviceModel.bindedSN]; } ``` #### 4.6 直播RTC通话流程 > 暂无 #### 4.7 观看云存流程 把云存地址给播放器播放并实例化播放器: ``` [QHVCPlayer setLogLevel:(QHVCPlayerLogLevel)[QHVCLogger getLoggerLevel]]; QHVCGlobalConfig* globalConfig = [QHVCGlobalConfig sharedInstance]; QHVCGVConfig* config = [QHVCGVConfig sharedInstance]; int inputStreamValue = [config playerReceiveDataModel] == QHVC_NET_GODSEES_PLAYER_RECEIVE_DATA_MODEL_CALLBACK?1:0; _player = [[QHVCPlayer alloc] initWithURL:_playerUrl channelId:globalConfig.appId userId:config.userName playType:QHVCPlayTypeLive options:@{@"hardDecode":@([config isHardDecode]),@"playMode":@(QHVCPlayModeLowLatency),@"inputStream":@(inputStreamValue),@"streamType":@(config.playerStreamType)}]; _player.playerDelegate = self; _player.playerAdvanceDelegate = self; [_player createPlayerView:_playerView]; [_player setSystemVolumeCallback:YES]; [_player setSystemVolumeViewHidden:NO]; [_player prepare]; ``` 播放器真实开始播放 ``` /** 播放器首次加载缓冲准备完毕,在此回调中调用play开始播放 */ - (void)onPlayerPrepared:(QHVCPlayer *_Nonnull)player { [_player play]; } ``` #### 4.8 获取视频流附加数据实例代码 ``` /** seiMeta信息 @param type 类型 @param data 数据 */ - (void)seiMeta:(long)type data:(NSString *_Nullable)data player:(QHVCPlayer *_Nonnull)player; ``` #### 4.9 文件下载实例代码 调用帝视获取设备文件下载链接 ``` NSInteger randNum = arc4random()%1000000 +1; NSUInteger authTime = [QHVCToolUtils getCurrentDateBySecond]; NSString *AK = @"视频云官网申请"; NSString *SK = @"视频云官网申请"; NSString *productId = @"视频云官网申请"; NSString *paramsStr = [NSString stringWithFormat:@"product_id=%@sn=%@", productId,_deviceModel.bindedSN]; NSString *paramsSign = [QHVCToolUtils getMD5String:[NSString stringWithFormat:@"%@%ld", [QHVCToolUtils getMD5String:paramsStr], (long)randNum]]; NSString *authString = [NSString stringWithFormat:@"%@\n%lu\n%ld\n%@", AK, authTime, randNum, paramsSign]; NSString *sign = [QHVCToolUtils hmacSha1:SK data:authString]; NSString *token = [NSString stringWithFormat:@"%@:%@", AK, sign]; [[QHVCNet sharedInstance] getDeviceFileDownloadUrlWithFileKeyByProductId:productId authTime:authTime randomNum:randNum productSign:token fileKey:model.imageName userId:userInfo.userId serialNumber:serialNumber token:@"业务验证码" rangeStart:0 rangeEnd:0 maxReconnectCount:3 completion:^(BOOL result, NSString * _Nonnull resultUrlString, NSError * _Nonnull error) { //文件下载 } ``` 拿到resultString后用任何下载工具都可自行下载 #### 4.10 数据解密代码实例 业务设置密钥给NetSDK即可 ``` /** 更新帝视视频流解密秘钥 @param keys 密钥表,形如 [{"27":"sfee23"},{"28":"fsjei"},@{"29":"ejis"}] @param serialNumber 设备唯一标识 @param durationBySecond 密钥更新周期,单位:秒 @return 0成功,非0表示失败 */ - (int) updateGodSeesVideoStreamSecurityKeys:(NSArray<NSDictionary<NSString *, NSString *> *> *)keys serialNumber:(NSString *)serialNumber duration:(NSInteger)durationBySecond; ``` 如果播放云存需要解密,设置播放器对外吐数据包,然后调用NetSDK的解密方法解密。 ``` - (void)initPlayer:(QHVCMonitorDeviceEventModel *)eventModel { BOOL needOutputPacket = NO; NSString* playUrl = eventModel.videoUrl; if (eventModel.eventType == QHVCMonitorDeviceEventTypeCloudEvent) { playUrl = eventModel.playUrl; needOutputPacket = ![QHVCToolUtils isNullString:eventModel.playKey]; } _player = [[QHVCPlayer alloc] initWithURL:playUrl channelId:@"1" userId:nil playType:QHVCPlayTypeVod options:@{@"hardDecode":@([QHVCConfig sharedInstance].hardDecode), @"outputPacket":@(needOutputPacket)}]; _player.playerDelegate = self; _player.playerAdvanceDelegate = self; [_player createPlayerConstraintView:_playerView]; [_player setSystemVolumeCallback:YES]; [_player setSystemVolumeViewHidden:NO]; [_player prepare]; [_player setAutomaticallySwitchResolution:YES]; } ``` 监听播放器回调: ``` - (void)onPlayerOutputPacket:(QHVCPacket)packet { QHVCNetGodSeesFrameDataType frameDataType = QHVC_NET_GODSEES_FRAME_DATA_TYPE_NONE; if (packet.flags == QHVC_PACKET_TYPE_AAC || packet.flags == QHVC_PACKET_TYPE_OPUS) { frameDataType = QHVC_NET_GODSEES_FRAME_DATA_TYPE_AAC; } else if (packet.flags == QHVC_PACKET_TYPE_H264) { frameDataType = QHVC_NET_GODSEES_FRAME_DATA_TYPE_H264; } else if (packet.flags == QHVC_PACKET_TYPE_H265) { frameDataType = QHVC_NET_GODSEES_FRAME_DATA_TYPE_H265; } [[QHVCNet sharedInstance] decryptGodSeesMediaDataWithSecretKey:_eventModel.playKey decryptionRules:QHVC_NET_GODSEES_DECRYPTION_RULES_XOR frameDataType:frameDataType originalMediaData:packet.pData originalDataLength:packet.size decryptedDataLength:&packet.size]; } ```
即刻开始使用
只需完成注册与实名认证,即可体验我们的贴心服务
立即使用
请您联系我们
邮箱
g-zyun@360.cn
电话
010-58781360
小安提醒您
试用小安,请确保该账户已通过智汇云实名认证
前往认证中心>>
1对1免费
咨询智汇云专属顾问
为您量身定制产品解决方案
您的姓名 :
手机号 :
公司名称(选填) :
相关产品 :
留言内容 :
需求描述
产品建议
其他
提交
登录后才可以留言哦
立即登录
去注册账号