更新记录
1.0.1(2025-12-09)
- 新增iOS端
1.0.0(2025-12-03)
- 新版发布
平台兼容性
uni-app(4.71)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | × | √ | 6.0 | √ | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | - | × | × |
uni-app x(4.71)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 6.0 | √ | × | × |
海康威视综合安防平台视频播放插件
基于海康威视软件平台 SDK 封装的 UTS 组件插件,支持 uni-app / uni-app x 项目,提供实时预览、录像回放、语音对讲、抓图、本地录像、电子放大、鱼眼矫正、云台控制等能力。
| 平台 | Android SDK | iOS SDK | 支持框架 |
|---|---|---|---|
| Android / iOS | v2.4.5 | v2.4.0 | uni-app(nvue)、uni-app x(uvue) |
SDK 详细说明请参考 海康官方开发指南。
特别提醒
- 购买前请先试用,并充分自测确认满足需求后再购买。虚拟物品一经购买,无法退款。
- 如有使用疑问或发现 bug,可进交流群联系作者。
- 请在合法范围内使用本插件;若用于非法开发,作者概不负责。
- 请结合本文档与示例 Demo 集成使用。
- Android 端请将
manifest.json中minSdkVersion设为 23 或以上。 - 示例项目:uni-app 示例见插件主页;uni-app x 示例见 uni-app 示例项目
/static/HKPlayDemo.zip。
插件功能
- 实时预览
- 网络录像回放
- 语音对讲
- 播放抓图
- 本地录像
- 电子放大
- 鱼眼矫正
- 云台控制(待测)
插件接口文档
兼容模式不支持 nvue 的同步返回值,因此 uni-app 与 uni-app x 项目的集成方式、回调机制、部分接口参数均不相同。请根据项目类型查阅对应章节:
| 项目类型 | 组件标签 | 页面类型 | 文档章节 |
|---|---|---|---|
| uni-app | <yt-hikvideo> |
nvue | uni-app 项目集成 · 完整示例 |
| uni-app x | <ytx-hikvideo> |
uvue | uni-app x 项目集成 · 完整示例 |
核心差异一览:
| 对比项 | uni-app | uni-app x |
|---|---|---|
| 组件标签 | yt-hikvideo |
ytx-hikvideo |
| 页面 | 仅 nvue | uvue |
| 有返回值接口 | 通过 @actionCallback 异步返回 |
方法同步返回 |
| 抓图参数 | screenshootThumbnail(fileName) |
screenshootThumbnail({ fileName }) |
| 类型声明 | 无需 import | 可 import YtxHikvideoElement 强类型调用 |
uni-app 项目集成
适用于 uni-app 的 nvue 项目。UI 类 UTS 组件只能在 nvue 中使用,无需 import,直接使用标签即可。
集成步骤
- 在 DCloud 插件市场 购买并绑定项目。
- 在
manifest.json→ App 原生插件配置 中勾选本插件。 - 在 nvue 页面中使用组件:
<yt-hikvideo
ref="hikVideo"
@playStatusCallback="onPlayStatus"
@voiceTalkCallback="onVoiceTalk"
@actionCallback="onAction"
></yt-hikvideo>
- 打包自定义基座或云打包后,在真机调试。
回调事件
playStatusCallback — 播放状态
| 字段 | 类型 | 说明 |
|---|---|---|
| status | Number | 0 播放成功 / 1 播放失败 / 2 取流异常 / 3 播放结束 |
| errorCode | String | 错误码,仅 status 为 1 或 2 时有值 |
- Android: 参数在事件对象根级 →
e.status、e.errorCode - iOS: 参数在
e.detail中 →e.detail.status、e.detail.errorCode
voiceTalkCallback — 语音对讲状态
| 字段 | 类型 | 说明 |
|---|---|---|
| status | Number | 0 开启成功 / 1 开启失败 / 2 取流异常 |
| errorCode | String | 错误码,仅 status 为 1 或 2 时有值 |
- Android: 根级字段
- iOS:
e.detail中
actionCallback — 操作结果
抓图、录像、查询时间、电子放大、鱼眼、云台等需要返回值的接口,均通过此事件异步返回(nvue 兼容模式不支持同步返回值)。
Android 回调结构:
{
functionName: 'getOSDTime', // 调用的方法名
errorCode: '0', // '0' 成功,'-1' 失败,其他为 SDK 错误码
time: '1234567890' // 部分接口附加字段(如 time、fullPath、frameRate)
}
iOS 回调结构:
{
detail: {
functionName: 'getOSDTime',
errorCode: '0',
time: '1234567890'
}
}
监听示例:
functionName 与触发接口一一对应,完整清单如下:
| functionName | 附加字段 | 说明 |
|---|---|---|
screenshootThumbnail |
fullPath | 抓图路径,仅 errorCode 为 '0' 时有值 |
getOSDTime |
time | 当前回放时间戳(毫秒) |
startRecord |
fullPath | 录像文件路径 |
startRecordAndConvert |
fullPath | 转码录像文件路径 |
stopRecord |
— | 停止录像 |
getTotalTime |
time | 文件总时长(秒) |
getPlayedTime |
time | 已播放时长(秒) |
setCurrentFrame |
— | 设置播放进度 |
openDigitalZoom |
— | 开启电子放大 |
closeDigitalZoom |
— | 关闭电子放大 |
setFishEyeEnable |
— | 开关鱼眼矫正 |
setFishEyeMode |
— | 设置鱼眼矫正方式 |
handleFishEyeCorrect |
— | 处理鱼眼矫正参数 |
getFrameRate |
frameRate | 码流帧率 |
setExpectedFrameRate |
— | 设置预期帧率 |
setDecodeThreadNum |
— | 设置解码线程数 |
ptzControl |
— | 云台控制 |
ptzSelZoom |
— | 云台框选放大 |
ptzPreset |
— | 云台预置点 |
ptzCruise |
— | 云台巡航 |
errorCode 为
'0'表示成功,'-1'表示失败,其他值为 SDK 错误码。Android 回调参数在根级,iOS 在e.detail中。
actionCallback(e) {
const data = e.detail || e; // 兼容 Android / iOS
const { functionName, errorCode } = data;
const success = `${errorCode}` === '0';
switch (functionName) {
case 'screenshootThumbnail':
if (success) console.log('抓图路径:', data.fullPath);
break;
case 'getOSDTime':
if (success) console.log('回放时间戳(ms):', data.time);
break;
case 'startRecord':
case 'startRecordAndConvert':
if (success) console.log('录像路径:', data.fullPath);
break;
case 'stopRecord':
console.log(success ? '录像已停止' : '停止录像失败:' + errorCode);
break;
case 'getTotalTime':
case 'getPlayedTime':
if (success) console.log('时长(秒):', data.time);
break;
case 'setCurrentFrame':
console.log(success ? '进度设置成功' : '进度设置失败:' + errorCode);
break;
case 'openDigitalZoom':
case 'closeDigitalZoom':
case 'setFishEyeEnable':
case 'setFishEyeMode':
case 'handleFishEyeCorrect':
case 'setExpectedFrameRate':
case 'setDecodeThreadNum':
case 'ptzControl':
case 'ptzSelZoom':
case 'ptzPreset':
case 'ptzCruise':
console.log(`${functionName} ${success ? '成功' : '失败:' + errorCode}`);
break;
case 'getFrameRate':
if (success) console.log('码流帧率:', data.frameRate);
break;
default:
console.log(`未知回调:${functionName}`, data);
}
}
使用示例
实时预览
this.$refs.hikVideo.setPlayConfig({
hardDecode: true,
privateData: true,
timeout: 20,
secretKey: '',
bufferLength: 5242880,
qualityType: 0,
fetchStreamType: 0
});
// realPlayUrl 为预览短链接,需通过 openApi 获取
this.$refs.hikVideo.setPlayParam(realPlayUrl, headers);
this.$refs.hikVideo.startPlay();
网络录像回放
this.$refs.hikVideo.setPlayConfig({ hardDecode: true, privateData: true });
let headers = {
startTime: '2021-07-29T00:00:00.000+08:00',
endTime: '2021-07-29T23:59:59.000+08:00'
};
this.$refs.hikVideo.setPlayParam(playbackUrl, headers);
this.$refs.hikVideo.startPlay();
抓图(异步回调)
this.$refs.hikVideo.screenshootThumbnail('snapshot.jpg');
// 结果在 onAction 中接收,functionName 为 'screenshootThumbnail'
查询回放时间(异步回调)
this.$refs.hikVideo.getOSDTime();
// 结果在 onAction 中接收,functionName 为 'getOSDTime'
完整示例代码(uni-app / nvue)
以下为 uni-app 项目完整 Demo 页面,覆盖插件全部接口。页面需保存为 nvue 文件(如 pages/hikvideo/demo.nvue)。
注意:
onLoad中需先调用initHikSDK()初始化 SDK- 预览/回放/对讲 URL 需替换为通过海康 openApi 获取的实际地址
- 回调中 iOS 参数在
e.detail;Android 的actionCallback参数在根级,使用时可用const result = e.detail || e
<template>
<view class="content">
<view class="video_bg" style="width: 750rpx;height: 500rpx;background-color: black;">
<yt-hikvideo ref="hikVideo" style="width: 750rpx;height: 450rpx;" @actionCallback="actionCallback"
@playStatusCallback="playStatusCallback" @voiceTalkCallback="voiceTalkCallback"></yt-hikvideo>
</view>
<!-- <image :src="imageScr" style="width: 750rpx;height: 300rpx;background-color: aquamarine;" mode="aspectFit">
</image> -->
<view class="row_view">
<view class="btn1" @click="setPlayConfig"><text>播放配置</text></view>
<view class="btn1" @click="setPlayParam"><text>设置播放参数</text></view>
<view class="btn1" @click="startPlay"><text>开始(预览/回放)</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="stopPlay"><text>停止预览/回放</text></view>
<view class="btn1" @click="pauseStream"><text>暂停取流(预览/回放)</text></view>
<view class="btn1" @click="resumeStream"><text>恢复取流(预览/回放)</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="changeStream"><text>切换码流</text></view>
<view class="btn1" @click="setPlayParam2"><text>设置回放播放参数</text></view>
<view class="btn1" @click="screenshootThumbnail"><text>预览/回放抓图</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="seekPlayback"><text>按时间回放定位</text></view>
<view class="btn1" @click="pause"><text>暂停回放</text></view>
<view class="btn1" @click="resume"><text>恢复回放</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setPlaybackSpeed(-2)"><text>回放倍数-2</text></view>
<view class="btn1" @click="setPlaybackSpeed(-1)"><text>回放倍数-1</text></view>
<view class="btn1" @click="setPlaybackSpeed(1)"><text>回放倍数1</text></view>
<view class="btn1" @click="setPlaybackSpeed(2)"><text>回放倍数2</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="startRecord"><text>开始录像</text></view>
<view class="btn1" @click="startRecordAndConvert"><text>开始转码录像</text></view>
<view class="btn1" @click="stopRecord"><text>停止录像</text></view>
<view class="btn1" @click="playFile"><text>播放录像</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="getTotalTime"><text>获取录像总时长</text></view>
<view class="btn1" @click="getPlayedTime"><text>获取已播放时长</text></view>
<view class="btn1" @click="setCurrentFrame"><text>设置播放进度</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setVoiceDataSource"><text>设置语⾳对讲参数</text></view>
<view class="btn1" @click="startVoiceTalk"><text>开启对讲</text></view>
<view class="btn1" @click="stopVoiceTalk"><text>关闭对讲</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="openDigitalZoom"><text>开启电子放大</text></view>
<view class="btn1" @click="closeDigitalZoom"><text>关闭电子放大</text></view>
<view class="btn1" @click="setFishEyeEnable"><text>开/关鱼眼</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setFishEyeMode"><text>⻥眼矫正⽅式</text></view>
<view class="btn1" @click="handleFishEyeCorrect"><text>处理⻥眼矫正参数</text></view>
<view class="btn1" @click="getFrameRate"><text>获取帧率</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setExpectedFrameRate"><text> 设置预期帧率</text></view>
<!-- <view class="btn1" @click="getOSDTime"><text> getOSDTime</text></view> -->
<view class="btn1" @click="requestRecordAudioPermission"><text>申请麦克风权限</text></view>
</view>
</view>
</template>
<script>
import * as HikVideoManger from '@/uni_modules/yt-hikvideo'
export default {
data() {
return {
title: 'Hello',
type: 1,
imageScr: "/var/mobile/Containers/Data/Application/7DCD19F6-66D0-408A-AECF-5494E6DFC16B/Documents/Pandora/apps/__UNI__84FA73D/data1765264672353.jpg",
path: '/var/mobile/Containers/Data/Application/7DCD19F6-66D0-408A-AECF-5494E6DFC16B/Documents/Pandora/apps/__UNI__84FA73D/data1765264769501.mp4',
fishEyeEnable: false //是否开启鱼眼
}
},
onLoad() {
HikVideoManger.initHikSDK();
//实时预览 | 网络视频回放 | 本地录像播放前必须先调用播放配置
setTimeout(() => {
this.setPlayConfig();
}, 1000)
},
methods: {
//实时预览|回放|本地录像播放回调
playStatusCallback(e) {
let result = e.detail || e;
let status = result.status;
let errorCode = result.errorCode;
console.log(`播放状态:${status} 错误码:${errorCode}`);
},
//对讲状态回调
voiceTalkCallback(e) {
let result = e.detail || e;
let status = result.status;
let errorCode = result.errorCode;
console.log(`对讲状态:${status} 错误码:${errorCode}`);
},
//操作回调
actionCallback(e) {
const result = e.detail || e; // 兼容 Android / iOS
console.log(result);
let functionName = result.functionName;
let errorCode = result.errorCode;
if (`${errorCode}` == "0") { //成功,其他是失败
}
console.log(`函数名称:${functionName}`);
if (functionName == 'screenshootThumbnail') { //抓图回调
let fullPath = result.fullPath; //抓拍图片路径--仅errorCode == 0有该值
console.log(`这是抓图回调路径:${fullPath}`);
this.imageScr = `file://${fullPath}`;
} else if (functionName ==
'getOSDTime') { //查询当前播放时间戳接⼝ 返回值errorCode:-1表⽰失败,errorCode==0 成功,time表⽰当前回放的时间戳,单位:毫秒。
console.log('查询当前播放时间戳回调,time=' + result.time);
} else if (functionName == 'startRecord') { //开始录像回调 errorCode==0 成功,否则errorCode是错误码
let fullPath = result.fullPath; //录像视频路径--仅errorCode == 0有该值
this.path = fullPath;
console.log(`开始录像回调视频地址:${fullPath}`);
} else if (functionName == 'startRecordAndConvert') { //开始转码录像 errorCode==0 成功,否则errorCode是错误码
let fullPath = result.fullPath; //录像视频路径--仅errorCode == 0有该值
this.path = fullPath;
console.log(`开始转码录像回调视频地址:${fullPath}`);
} else if (functionName == 'stopRecord') { //停止录像 errorCode==0 成功,否则errorCode是错误码
console.log('停止录像回调');
} else if (functionName == 'getTotalTime') { //获取播放文件总长-播放总时⻓,单位为:秒 . 播放成功后调⽤,否则errorCode返回-1;
console.log('获取播放文件总长回调,time=' + result.time);
} else if (functionName == 'getPlayedTime') { //获取播放⽂件的已播放时⻓,单位为:秒 . 播放成功后调⽤,否则errorCode返回-1;
console.log('获取已播放时长回调,time=' + result.time);
} else if (functionName == 'setCurrentFrame') { //设置播放进度 errorCode==0 成功,否则errorCode是错误码
console.log('设置播放进度回调');
} else if (functionName == 'openDigitalZoom') { //设置电子放大回调 errorCode==0 成功,否则errorCode是错误码
console.log('设置电子放大回调');
} else if (functionName == 'closeDigitalZoom') { //关闭电子放大回调 errorCode==0 成功,否则errorCode是错误码
console.log('关闭电子放大回调');
} else if (functionName == 'setFishEyeEnable') { //开关鱼眼矫正回调 errorCode==0 成功,否则errorCode是错误码
console.log('开关鱼眼矫正回调 ');
} else if (functionName ==
'setFishEyeMode') { //设置鱼眼矫正方式-打开⻥眼功能后,设置⻥眼矫正⽅式回调 errorCode==0 成功,否则errorCode是错误码
console.log('设置鱼眼矫正方式-打开⻥眼功能后,设置⻥眼矫正⽅式回调 ');
} else if (functionName == 'handleFishEyeCorrect') { //处理⻥眼矫正参数回调 errorCode==0 成功,否则errorCode是错误码
console.log('处理⻥眼矫正参数回调 ');
} else if (functionName == 'getFrameRate') { //获取成功返回码流帧率回调,获取失败返回errorCode == -1。frameRate若码流中的帧率⼩于1,返回0。
console.log('获取码流帧率回调,frameRate=' + result.frameRate);
} else if (functionName == 'setExpectedFrameRate') { //设置预期帧率回调 errorCode==0 成功,否则errorCode是错误码
console.log('设置预期帧率回调 ');
} else if (functionName ==
'setDecodeThreadNum') { //设置多线程解码线程数-设置多线程解码线程数回调 errorCode==0 成功,否则errorCode是错误码
console.log('设置多线程解码线程数-设置多线程解码线程数回调');
} else if (functionName == 'ptzControl') { //云台控制操作(需先启动预览)回调 errorCode==0 成功,否则errorCode是错误码
console.log('云台控制操作(需先启动预览)回调');
} else if (functionName == 'ptzSelZoom') { //云台框选放大回调 errorCode==0 成功,否则errorCode是错误码
console.log('云台框选放大回调');
} else if (functionName == 'ptzPreset') { //云台预置点操作(需先启动预览)回调 errorCode==0 成功,否则errorCode是错误码
console.log('云台预置点操作(需先启动预览)');
} else if (functionName == 'ptzCruise') { //云台巡航操作,需先启动预览回调 errorCode==0 成功,否则errorCode是错误码
console.log('云台巡航操作,需先启动预览');
} else {
console.log('未处理的回调:', functionName, result);
}
},
setPlayConfig() {
/*
let playConfig = {
hardDecode: true,//使用硬解码 Android, iOS
privateData: true,//开启智能信息 Android, iOS
timeout : 30,//取流超时时间 默认20s Android, iOS
secretKey : ""// 码流解密key Android, iOS 没有不传
bufferLength: 5*1024*1024// 流缓冲区大小,默认为5M 格式:5*1024*1024 Android, iOS
ip : "",//设备ip Android, iOS
port : 8080,//端口号 Android, iOS
username : "",//设备用户名Android, iOS 没有不传
password : "",//设备密码 Android, iOS 没有不传
channelNum: 1,//播放通道号 Android, iOS 可选参数默认不传
qualityType : 0,//清晰度 0-主码流 1-子码流 Android, iOS 可选参数
deviceSerial : ""//萤石设备序列号 Android, iOS 可选参数
fetchStreamType : 0///// 取流方式 0-hpsclient 1-设备直连 2-npclient, 默认hpsclient取流 可选参数
waterConfigs : ["11111111",'22222222222'],// 水印信息 iOS
// waterConfig: {// 水印信息 Android
// isWaterTrans:5,
// waterFontWidth:40,
// waterFontHeight:15,
// userWaterContent: ['1111', '2222', '3333'],
// waterOffset: [{
// OffsetX: 11,
// OffsetY: 11
// },
// {
// OffsetX: 22,
// OffsetY: 22
// },
// {
// OffsetX: 44,
// OffsetY: 44
// }]
// }
};
*/
let playConfig = {
hardDecode: true,
privateData: true,
timeout: 30
};
this.$refs["hikVideo"].setPlayConfig(playConfig)
},
setPlayParam() {
let param = {
token: ''
};
this.$refs["hikVideo"].setPlayParam("rtsp://122.225.221.210:554/openUrl/vsignWFm9qM67810acc192b4bf2b4b8d",
param);
},
setPlayParam2() {
let endTime = this.getFormattedTimeWithOffset()
let startTime = this.getBeforeTime(endTime, 1)
startTime = "2025-11-25T17:04:00.195-08:00"
endTime = "2025-11-26T17:04:30.195-08:00"
console.log(`开始:${startTime}----结束:${endTime}`)
let param = {
token: "",
startTime: startTime,
endTime: endTime
};
this.$refs["hikVideo"].setPlayParam("rtsp://122.225.221.210:554/openUrl/vsigzIaIMPm7c69790c15be4dfbb22f6",
param);
},
//回放设置时间-按绝对时间回放定位
//1. 使⽤按绝对时间回放定位接⼝之前,必须先调⽤开始回放接⼝;
//2. 定位播放时,时间格式为'yyyy-MM-dd'T'HH:mm:ss.SSSZ'。
seekPlayback() {
let startTime = "2025-11-25T17:09:00.195-08:00";
this.$refs["hikVideo"].seekPlayback(startTime)
},
//暂停回放-暂停录像回放取流及解码播放。
pause() {
this.$refs["hikVideo"].pause()
},
//恢复回放-恢复录像回放取流及解码播放。
resume() {
this.$refs["hikVideo"].resume()
},
//设置回放倍数
setPlaybackSpeed(e) {
this.$refs["hikVideo"].setPlaybackSpeed(e)
},
startPlay() {
this.$refs["hikVideo"].startPlay()
},
stopPlay() {
this.$refs["hikVideo"].stopPlay()
},
pauseStream() {
this.$refs["hikVideo"].pauseStream()
},
resumeStream() {
this.$refs["hikVideo"].resumeStream()
},
changeStream() {
this.type = this.type == 0 ? 1 : 0;
this.$refs["hikVideo"].changeStream(this.type)
},
screenshootThumbnail() {
let time = new Date().getTime();
var fileName = time + ".jpg"
this.$refs["hikVideo"].screenshootThumbnail(fileName);
},
//开始录像
startRecord() {
let time = new Date().getTime();
var fileName = time + ".mp4"
let map = {
fileName: fileName
};
this.$refs["hikVideo"].startRecord(map)
},
//开始转码录像
startRecordAndConvert() {
let time = new Date().getTime();
var fileName = time + ".mp4"
let map = {
fileName: fileName
};
this.$refs["hikVideo"].startRecordAndConvert(map)
},
//停止录像
stopRecord() {
this.$refs["hikVideo"].stopRecord()
},
//播放录像
playFile() {
this.$refs["hikVideo"].playFile(this.path)
},
//获取播放录像的时长-- 播放成功后调⽤,否则返回-1;
getTotalTime() {
this.$refs["hikVideo"].getTotalTime();
},
//获取播放⽂件的已播放时⻓-播放成功后调⽤,否则返回-1;
getPlayedTime() {
this.$refs["hikVideo"].getPlayedTime();
},
//设置当前⽂件的播放进度百分⽐-播放百分⽐,取值范围 0-1.0
setCurrentFrame() {
this.$refs["hikVideo"].setCurrentFrame(0.5);
},
//========================语音对讲==========================
setVoiceDataSource() {
let map = {
token: ''
};
this.$refs["hikVideo"].setVoiceDataSource(
"rtsp://122.225.221.210:554/openUrl/vsigE7OZkMUee5f2f552f6b47068247f", map)
},
//开始对讲
startVoiceTalk() {
this.$refs["hikVideo"].startVoiceTalk();
},
//结束
stopVoiceTalk() {
this.$refs["hikVideo"].stopVoiceTalk();
},
//======================电子放大============================
openDigitalZoom() {
let currentA = {
left: 3,
top: 4,
right: 3,
bottom: 4
};
let originalA = {
left: 1,
top: 2,
right: 1,
bottom: 2
};
let param = {
originalA: originalA, //android
currentA: currentA, //android
original: "{{0, 0}, {300, 300}}", // iOS
current: "{{40, 40}, {300, 300}}", // iOS
};
this.$refs["hikVideo"].openDigitalZoom(param);
},
closeDigitalZoom() {
this.$refs["hikVideo"].closeDigitalZoom();
},
//=========================鱼眼=========================
setFishEyeEnable() { //开启预览后,设置是否开启⻥眼矫正效果;
this.$refs["hikVideo"].setFishEyeEnable(!this.fishEyeEnable);
},
//设置鱼眼矫正方式
setFishEyeMode() {
this.$refs["hikVideo"].setFishEyeMode(3, 0);
},
//
setOriginalFECParam() {
},
//处理⻥眼矫正参数
/// @param isZoom 是否缩放
/// @param zoom 缩放系数
/// @param zoom3D 3D缩放比例 android独有
/// @param curX 当前X坐标值 android独有
/// @param curY 当前Y坐标值 android独有
/// @param originalPoint ios独有
/// @param currentPoint ios独有
/// @param translationPoint ios独有
///1. ⻥眼最多⽀持4路;
//2. 电⼦放⼤和⻥眼不能同时开启。
handleFishEyeCorrect() {
let param = {
isZoom: false, // Android, iOS
zoom: 0.3, // Android, iOS
originalPoint: "{0, 1}", // iOS
currentPoint: "{4, 2}", // iOS
translationPoint: "{3.5, 22.2}", // iOS
zoom3D: 3.5, // Android
curX: 10.5, // Android
curY: 20.5 // Android
}
this.$refs["hikVideo"].handleFishEyeCorrect(param);
},
//获取帧率-获取成功返回码流帧率,获取失败返回-1。若码流中的帧率⼩于1,返回0。
getFrameRate() {
this.$refs["hikVideo"].getFrameRate();
},
// 设置预期帧率
// / 设置期望帧率(硬解不支持)
// / @param frameRate 帧率范围(1~码流最大帧率),播放成功后可以通过getFrameRate获取当前码流最大帧率
// 1. 此接⼝需要在播放成功后调⽤。
// 2. 设置的预期帧率⼤于实际码流帧率的时候⽆效。
// 3. 设置预期帧率⼩于1时⽆效。
// 4. 开启硬解时⽆效。
// 5. 此⽅法从V2.1.0版本开始⽀持。
setExpectedFrameRate() {
this.$refs["hikVideo"].setExpectedFrameRate(25);
},
getOSDTime() {
this.$refs["hikVideo"].getOSDTime();
},
//申请麦克风权限
requestRecordAudioPermission() {
HikVideoManger.requestRecordAudioPermission();
},
getFormattedTimeWithOffset() {
const date = new Date();
const timezoneOffset = -date.getTimezoneOffset();
const offsetHours = Math.floor(timezoneOffset / 60);
const offsetMinutes = timezoneOffset % 60;
// 克隆日期对象并添加时区偏移
const adjustedDate = new Date(date.getTime());
adjustedDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
// 获取ISO字符串并替换时区部分
const isoString = adjustedDate.toISOString();
return isoString.slice(0, -1) +
(offsetHours >= 0 ? '+' : '-') +
Math.abs(offsetHours).toString().padStart(2, '0') + ':' +
Math.abs(offsetMinutes).toString().padStart(2, '0');
},
getBeforeTime(isoString, hour) {
// 解析输入的时间字符串
const date = new Date(isoString);
// 验证输入是否有效
if (isNaN(date.getTime())) {
throw new Error('Invalid ISO 8601 format provided');
}
const targetHoursEarlier = new Date(date.getTime() - (hour * 60 * 60 * 1000));
// 提取时间组件
const year = targetHoursEarlier.getFullYear();
const month = `${targetHoursEarlier.getMonth() + 1}`.padStart(2, '0');
const day = `${targetHoursEarlier.getDate()}`.padStart(2, '0');
const hours = `${targetHoursEarlier.getHours()}`.padStart(2, '0');
const minutes = `${targetHoursEarlier.getMinutes()}`.padStart(2, '0');
const seconds = `${targetHoursEarlier.getSeconds()}`.padStart(2, '0');
const milliseconds = `${targetHoursEarlier.getMilliseconds()}`.padStart(3, '0');
// 获取时区偏移
const offset = targetHoursEarlier.getTimezoneOffset();
const offsetHours = Math.floor(Math.abs(offset) / 60).toString().padStart(2, '0');
const offsetMinutes = (Math.abs(offset) % 60).toString().padStart(2, '0');
const offsetSign = offset >= 0 ? '+' : '-';
// 组合结果字符串
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${offsetSign}${offsetHours}:${offsetMinutes}`;
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 750rpx;
}
.btn {
display: flex;
width: 600rpx;
height: 60rpx;
margin-top: 15rpx;
background-color: antiquewhite;
border-radius: 8rpx;
align-items: center;
justify-content: center;
}
.btn1 {
display: flex;
padding: 0 10rpx;
height: 60rpx;
margin-top: 15rpx;
background-color: antiquewhite;
border-radius: 8rpx;
align-items: center;
justify-content: center;
margin-right: 10rpx;
}
.row_view {
margin-top: 10rpx;
display: flex;
width: 750rpx;
flex-direction: row;
padding: 0 16rpx;
}
</style>
uni-app 接口说明
以下接口中,标注 异步 的需监听
@actionCallback;未标注的为 void 方法,无返回值。
初始化
setPlayConfig(playConfig)
| 参数 | 类型 | 必填 | 说明 | 平台 |
|---|---|---|---|---|
| hardDecode | Boolean | 否 | 硬解码,默认 true | Android、iOS |
| privateData | Boolean | 否 | 智能信息,默认 true | Android、iOS |
| timeout | Number | 否 | 取流超时(秒),默认 20 | Android、iOS |
| secretKey | String | 否 | 码流解密密钥;萤石设备为验证码 | Android、iOS |
| bufferLength | Number | 否 | 流缓冲区,默认 5M | Android、iOS |
| ip / port / username / password | — | 否 | 设备直连参数 | Android、iOS |
| channelNum | Number | 否 | 播放通道号 | Android、iOS |
| qualityType | Number | 否 | 0 主码流 / 1 子码流 | Android、iOS |
| deviceSerial | String | 否 | 萤石设备序列号 | Android、iOS |
| fetchStreamType | Number | 否 | 0 hpsclient / 1 设备直连 / 2 npclient | Android、iOS |
| waterConfigs | Array | 否 | 水印信息 | iOS |
| waterConfig | Map | 否 | 水印信息(含 isWaterTrans、userWaterContent、waterOffset 等) | Android |
视频播放
| 方法 | 说明 |
|---|---|
setPlayParam(url, headers) |
设置取流 URL 及请求头 |
startPlay() |
开始预览或回放 |
stopPlay() |
停止播放 |
pauseStream() |
暂停取流 |
resumeStream() |
恢复取流 |
changeStream(qualityType) |
平滑切换码流,0 主码流 / 1 标清 / 2 低清 |
网络录像回放
| 方法 | 说明 | 返回 |
|---|---|---|
seekPlayback(seekTime) |
绝对时间定位,需先 startPlay | — |
getOSDTime() |
当前回放时间戳(毫秒) | 异步 |
pause() / resume() |
暂停 / 恢复回放 | — |
setPlaybackSpeed(speed) |
倍速:-2(0.25x) / -1(0.5x) / 1 / 2 / 4 / 8 / 16 | — |
语音对讲
| 方法 | 说明 |
|---|---|
setVoiceDataSource(url, headers) |
设置对讲 URL |
startVoiceTalk() |
开启对讲 → voiceTalkCallback |
stopVoiceTalk() |
停止对讲 |
抓图 / 录像
| 方法 | 说明 | 返回 |
|---|---|---|
screenshootThumbnail(fileName) |
抓图保存至本地 | 异步,返回 fullPath |
startRecord({ fileName }) |
开始录像 | 异步 |
startRecordAndConvert({ fileName }) |
开始录像并转 MP4 | 异步 |
stopRecord() |
停止录像 | 异步 |
声音 / 电子放大 / 鱼眼 / 本地播放 / 帧率 / 云台
| 方法 | 说明 | 返回 |
|---|---|---|
enableAudio(enable) |
开关声音 | — |
openDigitalZoom(map) |
Android 用 originalA/currentA;iOS 用 original/current 字符串 | 异步 |
closeDigitalZoom() |
关闭电子放大 | 异步 |
setFishEyeEnable(enable) |
开关鱼眼矫正 | 异步 |
setFishEyeMode(correctType, placeType) |
设置矫正方式 | 异步 |
setOriginalFECParam(x, y, w, h) |
初始 PTZ(Android) | — |
handleFishEyeCorrect(map) |
鱼眼手势,Android/iOS 参数不同 | 异步 |
playFile(path) |
播放本地文件 | — |
getTotalTime() / getPlayedTime() |
总时长 / 已播时长(秒) | 异步 |
setCurrentFrame(scale) |
进度 0~1.0 | 异步 |
getFrameRate() |
码流帧率 | 异步 |
setExpectedFrameRate(rate) |
预期帧率(硬解不支持) | 异步 |
setDecodeThreadNum(num) |
解码线程 1~8(硬解不支持) | 异步 |
ptzControl(action, command, speed) |
云台控制,需先预览 | 异步 |
ptzSelZoom(v1, v2, v3, v4) |
框选放大 | 异步 |
ptzPreset(cmd, index) |
预置点 | 异步 |
ptzCruise(cmd, index) |
巡航 | 异步 |
uni-app x 项目集成
适用于 uni-app x 的 uvue 项目。组件标签为
ytx-hikvideo(注意不是yt-hikvideo),接口同步返回结果,无@actionCallback事件。
集成步骤
- 在 DCloud 插件市场 购买并绑定项目。
- 在
manifest.json→ App 原生插件配置 中勾选本插件。 - 在 uvue 页面中使用组件:
<ytx-hikvideo
ref="hikVideo"
@playStatusCallback="playStatusCallback"
@voiceTalkCallback="voiceTalkCallback"
></ytx-hikvideo>
- 页面
onLoad中初始化 SDK:
import * as HikVideoManger from '@/uni_modules/yt-hikvideo'
onLoad() {
HikVideoManger.initHikSDK()
}
- 通过
(this.$refs["hikVideo"] as YtxHikvideoElement)调用组件方法。 - 打包自定义基座或云打包后,在真机调试。
与 uni-app 的核心差异
| 对比项 | uni-app x | uni-app |
|---|---|---|
| 组件标签 | ytx-hikvideo |
yt-hikvideo |
| 返回值 | 方法同步返回 | @actionCallback 异步返回 |
| 抓图 | screenshootThumbnail({ fileName }) |
screenshootThumbnail(fileName) |
| Map 参数 | Android 用 Map,iOS 用普通对象 |
均用普通对象 |
| 回调 | 仅 playStatusCallback、voiceTalkCallback |
另有 actionCallback |
回调事件
uni-app x 不含 actionCallback,播放状态与对讲状态通过以下两个事件回调:
playStatusCallback — 播放状态
| status | 说明 |
|---|---|
| 0 | 播放成功 |
| 1 | 播放失败 |
| 2 | 取流异常 |
| 3 | 播放结束(录像回放完成) |
- iOS: 参数在
res.detail中 - Android: 参数为
Map<string, any>,通过e.get("status")读取
voiceTalkCallback — 语音对讲状态
| status | 说明 |
|---|---|
| 0 | 开启对讲成功 |
| 1 | 开启对讲失败 |
| 2 | 取流异常 |
- iOS: 参数在
res.detail中 - Android: 参数为
Map<string, any>
错误码
errorCode仅在 status 为 1 或 2 时有值,具体含义请参考海康 SDK 文档。
完整示例代码(uni-app x / uvue)
以下为 uni-app x 项目完整 Demo 页面,覆盖插件全部接口。页面需保存为 uvue 文件(如 pages/hikvideo/demo.uvue)。
注意:
onLoad中需调用HikVideoManger.initHikSDK()初始化 SDK- 组件标签为
ytx-hikvideo,方法通过YtxHikvideoElement强类型调用- 无
@actionCallback,抓图/录像等结果直接从方法返回值获取- Android 与 iOS 部分参数类型不同,示例中使用
#ifdef APP-ANDROID/#ifdef APP-IOS区分
<template>
<view class="content">
<view class="video_bg" style="width: 750rpx;height: 500rpx;background-color: black;">
<ytx-hikvideo ref="hikVideo" style="width: 750rpx;height: 500rpx;" @playStatusCallback="playStatusCallback"
@voiceTalkCallback="voiceTalkCallback"></ytx-hikvideo>
</view>
<!-- <image :src="path" style="width: 750rpx;height: 300rpx;background-color: aquamarine;" mode="aspectFit"></image> -->
<view class="row_view">
<view class="btn1" @click="setPlayConfig"><text>播放设置配置</text></view>
<view class="btn1" @click="setPlayParam"><text>设置播放参数</text></view>
<view class="btn1" @click="startPlay"><text>开始(预览/回放)</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="stopPlay"><text>停止预览/回放</text></view>
<view class="btn1" @click="pauseStream"><text>暂停取流(预览/回放)</text></view>
<view class="btn1" @click="resumeStream"><text>恢复取流(预览/回放)</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="changeStream"><text>切换码流</text></view>
<view class="btn1" @click="setPlayParam2"><text>设置回放播放参数</text></view>
<view class="btn1" @click="screenshootThumbnail"><text>预览/回放抓图</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="seekPlayback"><text>按时间回放定位</text></view>
<view class="btn1" @click="pause"><text>暂停回放</text></view>
<view class="btn1" @click="resume"><text>恢复回放</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setPlaybackSpeed(-2)"><text>回放倍数-2</text></view>
<view class="btn1" @click="setPlaybackSpeed(-1)"><text>回放倍数-1</text></view>
<view class="btn1" @click="setPlaybackSpeed(1)"><text>回放倍数1</text></view>
<view class="btn1" @click="setPlaybackSpeed(2)"><text>回放倍数2</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="startRecord"><text>开始录像</text></view>
<view class="btn1" @click="startRecordAndConvert"><text>开始转码录像</text></view>
<view class="btn1" @click="stopRecord"><text>停止录像</text></view>
<view class="btn1" @click="playFile"><text>播放录像</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="getTotalTime"><text>获取录像总时长</text></view>
<view class="btn1" @click="getPlayedTime"><text>获取已播放时长</text></view>
<view class="btn1" @click="setCurrentFrame"><text>设置播放进度</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setVoiceDataSource"><text>设置语⾳对讲参数</text></view>
<view class="btn1" @click="startVoiceTalk"><text>开启对讲</text></view>
<view class="btn1" @click="stopVoiceTalk"><text>关闭对讲</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="openDigitalZoom"><text>开启电子放大</text></view>
<view class="btn1" @click="closeDigitalZoom"><text>关闭电子放大</text></view>
<view class="btn1" @click="setFishEyeEnable"><text>开/关鱼眼</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setFishEyeMode"><text>⻥眼矫正⽅式</text></view>
<view class="btn1" @click="handleFishEyeCorrect"><text>处理⻥眼矫正参数</text></view>
<view class="btn1" @click="getFrameRate"><text>获取帧率</text></view>
</view>
<view class="row_view">
<view class="btn1" @click="setExpectedFrameRate"><text> 设置预期帧率</text></view>
</view>
</view>
</template>
<script>
import *as HikVideoManger from '@/uni_modules/yt-hikvideo'
export default {
data() {
return {
title: 'Hello',
type: 1,
path: '/var/mobile/Containers/Data/Application/0349719B-D339-4C8F-97D7-B8C1F1A1E8B9/Documents/uni-app-x/apps/__UNI__798EC0C/1765190848716.mp4',
fishEyeEnable: false//是否开启鱼眼
}
},
onLoad() {
HikVideoManger.initHikSDK()
},
methods: {
//实时预览|回放|本地录播播放回调
// #ifdef APP-IOS
playStatusCallback(res) {
console.log(res.detail);
let status = res.detail.status ?? 1;
////错误码,只有 FAILED 和 EXCEPTION 才有值 返回的错误码可自行去海康咨询
let errorCode = res.detail.errorCode ?? "";
if (status == 0) {//播放成功
} else if (status == 1) {//播放失败
} else if (status == 2) {//取流异常
} else if (status == 3) {//FINISH(录像回放成功)
}
console.log(`状态码:${status} 错误码:${errorCode}`);
},
// #endif
// #ifdef APP-ANDROID
playStatusCallback(e : Map<string, any>) {
console.log(e);
let status = e.get("status") ?? 1
let errorCode = e.get("errorCode") ?? ""////错误码,只有 FAILED 和 EXCEPTION 才有值 返回的错误码可自行去海康咨询
if (status == 0) {//播放成功
} else if (status == 1) {//播放失败
} else if (status == 2) {//取流异常
} else if (status == 3) {//FINISH(录像回放成功)
}
},
// #endif
// #ifdef APP-IOS
voiceTalkCallback(res) {
console.log(e);
let status = res.detail.status ?? 1;
////错误码,只有 FAILED 和 EXCEPTION 才有值 返回的错误码可自行去海康咨询
let errorCode = res.detail.errorCode ?? "";
if (status == 0) {//开启对讲成功
} else if (status == 1) {//(开启对讲失败
} else if (status == 2) {//取流异常
}
console.log(`状态码:${status} 错误码:${errorCode}`);
},
// #endif
// #ifdef APP-ANDROID
//对讲回调
voiceTalkCallback(e : Map<string, any>) {
console.log(e);
let status = e.get("status") ?? 1
let errorCode = e.get("errorCode") ?? ""//错误码,只有 FAILED 和 EXCEPTION 才有值 返回的错误码可自行去海康咨询
if (status == 0) {//开启对讲成功
} else if (status == 1) {//(开启对讲失败
} else if (status == 2) {//取流异常
}
},
// #endif
//预览先调用
setPlayConfig() {
/*
let playConfig = {
hardDecode: true,//使用硬解码 Android, iOS
privateData: true,//开启智能信息 Android, iOS
timeout : 30,//取流超时时间 默认20s Android, iOS
secretKey : ""// 码流解密key Android, iOS 没有不传
bufferLength: 5*1024*1024// 流缓冲区大小,默认为5M 格式:5*1024*1024 Android, iOS
ip : "",//设备ip Android, iOS
port : 8080,//端口号 Android, iOS
username : "",//设备用户名Android, iOS 没有不传
password : "",//设备密码 Android, iOS 没有不传
channelNum: 1,//播放通道号 Android, iOS 可选参数默认不传
qualityType : 0,//清晰度 0-主码流 1-子码流 Android, iOS 可选参数
deviceSerial : ""//萤石设备序列号 Android, iOS 可选参数
fetchStreamType : 0///// 取流方式 0-hpsclient 1-设备直连 2-npclient, 默认hpsclient取流 可选参数
waterConfigs : ["11111111",'22222222222'],// 水印信息 iOS
// waterConfig: {// 水印信息 Android
// isWaterTrans:5,
// waterFontWidth:40,
// waterFontHeight:15,
// userWaterContent: ['1111', '2222', '3333'],
// waterOffset: [{
// OffsetX: 11,
// OffsetY: 11
// },
// {
// OffsetX: 22,
// OffsetY: 22
// },
// {
// OffsetX: 44,
// OffsetY: 44
// }]
// }
};
*/
// #ifdef APP-ANDROID
let playConfig = new Map<string, any>()
playConfig.set("hardDecode", true)//使用硬解码 Android, iOS
playConfig.set("privateData", true);//开启智能信息 Android, iOS
(this.$refs["hikVideo"] as YtxHikvideoElement).setPlayConfig(playConfig)
// #endif
// #ifdef APP-IOS
let playConfig = {
hardDecode: true,
privateData: true
};
(this.$refs["hikVideo"] as YtxHikvideoElement).setPlayConfig(playConfig)
// #endif
},
setPlayParam() {
// #ifdef APP-ANDROID
let map : Map<string, string> = new Map();
map.set("token", "");
(this.$refs["hikVideo"] as YtxHikvideoElement).setPlayParam("rtsp://122.225.221.210:554/openUrl/vsigAV2dJjq786a1522aca44b5a9e9f8", map)
// #endif
// #ifdef APP-IOS
let map = {
token: ""
};
(this.$refs["hikVideo"] as YtxHikvideoElement).setPlayParam("rtsp://122.225.221.210:554/openUrl/vsigAU1cMr6cf31ee51f96e484fa62b9", map)
// #endif
},
setPlayParam2() {
let endTime = this.getFormattedTimeWithOffset()
let startTime = this.getBeforeTime(endTime, 1);
startTime = "2025-11-25T17:04:00.195-08:00"
endTime = "2025-11-26T17:04:30.195-08:00";
console.log(`开始:${startTime}----结束:${endTime}`)
// #ifdef APP-ANDROID
let map : Map<string, string> = new Map();
map.set("token", "");
map.set("startTime", startTime);
map.set("endTime", endTime);
(this.$refs["hikVideo"] as YtxHikvideoElement).setPlayParam("rtsp://122.225.221.210:554/openUrl/vsiglDNtc1aed4e885a8e704b70be75e", map)
// #endif
// #ifdef APP-IOS
let map = {
token: "",
startTime: startTime,
endTime: endTime
};
(this.$refs["hikVideo"] as YtxHikvideoElement).setPlayParam("rtsp://122.225.221.210:554/openUrl/vsiglDNtc1aed4e885a8e704b70be75e", map)
// #endif
},
//回放设置时间-按绝对时间回放定位
//1. 使⽤按绝对时间回放定位接⼝之前,必须先调⽤开始回放接⼝;
//2. 定位播放时,时间格式为'yyyy-MM-dd'T'HH:mm:ss.SSSZ'。
seekPlayback() {
let startTime : string = "2025-11-25T17:09:00.195-08:00";
(this.$refs["hikVideo"] as YtxHikvideoElement).seekPlayback(startTime)
},
//暂停回放-暂停录像回放取流及解码播放。
pause() {
(this.$refs["hikVideo"] as YtxHikvideoElement).pause()
},
//恢复回放-恢复录像回放取流及解码播放。
resume() {
(this.$refs["hikVideo"] as YtxHikvideoElement).resume()
},
//设置回放倍数
setPlaybackSpeed(e : number) {
let flag = (this.$refs["hikVideo"] as YtxHikvideoElement).setPlaybackSpeed(e)
console.log(`setPlaybackSpeed:${flag}`);
},
//开始实时预览 || 网络录像回放
startPlay() {
(this.$refs["hikVideo"] as YtxHikvideoElement).startPlay()
},
//停止实时预览 || 网络录像回放
stopPlay() {
(this.$refs["hikVideo"] as YtxHikvideoElement).stopPlay()
},
//暂停取流
pauseStream() {
(this.$refs["hikVideo"] as YtxHikvideoElement).pauseStream()
},
//恢复取流
resumeStream() {
(this.$refs["hikVideo"] as YtxHikvideoElement).resumeStream()
},
//平滑切换码流
changeStream() {
this.type = this.type == 0 ? 1 : 0;
(this.$refs["hikVideo"] as YtxHikvideoElement).changeStream(this.type)
},
//抓图
screenshootThumbnail() {
let time = new Date().getTime();
var fileName = time + ".jpg"
let flag : Map<string, any>;
// #ifdef APP-ANDROID
let map = new Map<string, string>()
map.set("fileName", fileName)
flag = (this.$refs["hikVideo"] as YtxHikvideoElement).screenshootThumbnail(map)
// #endif
// #ifdef APP-IOS
let map = {
fileName: fileName
};
flag = (this.$refs["hikVideo"] as YtxHikvideoElement).screenshootThumbnail(map)
// #endif
console.log(flag);
let errorCode : number = flag["errorCode"] as number;
if (errorCode == 0) {
let fullPath : string = flag["fullPath"] as string;
this.path = fullPath;
} else {
uni.showToast({
title: '抓图失败',
icon: 'none'
})
}
},
//开始录像
startRecord() {
let time = new Date().getTime();
var fileName = time + ".mp4"
// #ifdef APP-ANDROID
let map : Map<string, string> = new Map();
map.set("fileName", fileName);
let flag : Map<string, any> = (this.$refs["hikVideo"] as YtxHikvideoElement).startRecord(map)
console.log(flag);
let errorCode : number = flag["errorCode"] as number;
if (errorCode == 0) {
let fullPath : string = flag["fullPath"] as string;
this.path = fullPath;
console.log(`录像地址:${fullPath}`)
} else {
uni.showToast({
title: '录制失败',
icon: 'none'
})
}
// #endif
// #ifdef APP-IOS
let map = {
fileName: fileName
};
let flag : Map<string, any> = (this.$refs["hikVideo"] as YtxHikvideoElement).startRecord(map)
console.log(flag);
let errorCode : number = flag["errorCode"] as number;
if (errorCode == 0) {
let fullPath : string = flag["fullPath"] as string;
this.path = fullPath;
console.log(`录像地址:${fullPath}`)
} else {
uni.showToast({
title: '录制失败',
icon: 'none'
})
}
// #endif
},
//开始转码录像
startRecordAndConvert() {
let time = new Date().getTime();
var fileName = time + ".mp4"
// #ifdef APP-ANDROID
let map : Map<string, string> = new Map();
map.set("fileName", fileName);
let flag : Map<string, any> = (this.$refs["hikVideo"] as YtxHikvideoElement).startRecordAndConvert(map)
console.log(flag);
let errorCode : number = flag["errorCode"] as number;
if (errorCode == 0) {
let fullPath : string = flag["fullPath"] as string;
this.path = fullPath;
console.log(`录像地址:${fullPath}`)
} else {
uni.showToast({
title: '录制失败',
icon: 'none'
})
}
// #endif
// #ifdef APP-IOS
let map = {
fileName: fileName
};
let flag : Map<string, any> = (this.$refs["hikVideo"] as YtxHikvideoElement).startRecordAndConvert(map)
console.log(flag);
let errorCode : number = flag["errorCode"] as number;
if (errorCode == 0) {
let fullPath : string = flag["fullPath"] as string;
this.path = fullPath;
console.log(`录像地址:${fullPath}`)
} else {
uni.showToast({
title: '录制失败',
icon: 'none'
})
}
// #endif
},
//停止录像
stopRecord() {
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).stopRecord()
let v = "停止录制失败";
if (flag == 0) {
v = "停止录制成功"
}
uni.showToast({
title: v,
icon: 'none'
})
},
//播放录像
playFile() {
(this.$refs["hikVideo"] as YtxHikvideoElement).playFile(this.path)
},
//获取播放录像的时长-- 播放成功后调⽤,否则返回-1;
getTotalTime() {
let time : number = (this.$refs["hikVideo"] as YtxHikvideoElement).getTotalTime();
console.log(`播放视频总时长:${time}`)
},
//获取播放⽂件的已播放时⻓-播放成功后调⽤,否则返回-1;
getPlayedTime() {
let time : number = (this.$refs["hikVideo"] as YtxHikvideoElement).getPlayedTime();
console.log(`已播放时⻓:${time}`)
},
//设置当前⽂件的播放进度百分⽐-播放百分⽐,取值范围 0-1.0
setCurrentFrame() {
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).setCurrentFrame(0.5);
console.log(flag == 0 ? '设置成功' : '设置失败')
},
//========================语音对讲==========================
setVoiceDataSource() {
// #ifdef APP-ANDROID
let map : Map<string, string> = new Map();
map.set("token", "");
(this.$refs["hikVideo"] as YtxHikvideoElement).setVoiceDataSource("rtsp://122.225.221.210:554/openUrl/vsigE7OZkMUee5f2f552f6b47068247f", map)
// #endif
// #ifdef APP-IOS
let map = {
token: ""
};
(this.$refs["hikVideo"] as YtxHikvideoElement).setVoiceDataSource("rtsp://122.225.221.210:554/openUrl/vsigE7OZkMUee5f2f552f6b47068247f", map)
// #endif
},
//开始对讲
startVoiceTalk() {
(this.$refs["hikVideo"] as YtxHikvideoElement).startVoiceTalk();
},
//结束
stopVoiceTalk() {
(this.$refs["hikVideo"] as YtxHikvideoElement).stopVoiceTalk();
},
//======================电子放大============================
openDigitalZoom() {
// #ifdef APP-ANDROID
let param : Map<string, any> = new Map();
let originalADict : Map<string, any> = new Map();
originalADict.set("left", 1);
originalADict.set("top", 2);
originalADict.set("right", 1);
originalADict.set("bottom", 2);
let currentADict : Map<string, any> = new Map();
currentADict.set("left", 3);
currentADict.set("top", 4);
currentADict.set("right", 3);
currentADict.set("bottom", 4);
param.set("originalA", originalADict);
param.set("currentA", currentADict);
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).openDigitalZoom(param);
console.log(flag)
// #endif
// #ifdef APP-IOS
let param = {
original: "{{0, 0}, {300, 300}}",// iOS
current: "{{40, 40}, {300, 300}}",// iOS
};
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).openDigitalZoom(param);
console.log(flag)
// #endif
},
closeDigitalZoom() {
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).closeDigitalZoom();
console.log(flag == 0 ? '关闭成功' : '关闭失败')
},
//=========================鱼眼=========================
setFishEyeEnable() {//开启预览后,设置是否开启⻥眼矫正效果;
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).setFishEyeEnable(!this.fishEyeEnable);
console.log(`开关鱼眼:${flag}`)
},
//设置鱼眼矫正方式
setFishEyeMode() {
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).setFishEyeMode(3, 0);
console.log(`设置鱼眼矫正方式:${flag}`)
},
//
setOriginalFECParam() {
},
//处理⻥眼矫正参数
/// @param isZoom 是否缩放
/// @param zoom 缩放系数
/// @param zoom3D 3D缩放比例
/// @param curX 当前X坐标值
/// @param curY 当前Y坐标值
///1. ⻥眼最多⽀持4路;
//2. 电⼦放⼤和⻥眼不能同时开启。
handleFishEyeCorrect() {
// #ifdef APP-ANDROID
let param : Map<string, any> = new Map();
param.set("isZoom", false);// Android, iOS
param.set("zoom", 0.3);// Android, iOS
param.set("zoom3D", 3.5);// Android
param.set("curX", 10.5);// Android
param.set("curY", 20.5);// Android
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).handleFishEyeCorrect(param);
console.log(`处理⻥眼矫正参数:${flag}`);
// #endif
// #ifdef APP-IOS
let param = {
isZoom: false,// Android, iOS
zoom: 0.3,// Android, iOS
originalPoint: "{0, 1}",// iOS
currentPoint: "{4, 2}",// iOS
translationPoint: "{3.5, 22.2}"// iOS
}
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).handleFishEyeCorrect(param);
console.log(`处理⻥眼矫正参数:${flag}`);
// #endif
},
//获取帧率-获取成功返回码流帧率,获取失败返回-1。若码流中的帧率⼩于1,返回0。
getFrameRate() {
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).getFrameRate();
console.log(`获取帧率:${flag}`);
},
// 设置预期帧率
// / 设置期望帧率(硬解不支持)
// / @param frameRate 帧率范围(1~码流最大帧率),播放成功后可以通过getFrameRate获取当前码流最大帧率
// 1. 此接⼝需要在播放成功后调⽤。
// 2. 设置的预期帧率⼤于实际码流帧率的时候⽆效。
// 3. 设置预期帧率⼩于1时⽆效。
// 4. 开启硬解时⽆效。
// 5. 此⽅法从V2.1.0版本开始⽀持。
setExpectedFrameRate() {
let flag : number = (this.$refs["hikVideo"] as YtxHikvideoElement).setExpectedFrameRate(60);
console.log(`设置预期帧率:${flag}`);
},
getFormattedTimeWithOffset() {
const date = new Date();
const timezoneOffset = -date.getTimezoneOffset();
const offsetHours = Math.floor(timezoneOffset / 60);
const offsetMinutes = timezoneOffset % 60;
// 克隆日期对象并添加时区偏移
const adjustedDate = new Date(date.getTime());
adjustedDate.setMinutes(date.getMinutes() + date.getTimezoneOffset());
// 获取ISO字符串并替换时区部分
const isoString = adjustedDate.toISOString();
return isoString.slice(0, -1) +
(offsetHours >= 0 ? '+' : '-') +
Math.abs(offsetHours).toString().padStart(2, '0') + ':' +
Math.abs(offsetMinutes).toString().padStart(2, '0');
},
getBeforeTime(isoString : string, hour : number) {
// 解析输入的时间字符串
const date = new Date(isoString);
// 验证输入是否有效
if (isNaN(date.getTime())) {
throw new Error('Invalid ISO 8601 format provided');
}
const targetHoursEarlier = new Date(date.getTime() - (hour * 60 * 60 * 1000));
// 提取时间组件
const year = targetHoursEarlier.getFullYear();
const month = `${targetHoursEarlier.getMonth() + 1}`.padStart(2, '0');
const day = `${targetHoursEarlier.getDate()}`.padStart(2, '0');
const hours = `${targetHoursEarlier.getHours()}`.padStart(2, '0');
const minutes = `${targetHoursEarlier.getMinutes()}`.padStart(2, '0');
const seconds = `${targetHoursEarlier.getSeconds()}`.padStart(2, '0');
const milliseconds = `${targetHoursEarlier.getMilliseconds()}`.padStart(3, '0');
// 获取时区偏移
const offset = targetHoursEarlier.getTimezoneOffset();
const offsetHours = Math.floor(Math.abs(offset) / 60).toString().padStart(2, '0');
const offsetMinutes = (Math.abs(offset) % 60).toString().padStart(2, '0');
const offsetSign = offset >= 0 ? '+' : '-';
// 组合结果字符串
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}${offsetSign}${offsetHours}:${offsetMinutes}`;
}
}
}
</script>
<style>
.content {
width: 750rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.btn {
display: flex;
width: 600rpx;
height: 60rpx;
margin-top: 15rpx;
background-color: antiquewhite;
border-radius: 8rpx;
align-items: center;
justify-content: center;
}
.btn1 {
display: flex;
padding: 0 10rpx;
height: 60rpx;
margin-top: 15rpx;
background-color: antiquewhite;
border-radius: 8rpx;
align-items: center;
justify-content: center;
margin-right: 10rpx;
}
.row_view {
margin-top: 10rpx;
display: flex;
width: 750rpx;
flex-direction: row;
padding: 0 16rpx;
}
</style>
同步返回值说明
以下接口调用后直接返回结果(0 或 '0' 表示成功,-1 表示失败):
| 方法 | 返回类型 | 说明 |
|---|---|---|
screenshootThumbnail(map) |
Map<string, any> |
含 errorCode、fullPath |
startRecord(map) |
Map<string, any> |
含 errorCode、fullPath |
startRecordAndConvert(map) |
Map<string, any> |
含 errorCode、fullPath |
stopRecord() |
number |
0 成功 |
getOSDTime() |
number |
回放时间戳(毫秒),-1 失败 |
getTotalTime() |
number |
总时长(秒) |
getPlayedTime() |
number |
已播时长(秒) |
setCurrentFrame(scale) |
number |
0 成功 |
openDigitalZoom(map) |
number |
0 成功 |
closeDigitalZoom() |
number |
0 成功 |
setFishEyeEnable(enable) |
number |
0 成功 |
setFishEyeMode(a, b) |
number |
0 成功 |
handleFishEyeCorrect(map) |
number |
0 成功 |
getFrameRate() |
number |
帧率,-1 失败 |
setExpectedFrameRate(rate) |
number |
0 成功 |
setDecodeThreadNum(num) |
number |
0 成功 |
ptzControl(...) 等云台接口 |
number |
0 成功 |
Map 返回值读取示例(Android / iOS 通用):
let flag = (this.$refs["hikVideo"] as YtxHikvideoElement).screenshootThumbnail(map)
let errorCode = flag["errorCode"] as number
if (errorCode == 0) {
let fullPath = flag["fullPath"] as string
}
平台参数差异
部分接口在 Android 与 iOS 上参数类型不同,需使用条件编译:
| 接口 | Android | iOS |
|---|---|---|
setPlayConfig |
Map<string, any> |
普通对象 { hardDecode, privateData, ... } |
setPlayParam headers |
Map<string, string> |
普通对象 { token, startTime, endTime } |
screenshootThumbnail |
Map 含 fileName |
对象 { fileName } |
startRecord 等录像 |
Map 含 fileName |
对象 { fileName } |
openDigitalZoom |
originalA / currentA(Rect Map) | original / current 字符串 |
handleFishEyeCorrect |
isZoom, zoom, zoom3D, curX, curY | isZoom, zoom, originalPoint, currentPoint, translationPoint |
uni-app x 接口说明
以下接口均为同步调用,标注返回类型的方法直接接收返回值。参数说明与 uni-app 相同,见 公共参数说明。
视频播放
| 方法 | 返回 | 说明 |
|---|---|---|
setPlayConfig(playConfig) |
void | Android 传 Map,iOS 传对象 |
setPlayParam(url, headers) |
void | Android headers 为 Map,iOS 为对象 |
startPlay() |
void | 开始预览或回放 |
stopPlay() |
void | 停止播放 |
pauseStream() |
void | 暂停取流 |
resumeStream() |
void | 恢复取流 |
changeStream(qualityType) |
void | 平滑切换码流 |
网络录像回放
| 方法 | 返回 | 说明 |
|---|---|---|
seekPlayback(seekTime) |
void | 绝对时间定位 |
getOSDTime() |
number | 回放时间戳(毫秒),-1 失败 |
pause() / resume() |
void | 暂停 / 恢复 |
setPlaybackSpeed(speed) |
void | 倍速:-2 / -1 / 1 / 2 / 4 / 8 / 16 |
语音对讲
| 方法 | 返回 | 说明 |
|---|---|---|
setVoiceDataSource(url, headers) |
void | 设置对讲 URL |
startVoiceTalk() |
void | 开启对讲 → voiceTalkCallback |
stopVoiceTalk() |
void | 停止对讲 |
抓图 / 录像
| 方法 | 返回 | 说明 |
|---|---|---|
screenshootThumbnail(map) |
Map | { fileName },返回 errorCode、fullPath |
startRecord(map) |
Map | 开始录像 |
startRecordAndConvert(map) |
Map | 录像并转 MP4 |
stopRecord() |
number | 0 成功 |
声音 / 电子放大 / 鱼眼 / 本地播放 / 帧率 / 云台
| 方法 | 返回 | 说明 |
|---|---|---|
enableAudio(enable) |
void | 开关声音 |
playFile(path) |
void | 播放本地文件 |
getTotalTime() |
number | 总时长(秒) |
getPlayedTime() |
number | 已播时长(秒) |
setCurrentFrame(scale) |
number | 进度 0~1.0 |
openDigitalZoom(map) |
number | Android/iOS 参数不同 |
closeDigitalZoom() |
number | 关闭电子放大 |
setFishEyeEnable(enable) |
number | 开关鱼眼 |
setFishEyeMode(correctType, placeType) |
number | 矫正方式 |
setOriginalFECParam(x, y, w, h) |
void | 初始 PTZ(Android) |
handleFishEyeCorrect(map) |
number | 鱼眼手势 |
getFrameRate() |
number | 码流帧率 |
setExpectedFrameRate(rate) |
number | 预期帧率(硬解不支持) |
setDecodeThreadNum(num) |
number | 解码线程 1~8 |
ptzControl(action, command, speed) |
number | 云台控制 |
ptzSelZoom(v1, v2, v3, v4) |
number | 框选放大 |
ptzPreset(cmd, index) |
number | 预置点 |
ptzCruise(cmd, index) |
number | 巡航 |
公共参数说明
以下参数在两个项目中通用,供查阅。
setPlayConfig 完整参数
| 参数 | 类型 | 必填 | 说明 | 平台 |
|---|---|---|---|---|
| hardDecode | Boolean | 否 | 硬解码,默认 true | Android、iOS |
| privateData | Boolean | 否 | 智能信息,默认 true | Android、iOS |
| timeout | Number | 否 | 取流超时(秒),默认 20 | Android、iOS |
| secretKey | String | 否 | 码流解密密钥 | Android、iOS |
| bufferLength | Number | 否 | 流缓冲区,默认 5M | Android、iOS |
| ip | String | 否 | 设备 IP | Android、iOS |
| port | Number | 否 | 设备端口 | Android、iOS |
| username | String | 否 | 设备用户名 | Android、iOS |
| password | String | 否 | 设备密码 | Android、iOS |
| channelNum | Number | 否 | 播放通道号 | Android、iOS |
| qualityType | Number | 否 | 0 主码流 / 1 子码流 | Android、iOS |
| deviceSerial | String | 否 | 萤石设备序列号 | Android、iOS |
| fetchStreamType | Number | 否 | 0 hpsclient / 1 设备直连 / 2 npclient | Android、iOS |
| waterConfigs | Array | 否 | 水印信息 | iOS |
| waterConfig | Map | 否 | 水印信息 | Android |
电子放大参数
Android openDigitalZoom:
{
originalA: { left: 0, top: 0, right: 100, bottom: 100 },
currentA: { left: 25, top: 25, right: 75, bottom: 75 }
}
iOS openDigitalZoom:
{
original: '{{0, 0}, {100, 100}}',
current: '{{25, 25}, {50, 50}}'
}
鱼眼参数
correctType: 0 PTZ / 1 180° / 2 360° / 3 LAT / 4 SEM / 5 CYC / 6 PLA / 7 CYC_SPL
placeType: 1 壁装 / 2 地装 / 3 顶装
Android handleFishEyeCorrect: { isZoom, zoom, zoom3D, curX, curY }
iOS handleFishEyeCorrect: { isZoom, zoom, originalPoint, currentPoint, translationPoint }
鱼眼最多支持 4 路;电子放大与鱼眼不能同时开启。
更多插件推荐
- 高德定位连续定位后台定位保活定位
- 百度汽车摩托车导航插件
- 百度鹰眼轨迹插件支持后台采集、保活
- 百度定位插件、连续定位、保活、坐标系转换、支持双端
- 【科大讯飞】离线语音合成(新版)插件
- 计步器插件,支持 Android、iOS 双端
- uts 经典蓝牙插件、蓝牙电子秤
- 获取唯一标识、ServiceID、卸载更新不变 iOS+Android
- Android 经典蓝牙
- 华为 ScanKit 统一扫码插件支持 iOS+Android 原生插件
- 【华为扫码】统一扫码插件支持多码连续扫码支持半屏扫码 uts 插件 iOS+Android+HarmonyOS
- 截屏、录屏、防截屏、录屏 iOS、Android
- 人脸采集插件 最新百度 SDK 离线人脸采集、活体检测
- 页面截长图、截取 WebView 内容,生成长截图 Android+iOS
- 百度 OCR 识别插件
- Android 无预览拍照、录制、静默拍照、静默录制、抓拍插件支持
- uni 高德地图功能拓展地图截图
- iOS 保活 Android 保活鸿蒙保活定位插件系统定位
- 高德定位、猎鹰轨迹插件

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(1)
下载 515
赞赏 11
下载 12436653
赞赏 1934
赞赏
京公网安备:11010802035340号