文章导读:继上节的内容,本节要完成的内容是完成视频采集参数以及滤镜参数的动态配置功能。推荐阅读方式:实操。
为了更好的讲解代码,我们还是把软件的截图贴出来,如下图2.5.1。
图 2.5.1 (软件界面截图)
先来看看本节要实现的第一个功能:动态配置视频采集的参数。不愿是视频采集的参数还是滤镜的参数,我们可以看成是同一种业务,于是我们新建一个对象来管理:configManager,目前该对象有两个方法:读取视频采集参数getConstrains
、读取滤镜参数getFilterConfig。先来实现第一个方法——getConstrains ,该方法中需要用JS中读取表单元素的值,因此,我们先要给对应的表单元素加上id,方便操作,代码如下。
<div class="constraints-item"> <label>是否启用音频</label> <input id="useAudio" type="checkbox"> </div> <div class="constraints-item"> <label>视频宽</label> <input value="300" id="videoWidth" type="number"> </div> <div class="constraints-item"> <label>视频高</label> <input value="200" id="videoHeight" type="number"> </div> <div class="constraints-item"> <label>采集设备选择</label> <select aria-placeholder="请选择采集的设备" name="" id="devicesList"> </select> </div> <div class="constraints-item"> <label>视频帧率</label><input value="30" id="frameRate" type="number"> </div>
上述代码中,除了为表单元素设置id外,还设置了默认值,但“采集设备选择”这个选项比较特殊,需要通过webrtc代码读取到本机可用的摄像头设备列表,那什么时候读取摄像头设备列表呢?根据2.1节 学习到的内容我们知道,首先用户通过getUserMedia读取默认设备的媒体流,这个过程会触发浏览器的对本域下的程序访问摄像机、麦克风权限的询问,只有通过了这个验证,我们才能“顺畅”的访问其他webrtc API ,如enumerateDevices(列举本机可用的音视频设备)。按照这个思路,只有“打开摄像头”的逻辑会调用getUserMedia,所以,我们将在打开摄像头成功之后去列举并显示可用设备列表,这部分的逻辑依旧属于摄像机的管理操作,于是我们在cameraManager中新增一个方法——enumerateVideoDevices,顾名思义,我们只需列举出视频输入设备即可,其他的设备如音频输入、音频输出暂时不考虑,这部分作为本章的扩展作业留给读者。
先分析下cameraManager的enumerateVideoDevices要实现的功能,首先要读取通过webrtc的相关API读取到可用的设备列表,注意默认的可用设备列表包含了 “音频输入(audioinpt)、音频输出(audiooutput)、视频输入(videoinput)”三种设备类型,所有我们要筛选出视频输入(videoinput)设备出来;其次,筛选出来的视频输入设备我们要动态创建dom元素放到”<select aria-placeholder="请选择采集的设备" name="" id="devicesList">“标签中,供用户选择。功能分析完毕,代码如下。
// 加载摄像头供用户选择 async enumerateVideoDevices() { let devices = await navigator.mediaDevices.enumerateDevices() let devicesListDom = domManager.getDom("devicesList"); devicesListDom.innerHTML = ""; // 清空子元素 if (devices) { for (let d of devices) { if (d && (d.kind == 'videoinput')) { let element = document.createElement("option"); if (element) { element.value = d.deviceId; element.innerHTML = d.label; devicesListDom.appendChild(element); } } } } },
至此,cameraManager对象就多了一个方法,该方法在哪里被调用?调用代码如下,即在cameraManager的openCamera方法中。
//开启摄像头 async openCamera(mediaStreamconstrains) { let media = await navigator.mediaDevices.getUserMedia(mediaStreamconstrains); this.enumerateVideoDevices();//调用列举可用视频设备列表 this.mediaStream = media; return media; },
到这里,视频采集参数的“初始化”工作做完了, 接下来开始读取这些参数,上述我们说到,参数的管理使用一个对象——configManager来管理,那视频参数的管理就非常简单了,只需要读取出对应表单元素的value值,并构建出一个webrtc能识别的constrains对象即可。代码如下。
//配置参数管理对象 const configManager = { //读取采集配置参数 getConstrains() { /** 读取视频采集参数 start */ let constrains = { audio: false, video: {} } // 读取是否开启音频 constrains.audio = domManager.getDom("useAudio").checked; constrains.video.width = domManager.getDom("videoWidth").value; constrains.video.height = domManager.getDom("videoHeight").value; constrains.video.frameRate = domManager.getDom("frameRate").value; constrains.video.deviceId = domManager.getDom("devicesList").value; /** 读取视频采集参数 end */ return constrains; }, }
上述代码中,需要注意的是“useAudio”这个表单元素是一个“选择按钮”,判断其是否被选中需要判断checked属性。
视频采集参数管理方法(getConstrains)实现完成了,接下来要使用了,在哪里使用该方法?很明显是在点击“更新配置”时调用,所以,我们需要在事件管理器——eventManager中新增一个事件监听,监听按钮“更新配置”的点击事件。 代码如下。
// 更新配置事件监听 domManager.getDom("updateConstrains").onclick = () => { // 读取视频采集配置信息 let constrains = configManager.getConstrains() //先关闭摄像头 cameraManager.closeCamera(); // 再根据新的配置参数打开摄像头 cameraManager.openCamera(constrains).then(media => { domManager.getDom("myvideo").srcObject = media; statusManager.openedCamera(); }).catch(err => { console.log("读取媒体失败", error) }) }
上述代码没有什么难点,唯一需要注意的地方就是更新采集配置时需要重新打开摄像头,所以我们逻辑顺序就变成了:读取配置参数 ---> 关闭已打开的摄像头 ---> 使用新参数打开摄像头。至此“更新配置”的功能搞定。接下来完成第二个功能:更新滤镜。再完成这个功能后,我们在本篇文章展示完整代码。