纯web技术一起实现摄像头和麦克风视频录制,并带历史记录功能

目录
文章目录隐藏
  1. 前言
  2. 效果演示
  3. 源码地址
  4. 思路
  5. 实现
  6. 小结

前言

如题,今天我们用纯 web 技术,实现摄像头+麦克风 视频的录制功能,代码约 100 余行, 主要涉及的知识点:

  1. MediaDevices
    提供对连接的媒体输入设备(如照相机和麦克风)的访问,以及屏幕共享等。
  2. MediaRecorder
    录制音频或者视频。
  3. IndexedDB
    储存较大数据结构的事务性数据库。
  4. URL
    用来把视频的 Blob 数据生成地址,提供给video标签使用。

效果演示

真机效果:

纯 web 技术一起实现摄像头和麦克风视频录制

PC 端 + 模拟移动 + 虚拟摄像头(VCam)

PC 端 + 模拟移动 + 虚拟摄像头(VCam)

源码地址

本文源码-recordAV

注意:

  1. 权限问题,需要显式的授权
  2. 如果手机端预览,需要启用 https,demo 已经附带证书

思路

  1. 利用 MediaDevices 唤起摄像头和麦克风
  2. 把第一步获取的流,同时用于videoMediaRecorder
    因为录制的同时需要看到我们摄像头的内容
  3. 录制结束后,把录制视频存入 indexedDB
  4. 按照 keys 列出已录制的视频,点击后,获取 Blob 文件,生成 url,提供给 video 标签播放。

实现

唤起摄像头和麦克风并获得其流

这里需要用的就是 MediaDevices,对应的 API 就是navigator.mediaDevices.getUserMedia

核心代码如下:

const stream = await navigator.mediaDevices.getUserMedia({
    video: { facingMode: "environment" },  // 唤起内面的摄像头,
    audio: true  // 需要音频,例如麦克风
})
// 把流传给 video 元素,即可看到摄像头内容
videoEL.srcObject = stream;  
// 初始化 MediaRecorder
mediaRecorder = new MediaRecorder(stream, { mimeType: "video/webm" });

注意事项:

  1. getUserMedia 方法的 facingMode 参数
    user为前置的摄像头,environment为后置摄像头。
  2. new MediaRecorder 的参数{ mimeType: "video/webm" }
    如果未设置正确,可能就只有视频,没有麦克风声音了

录制和保存

录制必然有开始和停止两个操作,实现方式很多,我们就采用最简单的两个按钮形式, 并分别给注册上相关的事件处理程序。

代码如下:

这里有一个小的知识点,任何有 id 属性的节点,你均可使用 id 属性对应的变量直接访问该元素。

<button id="btnRecord" class="btn">录制</button>
<button id="btnStop"  class="btn" >停止</button>

btnRecord.addEventListener("click", () => {
    startRecord(mediaRecorder);
    mediaRecorder.start();
});

btnStop.addEventListener("click", () => {
    mediaRecorder.stop();
})

是不是很简单。 注意上面停止按钮点击后,我们调用了mediaRecorder.stop方法,其之后会触发recorder.onstop事件,这个时候,我们唤起弹出框,让用户输入视频的名字,然后将内容保存到 indexedDB 即可。

indexedDB 的存取有很多封装库,indexedDB 参见部分列出了不少于 10 个库,这里我们采用 idb-keyval库,其简单且小巧的(~600B)基于 Promise 的键值对存储,使用也是极其简单,get, set 就行了。

具备上面的知识后,看代码:是不是很简单。

function startRecord(recorder) {
    var chunks = [];
    // 收集数据
    recorder.ondataavailable = function (e) {
        chunks.push(e.data);
    }
    // 监听停止事件
    recorder.onstop = async () => {
        var clipName = prompt('请输入视频的名字');
        var blob = new Blob(chunks, { 'type': 'audio/mp4;' });
        await idbKeyval.set(clipName + ".mp4", blob);
        listHistory();
    }
}

历史和观看

历史嘛,那就是读取 keys,严格意义上,应该使用 indexedDB 的游标来读取,本文为了简单,直接读取所有的 keys,然后判断文件后缀来过滤。

async function listHistory() {
    list.innerHTML = null;
    const keys = await idbKeyval.keys();
    console.log("keys:", keys);

    keys.filter(k => k.endsWith(".mp4")).forEach(key => {
        const divEl = document.createElement("div");
        divEl.textContent = key;
        divEl.onclick = () => playVideo(key);

        list.appendChild(divEl);
    });
}

到此为止,我们就差点击某个历史视频之后的播放逻辑了,也很简单:

async function playVideo(key) {
    const blob = await idbKeyval.get(key);
    // 生成地址
    fplayer.src = URL.createObjectURL(blob);
    fplayer.style.display = "block";
    fplayer.play();
}

到此文本,所有的核心代码都已经实现了。

小结

是不是很简单,一切都看起来没那么难,这样,你才容易入坑啊。

原文链接:点击这里

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 纯web技术一起实现摄像头和麦克风视频录制,并带历史记录功能

发表回复