// pages/faceRecognition/index.ts import { base } from "../../config/index"; let ctx: WechatMiniprogram.CameraContext | undefined = undefined; let listener: WechatMiniprogram.CameraFrameListener | undefined; let createVKSession: WechatMiniprogram.VKSession | undefined = undefined; let innerAudioContext: WechatMiniprogram.InnerAudioContext; const app = getApp(); const topTips = { ready: '请正对手机,保持光线充足', front: '请正对屏幕', left: '请向左转头', right: '请向右转头', } const bottomTips = { recording: '脸部信息录入中...', complete: '为达到更好的剪辑效果,请您跑步中接近摄像机,避免遮挡。', error: '脸部信息录入失败' } let T: number = 0; let notify = "" const daoJiShi: number = 15; let isOver = false; Page({ /** * 页面的初始数据 */ data: { isStartVideo: false, // 是否点击开始按钮 seconds: 0, // 倒计 topTips: topTips.ready, // 提示语句 bottomTips: "" // 底部提示语句 }, // 开始初始化录制 async initCamera() { if (this.data.isStartVideo) return; wx.showLoading({ title: "" }) this.setData({ isStartVideo: true }) wx.nextTick(() => { app.getPageInfo({ success: (res: any) => { const configPage = res || {}; this.getMssage(configPage).then(async (r: any) => { console.log('是否授权发送消息:', r); notify = r; ctx = wx.createCameraContext(); this.createVK(); this.addListen(); ctx.startRecord({ timeout: daoJiShi, // 录制时长 selfieMirror: false, timeoutCallback: (res) => { // 超出录制时长 关闭录屏 if(this.data.seconds) return this.setData({ isStartVideo: false, bottomTips: "", topTips: topTips.ready, // 提示语句 }) createVKSession?.stop(); listener?.stop(); this.getUrl(res); }, success: () => { // 调用成功,开始录制 wx.hideLoading(); this.setData({ seconds: daoJiShi, bottomTips: bottomTips.recording, topTips: topTips.front }); innerAudioContext.src = "assets/voice/front.mp3"; innerAudioContext?.play(); }, fail: () => { // 调用失败 wx.hideLoading(); this.overVideo(); wx.showToast({ icon: "none", title: "相机调用失败", duration: 2000 }) } }) }); } }) }) }, // 添加监听 addListen() { T = Date.now(); listener = ctx?.onCameraFrame((frame: any) => { const Time = daoJiShi * 1000 - (Date.now() - T); if (Time % 1000 >= 50) return const upData: { seconds: number, topTips?: string } = { seconds: Math.floor(Time / 1000) } if (upData.seconds == 10) { innerAudioContext.src = "assets/voice/left.mp3"; upData.topTips = topTips.left; } if (upData.seconds == 5) { innerAudioContext.src = "assets/voice/right.mp3"; upData.topTips = topTips.right; } if (upData.seconds % 5 === 0 && upData.seconds !== 0) innerAudioContext?.play(); this.setData(upData) // 识别人脸是否在画面种 createVKSession?.detectFace({ frameBuffer: frame.data, // 图片 ArrayBuffer 数据。人脸图像像素点数据,每四项表示一个像素点的 RGBA width: frame.width, // 图像宽度 height: frame.height, // 图像高度 scoreThreshold: 0.5, // 评分阈值 sourceType: 1 }) }); listener?.start(); }, // 创建人脸追踪 createVK() { // 初始化人脸识别 createVKSession = wx.createVKSession({ version: "v1", track: { plane: { mode: 1 }, face: { mode: 2 } // mode: 1 - 使用摄像头;2 - 手动传入图像 }, }) // 静态图片检测模式下,每调一次 detectFace 接口就会触发一次 updateAnchors 事件 createVKSession?.on('updateAnchors', (anchors) => { for (let I = 0; I < anchors.length; I++) { const anchor = anchors[I]; const W = anchor.size.width * 100; let titlet = ""; if (W < 20 || W > 80) titlet = "请远离屏幕" if (W < 20) titlet = "请靠近屏幕" titlet && wx.showToast({ icon: "none", title: titlet }) } }) createVKSession?.on('removeAnchors', () => { wx.showToast({ title: "未检测到人脸, 请重新采集", icon: "error" }); this.overVideo(); }) createVKSession?.start(() => { }); }, // 结束录像 overVideo() { if (isOver) return; isOver = true; ctx?.stopRecord({ compressed: true, success: () => { ctx = undefined; isOver = false; listener?.stop(); this.setData({ isStartVideo: false, bottomTips: "", topTips: topTips.ready, seconds: 0 }) }, fail: () => { ctx = undefined; isOver = false; listener?.stop(); this.setData({ isStartVideo: false, bottomTips: "", topTips: topTips.ready, seconds: 0 }) } }) createVKSession?.stop(); innerAudioContext?.pause(); innerAudioContext?.destroy(); }, // 获取本地临时地址 getUrl(res: WechatMiniprogram.StartRecordTimeoutCallbackResult) { wx.showLoading({ title: '上传进度:0%', mask: true //是否显示透明蒙层,防止触摸穿透 }) const uploadTask = wx.uploadFile({ url: base.url + '/v3/upload', filePath: res.tempVideoPath, name: 'file', //服务器定义的Key值 formData: { notify }, header: { Authorization: wx.getStorageSync("token") }, success: () => { wx.hideLoading(); wx.showToast({ title: "上传成功", duration: 2000, icon: "none" }); this.setData({ topTips: topTips.ready, // 提示语句 bottomTips: bottomTips.complete }) let time = setTimeout(() => { clearTimeout(time); wx.reLaunch({ url: "/pages/downloadPage/index" }) }, 2000) }, fail: () => { wx.hideLoading(); wx.showToast({ title: "上传失败", icon: "none", duration: 2000 }) this.setData({ topTips: topTips.ready, // 提示语句 bottomTips: bottomTips.error }) }, complete: () => { } }) //监听上传进度变化事件 uploadTask.onProgressUpdate((res) => { wx.showLoading({ title: '上传进度:' + res.progress + '%', mask: true //是否显示透明蒙层,防止触摸穿透 }) }) }, // 非正常中止 improperStop() { this.overVideo(); wx.navigateBack(); }, // 未授权 unauthorized() { wx.showToast({ title: "拒绝授权将无法录制视频信息" }); this.overVideo(); wx.navigateBack(); }, // 初始化完成 initialization() { }, // 获取消息授权 getMssage(configPage: any) { return new Promise((resolve) => { if (!configPage.messageID || !wx.canIUse("requestSubscribeMessage")) { resolve("reject"); return } wx.requestSubscribeMessage({ tmplIds: configPage?.messageID || [], success: (res: WechatMiniprogram.RequestSubscribeMessageSuccessCallbackResult) => { resolve(res.p1mpCydIQ6OtxCSa62NaSFiEkQiTsb8KPFaAs1SuKMw || 'reject'); }, fail: () => { resolve("reject"); } }) }) }, /** * 生命周期函数--监听页面加载 */ onLoad() { innerAudioContext = wx.createInnerAudioContext(); innerAudioContext.loop = false; }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady() { }, /** * 生命周期函数--监听页面显示 */ onShow() { }, /** * 生命周期函数--监听页面隐藏 */ onHide() { // 在录制中退出后台页面隐藏,返回上一页,确保重新进入当前页 this.overVideo(); }, /** * 生命周期函数--监听页面卸载 */ onUnload() { this.overVideo(); }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { }, /** * 用户点击右上角分享 */ // onShareAppMessage() { // }, }) export { }