如何使用getUserMedia()接入用户输入设备的简单教程
作者:Sebastian Patron(原文链接)
翻译:刘通
很多年来,通过浏览器的低层接入只能够通过复杂的flash软件或者Java程序来完成。随着flash和Java小程序的渐渐没落,我们需要一个新的解决办法来接入用户电脑的低层部分。这个新方法就是WebRTC,一个允许很简单地接入用户输入设备并且产生点对点连接的JavaScript框架。
WebRTC因为简化了浏览器之间的点到点连接而与众不同。这点对发送信息,视频聊天,甚至是文件分享软件都十分有用。为了做到这点,WebRTC包括了一系列的协议和api来简便的开展实时通信。我们在这篇文章中想做到的是,使用getUserMedia API来十分容易的获取用户的内置摄像头,为我们的自拍软件捕捉图像。
WebRTC的限制
尽管WebRTC是一项十分出色的技术,但是其还是有着很多的限制。就比如说有些API并不能兼容所有的浏览器。好事是在http://iswebrtcreadyyet.com/中可以找到哪些可以兼容哪些不可以兼容。对于我们本文中的目的来说,Chrome,Firfox,Edge,和Opera浏览器都可以完成,它们都可以允许使用getUserMedia()。Edge浏览器在有些功能上面有些落后,但是正在快速赶上。但是Safari浏览器现在甚至连WebRTC本身都不支持。
现在开始
安装node并且设置我们我们的程序
在我们开始之前,你需要在你的电脑上安装Node.js。我不会对这部进行详细的说明,但是在https://nodejs.org/en/download/上可以找到相关说明,以及如何在任何操作系统上安装node。
一旦你把node安装好了,我们就可以开始设定我们的文件夹结构。你可以通过键入$ mkdir directoryname来非常简单地创建一个项目文件夹。你的文件夹结构应该是这个样子的:
当我们设定好文件夹了之后,我们需要安装几个node的模组来让我们的开发过程更简单一些。Node模组是一种外部库,我们可以将它们插入到我们的项目中,来帮助我们将程序代码整理分成不同的部分,以及留意特定的功能。可以把它看成一个乐高积木块,别人已经做好了供我们使用,我们只需要将它和其他乐高积木都拼起来做成我们最终的成品就可以了。我们要用到node-static模组来帮助我们在浏览器中服务一个静态文件。
在命令栏中,输入:$ npm install node-static
现在,在我们的run.js文件里我们输入下面这些代码:
让我们快快的看一眼这段代码都干了什么:var static = require (‘node-static’);找到并且加载node-static模组,我们就可以使用它提供的功能了。new static.Server(‘./public’);创建一个文件服务器实例。这是我们可以从node-static模组中获得的功能之一。我们可以设置’./public’,这样它就可以在这个地址中服务文件了。require (‘http’).createServer (function (request, response) {…})。这个函数开启了我们的服务器实例,并且将其传给了我们的HTTP请求。.listen (8080)设定了我们将要在接入浏览器中自拍应用时而使用的端口。
有了这些,我们的服务器就设置好了!我们可以现在测试一下刚才的结果,进入命令行并且输入$ node run.js并且访问http://localhost:8o8o。如果我们刚才的步骤都做对了的话我们应该会看到一个空白的网页。如果你看到的是一个报错信息显示“localhost refused to connect”,再次检查一下你的代码然后确认你连接的是正确的端口号(而别不要在localhost前面打错打成了https://)。在命令行中输入“control + c”来终止运行你的服务器。
接下来我们需要设置我们的html页。代码如下:
现在,如果我们再次使用$ node run.js运行我们的服务器,在进入http://localhost:8o8o网页之后应该会看到这样的一个网页。
接下来,WebRTC和JavaScript部分
现在,我们把html页已经设置好了,我们现在将注意力转移到JavaScript文件上面。我会将这部分拆开分析,这样我们就能明白我们到底在干什么。首先,让我们设置一些我们需要用到的变量:
让我们看看这里面发生了什么:
constraints是我们要传入我们视频流的参数。我们要指定一下摄像头数据流的大小以至于它不会过大,而且因为我们用不到音频功能,所以取消掉音频。
canvas选择画布元素,我们可以使用它来绘制图形。这是我们要显示我们照的自拍的地方。
filters是包括了我们所有可能会用到的滤镜的数组。我们还可以在这定义currentFilter,以及将其设为‘ ’,或者没有滤镜。
接下来我们准备接入用户的摄像头并且在我们的自拍软件中展示图像。这就是我们用到getUserMedia() API的地方。
通过这些,我们已经有了正在工作的视频流!较为简单明了,特别是与几个月前的这项API对比而言。让我们来快快看一眼我们在做什么:navigator.mediaDevices.getUserMedia()提示用户是否允许使用它们的网络摄像头。如果请求得到了允许,会返回一个有着结果流对象的承诺。我们传到之前设定的约束中。
stream.getVideoTracks()会返回一个有流对象的所有视频轨道的表单。如果有不止一个摄像头连入,我们可以通过这个表单看到用户所有的摄像头。
video.srcObject = stream;允许我们将我们的视频流与我们网页上的元素所对应起来。换句话说,通过这条指令我们终于将视频流加入到了我们的网页中。
此段代码的最后一部分,.catch (…)描述是针对错误处理的。在处理像WebRTC这种处于实验阶段的技术时,这部分代码十分的有用,在错误发生的时候它会产生解决方案,而不是让整个程序都崩溃。
现在我们的视频流也工作了,是时候该做这些:
这里的代码比较简单。首先,我们在捕捉按钮中加入了一个事件监测器。一旦在我们的程序中点击了捕捉按钮,这个函数会检查确保我们的视频流已经开始工作。context.drawimage(..)会对视频进行一个快速抓拍,然后将其展示在我们的画布上。
现在我们的程序已经差不多快完成了!仅剩下实现我们的滤镜。有两个步骤。第一,在我们的JavaScript文件中,我们需要将事件监视器添加到我们的滤镜按钮中。然后,我们需要在CSS文件中定义我们的滤镜。让我们从JavaScript文件开始入手:
这一小段代码与之前的那个来给我们自拍的代码差不多。我们首先将事件监视器添加到滤镜按钮中。然后点击它,改变我们在滤镜数组中的位置来使用我们想要用的滤镜。
在我们开始处理CSS之前,让我们把最后一个函数加入到JavaScript中,其功能是保存我们的自拍:
还是,这段与我们之前写的那段很像。canvas.toDataUrl(..)将我们的画布对象转换成jpeg图像,this.href将这个jpeg图像超链接回我们的html网页。
现在我们就完成JavaScript文件了!整个文件看起来是这个样子的:
你会注意到getUserMedia(..)函数发生了几处变化。其中大部分都是对我们的控制台打日志,以确保所有内容都工作正常。它们对你的应用来说是没有用的,但是在现实世界中这些日志会使debug和测试大幅度的简单话。现在,让我们进到CSS文件中。这是我们实际产生滤镜的地方。
这段代码很直接。.grayscale将我们的图像转换成黑白的,.sephia将图像转换成褐色的,.invert将我们的图像进行反色。
我们这就完成这个程序了!让我们来测试一下,看看各部分是不是都能正确运行。在命令行中输入$ node run.js然后在浏览器中访问http://localhost:8o8o。如果没有问题,你看到的页面应该是这样的:
如果你的程序出了问题,请再次核查你的代码,也可以在git hub智库中查看相关资料。
更进一步
尽管我们完成了这个自拍软件,我们还可以实现新的特性或者让整个软件对用户更加友好。我们可以使用css反转视频流来是图像看起来更自然,使用JavaScript来实现我们的滤镜以更好的控制,或者我们甚至还可以使用画布对象来在我们的脑袋上加一个帽子。有了WebRTC和JavaScript就没有什么不可能。