前言:
今天看官们对“js监控屏幕”大体比较着重,同学们都想要了解一些“js监控屏幕”的相关内容。那么小编在网络上收集了一些对于“js监控屏幕””的相关文章,希望大家能喜欢,我们快快来学习一下吧!前言
大多数智能手机都有前置和后置摄像头,当你在创建视频应用时你可能想要选择或者切换前置、后置摄像头。
如果你开发的是一款聊天应用,你很可能会想调用前置摄像头,但如果你开发的是一款拍照软件,那么你会更倾向于使用后置摄像头。在这篇文章中我们将探讨如何通过 mediaDevices API 和 media constraints (媒体约束) 选择或者切换摄像头。
准备工作
要跟着本文一起动手实践你需要:
一款拥有两个可供测试的摄像头的 iOS 或 Android 设备,如果你的电脑有两个摄像头那也可以ngrok 以便你能通过移动设备轻松访问到你的项目(也因为我觉得 ngrok 炒鸡棒)地址:这个 GitHub 库 的代码让你起步地址:
要获取代码,先把这个项目 clone 下来然后 checkout 到 initial-project tag 下。
git clone -b initial-projectcd mediadevices-camera-selection
这个起步项目已经为你准备好了一些 HTML 和 CSS,所以我们就可以把注意集中到 JavaScript 上了。你可以直接打开 index.html,但我建议你用一款 webserver 把这些文件托管起来。我喜欢用 npm 的 serve 模块。我在这个库里已经引入了 serve,要使用它你需要先用 npm 安装依赖然后启动这个服务。
npm installnpm start
服务运行起来后,我们要用 ngrok 开启一条隧道。serve 用 5000 端口托管文件,要用 ngrok 开隧道通到这个端口,新开一个命令行窗口输入以下命令:
ngrok http 5000
好了你现在可以公网访问这个站点了,你可以在移动设备上打开这个网站,这样接下来就可以测试啦。确保你打开的是 HTTPS 的 URL,因为我们用的 API 只能在安全环境下使用。
网站看起来像这样:
获取 media stream
我们的第一个任务是从任意摄像头获取视频流显示到屏幕上。完成这个之后我们再调研如何选择特定摄像头。打开 app.js , 我们以从 DOM 中选择按钮和 video 元素开始:
// app.jsconst video = document.getElementById('video');const button = document.getElementById('button');
当用户点击或触摸按钮时,我们要使用 mediaDevices API 请求摄像头权限。要这样做,我们要调用 navigator.mediaDevices.getUserMedia ,传递 media constraints 对象。让我们从简单的 constraints 开始,我们只需要视频,因此我们把 video 设置为 true,audio 设置为 false。
getUserMedia 会返回一个 promise,当 resolve 的时候我们就可以访问到摄像头的媒体流了。把媒体流赋值给 video 元素的 srcObj 属性,我们就能从屏幕上看到视频了。
button.addEventListener('click', event => { const constraints = { video: true, audio: false }; navigator.mediaDevices .getUserMedia(constraints) .then(stream => { video.srcObject = stream; }) .catch(error => { console.error(error); });});
保存文件,重新加载页面然后点击按钮。你应该能看到一个权限对话框请求访问你的摄像头,一旦授权屏幕上就应该会出现视频。在你的电脑和手机上试一试,我在我的 iPhone 上市了,被选择的是前置摄像头。
如果你用的是一部 iPhone 手机,确认你在 Safari 里尝试,因为其他浏览器貌似并没有效果。
可用摄像头
media Devices API 为我们提供了一种枚举所有可用音频和视频输入设备的方式。我们要用 enumerateDevices 函数来为 <select> 框构建选项,这样我们就能用它来选择我们想看的摄像头了。再次打开 app.js,从 DOM 中选出 <select> 元素:
const video = document.getElementById('video');const button = document.getElementById('button');const select = document.getElementById('select');
enumerateDevices 会返回一个 promise,所以让我们写一个用来接受 promise 结果的函数吧。这个函数接收一个 media device 数组作为参数。
首先要做的是清空 <select> 现有的任何选项,然后插入一个空的 <option>。接着循环遍历所有设备,过滤掉非 “videoinput”类型的设备。然后我们创建一个 <option> 元素,用设备 ID 当作 option value,设备 label 当作 option text。我们还要处理一种情况,如果一个设备没有 label 存在,生成一个简单的 “Camera n” 作为标签。
const video = document.getElementById('video');const button = document.getElementById('button');const select = document.getElementById('select');function gotDevices(mediaDevices) { select.innerHTML = ''; select.appendChild(document.createElement('option')); let count = 1; mediaDevices.forEach(mediaDevice => { if (mediaDevice.kind === 'videoinput') { const option = document.createElement('option'); option.value = mediaDevice.deviceId; const label = mediaDevice.label || `Camera ${count++}`; const textNode = document.createTextNode(label); option.appendChild(textNode); select.appendChild(option); } });}
在 app.js 末尾调用一下 enumerateDevices。
navigator.mediaDevices.enumerateDevices().then(gotDevices);
刷新页面,看一下按钮旁边的下拉选择框。如果你用的是 Android ,或者使用 Chrome 或 Firefox,你就能看到可用的摄像头名称了。
然而在 iPhone 上,你将看到我们函数生成的通用名字 “Camera 1” 和 “Camera 2”。在 iOS 上只有你授权至少一个摄像头给网站,你才能看到摄像头的名字。这让在我们的界面上选择摄像头变得更不方便,因为尽管你能获取到设备 ID,你还是不能分辨哪个摄像头是哪个。
目前我们还没有处理下拉选择框来改变摄像头。在这之前,让我们来看另一种能改变哪个摄像头被使用的方法。
FacingMode
FacingMode 约束是一个可以用来选择摄像头的替代方法。这个方法比起通过 enumerateDevices 函数获取 ID 来说更不那么精确,但在移动设备上效果非常好。对于这个约束,一共有四种选项可供你选择:用户(user),环境(environment),左(left),右(right)。MDN 上的文档对这个约束做了详细介绍, 以本文的目的我们将使用用户和环境模式,在移动设备上它们正好对应到前置和后置摄像头。
要使用 facingMode 约束我们需要修改调用 getUserMedia 时使用的 constraints 对象。对于 video 我们需要一个对象来控制具体的约束,而不是给一个 true 值。像这样修改代码来使用前置摄像头:
button.addEventListener('click', event => { const videoConstraints = { facingMode: 'user' }; const constraints = { video: videoConstraints, audio: false };
现在可以用你的手机测试。你应该能看到前置摄像头被使用。更改 facingMode 为 environment 再试一次, 使用的应该是后置摄像头。让我们把这些代码和上面通过 enumerateDevices 获取到的结果放到一块儿,只要我们获得了读取摄像头数据的权限,就能构建一个摄像头切换器了。
切换摄像头
现在我们有在首次选择时挑选用户或环境摄像头的代码了,但如果我们要切换摄像头那还有一丢丢额外的工作要做。
首先,我们应该保留对当前流的引用,这样当我们切换到另一个流时就能停止当前流。在 app.js 的最前面添加一个额外的变量和辅助函数来停止流中的轨。
const video = document.getElementById('video');const button = document.getElementById('button');const select = document.getElementById('select');let currentStream;function stopMediaTracks(stream) { stream.getTracks().forEach(track => { track.stop(); });}
函数 stopMediaTracks 接收一个媒体流,循环遍历流中的每一个媒体轨道,调用 stop 方法停止媒体轨。
我们要在点击同一个按钮时改变摄像头,所以我们需要更新一下按钮的事件监听器了。如果当前有媒体流,我们应该先停止掉它。然后我们要检查 <select> 元素看是否选择了特定的设备,然后基于此构造 media constraints 对象。
这样修改按钮的点击处理函数和 video constraints:
button.addEventListener('click', event => { if (typeof currentStream !== 'undefined') { stopMediaTracks(currentStream); } const videoConstraints = {}; if (select.value === '') { videoConstraints.facingMode = 'environment'; } else { videoConstraints.deviceId = { exact: select.value }; } const constraints = { video: videoConstraints, audio: false };
当我们想通过 deviceId 来选择设备时,使用 exact 约束。 可是对于 facingMode,我们没有使用 exact 约束, 否则在一个无法识别有没有用户或环境模式的设备上将会失败,导致我们什么媒体设备也拿不到。
当我们获得使用视频的权限时,在点击处理函数内,我们还要修改一些别的东西。把传递给函数的新流赋值给 currentStream 以便后续调用 stop,触发另一次 enumerateDevices 的调用。
enumerateDevices 返回一个 promise,所以在我们的 then 函数中可以直接返回它,然后链式创建一个新的 then 把结果传递给 gotDevices 函数处理。
用以下代码替换现有的 getUserMedia 调用:
button.addEventListener('click', event => { if (typeof currentStream !== 'undefined') { stopMediaTracks(currentStream); } const videoConstraints = {}; if (select.value === '') { videoConstraints.facingMode = 'environment'; } else { videoConstraints.deviceId = { exact: select.value }; } const constraints = { video: videoConstraints, audio: false }; navigator.mediaDevices .getUserMedia(constraints) .then(stream => { currentStream = stream; video.srcObject = stream; return navigator.mediaDevices.enumerateDevices(); }) .then(gotDevices) .catch(error => { console.error(error); });});
当你添加完所有的代码,你的 app.js 应该看起来像这个文件一样。刷新页面然后你就能愉快地选择和改变摄像头了。这个页面在移动设备和电脑上都有效。
下一步
我们已经看到如何通过使用 facingMode 和 deviceId 约束来选择用户的摄像头。记住,在你有权限使用摄像头之前,facingMode 更可靠,但是选择 deviceId 更加精确。你可以从 GitHub 仓库 中得到所有本文中的代码,你也可以从这里尝试在线版的应用。
如果你正在使用 Twilio Video 构建视频应用,你可以在调用 connect 或者 createLocalVideoTrack 的时候使用这些 constraints。
Twilio地址:
对于视频聊天来说,选择和切换摄像头是非常有用的功能,允许用户在你的应用界面准确地选择他们想用的摄像头,并且还能做到在视频通话时分享你的屏幕。
参考链接:
推荐JavaScript经典实例学习资料文章
《手把手教你前端代码如何做错误上报「JS篇」》
《一文让你彻底搞懂移动前端和Web 前端区别在哪里》
《63个JavaScript 正则大礼包「值得收藏」》
《提高你的 JavaScript 技能10 个问答题》
《JavaScript图表库的5个首选》
《一文彻底搞懂JavaScript 中Object.freeze与Object.seal的用法》
《可视化的 JS:动态图演示 - 事件循环 Event Loop的过程》
《教你如何用动态规划和贪心算法实现前端瀑布流布局「实践」》
《可视化的 js:动态图演示 Promises & Async/Await 的过程》
《原生JS封装拖动验证滑块你会吗?「实践」》
《如何实现高性能的在线 PDF 预览》
《细说使用字体库加密数据-仿58同城》
《Node.js要完了吗?》
《Pug 3.0.0正式发布,不再支持 Node.js 6/8》
《纯JS手写轮播图(代码逻辑清晰,通俗易懂)》
《JavaScript 20 年 中文版之创立标准》
《值得收藏的前端常用60余种工具方法「JS篇」》
《箭头函数和常规函数之间的 5 个区别》
《通过发布/订阅的设计模式搞懂 Node.js 核心模块 Events》
《「前端篇」不再为正则烦恼》
《「速围」Node.js V14.3.0 发布支持顶级 Await 和 REPL 增强功能》
《深入细品浏览器原理「流程图」》
《JavaScript 已进入第三个时代,未来将何去何从?》
《前端上传前预览文件 image、text、json、video、audio「实践」》
《深入细品 EventLoop 和浏览器渲染、帧动画、空闲回调的关系》
《推荐13个有用的JavaScript数组技巧「值得收藏」》
《前端必备基础知识:window.location 详解》
《不要再依赖CommonJS了》
《犀牛书作者:最该忘记的JavaScript特性》
《36个工作中常用的JavaScript函数片段「值得收藏」》
《Node + H5 实现大文件分片上传、断点续传》
《一文了解文件上传全过程(1.8w字深度解析)「前端进阶必备」》
《【实践总结】关于小程序挣脱枷锁实现批量上传》
《手把手教你前端的各种文件上传攻略和大文件断点续传》
《字节跳动面试官:请你实现一个大文件上传和断点续传》
《谈谈前端关于文件上传下载那些事【实践】》
《手把手教你如何编写一个前端图片压缩、方向纠正、预览、上传插件》
《最全的 JavaScript 模块化方案和工具》
《「前端进阶」JS中的内存管理》
《JavaScript正则深入以及10个非常有意思的正则实战》
《前端面试者经常忽视的一道JavaScript 面试题》
《一行JS代码实现一个简单的模板字符串替换「实践」》
《JS代码是如何被压缩的「前端高级进阶」》
《前端开发规范:命名规范、html规范、css规范、js规范》
《【规范篇】前端团队代码规范最佳实践》
《100个原生JavaScript代码片段知识点详细汇总【实践】》
《关于前端174道 JavaScript知识点汇总(一)》
《关于前端174道 JavaScript知识点汇总(二)》
《关于前端174道 JavaScript知识点汇总(三)》
《几个非常有意思的javascript知识点总结【实践】》
《都2020年了,你还不会JavaScript 装饰器?》
《JavaScript实现图片合成下载》
《70个JavaScript知识点详细总结(上)【实践】》
《70个JavaScript知识点详细总结(下)【实践】》
《开源了一个 JavaScript 版敏感词过滤库》
《送你 43 道 JavaScript 面试题》
《3个很棒的小众JavaScript库,你值得拥有》
《手把手教你深入巩固JavaScript知识体系【思维导图】》
《推荐7个很棒的JavaScript产品步骤引导库》
《Echa哥教你彻底弄懂 JavaScript 执行机制》
《一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧》
《深入解析高频项目中运用到的知识点汇总【JS篇】》
《JavaScript 工具函数大全【新】》
《从JavaScript中看设计模式(总结)》
《身份证号码的正则表达式及验证详解(JavaScript,Regex)》
《浏览器中实现JavaScript计时器的4种创新方式》
《Three.js 动效方案》
《手把手教你常用的59个JS类方法》
《127个常用的JS代码片段,每段代码花30秒就能看懂-【上】》
《深入浅出讲解 js 深拷贝 vs 浅拷贝》
《手把手教你JS开发H5游戏【消灭星星】》
《深入浅出讲解JS中this/apply/call/bind巧妙用法【实践】》
《手把手教你全方位解读JS中this真正含义【实践】》
《书到用时方恨少,一大波JS开发工具函数来了》
《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《手把手教你JS 异步编程六种方案【实践】》
《让你减少加班的15条高效JS技巧知识点汇总【实践】》
《手把手教你JS开发H5游戏【黄金矿工】》
《手把手教你JS实现监控浏览器上下左右滚动》
《JS 经典实例知识点整理汇总【实践】》
《2.6万字JS干货分享,带你领略前端魅力【基础篇】》
《2.6万字JS干货分享,带你领略前端魅力【实践篇】》
《简单几步让你的 JS 写得更漂亮》
《恭喜你获得治疗JS this的详细药方》
《谈谈前端关于文件上传下载那些事【实践】》
《面试中教你绕过关于 JavaScript 作用域的 5 个坑》
《Jquery插件(常用的插件库)》
《【JS】如何防止重复发送ajax请求》
《JavaScript+Canvas实现自定义画板》
《Continuation 在 JS 中的应用「前端篇」》
标签: #js监控屏幕