517 lines
13 KiB
Vue
517 lines
13 KiB
Vue
![]() |
<template>
|
||
|
<view class="content">
|
||
|
<canvas canvas-id="flashCanvas"
|
||
|
style="width: 160px; height: 80px; z-index: 9999;position: fixed; top:-9999px;left:-9999px;"></canvas>
|
||
|
|
||
|
<f-video ref="compARef" :src="videoPath" :direction="-90" :autoplay="true" @shotVideoClick="shotVideoClick"
|
||
|
:videoWidth="videoWidth" :videoHeight="videoHeight"></f-video>
|
||
|
|
||
|
<view>
|
||
|
<text>并发包数量</text>
|
||
|
<input type="text" v-model="packgeCnt" />
|
||
|
</view>
|
||
|
<view>
|
||
|
<text>发送间隔</text>
|
||
|
<input type="text" v-model="inteval" />
|
||
|
</view>
|
||
|
<view>
|
||
|
<button @click="checkVideo">选择视频</button>
|
||
|
<!-- <button @click="CutImg">发送</button> -->
|
||
|
<button @click="uploadVideo">发送</button>
|
||
|
</view>
|
||
|
|
||
|
|
||
|
<view class="sending-progress" v-if="isSending">
|
||
|
<view class="progress-bar">
|
||
|
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
||
|
</view>
|
||
|
<text>正在发送: {{ progress }}% ({{ currentPacket }}/{{ totalPackets }})</text>
|
||
|
</view>
|
||
|
|
||
|
</view>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
export default {
|
||
|
data() {
|
||
|
return {
|
||
|
videoPath: '',
|
||
|
packgeCnt: 20,
|
||
|
inteval: 0,
|
||
|
progress: 0,
|
||
|
currentPacket: 0,
|
||
|
totalPackets: 100,
|
||
|
|
||
|
connectedDeviceId: '',
|
||
|
serviceId: '0xFFE1',
|
||
|
writeCharacteristicId: '0xFFE1',
|
||
|
notifyCharacteristicId: '0xFFE2',
|
||
|
isSending: "",
|
||
|
textProgress: "",
|
||
|
|
||
|
imgs: [],
|
||
|
videoWidth: 320,
|
||
|
videoHeight: 160,
|
||
|
videoDuration: 2,
|
||
|
|
||
|
hexArray: []
|
||
|
|
||
|
}
|
||
|
},
|
||
|
onLoad() {
|
||
|
const eventChannel = this.getOpenerEventChannel();
|
||
|
|
||
|
eventChannel.on('receiveDevice', (data) => {
|
||
|
this.connectedDeviceId = data.connectedDeviceId;
|
||
|
this.serviceId = data.serviceId;
|
||
|
this.writeCharacteristicId = data.writeCharacteristicId;
|
||
|
this.notifyCharacteristicId = data.notifyCharacteristicId;
|
||
|
})
|
||
|
},
|
||
|
methods: {
|
||
|
checkVideo: function() {
|
||
|
uni.chooseVideo({
|
||
|
sourceType: ['album', 'camera'],
|
||
|
compressed: false,
|
||
|
maxDuration: 2,
|
||
|
camera: 'back',
|
||
|
success: (res) => {
|
||
|
this.videoPath = res.tempFilePath;
|
||
|
|
||
|
this.imgs = [];
|
||
|
this.hexArray = [];
|
||
|
this.$refs.compARef.base64 = [];
|
||
|
this.videoWidth = res.width;
|
||
|
this.videoHeight = res.height;
|
||
|
this.videoDuration = res.duration;
|
||
|
console.log("视频宽:" + res.width + ",视频高:" + res.height + ",视频时长:" + res.duration);
|
||
|
}
|
||
|
})
|
||
|
},
|
||
|
|
||
|
uploadVideo: function() {
|
||
|
|
||
|
if (this.hexArray.length > 0) {
|
||
|
console.log("开始处理,无需上传");
|
||
|
this.shotVideoClick(this.hexArray, 'rgb565');
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
if(!this.videoPath){
|
||
|
uni.showToast({
|
||
|
title: "请选择视频",
|
||
|
icon: 'fail'
|
||
|
})
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
console.log("正在上传视频");
|
||
|
uni.showLoading({
|
||
|
title: "上传中"
|
||
|
});
|
||
|
|
||
|
let p2=new Promise((resolve,reject)=>{
|
||
|
console.log("Common.baseURL="+Common.baseURL);
|
||
|
let start = new Date();
|
||
|
uni.uploadFile({
|
||
|
url: Common.baseURL+'video/upload',
|
||
|
// url: 'http://192.168.110.169:5000/video/upload',
|
||
|
filePath: this.videoPath,
|
||
|
name: 'file',
|
||
|
header: {
|
||
|
"Method": "POST",
|
||
|
"Content-Type": "multipart/form-data"
|
||
|
},
|
||
|
timeout: 600000,
|
||
|
fail: (ex) => {
|
||
|
//console.log("上传视频失败" + JSON.stringify(ex));
|
||
|
uni.showToast({
|
||
|
title: "视频文件上传失败了,请检查网络连接",
|
||
|
icon: 'fail'
|
||
|
})
|
||
|
uni.hideLoading();
|
||
|
reject(ex);
|
||
|
},
|
||
|
success: (res) => {
|
||
|
let end = new Date();
|
||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||
|
let s = diff % 60;
|
||
|
let m = (diff - s) / 60;
|
||
|
console.log("上传完成,耗时:" + m + "分" + s + "秒");
|
||
|
uni.hideLoading();
|
||
|
resolve(res);
|
||
|
}
|
||
|
|
||
|
});
|
||
|
});
|
||
|
|
||
|
let p1=this.HoldYouHand();
|
||
|
|
||
|
Promise.all([p2,p1]).then((arr)=>{
|
||
|
if(arr[1]===true){
|
||
|
let res=arr[0];
|
||
|
res = JSON.parse(res.data);
|
||
|
|
||
|
if (res.data) {
|
||
|
this.hexArray = res.data;
|
||
|
uni.showLoading({
|
||
|
title: "正在发送"
|
||
|
});
|
||
|
|
||
|
setTimeout(() => {
|
||
|
this.shotVideoClick(res.data, 'rgb565');
|
||
|
}, 0)
|
||
|
|
||
|
} else {
|
||
|
console.log("res")
|
||
|
uni.showModal({
|
||
|
content: "服务器未返回RGB565数据",
|
||
|
title: '错误'
|
||
|
})
|
||
|
}
|
||
|
}else{
|
||
|
uni.showModal({
|
||
|
content:"与设备握手失败了",
|
||
|
title:"错误"
|
||
|
})
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
},
|
||
|
pause(e) {
|
||
|
////console.log('pause--------------------------', e);
|
||
|
},
|
||
|
shotVideoClick: function(array, type) {
|
||
|
//console.log("处理视频完成", array);
|
||
|
//console.log("type=" + type)
|
||
|
//console.log("array=", array);
|
||
|
this.imgs = array;
|
||
|
|
||
|
|
||
|
|
||
|
var sendImagePackets = (imageData) => {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
|
||
|
this.isSending = true;
|
||
|
this.progress = 0;
|
||
|
this.currentPacket = 0;
|
||
|
|
||
|
// 总数据包数
|
||
|
const totalPackets = 1536;
|
||
|
this.totalPackets = totalPackets;
|
||
|
let currentPacket = 1;
|
||
|
let promises = [];
|
||
|
// 发送单个数据包
|
||
|
const sendNextPacket = () => {
|
||
|
////console.log("currentPacket="+currentPacket+",imageData.length="+imageData.length);
|
||
|
if (currentPacket > totalPackets) {
|
||
|
this.isSending = false;
|
||
|
resolve();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 计算当前包的数据
|
||
|
let packetSize = 250;
|
||
|
if (type == 'rgb565') {
|
||
|
packetSize = 500;
|
||
|
}
|
||
|
|
||
|
// 创建数据包
|
||
|
const startIndex = (currentPacket - 1) * packetSize;
|
||
|
const endIndex = Math.min(startIndex + packetSize, imageData.length);
|
||
|
if (startIndex > endIndex) {
|
||
|
resolve();
|
||
|
return;
|
||
|
}
|
||
|
////console.log("111111");
|
||
|
const packetData = imageData.slice(startIndex, endIndex);
|
||
|
|
||
|
// 构建数据包
|
||
|
////console.log("packetData.length"+packetData.length);
|
||
|
const bufferSize = 506; // 头部5字节 + 数据部分
|
||
|
const buffer = new ArrayBuffer(bufferSize);
|
||
|
const dataView = new DataView(buffer);
|
||
|
|
||
|
let sortNo = currentPacket.toString(16).padStart(4, '0');
|
||
|
|
||
|
// 填充头部
|
||
|
dataView.setUint8(0, 0x55); // 帧头
|
||
|
dataView.setUint8(1, 0x04); // 帧类型:开机画面
|
||
|
dataView.setUint8(2, '0x' + sortNo.substring(0, 2)); // 包序号
|
||
|
dataView.setUint8(3, '0x' + sortNo.substring(2, 4)); // 包序号
|
||
|
|
||
|
|
||
|
dataView.setUint8(4, 0x01);
|
||
|
dataView.setUint8(5, 0xF4);
|
||
|
|
||
|
|
||
|
if (type == 'rgb565') {
|
||
|
for (let i = 0; i < packetData.length; i++) {
|
||
|
dataView.setUint8(6 + i, '0x' + packetData[i]);
|
||
|
}
|
||
|
} else {
|
||
|
for (let i = 0; i < packetData.length; i++) {
|
||
|
dataView.setUint16(6 + i * 2, packetData[i], false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
let inteval = parseInt(this.inteval ? this.inteval : 0);
|
||
|
let promise = this.sendData(buffer);
|
||
|
promises.push(promise);
|
||
|
let packgeCnt = parseInt(this.packgeCnt || 20);
|
||
|
if (currentPacket % packgeCnt == 0 || (currentPacket >= totalPackets &&
|
||
|
promises.length > 0)) {
|
||
|
Promise.all(promises).then(() => {
|
||
|
if (currentPacket >= totalPackets) {
|
||
|
this.isSending = false;
|
||
|
resolve();
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
this.currentPacket = currentPacket;
|
||
|
this.progress = Math.round((currentPacket / totalPackets) *
|
||
|
100);
|
||
|
currentPacket++;
|
||
|
setTimeout(sendNextPacket, inteval);
|
||
|
})
|
||
|
} else {
|
||
|
currentPacket++;
|
||
|
sendNextPacket();
|
||
|
}
|
||
|
// .then(() => {
|
||
|
// // 更新进度
|
||
|
// this.currentPacket = currentPacket;
|
||
|
// this.progress = Math.round((currentPacket / totalPackets) *
|
||
|
// 100);
|
||
|
|
||
|
// currentPacket++;
|
||
|
|
||
|
|
||
|
// setTimeout(sendNextPacket, inteval);
|
||
|
// }).catch(err => {
|
||
|
|
||
|
// console.log(err.errMsg+",发送失败了,正在补偿:" + currentPacket);
|
||
|
// setTimeout(sendNextPacket, inteval);
|
||
|
|
||
|
// });
|
||
|
};
|
||
|
|
||
|
//
|
||
|
|
||
|
|
||
|
sendNextPacket();
|
||
|
|
||
|
});
|
||
|
}
|
||
|
|
||
|
|
||
|
if (type == 'rgb565') {
|
||
|
let start = new Date();
|
||
|
console.log("开始发送");
|
||
|
sendImagePackets(array).then(() => {
|
||
|
|
||
|
let end = new Date();
|
||
|
|
||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||
|
let s = diff % 60;
|
||
|
let m = (diff - s) / 60;
|
||
|
console.log("发送完成,耗时:" + m + "分" + s + "秒");
|
||
|
uni.showToast({
|
||
|
title: "发送完成,耗时:" + m + "分" + s + "秒",
|
||
|
icon: 'success',
|
||
|
|
||
|
})
|
||
|
}).catch((ex1) => {
|
||
|
//console.log("出现了异常", ex1)
|
||
|
}).finally(() => {
|
||
|
uni.hideLoading();
|
||
|
});
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
},
|
||
|
HoldYouHand() {
|
||
|
|
||
|
var promise=new Promise((resolve,reject)=>{
|
||
|
try{
|
||
|
let start=new Date();
|
||
|
var str = "video transmit start"; //握手的协议字符串
|
||
|
console.log("开始握手:"+str)
|
||
|
|
||
|
// 1. 创建 ArrayBuffer 和 DataView
|
||
|
const buffer = new ArrayBuffer(str.length);
|
||
|
const dataView = new DataView(buffer);
|
||
|
|
||
|
// 2. 将字符串转换为 ASCII 码并写入 DataView
|
||
|
for (let i = 0; i < str.length; i++) {
|
||
|
dataView.setUint8(i, str.charCodeAt(i));
|
||
|
}
|
||
|
//console.log("111111");
|
||
|
this.sendData(buffer).then(() => {
|
||
|
// 开始发送第一个包
|
||
|
setTimeout(()=>{
|
||
|
|
||
|
let end = new Date();
|
||
|
var diff = (end.getTime() - start.getTime()) / 1000;
|
||
|
let s = diff % 60;
|
||
|
let m = (diff - s) / 60;
|
||
|
|
||
|
console.log("握手成功并完成2200ms等待,耗时"+m+"分"+s+"秒");
|
||
|
|
||
|
resolve(true);
|
||
|
}, 2200);
|
||
|
|
||
|
}).catch(err => {
|
||
|
//console.log("握手没有成功");
|
||
|
reject(err);
|
||
|
});
|
||
|
}catch(ex){
|
||
|
reject(ex);
|
||
|
}
|
||
|
|
||
|
|
||
|
});
|
||
|
|
||
|
return promise;
|
||
|
|
||
|
},
|
||
|
sendData(buffer) {
|
||
|
let sendBuffer = () => {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
|
||
|
var promise = new Promise((succ, err) => {
|
||
|
uni.writeBLECharacteristicValue({
|
||
|
deviceId: this.connectedDeviceId,
|
||
|
serviceId: this.serviceId,
|
||
|
characteristicId: this.writeCharacteristicId,
|
||
|
value: buffer,
|
||
|
writeType: plus.os.name == 'iOS' ? 'write' : 'writeNoResponse',
|
||
|
success: () => {
|
||
|
// console.log("发送数据成功");
|
||
|
succ();
|
||
|
},
|
||
|
fail: (ex) => {
|
||
|
if (ex.code == '10007') {
|
||
|
// console.log("失败重试");
|
||
|
setTimeout(() => {
|
||
|
sendBuffer().then(succ).catch(err);
|
||
|
}, this.inteval || 0)
|
||
|
// succ()
|
||
|
|
||
|
} else
|
||
|
|
||
|
{
|
||
|
// console.log("发送数据失败",ex);
|
||
|
err(ex);
|
||
|
}
|
||
|
},
|
||
|
complete: function() {
|
||
|
//console.log("123456");
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
if (plus.os.name == 'iOS') {
|
||
|
|
||
|
function timeout(ms) {
|
||
|
return new Promise((_, err) => {
|
||
|
setTimeout(() => {
|
||
|
err({
|
||
|
code: -1,
|
||
|
errMsg: '超时了'
|
||
|
})
|
||
|
}, ms);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
Promise.race([promise, timeout(this.inteval ? this.inteval : 0)]).then(() => {
|
||
|
// console.log("成功了");
|
||
|
resolve();
|
||
|
})
|
||
|
.catch((ex) => {
|
||
|
|
||
|
if (ex.code == -1) {
|
||
|
// console.log("超时了")
|
||
|
resolve();
|
||
|
} else {
|
||
|
reject(ex);
|
||
|
// console.log("异常了", ex);
|
||
|
//sendBuffer().then(resolve).catch(reject);
|
||
|
}
|
||
|
|
||
|
});
|
||
|
} else {
|
||
|
|
||
|
promise.then(() => {
|
||
|
//console.log("then........")
|
||
|
resolve();
|
||
|
}).catch(() => {
|
||
|
//console.log("catch.........")
|
||
|
reject()
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
}
|
||
|
|
||
|
return sendBuffer();
|
||
|
},
|
||
|
CutImg: function() {
|
||
|
if (this.imgs.length == 30) {
|
||
|
this.shotVideoClick(this.imgs, 'img');
|
||
|
return;
|
||
|
}
|
||
|
//console.log("开始处理视频")
|
||
|
uni.showLoading({
|
||
|
title: '开始处理'
|
||
|
});
|
||
|
this.$refs.compARef.shotVideoClick(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style>
|
||
|
.sending-progress {
|
||
|
margin-top: 30rpx;
|
||
|
width: 100%;
|
||
|
}
|
||
|
|
||
|
.progress-bar {
|
||
|
height: 12rpx;
|
||
|
background-color: #e0e0e0;
|
||
|
border-radius: 6rpx;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
|
||
|
.progress-fill {
|
||
|
height: 100%;
|
||
|
background-color: #409eff;
|
||
|
transition: width 0.3s;
|
||
|
}
|
||
|
|
||
|
input {
|
||
|
border: 2rpx solid #000000;
|
||
|
}
|
||
|
|
||
|
button {
|
||
|
height: 100rpx;
|
||
|
line-height: 100rpx;
|
||
|
font-size: 28rpx;
|
||
|
float: left;
|
||
|
}
|
||
|
|
||
|
.content {
|
||
|
width: 100vw;
|
||
|
height: 300px;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
align-items: center;
|
||
|
justify-content: center;
|
||
|
}
|
||
|
</style>
|