五分钟,100余行代码,纯web技术一起实现摄像头和麦克风视频录制,并带历史记录功能

前言

关于关于【SSD系列】
前端一些有意思的内容,旨在3-10分钟里, 500-1500字,有所获,又不为所累。

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

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

效果演示

真机效果

品目录制,gif.gif

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

录制.gif

源码地址

本文源码-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();
    }

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

小结

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

写在最后

不忘初衷,【SSD系列】,3-5分钟,500-1000字,有所得,而不为所累,如果你觉得不错,你的一赞一评就是我前行的最大动力。

技术交流群请到 这里来
或者添加我的微信 dirge-cloud,一起交流学习。

MediaDevices.getUserMedia()的部分坑和解决方案

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现摄像头自建HTML直播,需要使用WebRTC技术WebRTC是一种开放源代码项目,它提供了实时通信(RTC)功能,允许浏览器和移动应用程序之间进行语音通话,视频聊天和P2P文件共享,而无需插件或其他软件。 下面是一个基于WebRTC实现调用本地摄像头实时视频和拍照的示例H5代码: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>摄像头直播</title> <style> #video { width: 640px; height: 480px; } </style> </head> <body> <h1>摄像头直播</h1> <video id="video" autoplay></video> <br> <button id="btn-photo">拍照</button> <canvas id="canvas"></canvas> <script> // 获取video元素 var video = document.getElementById('video'); // 获取拍照按钮 var btnPhoto = document.getElementById('btn-photo'); // 获取canvas元素 var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); // 获取用户媒体设备(摄像头) navigator.mediaDevices.getUserMedia({ video: true, audio: false }) .then(function (stream) { // 将媒体流绑定到video元素上 video.srcObject = stream; video.play(); }) .catch(function (error) { console.log('获取摄像头失败:', error); }); // 拍照事件 btnPhoto.addEventListener('click', function () { // 将canvas的大小设置为和video一样大 canvas.width = video.videoWidth; canvas.height = video.videoHeight; // 将video中的图像绘制到canvas上 context.drawImage(video, 0, 0, canvas.width, canvas.height); // 将canvas中的图像保存为图片 var imgUrl = canvas.toDataURL('image/png'); // 显示图片 var img = new Image(); img.src = imgUrl; document.body.appendChild(img); }); </script> </body> </html> ``` 上述代码中,首先获取了video元素、拍照按钮和canvas元素。然后通过`navigator.mediaDevices.getUserMedia()`方法获取用户媒体设备(摄像头),将媒体流绑定到video元素上,并播放视频。当用户点击拍照按钮时,将canvas的大小设置为和video一样大,将video中的图像绘制到canvas上,然后将canvas中的图像保存为图片,并显示在页面上。 需要注意的是,由于涉及到摄像头麦克风等敏感设备的访问,需要使用HTTPS协议或localhost来访问页面,否则浏览器会提示用户授权访问设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值