关于使用Electron调用摄像头导致内存泄漏与占用的相关问题

661 阅读1分钟

场景:使用同一个摄像头在两个页面下分别调用摄像头拍照,此时第一次可以正常拍照,第二次无法拍照。

原因:第一次拍照后video流未被释放掉,离开当前页面后,再次调用,此时video流仍然存在,导致第二次无法拍照。

 // 调用摄像头拍照
navigator.mediaDevices.enumerateDevices().then((devices) => {
     // 获取设备
     let camera = {
         audio: false,
         video: {
             deviceId: devices[0].deviceId
         }
     }
     navigator.mediaDevices.getUserMedia(camera).then((stream) => {
         let video = this.$refs["video"];
         video.srcObject = stream;
         video.onloadedmetadata = () => {
             let canvas = this.$refs["canvas"];
             video.play();
             canvas.getContext("2d").drawImage(video, 0, 0, 1920, 1080);
             video.pause();
              canvas.toBlob((blobObj) => {
                  this.sendImage(blobObj); // 上传照片
              });
         }
     }).catch((e) => {
         
     })
 }).catch((e) => {
     
 })
​
// 需要在页面销毁前释放video
function cloesVideo () {
    let video = this.$refs["video"];
    video.srcObject = null;
    // 或者 video.srcObject.getTracks()[0].stop();
}

释放掉后在下一个页面调用摄像头就不会因为占用而导致无法拍照了。

还要一种情况是:摄像头兼容多个分辨率,但是我们强制要求两个页面video使用同一个宽高,此时可以不释放video。

// 强制使用同一个宽高,此时video流不被释放,即使摄像头兼容多个分辨率也会强制使用规定的宽高,此时可以不释放video流
let camera = {
    audio: false,
    video: {
        deviceId: devices[0].deviceId,
        width: { min: 1920 },
        height: { min: 1080 },
    }
}
​
// not need
function cloesVideo () {
    let video = this.$refs["video"];
    video.srcObject = null;
    // 或者 video.srcObject.getTracks()[0].stop();
}

总结:不强制video流宽高,不同页面使用同一个摄像头需要释放,即使离开页面了,video流仍然可能存在。不同页面强制宽高可以不释放video流,此时多个页面用的都是同一个video流,所以不会有占用问题。

猜测:离开页面后video流没有被chrome释放掉。

开发环境:

{
    "electron": "^15.3.0", // 此时的 Chromium 版本94.0.4606.81
    "vue": "^2.6.11",
}

其他:

拍摄照片上传时超过10MB在network请求参数中无法看到Form Data,但是请求是成功的,且在请求头中Content-Type有form-data,数据库中也有更新。

猜测:可能与chrome版本有关系,当前使用electron打包后的Chromium版本是94.0.4606.81,但是chrome浏览器在96版本后就把请求参数放入了payload中,此时因为文件超过10MB,所以在Form Data中就不再进行渲染了。