在 HTML5 中捕获音频和视频
简介
长久以来,音频/视频捕获都是网络开发中的“圣杯”。多年来,我们总是依赖于浏览器插件(Flash 或 Silverlight)实现这一点。快来看看吧!
现在轮到 HTML5 大显身手了。也许看起来不是很显眼,但是 HTML5 的崛起引发了对设备硬件访问的激增。地理位置 (GPS)、Orientation API(加速计)、WebGL(GPU) 和 Web Audio API(视频硬件)都是很好的例子。这些功能非常强大,展示了基于系统底层硬件功能之上的高级 JavaScript API。
本教程介绍了一种新 API:navigator.getUserMedia(),可让网络应用访问用户的相机和麦克风。
getUserMedia() 的历史
如果您还不知道,getUserMedia() 的历史可谓一段有趣的故事。
过去几年中出现过好几种“Media Capture API”的变体。很多人意识到,需要能够在网络上访问本地设备,但这要所有人合力开发出一种新的规范。局面一片混乱,以至于 W3C 最终决定成立一个工作组。他们只有一个目的:理清混乱的局面!设备 API 政策 (DAP) 工作组负责对过剩的提议进行统一和标准化。
我会试着总结一下 2011 所发生的事情...
第 1 轮:HTML 媒体捕获
HTML 媒体捕获是 DAP 在网络媒体捕获标准化上迈出的第一步。具体方法是超载<input type="file"> 并为 accept 参数添加新值。
如果您要让用户通过网络摄像头拍摄自己的快照,就可以使用 capture=camera:
<input type="file" accept="image/*;capture=camera">
录制视频或音频也是类似的:
<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">
挺不错吧?它可以重复使用文件输入,这点我特别喜欢。这在语义上非常有意义。这种特定“API”的不足之处在于,无法处理即时效果(例如将实时网络摄像头数据呈现到 <canvas> 并应用 WebGL 过滤器)。HTML 媒体捕获只能让您录制媒体文件或及时拍摄快照。
支持:
- Android 3.0 浏览器 - 首次实施的一个例子。请观看此视频,了解其实际使用情况。
- Android 版 Chrome 浏览器 (0.16)
除非您使用的是以上某个移动浏览器,否则我建议您不要使用该 API。供应商纷纷转向 getUserMedia()。其他任何人都不太可能会长期实施 HTML 媒体捕获。
第 2 轮:设备元素
很多人认为 HTML 媒体捕获的局限性太大,因此一种新的规范应运而生,可以支持任何类型的(未来)设备。不出意料地,该设计需要新的 <device>元素,也就是getUserMedia() 的前身。
Opera 是第一批根据 <device> 元素创建视频捕获的初始实施的浏览器之一。不久之后(准确地说是同一天),WhatWG 决定废止 <device> 标记,以支持称为navigator.getUserMedia() 的新兴 JavaScript API。一周后,Opera 推出的新版本中加入了对更新的 getUserMedia() 规范的支持。当年年底,Microsoft 也加入这一行列,发布了 IE9 实验室以支持新规范。
<device> 的效果如下:
<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>
function update(stream) {
document.querySelector('video').src = stream.url;
}
</script>
支持:
很遗憾,已发布的浏览器中没有任何一款曾经包含 <device>。我猜这是一个不太需要担心的 API。但是 <device> 确实有两大优点:一是语义方面,二是可以轻松进行扩展,而不仅仅是支持音频/视频设备。
现在深吸一口气。这玩意儿速度飞快!
第 3 轮:WebRTC
<device> 元素最终还是像渡渡鸟一样销声匿迹了。
依靠 WebRTC(网络即时通信)的大力协助,最近几个月寻找合适捕获 API 的步伐加快了很多。该规范由 W3C WebRTC 工作组负责监管。Google、Opera、Mozilla 和其他一些公司目前正致力于在自己的浏览器中实施该 API。
getUserMedia() 与 WebRTC 相关,因为它是通向这组 API 的门户。它提供了访问用户本地相机/麦克风媒体流的手段。
支持:
在 Chrome 浏览器 18.0.1008 和更高版本中,可在 about:flags 下启用 WebRTC。
使用入门
利用 navigator.getUserMedia(),我们最终实现了在没有插件的情况下访问网络摄像头和麦克风输入内容。相机访问权限现在和调用有关,而不是和安装有关。它直接内嵌在浏览器中。感到兴奋了吗?
启用
getUserMedia() API 还很新,只有 Google 和 Opera 在开发人员版本中加入了它。在 Chrome 18 和更高版本中,可通过访问 about:flags 启用该 API。

在 Chrome 浏览器的 about:flags 页中启用 getUserMedia()。
对于 Opera,请下载某个实验性 Android 和桌面计算机版本。
功能检测
功能检测是简单地检查是否存在 navigator.getUserMedia:
function hasGetUserMedia() {
// Note: Opera builds are unprefixed.
return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia);
}
if (hasGetUserMedia()) {
// Good to go!
} else {
alert('getUserMedia() is not supported in your browser');
}
获取输入设备的访问权限:
要使用网络摄像头或麦克风,我们需要请求权限。getUserMedia() 的第一个参数用于指定您要访问的媒体类型。例如,如果您要请求访问网络摄像头,第一个参数就应该是 "video"。要同时使用麦克风和相机,则传递 "video, audio":
<video autoplay></video> <script>
var onFailSoHard=function(e) {
console.log('Reeeejected!', e);
}; // Not showing vendor prefixes.
navigator.getUserMedia('video, audio', function(localMediaStream) {
var video = document.querySelector('video');
video.src = window.URL.createObjectURL(localMediaStream); // Note: onloadedmetadata doesn't fire in Chrome when using it with getUserMedia.
// See crbug.com/110938.
video.onloadedmetadata = function(e) {
// Ready to go. Do some stuff.
};
}, onFailSoHard);
</script>
好吧,这到底是怎么一回事呢?媒体捕获是各种新 HTML5 API 进行协作的绝佳示例。参与协作的还有其他一些 HTML 元素,例如 <audio> 和 <video>。请注意,我们不是要设置 src 属性或在 <video> 元素中加入 <source> 元素。我们不会向视频馈入媒体文件的网址,而是馈入从代表网络摄像头的 LocalMediaStream 对象获得的 Blob 网址。
我还会将 <video> 设置为 autoplay,否则它会停在第一帧。添加 controls 也能达到您预期的效果。
请注意:在 Chrome 浏览器中存在一个错误,导致仅仅传递“audio”无效:crbug.com/112367。我也无法在 Opera 中正常使用 <audio>。
Opera 和 Chrome 浏览器实施的是该规范的不同版本。这导致实际使用起来要比预期的更有“挑战性”。
在 Chrome 浏览器中:
该代码段适用于 Chrome 18 和更高版本(在 about:flags 中启用):
navigator.webkitGetUserMedia('audio, video', function(localMediaStream) {
var video = document.querySelector('video');
video.src = window.webkitURL.createObjectURL(localMediaStream);
}, onFailSoHard);
在 Opera 中:
Opera 开发人员版本不支持该规范的更新版本。该代码段适用于 Opera:
navigator.getUserMedia({audio: true, video: true}, function(localMediaStream) {
video.src = localMediaStream;
}, onFailSoHard);
关键的区别之处在于:
getUserMedia()是无前缀的。- 对象作为第一个参数而不是字符串列表进行传递。
- 将
video.src直接设置为LocalMediaStream对象,而不是 Blob 网址。据我所知,Opera 最终会更新此设置,改为要求 Blob 网址。
对于这两者:
如果您希望能跨浏览器通用(但是这样很容易出问题),请尝试如下方法:
var video = document.querySelector('video');
if (navigator.getUserMedia) {
navigator.getUserMedia({audio: true, video: true}, function(stream) {
video.src = stream;
}, onFailSoHard);
} else if (navigator.webkitGetUserMedia) {
navigator.webkitGetUserMedia('audio, video', function(stream) {
video.src = window.webkitURL.createObjectURL(stream);
}, onFailSoHard);
} else {
video.src = 'somevideo.webm'; // fallback.
}
请务必查看 Mike Taylor 和 Mike Robinson 的 gUM Shield。它可以很好地将各浏览器实施之间的不一致“标准化”。
安全
将来,浏览器在调用 getUserMedia() 时可能会弹出信息栏,让用户选择授予还是拒绝对其相机/麦克风的访问权限。很遗憾,该规范在安全方面非常薄弱。目前,没有任何浏览器实施了权限栏。
提供回退
对于无法获得 getUserMedia() 支持的用户,如果 API 不受支持且/或由于某些原因而调用失败,可以选择回退到现有的视频文件:
// Not showing vendor prefixes or code that works cross-browser:
function fallback(e) {
video.src = 'fallbackvideo.webm';
}
function success(stream) {
video.src = window.URL.createObjectURL(stream);
}
if (!navigator.getUserMedia) {
fallback();
} else {
navigator.getUserMedia({video: true}, success, fallback);
}
<canvas> API 的 ctx.drawImage(video, 0, 0) 方法可以轻松地将 <video> 帧绘制到 <canvas> 上。当然,既然我们通过 getUserMedia() 获得了视频输入,就可轻松地使用即时视频创建照相亭应用了。
<video autoplay></video>
<img src="">
<canvas style="display:none;"></canvas> var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var localMediaStream = null; function snapshot() {
if (localMediaStream) {
ctx.drawImage(video, 0, 0);
// "image/webp" works in Chrome 18. In other browsers, this will fall back to image/png.
document.querySelector('img').src = canvas.toDataURL('image/webp');
}
} video.addEventListener('click', snapshot, false); // Not showing vendor prefixes or code that works cross-browser.
navigator.getUserMedia({video: true}, function(stream) {
video.src = window.URL.createObjectURL(stream);
localMediaStream = stream;
}, onFailSoHard);
总结
总体而言,网络上的设备访问向来是一大难题。很多人曾经尝试过,但是没什么人取得成功。大多数早期的思路从未在专有环境之外占据主导地位,也从未广泛采用过。
真正的问题在于,网络的安全模式与本地系统有天壤之别。例如,我可能不希望随便什么网站都有权访问我的摄像机,但是这个问题很难解决。
PhoneGap 等桥接框架有助于突破这方面的限制,但这种临时性的解决方案对于深层的根本问题而言还远远不够。要让网络应用具备与桌面计算机应用一较高下的实力,我们需要能够访问本地设备。
getUserMedia() 仅仅是对新设备类型的第一波访问。我希望在不久的将来能看到更多。
摘自:https://www.html5rocks.com/zh/tutorials/getusermedia/intro/
在 HTML5 中捕获音频和视频的更多相关文章
- 网页中创建音频、视频和Flash等多媒体:object元素
<object>元素:它主要用于定义网页中的多媒体,比如音频.视频.Java applets.PDF.ActiveX和Flash.Object标签是成对出现的,在object标签内可以使用 ...
- 小强的HTML5移动开发之路(15)——HTML5中的音频
浏览器虽然发展很快,但是浏览器中的标准还是不完善,在HTML4+CSS2+JS的前段开发中让很多程序员头疼的就是浏览器的兼容性问题,音频播放也一样,直到现在,仍然不存在一项网页上播放视频和音频的标准. ...
- 总结: 在fc23中, 安装音频mp3 视频flv 的播放插件其实很简单, 只要一步就可以了: dnf install gstreamer1-libav
同样是 firefox, 单词的在线发音, 跟 百度mp3的在线播放不是一样的!!! 百度/优酷 的在线播放, 用的确实是 flash player , 所以 你安装好libflashplayer后, ...
- [译] 用HTML5捕获音频和视频
原文地址:http://www.html5rocks.com/en/tutorials/getusermedia/intro/ 概述 有了HTML5,我们就可以在不借助Flash或者Silverlig ...
- 【Android】实验6 在应用程序中播放音频和视频 截止提交报告时间2016.4.21
注:也可以在数独游戏项目中完成该实验的内容.
- html5音频和视频标签
在html5之前的版本中如果想要在网页中插入音频和视频必须要安装插件才可以,比如最常见的flash插件.很多人在刚安装一款浏览器的时候都会遇到浏览器建议安装flash插件,在移动端也是如此.如果想要在 ...
- html5 音频和视频(audio And video)
1.音频和视频 Web 上的视频 直到现在,仍然不存在一项旨在网页上显示视频的标准. 今天,大多数视频是通过插件(比如 Flash)来显示的.然而,并非所有浏览器都拥有同样的插件. HTML5 规定 ...
- html5页面怎么播放音频和视频
html5页面怎么播放音频和视频 一.总结 一句话总结:html5 音频和视频标签:(audio And video),局限是不同浏览器对音频视频的格式支持很让人头痛 1.最基础的音频和视频标签的使用 ...
- 详解HTML5中rel属性的prefetch预加载功能使用
在HTML5中,有个很有用但常被忽略的特性,就是预先加载(prefetch),它的原理是: 利用浏览器的空闲时间去先下载用户指定需要的内容,然后缓存起来,这样用户下次加载时,就直接从缓存中取出来,效率 ...
随机推荐
- MySQL双主一致性架构优化
一.双主保证高可用 MySQL数据库集群常使用一主多从,主从同步,读写分离的方式来扩充数据库的读性能,保证读库的高可用,但此时写库仍然是单点. 在一个MySQL数据库集群中可以设置两个主库,并设置双向 ...
- 重新编译Linux内核必要性及其准备工作
内核简介 内核,是一个操作系统的核心.它负责管理系统的进程.内存.设备驱动程序.文件和网络系统,决定着系统的性能和稳定性. Linux的一个重要的特点就是其源代码的公开性,所有的内核源程序都可以在/u ...
- @restcontroller与@controller的区别
这段时间偷偷看了下spring boot.结果引用模板时没注意,把@restcontroller替换了@controlle,结果模板出不来.终究原因是spring的知识不到位. 下面说说这2的说明和区 ...
- mysql常用基础操作语法(三)~~对数据的增删改操作【命令行模式】
1.插入单条数据:insert into tablename(字段名1,字段名2,...) values(值1,值2,...); 从图中可以看出,插入时不需要每个字段都有值(在没有相关的约束前提下), ...
- mongodb一些使用技巧或注意事项记录
1.有的时候需要删除指定字段那一列,使用update操作.例如要删除name这一列: query json: {"name":{$exists:true}} update jso ...
- IE浏览器因缓存问题未能成功向后端发送请求的几个解决办法
这段时间前后端联调,解决IE.谷歌等浏览器兼容问题,真是让人有点焦头烂额,各种奇葩问题层出不穷,旧问题刚去,新麻烦又来,其中尤其以IE浏览器缓存的问题最多.有若干次都是因为这个缓存,使得前端的请求没有 ...
- FusionCharts MSBar3D图
1.静态页面 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> ...
- VxWorks 操作系统内存布局
在VxWorks操作系统过程中可能使用到的BootRom和VxWorks内核映像本身都可以存在两种方式:压缩的和非压缩的. 1.非压缩形式 如果没有进行压缩,则只有一次重定位,即从ROM到RAM只存在 ...
- linux内核移植X86平台的例子
bootloader支持启动多个Linux 内核安装(X86平台) 1. cparch/x86/boot/bzImage /boot/vmlinuz-$version 2. cp $initrd /b ...
- C#之AES256位加密解密
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分 ...