1
0
forked from dyf/APP
Files
APP/pages/BlueTooth/ModeSetting/VideoSend.vue
2025-08-27 11:06:49 +08:00

472 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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="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>
import Common from '@/utils/Common';
export default {
data() {
return {
videoPath: '',
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)=>{
let start = new Date();
console.log("Common.baseURL="+Common.baseURL);
uni.uploadFile({
url:Common.baseURL+'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:"错误"
})
}
});
},
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;
// 发送单个数据包
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);
this.sendData(buffer).then(() => {
// 更新进度
this.currentPacket = currentPacket;
this.progress = Math.round((currentPacket / totalPackets) *
100);
//console.log(`发送数据包完成 ${currentPacket}/${totalPackets}`);
// 发送下一个包(添加延迟避免蓝牙缓冲区溢出)
currentPacket++;
setTimeout(sendNextPacket, inteval);
}).catch(err => {
// console.log(err.errMsg + ",发送失败了,正在补偿:" + currentPacket);
setTimeout(sendNextPacket, inteval);
// uni.showToast({
// title:"发送失败"+JSON.stringify(err)
// })
});
};
sendNextPacket();
});
}
if (type == 'rgb565') {
let start = new Date();
console.log("开始发送");
sendImagePackets(array).then(() => {
console.log("发送完成");
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) {
////console.log("deviceId=" + this.connectedDeviceId);
////console.log("serviceId=" + this.serviceId);
return new Promise(async (resolve, reject) => {
// //console.log("开始发送数据buffer");
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) => {
//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);
});
}
let inteval = parseInt(this.inteval ? this.inteval : 0);
Promise.race([promise, timeout(inteval)]).then(resolve).catch((ex) => {
//console.log("ex=", ex);
if (ex.code == -1) {
resolve();
} else {
reject();
}
}).finally(() => {
//console.log("完成了")
});
} else {
promise.then(resolve).catch(reject);
}
});
},
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>