JavaScript操作摄像头指南

前端js调取摄像头并实现拍照功能 实现拍照的整体思路其实很简单,仅仅需要了解到视频其实也是一帧一帧画面构成的,而 canvas 恰好有捕捉当前帧的能力。 阅读详情

英文:Phil Nash  译文:众成翻译/Will Liu

www.zcfy.cc/article/choosing-cameras-in-javascript-with-the-mediadevices-api

大多数智能手机都有前置和后置摄像头,当你在创建视频应用时你可能想要选择或者切换前置、后置摄像头。

如果你开发的是一款聊天应用,你很可能会想调用前置摄像头,但如果你开发的是一款拍照软件,那么你会更倾向于使用后置摄像头。在这篇文章中我们将探讨如何通过 mediaDevices API 和 media constraints (媒体约束) 选择或者切换摄像头。

准备工作

要跟着本文一起动手实践你需要:

  • 一款拥有两个可供测试的摄像头的 iOS 或 Android 设备,如果你的电脑有两个摄像头那也可以
  • ngrok 以便你能通过移动设备轻松访问到你的项目(也因为我觉得 ngrok 炒鸡棒)
  • 这个 GitHub 库 的代码让你起步

要获取代码,先把这个项目 clone 下来然后 checkout 到 initial-project tag 下。

git clone https://github.com/philnash/mediadevices-camera-selection.git -b initial-project
cd mediadevices-camera-selection

这个起步项目已经为你准备好了一些 HTML 和 CSS,所以我们就可以把注意集中到 JavaScript 上了。你可以直接打开 index.html,但我建议你用一款 webserver 把这些文件托管起来。我喜欢用 npm 的 serve 模块。我在这个库里已经引入了 serve,要使用它你需要先用 npm 安装依赖然后启动这个服务。

npm install
npm start

服务运行起来后,我们要用 ngrok 开启一条隧道。serve 用 5000 端口托管文件,要用 ngrok 开隧道通到这个端口,新开一个命令行窗口输入以下命令:

ngrok http  5000

好了你现在可以公网访问这个站点了,你可以在移动设备上打开这个网站,这样接下来就可以测试啦。确保你打开的是 HTTPS 的 URL,因为我们用的 API 只能在安全环境下使用。

ngrok 窗口显示了两个你可以用的 URL,选 HTTPS 版本的。

网站看起来像这样:

网站应该有一个 'Camera fun' 的标题,一个按钮和一个空的下拉选择框

获取 media stream

我们的第一个任务是从任意摄像头获取视频流显示到屏幕上。完成这个之后我们再调研如何选择特定摄像头。打开 app.js , 我们以从 DOM 中选择按钮和 video 元素开始:

// app.js
const  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。

对于视频聊天来说,选择和切换摄像头是非常有用的功能,允许用户在你的应用界面准确地选择他们想用的摄像头,并且还能做到在视频通话时分享你的屏幕。

前端调取摄像头并实现拍照功能 实现拍照的整体思路其实很简单,仅仅需要了解到视频其实也是一帧一帧画面构成的,而canvas恰好有捕捉当前帧的能力。预告:在下一篇会讲解如何实现扫一扫的功能,需要用到插件,感兴趣的同学可以先预习一下功课。🎁二维码扫码插件趁热打铁前端实现微信扫一扫的思路。 阅读详情

相关推荐

HTML JS调用摄像头

启动本地服务 或者 远程服务器例如window.location.host,但是无法获取本地摄像头,这是因为目前的浏览器不支持getUSERmedia (安全问题:如果通过未加密的HTTP启用它,则会允许攻击者注入侦听的代码并将对话发送给攻击者。例如,如果您在酒店的私人会议室中使用未加密的WiFi,酒店附近的每个人都可以收听。即使您的应用通常不处理敏感对话,攻击者也可以用当他们正在使用另一个应用...

一摩尔自由的博客 6708

H5前后摄像头切换功能实现(VUE写法和原生js写法都有)

js调用本地摄像头,前后摄像头切换,vue调用本地摄像头,vue前后摄像头切换

阿布阿朵 5276

AR.js摄像头前置的问题(已解决)(H5调用摄像头)

                                          AR.js摄像头前置的问题(已解决)         终于放假了,开始搬砖。很多开发者对AR.js摄像头前置的这个问题比较苦恼,网上也有很多解决办法,但是有些过时。接下来,我们来一起解决这个问题。先看一下效果。(PS:下面的QQ摄像头图,标注反了)          不久前,我看一片关于WebAR的文章,很...

Webglzhang 1万+

JS调用摄像头

&lt;!doctype html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8"&gt; &lt;meta name="viewport" content="width=device-width, user-scalable=no, initial

天边那朵云的博客 1936

js获取摄像头权限实现拍照功能

首先说一下js打开摄像头的流程: 使用getUserMedia打开摄像头然后将获取到的流媒体转成url放在video标签中的src中; 使用canvas的drawImage方法将video的内容绘至canvas中,这样就形成了截图的效果; 使用stream.getTracks()[0].stop()关闭摄像头。 1.开启摄像头 开启摄像头主要有两种方法,一个是旧方法window.navigator.getUserMedia()方法,还有一个就是新方法navigator.mediaDevices.get

qq_45279180的博客 6418

html+js 调用摄像头识别二维码

1.html调起摄像头,参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia 2.识别二维码,QRcode.js IIS发布测试请用https端口 整体思路就是:调起摄像头 =>截屏 =>调用QRcode识别图片二维码 =>返回识别结果 样例代码:也可以下...

m0_37693130的博客 3053

HTML5调用手机前置摄像头或后置摄像头拍照,canvas显示,经过Android测试

HTML5,调用手机前置摄像头,调用手机后置摄像头

小朱的专栏 5万+

HTML5通过js调用手机摄像头

HTML5 调用手机摄像头      window.addEventListener("DOMContentLoaded", function() { var canvas = document.getElementById("canvas"), context = canvas.getContext("2d"), video = document.getElementById

蚂蚁小帅哥的专栏 2万+

海康威视摄像头web端播放

参考:https://blog.youkuaiyun.com/Staveabc/article/details/98194427 基本架构:FFmpeg+node.js+jsmpeg 软件安装连接: 1、FFmpeg安装,地址:https://www.bytesin.com/software/Download-FFmpeg/ 2、node.js下载地址:https://nodejs.org/zh-cn/ 3、jsmpeg下载地址:https://github.com/phoboslab/jsmpeg FFm

weixin_44174243的博客 2813

UI-TARS本地部署

UI-TARS是一个用于本地部署的交互控制模型,支持桌面应用的自动化操作。部署步骤包括:首先,从官方GitHub仓库下载项目源码和模型checkpoint;其次,使用vLLM框架进行本地模型部署,启动API服务;最后,通过客户端调用API实现功能。部署过程中可能遇到pynvml模块或模型配置问题,提供了相应的解决方案。此外,还支持通过UI-TARS-Desktop客户端进行本地桌面应用的交互控制。整体流程旨在帮助用户快速实现UI-TARS的本地部署与应用。

DYF的博客 2531

(MATLAB)一维信号峰值检测findpeaks

一维信号波峰波谷检测,峰值、峰宽、到达时间计算。MATLAB自带的findpeaks函数能完成这一任务,在这里分享其基本用法与特殊用法。

HPC_ZY 2万+

使用js打开摄像头和拍照

使用js打开摄像头和拍照 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equ...

Major_S的博客 1278

VirusTotal API密钥获取与Python实战:从注册到自动化威胁分析

在网络安全和自动化运维领域,API(应用程序编程接口)是实现系统间数据交互与功能集成的核心技术。其工作原理是通过预定义的协议和端点,允许程序化访问特定服务的数据与功能。对于安全工程师和威胁分析师而言,API的价值在于能够将手动、重复的安全操作(如文件扫描、情报查询)转化为自动化工作流,从而极大提升威胁检测与响应的效率。一个典型的应用场景是集成第三方威胁情报平台,以实现对可疑文件、URL或哈希值的批量与实时分析。本文聚焦于全球知名的威胁情报服务VirusTotal,详细解析其API密钥的注册流程、安全配置要点

weixin_28707739的博客 420

Node.js V4L2 Camera 开源项目指南

Node.js V4L2 Camera 开源项目指南 项目概述 Node.js V4L2 Camera 是一个专为Linux系统设计的npm包,允许开发者通过USB(UVC)摄像头捕获图像。该项目托管在GitHub上,遵循MIT许可协议,适用于需要集成摄像头功能的Node.js应用程序。 1. 目录结构及介绍 以下展示的是node-v4l2camera的基本目录架构及其简要说明: - node-v...

gitblog_00315的博客 610

数据资产目录(SailCatalog)和数据地图(SailMap)

笔者接下来准备开发大数据平台(XSailboat)中的数据资产目录(SailCatalog)和数据地图(SailMap)相关的功能,本文用以记录笔者关于此部分功能的概念梳理和主体功能设计。

OkGogooXSailboat的博客 2326

智能座舱测试工程师必看:从零搭建自动化测试框架的5个实战技巧

本文为智能座舱测试工程师提供从零搭建自动化测试框架的5个实战技巧,涵盖环境搭建、ADB高级应用、Python脚本工程化、Monkey测试优化及性能调优。通过ADB深度操作和Python脚本封装,帮助测试人员构建高可复用的智能座舱测试解决方案,显著提升测试效率与问题发现率。

python9snake的博客 634

js获取摄像头中的视频流并上传到后台

今天研究了下js获取摄像头中的视频流,全网搜索相关的文章,终于上天不负有心人。以下是原文代码: html: <!DOCTYPE html> <html> <head> <title>video recoder</title> <script src="../js/fileSaver.js"></script&...

weixin_44411302的博客 1万+

一、OpenSM 架构部署及原理详解

OpenSM 是 InfiniBand 网络的核心组件,通过自动化的拓扑发现、路由计算和状态维护,确保网络的高效运行。部署时需关注配置文件参数、路由算法选择和高可用性设计,调试时可借助日志和诊断工具快速定位问题。

jundao1997的专栏 1130

网页端接入海康摄像头画面操作指南

一、摄像头rtsp流画面测试 首先根据相关摄像头内附的说明书对摄像头进行安装以及wifi配置或者通过网线直连,配置完成后确保摄像头画面能够在手机APP或者相关应用程序上正常播放。 然后进入海康威视官网下载并安装SADP摄像头IP搜索工具。 打开SADP(设备网络搜索),即能查看当前局域网下的所有海康摄像头IP地址。 下面进行摄像头rtsp流播放测试: 1.下载VLC media player,并安装打开。 2.打开媒体 --> 网络串流 --> 网络。 3.输入海康摄像头的rtsp地址并进

weixin_45350072的博客 3万+

基于fme和python-docx第三方库批量更新不动产调查表

最近应朋友需要批量更新在不动产成果中提交的各种word报表中的指定数据,根据初步的了解,我做了一个基于fme软件和python-docx第三方库进行一个批量的更新方案。

weixin_43229258的博客 1240

华为OD新系统机试真题 - 获取大写字母瓷砖拼出独特图案数量

华为OD机试新系统真题【获取大写字母瓷砖拼出独特图案数量】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD新系统四月二十九号机试真题【获取大写字母瓷砖拼出独特图案数量】

qq_45776114的博客 1218

实战指南:使用 JavaScript 访问网络摄像头

网络摄像头访问是网络应用程序中的一项流行功能,它扩大了从视频聊天到实时拍摄照片的各种范围。本文将向您展示如何使用 JavaScript 手动访问和关闭网络摄像头,并在关闭摄像头时将背景设置为黑色。我们将使其变得易于理解和遵循,以便您可以开始将此功能集成到您自己的 Web 项目中。使用 WebRTC API 在 JavaScript 中手动访问和关闭网络摄像头非常简单。通过执行这些简单的步骤,您可以将网络摄像头功能集成到您的 Web 应用程序中,并在关闭摄像头时将背景设置为黑色。

m0_55666986的博客 2120

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

JavaScript如何调用摄像头

如何使用浏览器调用摄像头

沐水莲心的博客 1万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

JavaScript摄像头输入封装库——camera.js

JavaScript摄像头输入封装库——camera.js 1. 项目基础介绍 camera.js 是一个开源的JavaScript库,由 Andrei Gheorghe 开发。该项目提供了一个简单的封装,围绕HTML5的 getUserMedia API,以实现对用户摄像头视频流的跨浏览器访问。这个库的目的是简化获取和操作摄像头视频流的过程,使得开发者可以更加方便地在其Web应用中集成视频捕获功...

gitblog_00063的博客 637

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JavaScript打开摄像头

html部分 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>一、</title> </head> <body> <video id="video" playsinline=""></video> <input type="button" class="layui-btn

xianghai 1656

如何使用JavaScript访问设备前后置摄像头,真人出镜!

在这篇文章中,我将向您展示如何通过JavaScript在网页上访问设备的摄像头,并支持多种浏览器,而无需外部库。 如何使用相机API 要访问用户的相机(或麦克风),我们使用JavaScript MediaStream API。该API允许通过流访问这些设备捕获的视频和音频。 第一步是检查浏览器是否支持此API: if ( "mediaDevices" in navigator && "getUserMedia" in navigator.mediaDevices ) { // .

前端全栈开发者 6006
上一篇: 我猜,每个程序员对着电梯都想过调度算法吧!
下一篇: 一秒看懂的 async/await
! 不再维护
博客等级 码龄11年 63粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值