【踩坑日记】uni-app相机抽帧,相机被多次初始化问题
缘起:最近频繁接到使用我们
AI运行识别插件
用户的反馈,部分机型在uni
中抽几帧后,就不再帧的了。开始以为又是小程序的API兼容的问题(确有机型出现过抽帧兼容性问题),后面越来越多的反馈在原生下无问题,只有采用uni-app
方案的有问题...
一、先看抽帧简略代码
下面是小程序做AI运动识别的第一步,摄像头帧数据采集的精简代码版段,大致流程是:在摄像头初始化完成后,初始化一个CameraFrameListener
、进行抽帧,并根据抽取的帧图像大小,调整Camera
组件大小与帧图大小同比缩放(宽全为全屏、高自适应)。
为什么要同比缩放的原因,请见我们的系列分享:【一步步开发AI运动小程序】四、小程序如何抽帧
<template>
<view class="container">
<camera id="preview" class="preview" :style="videoStyles" flash="off" :device-position="deviceKey"
resolution="high" frame-size="low" @initdone="onCameraReady">
</camera>
</view>
</template>
<script>
export default {
data() {
return {
deviceKey: "back",
previewWidth: 480,
previewHeight: 640,
previewRate: 1,
frameWidth: 480,
frameHeight: 640
};
},
computed: {
videoStyles() {
const style = `width:${this.previewWidth}px;height:${this.previewHeight}px;`;
return style;
}
},
methods: {
autoFitPreview(width, height) {
const sifno = uni.getSystemInfoSync();
let rate = sifno.windowWidth / width;
this.previewWidth = width * rate;
this.previewHeight = height * rate;
this.previewRate = rate;
this.frameWidth = width;
this.frameHeight = height;
},
initCamera(){
//防止重初始化
if(this.listener)
return;
const that = this;
const context = wx.createCameraContext();
const listener = context.onCameraFrame((frame) => {
//当帧图像大小发生变化时,重新调整摄像头代码
if(that.frameWidth != frame.width)
that.autoFitPreview(frame.width, frame.height);
console.log(frame.data instanceof ArrayBuffer, frame.width, frame.height)
});
listener.start();
},
onCameraReady(e) {
this.autoFitPreview(480, 640);
this.initCamera();
},
onStart(){
this.listener.start();
},
onStop(){
this.listener.stop();
}
}
}
</script>
二、BUG复现
在确认原生小程序抽帧无问题后,我们偿试了问题复现,经过多次测试,发现在uni
下,Camera
组件会多次触发initdone
事件,进一步测试后发现,只要动态改变camera
的style高、宽,便会触发重新初始化。
initCamera(){
//这里的防初始化,便是引发抽帧断流的原因,因为相机重新初始化了,所以listener实际已经无法再监听帧流了,必须重新创建
if(this.listener)
return;
const that = this;
const context = wx.createCameraContext();
const listener = context.onCameraFrame((frame) => {
//当帧图像大小发生变化时,重新调整摄像头代码
//此处的重新适应,便导致了相机的重初始化
if(that.frameWidth != frame.width)
that.autoFitPreview(frame.width, frame.height);
console.log(frame.data instanceof ArrayBuffer, frame.width, frame.height)
});
listener.start();
}
三、问题修复
找出问题原因,修复便很简单了,去除相应的防CameraFrameListener
重新始化锁,只要触发initdone
便重新初始化,并同步初始化其它逻辑。同时也要注意尽量将camera大小一次绑定到位,减少动态绑定的次数。
四、问题总结
虽然uni-app
大部分场景都与原生无异,但是受限于vue的值绑定和节点渲染机制,在实际使用中还是有细微的差别的,特别是原生组件。
另外,针对此问题,我们已经更新了我们的
AI运动识别小程序插件
的uni
版本Demo,请各用户联系我们索取。
提供信息系统、公众号、小程序、APP订制开发服务
QQ:316455841
欢迎通过各种渠道咨询了解,免费提供信息系统建设咨询服务。