Files
zyt/TUICallKit-Vue3/training/motion/camera-frames.ts
T
longandCursor 729d2a084d feat(training): 新增握力环 2.0 摄像头手势识别页
用前置摄像头 + VisionKit/ROI 管线驱动开合计数,复用跟练舞台与连击粒子,并加固结束收尾避免末段卡死无响应。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 18:31:31 +08:00

108 lines
2.8 KiB
TypeScript

import type { CameraFrame } from './types'
type FrameListener = {
start: () => void
stop: () => void
}
type CameraContextLike = {
onCameraFrame?: (cb: (frame: { width: number; height: number; data: ArrayBuffer }) => void) => FrameListener
}
function createContext(cameraId?: string): CameraContextLike | null {
try {
// uni-app 优先:可按 camera 组件 id 绑定
if (typeof uni !== 'undefined' && typeof uni.createCameraContext === 'function') {
return uni.createCameraContext(cameraId || 'gripCamera') as CameraContextLike
}
} catch (_) {}
// #ifdef MP-WEIXIN
try {
// @ts-ignore
if (typeof wx !== 'undefined' && typeof wx.createCameraContext === 'function') {
// @ts-ignore
return wx.createCameraContext() as CameraContextLike
}
} catch (_) {}
// #endif
return null
}
export function isCameraFrameSupported(): boolean {
try {
const ctx = createContext('gripCamera')
return typeof ctx?.onCameraFrame === 'function'
} catch (_) {
return false
}
}
/**
* 管理 CameraContext.onCameraFrame:只保留最新一帧,不入 Vue 响应式。
*/
export function createCameraFramePump(options?: { cameraId?: string }) {
let listener: FrameListener | null = null
let latest: CameraFrame | null = null
let running = false
let callbackCount = 0
let fpsWindowStart = Date.now()
let fps = 0
let onFrame: ((frame: CameraFrame) => void) | null = null
function start(cb: (frame: CameraFrame) => void) {
stop()
onFrame = cb
const ctx = createContext(options?.cameraId || 'gripCamera')
if (!ctx?.onCameraFrame) {
throw new Error('当前基础库不支持 onCameraFrame')
}
listener = ctx.onCameraFrame((raw) => {
if (!running) return
const frame: CameraFrame = {
width: raw.width,
height: raw.height,
data: raw.data,
ts: Date.now(),
}
latest = frame
callbackCount += 1
const now = Date.now()
if (now - fpsWindowStart >= 1000) {
fps = callbackCount
callbackCount = 0
fpsWindowStart = now
}
onFrame?.(frame)
})
running = true
listener.start()
}
function stop() {
running = false
try {
listener?.stop()
} catch (_) {}
listener = null
onFrame = null
}
function getLatest() {
return latest
}
function getFps() {
return fps
}
function isRunning() {
return running
}
return { start, stop, getLatest, getFps, isRunning }
}
export type CameraFramePump = ReturnType<typeof createCameraFramePump>