关于uni-app:踩坑日记uniapp相机抽帧相机被多次初始化问题

缘起:最近频繁接到应用咱们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,请各用户分割咱们索取。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理